feat: complete trading system with FastAPI backend, web frontend, and auto-analysis

This commit is contained in:
Stock Buddy Bot
2026-03-22 21:59:14 +08:00
parent 17c124009f
commit 3d8e59cc0e
16 changed files with 2923 additions and 0 deletions

137
backend/database.py Normal file
View File

@@ -0,0 +1,137 @@
"""
数据库模型 - 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()