Files
stockbuddy/backend/database.py

138 lines
4.8 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.
"""
数据库模型 - SQLAlchemy
"""
from sqlalchemy import create_engine, Column, Integer, Float, String, DateTime, Text, JSON
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime
import os
# 数据库路径
DB_PATH = os.path.join(os.path.dirname(__file__), '..', 'data', 'stocks.db')
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
SQLALCHEMY_DATABASE_URL = f"sqlite:///{DB_PATH}"
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# ═════════════════════════════════════════════════════════════════════
# 数据表模型
# ═════════════════════════════════════════════════════════════════════
class Position(Base):
"""持仓表"""
__tablename__ = "positions"
id = Column(Integer, primary_key=True, index=True)
stock_name = Column(String(50), nullable=False)
ticker = Column(String(20), nullable=False, index=True)
shares = Column(Integer, nullable=False)
cost_price = Column(Float, nullable=False)
current_price = Column(Float, default=0)
market_value = Column(Float, default=0)
pnl = Column(Float, default=0) # 盈亏金额
pnl_percent = Column(Float, default=0) # 盈亏百分比
# 策略参数
strategy = Column(String(10), default="C") # A/B/C
stop_loss = Column(Float, default=0.08) # 止损比例
# 元数据
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
notes = Column(Text, nullable=True)
class StockData(Base):
"""股票数据缓存表"""
__tablename__ = "stock_data"
id = Column(Integer, primary_key=True)
ticker = Column(String(20), nullable=False, index=True)
date = Column(String(10), nullable=False)
open_price = Column(Float)
high_price = Column(Float)
low_price = Column(Float)
close_price = Column(Float)
volume = Column(Float)
ma5 = Column(Float)
ma20 = Column(Float)
ma60 = Column(Float)
rsi = Column(Float)
atr = Column(Float)
updated_at = Column(DateTime, default=datetime.now)
class SentimentData(Base):
"""舆情数据表"""
__tablename__ = "sentiment_data"
id = Column(Integer, primary_key=True)
ticker = Column(String(20), nullable=False, index=True)
date = Column(String(10), nullable=False)
score = Column(Integer) # -5 ~ +5
label = Column(String(20)) # 极度悲观/悲观/中性/乐观/极度乐观
factors = Column(JSON) # 影响因素列表
outlook = Column(String(50))
source = Column(String(20), default="llm") # llm / manual / system
created_at = Column(DateTime, default=datetime.now)
class AnalysisResult(Base):
"""分析结果表"""
__tablename__ = "analysis_results"
id = Column(Integer, primary_key=True)
ticker = Column(String(20), nullable=False, index=True)
date = Column(String(10), nullable=False)
# 信号
action = Column(String(20)) # BUY / SELL / HOLD
score = Column(Float) # 综合评分
confidence = Column(String(10)) # HIGH / MEDIUM / LOW
# 详情
tech_score = Column(Float)
fund_score = Column(Float)
sent_score = Column(Float)
# 止损建议
suggested_stop = Column(Float)
position_ratio = Column(Float)
# 完整数据JSON
full_data = Column(JSON)
created_at = Column(DateTime, default=datetime.now)
class TradeLog(Base):
"""交易日志表"""
__tablename__ = "trade_logs"
id = Column(Integer, primary_key=True)
ticker = Column(String(20), nullable=False)
action = Column(String(10), nullable=False) # BUY / SELL
shares = Column(Integer)
price = Column(Float)
reason = Column(Text)
pnl = Column(Float, nullable=True)
created_at = Column(DateTime, default=datetime.now)
# ═════════════════════════════════════════════════════════════════════
# 初始化数据库
# ═════════════════════════════════════════════════════════════════════
def init_db():
Base.metadata.create_all(bind=engine)
print(f"✅ 数据库初始化完成: {DB_PATH}")
if __name__ == "__main__":
init_db()