using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Domain.Entities.Paper;
///
/// 모의투자 체결 결과 — 주문당 1건(OrderID UNIQUE)으로 재실행 멱등을 보장한다 (d4 §③).
/// 배치(M2)가 TargetDate 시세로 기표한다. 매도 시 RealizedPnL(실현손익)을 기록.
///
public class PaperFill
{
[ForeignKey(nameof(OrderID))]
public virtual PaperOrder Order { get; private set; } = null!;
[Key]
public int ID { get; private set; }
public int OrderID { get; private set; }
/// 체결가 (18,0)
public decimal Price { get; private set; }
public int Quantity { get; private set; }
/// 수수료 (토큰 sink)
public decimal Fee { get; private set; }
/// 거래세 (매도 시, 토큰 sink)
public decimal Tax { get; private set; }
/// 체결 총액 (Price × Quantity ± 수수료/세금 반영은 핸들러/배치 정책)
public decimal Amount { get; private set; }
/// 매도 확정 손익 (매수는 null)
public decimal? RealizedPnL { get; private set; }
/// 체결가 기준일
public DateOnly PriceDate { get; private set; }
public DateTime FilledAt { get; private set; } = DateTime.UtcNow;
private PaperFill() { }
public static PaperFill Create(
int orderID,
decimal price,
int quantity,
decimal fee,
decimal tax,
decimal amount,
DateOnly priceDate,
decimal? realizedPnL = null
) {
if (orderID <= 0)
{
throw new ArgumentOutOfRangeException(nameof(orderID));
}
if (quantity <= 0)
{
throw new ArgumentOutOfRangeException(nameof(quantity));
}
return new PaperFill
{
OrderID = orderID,
Price = price,
Quantity = quantity,
Fee = fee,
Tax = tax,
Amount = amount,
PriceDate = priceDate,
RealizedPnL = realizedPnL
};
}
///
/// 신규 주문(ID 미확정) 케이스 — Order 내비게이션으로 생성해 EF 가 저장 시 FK(OrderID)를 자동 채우게 한다.
/// 상폐 강제청산 등 시스템 주문+체결을 한 번에 저장할 때 사용 (d4 §⑨).
///
public static PaperFill CreateFor(
PaperOrder order,
decimal price,
int quantity,
decimal fee,
decimal tax,
decimal amount,
DateOnly priceDate,
decimal? realizedPnL = null
) {
ArgumentNullException.ThrowIfNull(order);
if (quantity <= 0)
{
throw new ArgumentOutOfRangeException(nameof(quantity));
}
return new PaperFill
{
Order = order,
Price = price,
Quantity = quantity,
Fee = fee,
Tax = tax,
Amount = amount,
PriceDate = priceDate,
RealizedPnL = realizedPnL
};
}
}