"""数据库表定义""" from sqlalchemy import ( MetaData, Table, Column, Integer, Float, Text, Boolean, DateTime, func ) metadata = MetaData() recommendations_table = Table( "recommendations", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("ts_code", Text, nullable=False), Column("name", Text, nullable=False), Column("sector", Text), Column("score", Float), Column("market_temp_score", Float), Column("sector_score", Float), Column("capital_score", Float), Column("technical_score", Float), Column("supply_demand_score", Float, default=0), Column("price_action_score", Float, default=0), Column("position_score", Float), Column("valuation_score", Float), Column("signal", Text), Column("entry_price", Float), Column("target_price", Float), Column("stop_loss", Float), Column("reasons", Text), Column("risk_note", Text, default=""), Column("action_plan", Text, default="观察"), Column("trigger_condition", Text, default=""), Column("invalidation_condition", Text, default=""), Column("suggested_position_pct", Float, default=0), Column("review_after_days", Integer, default=3), Column("lifecycle_status", Text, default="candidate"), Column("data_freshness", Text, default=""), Column("llm_analysis", Text, default=""), Column("strategy", Text, default="trend_breakout"), Column("entry_signal_type", Text, default="none"), Column("entry_timing", Text, default=""), Column("llm_score", Float, default=None), Column("recall_tags", Text, default="[]"), Column("prefilter_decision", Text, default=""), Column("prefilter_reason", Text, default=""), Column("focus_points", Text, default="[]"), Column("scan_session", Text), Column("created_at", DateTime, server_default=func.now()), ) sector_heat_table = Table( "sector_heat", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("sector_code", Text, nullable=False), Column("sector_name", Text, nullable=False), Column("pct_change", Float), Column("capital_inflow", Float), Column("limit_up_count", Integer), Column("heat_score", Float), Column("stage", Text), Column("days_continuous", Integer), Column("member_count", Integer), Column("leading_stocks", Text), # JSON string Column("pct_trend", Text), # JSON string Column("turnover_avg", Float), Column("main_force_ratio", Float), Column("trade_date", Text, nullable=False), Column("created_at", DateTime, server_default=func.now()), ) market_temperature_table = Table( "market_temperature", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("trade_date", Text, nullable=False, unique=True), Column("up_count", Integer), Column("down_count", Integer), Column("limit_up_count", Integer), Column("limit_down_count", Integer), Column("max_streak", Integer), Column("broken_rate", Float), Column("temperature", Float), Column("created_at", DateTime, server_default=func.now()), ) recommendation_tracking_table = Table( "recommendation_tracking", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("recommendation_id", Integer), Column("track_date", Text, nullable=False), Column("current_price", Float), Column("pct_from_entry", Float), Column("max_price", Float), Column("min_price", Float), Column("max_return_pct", Float), Column("max_drawdown_pct", Float), Column("days_since_recommendation", Integer, default=0), Column("hit_target", Boolean, default=False), Column("hit_stop_loss", Boolean, default=False), Column("close_reason", Text, default=""), Column("review_note", Text, default=""), Column("status", Text, default="active"), Column("created_at", DateTime, server_default=func.now()), ) users_table = Table( "users", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("username", Text, nullable=False, unique=True), Column("password_hash", Text, nullable=False), Column("role", Text, default="user"), Column("is_active", Boolean, default=True), Column("created_at", DateTime, server_default=func.now()), Column("updated_at", DateTime, server_default=func.now()), ) stock_diagnoses_table = Table( "stock_diagnoses", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("ts_code", Text, nullable=False), Column("name", Text, nullable=False), Column("diagnosis_mode", Text, default="entry"), Column("diagnosis", Text, nullable=False), Column("created_at", DateTime, server_default=func.now()), ) user_watchlists_table = Table( "user_watchlists", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("user_id", Integer, nullable=False), Column("ts_code", Text, nullable=False), Column("name", Text, nullable=False), Column("note", Text, default=""), Column("watch_group", Text, default="observe"), Column("cost_price", Float, default=None), Column("is_active", Boolean, default=True), Column("created_at", DateTime, server_default=func.now()), Column("updated_at", DateTime, server_default=func.now()), ) watchlist_analyses_table = Table( "watchlist_analyses", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("user_id", Integer, nullable=False), Column("watchlist_id", Integer, nullable=False), Column("ts_code", Text, nullable=False), Column("name", Text, nullable=False), Column("conclusion", Text, default="观察"), Column("advice", Text, default=""), Column("trigger_condition", Text, default=""), Column("risk_note", Text, default=""), Column("summary", Text, default=""), Column("full_analysis", Text, default=""), Column("score_reference", Float, default=0), Column("analysis_mode", Text, default="scheduled"), Column("created_at", DateTime, server_default=func.now()), ) error_logs_table = Table( "error_logs", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("source", Text, nullable=False), # 模块来源,如 "recommender", "screener" Column("level", Text, default="error"), # error / warning Column("message", Text, nullable=False), # 错误消息 Column("detail", Text, default=""), # 完整异常信息(traceback) Column("created_at", DateTime, server_default=func.now()), )