stock-ai-agent/backend/app/models/paper_trading.py
2026-02-15 21:43:43 +08:00

122 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
模拟交易数据模型
"""
from enum import Enum
from datetime import datetime
from sqlalchemy import Column, Integer, String, Float, DateTime, JSON, Text, Enum as SQLEnum
from app.models.database import Base
class OrderStatus(str, Enum):
"""订单状态"""
PENDING = "pending" # 等待入场
OPEN = "open" # 持仓中
CLOSED_TP = "closed_tp" # 止盈平仓
CLOSED_SL = "closed_sl" # 止损平仓
CLOSED_BE = "closed_be" # 保本止损平仓
CLOSED_MANUAL = "closed_manual" # 手动平仓
CANCELLED = "cancelled" # 已取消
class OrderSide(str, Enum):
"""订单方向"""
LONG = "long" # 做多
SHORT = "short" # 做空
class SignalGrade(str, Enum):
"""信号等级"""
A = "A"
B = "B"
C = "C"
D = "D"
class EntryType(str, Enum):
"""入场类型"""
MARKET = "market" # 现价入场
LIMIT = "limit" # 挂单入场
class PaperOrder(Base):
"""模拟交易订单表"""
__tablename__ = "paper_orders"
id = Column(Integer, primary_key=True, index=True)
# 订单标识
order_id = Column(String(64), unique=True, nullable=False, index=True)
# 交易对信息
symbol = Column(String(20), nullable=False, index=True)
side = Column(SQLEnum(OrderSide), nullable=False)
# 价格信息
entry_price = Column(Float, nullable=False) # 目标入场价
stop_loss = Column(Float, nullable=False) # 止损价
take_profit = Column(Float, nullable=False) # 止盈价
filled_price = Column(Float, nullable=True) # 实际成交价
exit_price = Column(Float, nullable=True) # 出场价
# 仓位信息
quantity = Column(Float, default=1000) # 仓位大小 (USDT)
# 信号信息
signal_grade = Column(SQLEnum(SignalGrade), default=SignalGrade.D)
signal_type = Column(String(20), default="swing") # swing / short_term
confidence = Column(Float, default=0) # 置信度 (0-100)
trend = Column(String(20), nullable=True) # 趋势方向
entry_type = Column(SQLEnum(EntryType, values_callable=lambda x: [e.value for e in x]), default=EntryType.MARKET) # 入场类型
# 订单状态
status = Column(SQLEnum(OrderStatus), default=OrderStatus.PENDING, index=True)
# 盈亏信息
pnl_amount = Column(Float, default=0) # 盈亏金额 (USDT)
pnl_percent = Column(Float, default=0) # 盈亏百分比
# 风险指标
max_drawdown = Column(Float, default=0) # 持仓期间最大回撤
max_profit = Column(Float, default=0) # 持仓期间最大盈利
breakeven_triggered = Column(Integer, default=0) # 是否触发过保本止损0=否1=是)
# 时间戳
created_at = Column(DateTime, default=datetime.utcnow)
opened_at = Column(DateTime, nullable=True) # 开仓时间
closed_at = Column(DateTime, nullable=True) # 平仓时间
# 附加数据
entry_reasons = Column(JSON, nullable=True) # 入场原因
indicators = Column(JSON, nullable=True) # 技术指标快照
notes = Column(Text, nullable=True) # 备注
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'order_id': self.order_id,
'symbol': self.symbol,
'side': self.side.value if self.side else None,
'entry_price': self.entry_price,
'stop_loss': self.stop_loss,
'take_profit': self.take_profit,
'filled_price': self.filled_price,
'exit_price': self.exit_price,
'quantity': self.quantity,
'signal_grade': self.signal_grade.value if self.signal_grade else None,
'signal_type': self.signal_type,
'confidence': self.confidence,
'trend': self.trend,
'entry_type': self.entry_type.value if self.entry_type else 'market',
'status': self.status.value if self.status else None,
'pnl_amount': self.pnl_amount,
'pnl_percent': self.pnl_percent,
'max_drawdown': self.max_drawdown,
'max_profit': self.max_profit,
'breakeven_triggered': self.breakeven_triggered,
'created_at': self.created_at.isoformat() if self.created_at else None,
'opened_at': self.opened_at.isoformat() if self.opened_at else None,
'closed_at': self.closed_at.isoformat() if self.closed_at else None,
'entry_reasons': self.entry_reasons,
}