PaperDailySnapshot.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. namespace Domain.Entities.Paper;
  4. /// <summary>
  5. /// 계좌 일별 스냅샷 — (AccountID, TradeDate) UNIQUE. 좌수 NAV·수익률·MDD 를 배치(M2)가 산출/upsert 한다 (d4 §③).
  6. /// 리더보드 기간 수익률은 스냅샷 nav 로 조회한다.
  7. /// </summary>
  8. public class PaperDailySnapshot
  9. {
  10. [ForeignKey(nameof(AccountID))]
  11. public virtual PaperAccount Account { get; private set; } = null!;
  12. [Key]
  13. public int ID { get; private set; }
  14. public int AccountID { get; private set; }
  15. /// <summary>거래일</summary>
  16. public DateOnly TradeDate { get; private set; }
  17. /// <summary>자유 + 예약 토큰</summary>
  18. public decimal Token { get; private set; }
  19. /// <summary>포지션 평가액</summary>
  20. public decimal PositionsValue { get; private set; }
  21. /// <summary>순자산 = Token + PositionsValue</summary>
  22. public decimal Equity { get; private set; }
  23. /// <summary>좌당 순자산 (18,8) = Equity / Units</summary>
  24. public decimal UnitNav { get; private set; }
  25. /// <summary>일간 수익률 Bp</summary>
  26. public int DailyReturnBp { get; private set; }
  27. /// <summary>누적 수익률 Bp = (nav - 1) × 10000</summary>
  28. public int CumReturnBp { get; private set; }
  29. /// <summary>최고 순자산 (MDD 산출용)</summary>
  30. public decimal PeakEquity { get; private set; }
  31. /// <summary>최대 낙폭 Bp</summary>
  32. public int MddBp { get; private set; }
  33. /// <summary>누적 체결 수 (리더보드 등재 요건)</summary>
  34. public int FillCountCum { get; private set; }
  35. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  36. private PaperDailySnapshot() { }
  37. public static PaperDailySnapshot Create(
  38. int accountID,
  39. DateOnly tradeDate,
  40. decimal token,
  41. decimal positionsValue,
  42. decimal equity,
  43. decimal unitNav,
  44. int dailyReturnBp,
  45. int cumReturnBp,
  46. decimal peakEquity,
  47. int mddBp,
  48. int fillCountCum
  49. ) {
  50. if (accountID <= 0)
  51. {
  52. throw new ArgumentOutOfRangeException(nameof(accountID));
  53. }
  54. return new PaperDailySnapshot
  55. {
  56. AccountID = accountID,
  57. TradeDate = tradeDate,
  58. Token = token,
  59. PositionsValue = positionsValue,
  60. Equity = equity,
  61. UnitNav = unitNav,
  62. DailyReturnBp = dailyReturnBp,
  63. CumReturnBp = cumReturnBp,
  64. PeakEquity = peakEquity,
  65. MddBp = mddBp,
  66. FillCountCum = fillCountCum
  67. };
  68. }
  69. /// <summary>동일 (AccountID, TradeDate) 재실행 시 값 갱신 (upsert, 배치 멱등).</summary>
  70. public void Update(
  71. decimal token,
  72. decimal positionsValue,
  73. decimal equity,
  74. decimal unitNav,
  75. int dailyReturnBp,
  76. int cumReturnBp,
  77. decimal peakEquity,
  78. int mddBp,
  79. int fillCountCum
  80. ) {
  81. Token = token;
  82. PositionsValue = positionsValue;
  83. Equity = equity;
  84. UnitNav = unitNav;
  85. DailyReturnBp = dailyReturnBp;
  86. CumReturnBp = cumReturnBp;
  87. PeakEquity = peakEquity;
  88. MddBp = mddBp;
  89. FillCountCum = fillCountCum;
  90. }
  91. }