|
|
|
|
"""
|
|
|
|
|
数据缓冲平台 - 数据模型 (SQLAlchemy ORM)
|
|
|
|
|
"""
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from sqlalchemy import Column, String, Integer, Float, Text, DateTime, Boolean, Index, UniqueConstraint
|
|
|
|
|
from app.database import Base
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MarketData(Base):
|
|
|
|
|
"""缓存的市场数据表"""
|
|
|
|
|
__tablename__ = "market_data"
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
|
|
|
symbol = Column(String(32), nullable=False, index=True, comment="品种合约代码")
|
|
|
|
|
data_type = Column(String(16), nullable=False, default="futures", comment="数据类型: futures/stock")
|
|
|
|
|
period = Column(String(16), nullable=False, index=True, comment="周期: 5min/15min/30min/60min/daily")
|
|
|
|
|
# K线数据以 JSON 字符串形式存储
|
|
|
|
|
candles_json = Column(Text, nullable=False, comment="K线数据JSON")
|
|
|
|
|
current_price = Column(Float, nullable=True, comment="当前价格")
|
|
|
|
|
fetched_at = Column(DateTime, nullable=False, default=datetime.now, index=True, comment="获取时间")
|
|
|
|
|
candle_count = Column(Integer, default=0, comment="K线数量")
|
|
|
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
|
UniqueConstraint("symbol", "data_type", "period", name="uq_symbol_period"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return f"<MarketData {self.symbol} {self.period} candles={self.candle_count}>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SymbolTimestamp(Base):
|
|
|
|
|
"""合约数据时间戳表 - 记录每个合约的最新数据时间"""
|
|
|
|
|
__tablename__ = "symbol_timestamps"
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
|
|
|
symbol = Column(String(32), nullable=False, unique=True, index=True, comment="品种合约代码")
|
|
|
|
|
data_type = Column(String(16), nullable=False, default="futures", comment="数据类型")
|
|
|
|
|
last_refresh_at = Column(DateTime, nullable=False, default=datetime.now, comment="最后刷新时间")
|
|
|
|
|
refresh_count = Column(Integer, default=0, comment="刷新次数")
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return f"<SymbolTimestamp {self.symbol} last_refresh={self.last_refresh_at}>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ScheduledTask(Base):
|
|
|
|
|
"""定时任务配置表"""
|
|
|
|
|
__tablename__ = "scheduled_tasks"
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
|
|
|
symbol = Column(String(32), nullable=False, comment="品种合约代码")
|
|
|
|
|
data_type = Column(String(16), nullable=False, default="futures", comment="数据类型")
|
|
|
|
|
periods = Column(String(256), nullable=False, comment="周期列表(逗号分隔), 如 5min,15min,60min")
|
|
|
|
|
interval_seconds = Column(Integer, nullable=False, default=300, comment="轮询间隔(秒)")
|
|
|
|
|
task_type = Column(String(16), nullable=False, default="interval", comment="任务类型: interval, daily, once")
|
|
|
|
|
run_time = Column(String(8), nullable=True, comment="执行时间,格式 HH:MM")
|
|
|
|
|
enabled = Column(Boolean, nullable=False, default=True, comment="是否启用")
|
|
|
|
|
is_finished = Column(Boolean, nullable=False, default=False, comment="是否已完成(仅一次任务执行完成后为True)")
|
|
|
|
|
job_id = Column(String(64), nullable=True, unique=True, comment="APScheduler job_id")
|
|
|
|
|
last_run = Column(DateTime, nullable=True, comment="最后执行时间")
|
|
|
|
|
last_status = Column(String(16), nullable=True, comment="最后状态: success/failed")
|
|
|
|
|
created_at = Column(DateTime, nullable=False, default=datetime.now)
|
|
|
|
|
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
|
UniqueConstraint("symbol", "data_type", name="uq_task_symbol"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return f"<Task {self.symbol} every {self.interval_seconds}s enabled={self.enabled}>"
|