PaperFill.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. namespace Domain.Entities.Paper;
  4. /// <summary>
  5. /// 모의투자 체결 결과 — 주문당 1건(OrderID UNIQUE)으로 재실행 멱등을 보장한다 (d4 §③).
  6. /// 배치(M2)가 TargetDate 시세로 기표한다. 매도 시 RealizedPnL(실현손익)을 기록.
  7. /// </summary>
  8. public class PaperFill
  9. {
  10. [ForeignKey(nameof(OrderID))]
  11. public virtual PaperOrder Order { get; private set; } = null!;
  12. [Key]
  13. public int ID { get; private set; }
  14. public int OrderID { get; private set; }
  15. /// <summary>체결가 (18,0)</summary>
  16. public decimal Price { get; private set; }
  17. public int Quantity { get; private set; }
  18. /// <summary>수수료 (토큰 sink)</summary>
  19. public decimal Fee { get; private set; }
  20. /// <summary>거래세 (매도 시, 토큰 sink)</summary>
  21. public decimal Tax { get; private set; }
  22. /// <summary>체결 총액 (Price × Quantity ± 수수료/세금 반영은 핸들러/배치 정책)</summary>
  23. public decimal Amount { get; private set; }
  24. /// <summary>매도 확정 손익 (매수는 null)</summary>
  25. public decimal? RealizedPnL { get; private set; }
  26. /// <summary>체결가 기준일</summary>
  27. public DateOnly PriceDate { get; private set; }
  28. public DateTime FilledAt { get; private set; } = DateTime.UtcNow;
  29. private PaperFill() { }
  30. public static PaperFill Create(
  31. int orderID,
  32. decimal price,
  33. int quantity,
  34. decimal fee,
  35. decimal tax,
  36. decimal amount,
  37. DateOnly priceDate,
  38. decimal? realizedPnL = null
  39. ) {
  40. if (orderID <= 0)
  41. {
  42. throw new ArgumentOutOfRangeException(nameof(orderID));
  43. }
  44. if (quantity <= 0)
  45. {
  46. throw new ArgumentOutOfRangeException(nameof(quantity));
  47. }
  48. return new PaperFill
  49. {
  50. OrderID = orderID,
  51. Price = price,
  52. Quantity = quantity,
  53. Fee = fee,
  54. Tax = tax,
  55. Amount = amount,
  56. PriceDate = priceDate,
  57. RealizedPnL = realizedPnL
  58. };
  59. }
  60. /// <summary>
  61. /// 신규 주문(ID 미확정) 케이스 — Order 내비게이션으로 생성해 EF 가 저장 시 FK(OrderID)를 자동 채우게 한다.
  62. /// 상폐 강제청산 등 시스템 주문+체결을 한 번에 저장할 때 사용 (d4 §⑨).
  63. /// </summary>
  64. public static PaperFill CreateFor(
  65. PaperOrder order,
  66. decimal price,
  67. int quantity,
  68. decimal fee,
  69. decimal tax,
  70. decimal amount,
  71. DateOnly priceDate,
  72. decimal? realizedPnL = null
  73. ) {
  74. ArgumentNullException.ThrowIfNull(order);
  75. if (quantity <= 0)
  76. {
  77. throw new ArgumentOutOfRangeException(nameof(quantity));
  78. }
  79. return new PaperFill
  80. {
  81. Order = order,
  82. Price = price,
  83. Quantity = quantity,
  84. Fee = fee,
  85. Tax = tax,
  86. Amount = amount,
  87. PriceDate = priceDate,
  88. RealizedPnL = realizedPnL
  89. };
  90. }
  91. }