119 lines
4.3 KiB
Python
119 lines
4.3 KiB
Python
"""
|
|
模拟交易数据模型
|
|
"""
|
|
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_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) # 持仓期间最大盈利
|
|
|
|
# 时间戳
|
|
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,
|
|
'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,
|
|
}
|