|
|
|
|
|
"""
|
|
|
|
|
|
数据库模型 - SQLAlchemy Models
|
|
|
|
|
|
"""
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from sqlalchemy import Column, Integer, String, Numeric, BigInteger, DateTime, Boolean, Text, ForeignKey
|
|
|
|
|
|
from sqlalchemy.orm import declarative_base, relationship
|
|
|
|
|
|
|
|
|
|
|
|
# TimescaleDB 基础类 (时序数据)
|
|
|
|
|
|
TimescaleBase = declarative_base()
|
|
|
|
|
|
|
|
|
|
|
|
# SQLite 基础类 (配置数据)
|
|
|
|
|
|
SQLiteBase = declarative_base()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== SQLite Models (配置数据) ====================
|
|
|
|
|
|
|
|
|
|
|
|
class User(SQLiteBase):
|
|
|
|
|
|
"""用户模型"""
|
|
|
|
|
|
__tablename__ = "users"
|
|
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
|
|
|
|
username = Column(String(50), unique=True, nullable=False, index=True)
|
|
|
|
|
|
password_hash = Column(String(255), nullable=False)
|
|
|
|
|
|
email = Column(String(100))
|
|
|
|
|
|
role = Column(String(20), default="user") # admin, user
|
|
|
|
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
|
|
|
|
|
|
# 关系
|
|
|
|
|
|
api_keys = relationship("APIKey", back_populates="user", cascade="all, delete-orphan")
|
|
|
|
|
|
alerts = relationship("Alert", back_populates="user", cascade="all, delete-orphan")
|
|
|
|
|
|
subscriptions = relationship("Subscription", back_populates="user", cascade="all, delete-orphan")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class APIKey(SQLiteBase):
|
|
|
|
|
|
"""API Key 模型"""
|
|
|
|
|
|
__tablename__ = "api_keys"
|
|
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
|
|
|
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
|
|
|
|
key_hash = Column(String(255), unique=True, nullable=False, index=True)
|
|
|
|
|
|
name = Column(String(100))
|
|
|
|
|
|
permissions = Column(Text) # JSON 格式存储权限
|
|
|
|
|
|
expires_at = Column(DateTime)
|
|
|
|
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
last_used_at = Column(DateTime)
|
|
|
|
|
|
|
|
|
|
|
|
# 关系
|
|
|
|
|
|
user = relationship("User", back_populates="api_keys")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Alert(SQLiteBase):
|
|
|
|
|
|
"""告警配置模型"""
|
|
|
|
|
|
__tablename__ = "alerts"
|
|
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
|
|
|
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
|
|
|
|
symbol = Column(String(20), nullable=False, index=True)
|
|
|
|
|
|
condition_type = Column(String(20), nullable=False) # greater_than, less_than, equals
|
|
|
|
|
|
condition_value = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
alert_type = Column(String(20), default="price") # price, percent_change
|
|
|
|
|
|
status = Column(String(20), default="active") # active, triggered, disabled
|
|
|
|
|
|
triggered_at = Column(DateTime)
|
|
|
|
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
|
|
|
|
|
|
# 关系
|
|
|
|
|
|
user = relationship("User", back_populates="alerts")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Subscription(SQLiteBase):
|
|
|
|
|
|
"""数据订阅模型"""
|
|
|
|
|
|
__tablename__ = "subscriptions"
|
|
|
|
|
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
|
|
|
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
|
|
|
|
symbol = Column(String(20), nullable=False, index=True)
|
|
|
|
|
|
period = Column(String(10)) # 1m, 5m, 1h, 1d 等
|
|
|
|
|
|
subscription_type = Column(String(20), default="kline") # kline, realtime
|
|
|
|
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
|
|
|
|
|
|
# 关系
|
|
|
|
|
|
user = relationship("User", back_populates="subscriptions")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== TimescaleDB Models (时序数据) ====================
|
|
|
|
|
|
# 注意:TimescaleDB 表使用原生 SQL 操作,这里仅作为参考
|
|
|
|
|
|
|
|
|
|
|
|
class KlineData(TimescaleBase):
|
|
|
|
|
|
"""K 线数据模型 (TimescaleDB hypertable)"""
|
|
|
|
|
|
__tablename__ = "kline_data"
|
|
|
|
|
|
|
|
|
|
|
|
time = Column(DateTime, primary_key=True)
|
|
|
|
|
|
symbol = Column(String(20), primary_key=True)
|
|
|
|
|
|
period = Column(String(10), primary_key=True)
|
|
|
|
|
|
open = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
high = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
low = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
close = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
volume = Column(BigInteger, nullable=False)
|
|
|
|
|
|
amount = Column(Numeric(30, 8), default=0)
|
|
|
|
|
|
open_interest = Column(BigInteger, default=0)
|
|
|
|
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RealtimeQuote(TimescaleBase):
|
|
|
|
|
|
"""实时行情模型 (TimescaleDB hypertable)"""
|
|
|
|
|
|
__tablename__ = "realtime_quotes"
|
|
|
|
|
|
|
|
|
|
|
|
time = Column(DateTime, primary_key=True)
|
|
|
|
|
|
symbol = Column(String(20), primary_key=True)
|
|
|
|
|
|
last_price = Column(Numeric(20, 8), nullable=False)
|
|
|
|
|
|
open_price = Column(Numeric(20, 8))
|
|
|
|
|
|
high_price = Column(Numeric(20, 8))
|
|
|
|
|
|
low_price = Column(Numeric(20, 8))
|
|
|
|
|
|
prev_close = Column(Numeric(20, 8))
|
|
|
|
|
|
volume = Column(BigInteger)
|
|
|
|
|
|
amount = Column(Numeric(30, 8))
|
|
|
|
|
|
bid_price_1 = Column(Numeric(20, 8))
|
|
|
|
|
|
bid_volume_1 = Column(BigInteger)
|
|
|
|
|
|
ask_price_1 = Column(Numeric(20, 8))
|
|
|
|
|
|
ask_volume_1 = Column(BigInteger)
|
|
|
|
|
|
position = Column(BigInteger, default=0)
|