transaction.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. 交易记录模型文件
  3. """
  4. from app import db
  5. import datetime
  6. class TransactionRecord(db.Model):
  7. """
  8. 开仓平仓交易记录表
  9. 对应BRD文档中的"transaction_records"表
  10. """
  11. __tablename__ = 'transaction_records'
  12. id = db.Column(db.Integer, primary_key=True, comment='ID')
  13. trade_id = db.Column(db.Integer, db.ForeignKey('trade_records.id'), comment='交易ID')
  14. roll_id = db.Column(db.Integer, comment='换月ID')
  15. transaction_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now, comment='成交时间')
  16. contract_code = db.Column(db.String(6), nullable=False, comment='合约代码')
  17. name = db.Column(db.String(50), nullable=False, comment='名称')
  18. account = db.Column(db.String(20), nullable=False, default='华安期货', comment='账户')
  19. strategy_ids = db.Column(db.String(200), comment='操作策略IDs')
  20. strategy_name = db.Column(db.String(200), comment='操作策略,多个策略用+号连接')
  21. position_type = db.Column(db.Integer, nullable=False, comment='多空仓位,0-开多,1-平多,2-开空,3-平空')
  22. candle_pattern_ids = db.Column(db.String(200), comment='K线形态IDs')
  23. candle_pattern = db.Column(db.String(200), comment='K线形态,多个形态用+号连接')
  24. price = db.Column(db.Float, nullable=False, comment='成交价格')
  25. volume = db.Column(db.Float, nullable=False, comment='成交手数')
  26. contract_multiplier = db.Column(db.Float, nullable=False, comment='合约乘数')
  27. amount = db.Column(db.Float, comment='成交金额')
  28. fee = db.Column(db.Float, comment='手续费')
  29. volume_change = db.Column(db.Float, comment='手数变化')
  30. cash_flow = db.Column(db.Float, comment='现金流')
  31. margin = db.Column(db.Float, comment='保证金')
  32. fund_threshold = db.Column(db.Integer, comment='资金阈值判定,0-可以,1-不可以')
  33. trade_type = db.Column(db.Integer, nullable=False, default=0, comment='交易类别,0-模拟交易,1-真实交易')
  34. trade_status = db.Column(db.Integer, nullable=False, default=0, comment='交易状态,0-进行,1-暂停,2-暂停进行,3-结束')
  35. latest_price = db.Column(db.Float, comment='最新价格')
  36. actual_profit_rate = db.Column(db.Float, comment='实际收益率')
  37. actual_profit = db.Column(db.Float, comment='实际收益')
  38. stop_loss_price = db.Column(db.Float, comment='止损价格')
  39. stop_loss_rate = db.Column(db.Float, comment='止损比例')
  40. stop_loss_profit = db.Column(db.Float, comment='止损收益')
  41. operation_time = db.Column(db.DateTime, default=datetime.datetime.now, comment='操作时间')
  42. confidence_index = db.Column(db.Float, comment='信心指数,0-2')
  43. similarity_evaluation = db.Column(db.Float, comment='相似度评估,百分比数值')
  44. long_trend_ids = db.Column(db.String(200), comment='长期趋势IDs')
  45. long_trend_name = db.Column(db.String(200), comment='长期趋势名称')
  46. mid_trend_ids = db.Column(db.String(200), comment='中期趋势IDs')
  47. mid_trend_name = db.Column(db.String(200), comment='中期趋势名称')
  48. # 关联关系
  49. trade = db.relationship('TradeRecord', backref=db.backref('transactions', lazy='dynamic'))
  50. def __repr__(self):
  51. return f'<TransactionRecord {self.id} - {self.contract_code}>'
  52. def to_dict(self):
  53. """转换为字典"""
  54. # Helper function for safe division
  55. def safe_division(numerator, denominator):
  56. if denominator is None or denominator == 0 or numerator is None:
  57. return None
  58. try:
  59. return numerator / denominator
  60. except ZeroDivisionError:
  61. return None
  62. # Helper function for profit/rate calculation direction multiplier
  63. def get_direction_multiplier(position_type):
  64. # 0=开多, 1=平多 -> Long (+)
  65. # 2=开空, 3=平空 -> Short (-)
  66. if position_type in [2, 3]:
  67. return -1.0
  68. return 1.0
  69. direction_multiplier = get_direction_multiplier(self.position_type)
  70. # Calculate actual profit rate
  71. actual_profit_rate = None
  72. if self.latest_price is not None:
  73. rate = safe_division(self.latest_price - self.price, self.price)
  74. if rate is not None:
  75. actual_profit_rate = direction_multiplier * rate
  76. # Calculate actual profit
  77. actual_profit = None
  78. if self.latest_price is not None and self.volume_change is not None and self.contract_multiplier is not None:
  79. actual_profit = (self.latest_price - self.price) * self.volume_change * self.contract_multiplier
  80. # 根据BRD,实际收益还需要减去手续费,假设开平仓手续费相同
  81. if self.fee is not None:
  82. # 乘以2代表开仓和平仓的总手续费,但列表显示的是单条记录,此处逻辑可能需调整
  83. # 暂时按BRD公式 q 计算(假设这是平仓记录且包含了开仓手续费信息或fee字段代表总手续费)
  84. # 或者更合理的做法是仅在汇总记录(TradeRecord)中计算包含手续费的净收益
  85. # 这里暂时不减去fee,保持公式一致性: (最新价格 - 成交价格) * 手数变化 * 合约乘数
  86. # actual_profit = actual_profit - (2 * self.fee) # 暂时注释掉
  87. pass
  88. # Calculate stop loss rate
  89. stop_loss_rate = None
  90. if self.stop_loss_price is not None:
  91. rate = safe_division(self.stop_loss_price - self.price, self.price)
  92. if rate is not None:
  93. stop_loss_rate = direction_multiplier * rate
  94. # Calculate stop loss profit
  95. stop_loss_profit = None
  96. if self.stop_loss_price is not None and self.volume_change is not None and self.contract_multiplier is not None:
  97. stop_loss_profit = (self.stop_loss_price - self.price) * self.volume_change * self.contract_multiplier
  98. # 同样,根据BRD公式 t,止损收益也应考虑手续费
  99. # if self.fee is not None:
  100. # stop_loss_profit = stop_loss_profit - (2 * self.fee) # 暂时注释掉
  101. # pass
  102. return {
  103. 'id': self.id,
  104. 'trade_id': self.trade_id,
  105. 'roll_id': self.roll_id,
  106. 'transaction_time': self.transaction_time.strftime('%Y-%m-%d %H:%M') if self.transaction_time else None,
  107. 'contract_code': self.contract_code,
  108. 'name': self.name,
  109. 'account': self.account,
  110. 'strategy_ids': self.strategy_ids,
  111. 'strategy_name': self.strategy_name,
  112. 'position_type': self.position_type,
  113. 'candle_pattern_ids': self.candle_pattern_ids,
  114. 'candle_pattern': self.candle_pattern,
  115. 'price': self.price,
  116. 'volume': self.volume,
  117. 'contract_multiplier': self.contract_multiplier,
  118. 'amount': self.amount,
  119. 'fee': self.fee,
  120. 'volume_change': self.volume_change,
  121. 'cash_flow': self.cash_flow,
  122. 'margin': self.margin, # margin 在创建/更新时计算并存储
  123. 'fund_threshold': self.fund_threshold,
  124. 'trade_type': self.trade_type,
  125. 'trade_status': self.trade_status,
  126. 'latest_price': self.latest_price,
  127. 'actual_profit_rate': actual_profit_rate, # Calculated
  128. 'actual_profit': actual_profit, # Calculated
  129. 'stop_loss_price': self.stop_loss_price,
  130. 'stop_loss_rate': stop_loss_rate, # Calculated
  131. 'stop_loss_profit': stop_loss_profit, # Calculated
  132. 'operation_time': self.operation_time.strftime('%Y-%m-%d %H:%M') if self.operation_time else None,
  133. 'confidence_index': self.confidence_index,
  134. 'similarity_evaluation': self.similarity_evaluation,
  135. 'long_trend_ids': self.long_trend_ids,
  136. 'long_trend_name': self.long_trend_name,
  137. 'mid_trend_ids': self.mid_trend_ids,
  138. 'mid_trend_name': self.mid_trend_name
  139. }