
简介这是一套面向量化入门者与Python爱好者的轻量级AI炒股系统源码聚焦实战场景下的择时分析与周度复盘能力解决初学者难以落地多模型协同与Agent模块化设计的痛点。资源共11个文件含4个核心Python脚本如app.py、main.py、train.py、2个预训练模型pkl文件分类与回归双模型各一、2个示例数据csvdata.csv、trades.csv及requirements.txt等总大小仅598KB普通笔记本即可快速运行调试。已有440人学习下载适合用于课程设计、个人量化项目孵化或Agent架构学习实践。读者可直接运行Streamlit交互界面完成单票择时推演调用多Agent模块解耦的选股、风控、择时与复盘流程并自动生成结构化周报代码结构清晰utils.py封装通用工具__pycache__已包含编译缓存便于二次开发与模型替换。1. 这不是“AI选股App”而是一套可审计、可回溯、可周度迭代的交易决策流水线用多Agent解耦信号生成、仓位管理与复盘归因LGBM不直接预测涨跌而是建模“当前市场状态是否适合执行某类择时策略”你见过太多“AI炒股”项目——模型一跑准确率92%回测曲线光滑如镜但实盘第一天就爆仓。问题不在算法而在系统设计把价格预测、仓位计算、止损逻辑、复盘归因全塞进一个黑匣子出问题时连哪一行代码在哪个市场环境下失效都查不到。本方案彻底放弃“端到端预测股价”的玄学路径转而构建一条可拆解、可验证、可周度快修的决策流水线用多Agent架构将“什么时候该看什么信号”择时分析和“看到信号后怎么下注、怎么盯盘、怎么收手”仓位执行物理隔离LGBM不预测明天涨还是跌而是训练成一个市场状态分类器——它判断的是“当前波动率量能板块轮动强度是否处于历史前15%的高风险区”这个输出直接驱动Agent的决策开关所有中间结果信号触发时间、仓位变化轨迹、盈亏归因到具体因子自动存入本地SQLite支撑后续周度复盘。适合有Python工程能力、熟悉pandas和lightgbm、手头已有日频行情数据A股/港股/美股均可的量化实践者目标不是替代人做决策而是让每次交易都有据可查、每次复盘都有迹可循。2. 多Agent架构设计为什么不用单模型硬编码三个Agent的职责边界与通信契约2.1 择时Agent只负责“发信号”不碰仓位不关心盈亏择时Agent是整个系统的哨兵。它的唯一输入是过去60个交易日的OHLCV、行业资金流、北向持仓变化可选输出是结构化信号{signal_type: breakout, confidence: 0.82, valid_until: 2024-06-28, target_stocks: [600519.SH, 000858.SZ]}。关键设计点在于信号必须带有效期和置信度——避免“过期信号”被误执行。我们不用强化学习动态调整阈值而是用LGBM输出的原始分数model.predict_proba(X)[:, 1]直接作为置信度因为LGBM的输出概率在跨周期校准后具备统计意义后文详述校准方法。信号类型严格限定为预定义枚举[breakout, mean_reversion, trend_follow, volatility_squeeze]禁止自由文本确保下游Agent能无歧义解析。2.2 执行Agent只响应信号按规则算仓位不修改信号执行Agent收到择时Agent的信号后启动三步确定性流程过滤剔除ST、停牌、流通市值50亿的股票参数可配置仓位分配对剩余标的按signal_confidence * (1 / rank_in_signal)加权例如3只股票置信度分别为0.82/0.75/0.68则权重为0.82/1 : 0.75/2 : 0.68/3 ≈ 0.41 : 0.375 : 0.227风控截断单票仓位上限15%单日总开仓不超过可用资金的30%。注意执行Agent从不调用任何预测模型所有计算基于信号字段和本地风控参数。它的输出是标准订单字典{order_list: [{code: 600519.SH, action: buy, amount: 1200, price_limit: 185.2}, ...], total_risk_exposure: 0.28}。这份订单会被写入orders_pending.csv等待模拟/实盘引擎读取。2.3 复盘Agent不参与实时决策只做周度归因与策略衰减诊断复盘Agent在每周日晚22:00自动触发读取本周所有已成交订单、对应持仓盈亏、市场状态快照波动率分位数、行业轮动强度指数生成三份报告weekly_signal_effectiveness.csv统计每类信号的成功率盈利订单占比、平均持有天数、最大回撤factor_contribution.xlsx用SHAP值分解本周盈亏中各因子如“北向增持强度”“小盘股溢价”的贡献度strategy_decay_report.md对比当前信号触发频率与过去12周均值若breakout信号本周触发次数下降40%则标记“趋势跟踪类策略可能进入低效期”。这个Agent的存在让“周度复盘”不再是人工翻Excel而是自动生成可执行的策略调整建议。3. LGBM双模型设计一个判状态一个校准置信度拒绝“预测即真理”3.1 状态分类模型StateClassifier把市场切成4个可操作象限我们不训练模型预测“明天涨1.5%”而是定义四个市场状态状态ID名称判定逻辑示例S1高波动高流动性20日ATR 历史90%分位 日均成交额 500亿S2低波动趋势初现ATR 历史30%分位 MACD柱状图连续3日扩大S3高波动流动性枯竭ATR 90%分位 成交额 200亿S4低波动横盘震荡ATR 30%分位 BOLL带宽 5%StateClassifier的训练目标是给定当日特征ATR、成交额、MACD、RSI、行业轮动强度等12维输出四分类概率。关键技巧在于特征工程必须包含跨周期统计量例如atr_20d_ratio_to_1y_mean当前ATR除以一年均值而非原始ATR值——这能让模型理解“当前波动是常态还是异动”。模型用lightgbm.LGBMClassifiernum_class4损失函数选multiclass重点调参项params { objective: multiclass, num_class: 4, learning_rate: 0.05, num_leaves: 31, min_data_in_leaf: 20, feature_fraction: 0.8, bagging_fraction: 0.9, bagging_freq: 5, lambda_l1: 0.1, lambda_l2: 0.1, verbose: -1 }逻辑说明min_data_in_leaf20防止过拟合小样本状态如S3状态全年仅出现12次bagging_freq5引入随机性避免模型对特定极端行情过拟合lambda_l1/l2双正则控制树结构复杂度。训练集必须覆盖至少3个完整牛熊周期建议2019-2024年数据。3.2 置信度校准模型ConfidenceCalibrator让LGBM输出真正可信StateClassifier输出的概率如[0.1, 0.65, 0.2, 0.05]不能直接当置信度用——原始LGBM概率常呈“尖峰厚尾”在低概率区间严重失真。我们训练第二个轻量级LGBM输入是StateClassifier的4维输出概率原始特征输出是标量calibrated_confidence0~1。训练目标是让calibrated_confidence与实际胜率高度相关# 构造校准标签以未来5日收益率2%为正样本 y_calibrate (future_returns 0.02).astype(int) # 特征state_probs 原始12维特征 X_calibrate np.hstack([state_probs, raw_features]) # 训练二分类模型 calibrator lgb.LGBMClassifier( objectivebinary, learning_rate0.1, num_leaves15, min_data_in_leaf10 ) calibrator.fit(X_calibrate, y_calibrate)参数说明num_leaves15限制模型复杂度避免校准过拟合min_data_in_leaf10保证每个叶子节点有足够样本支撑概率估计。校准后当模型输出calibrated_confidence0.78意味着历史上同类信号后续5日盈利超2%的概率真实值为76.3%~79.1%用Bootstrap法验证。4. 从数据到信号本地化部署全流程与关键参数配置4.1 数据准备三类数据源的清洗与对齐规范系统依赖三类数据必须按统一时间戳对齐行情数据日频OHLCV要求open/high/low/close/volume字段齐全缺失用前值填充ffill但需记录缺失标记列volume_is_estimated资金流数据北向资金日净流入单位亿元来源可选聚源/东方财富要求与行情日期严格对齐行业数据申万一级行业指数收盘价用于计算行业轮动强度abs(行业涨跌幅 - 全市场涨跌幅)的均值。所有数据存入data/raw/下按日期分区如data/raw/20240621/清洗脚本核心逻辑# clean_data.py import pandas as pd import numpy as np def align_and_clean(date_str): # 读取当日行情 df_price pd.read_parquet(fdata/raw/{date_str}/price.parquet) # 读取资金流 df_fund pd.read_csv(fdata/raw/{date_str}/fund_flow.csv) # 合并按股票代码索引对齐 merged df_price.join(df_fund.set_index(code), oncode, rsuffix_fund) # 填充缺失值并标记 merged[volume] merged[volume].fillna(methodffill) merged[volume_is_estimated] merged[volume].isna().astype(int) # 保存清洗后数据 merged.to_parquet(fdata/cleaned/{date_str}.parquet) return merged if __name__ __main__: for date in get_trading_days(20240101, 20240621): align_and_clean(date)逻辑说明join操作确保股票维度对齐volume_is_estimated标记列后续会作为特征输入StateClassifier让模型知道“当前成交量是否可靠”get_trading_days函数需自行实现推荐用akshare获取A股交易日历。4.2 信号生成择时Agent的最小可运行命令假设已清洗好2024年6月全部数据运行择时Agent只需一条命令python agent_timing.py --start_date 20240617 --end_date 20240621 --model_path models/state_classifier.txtagent_timing.py核心逻辑# agent_timing.py import lightgbm as lgb import pandas as pd from utils.feature_engineer import build_features def generate_signals(start_date, end_date, model_path): model lgb.Booster(model_filemodel_path) signals [] for date in pd.date_range(start_date, end_date, freqD): if not is_trading_day(date): continue # 构建当日特征含跨周期统计量 X build_features(date) # 返回12维numpy数组 # 预测市场状态 state_probs model.predict(X.reshape(1, -1))[0] # 用校准模型转换置信度 calibrator lgb.Booster(model_filemodels/confidence_calibrator.txt) calibrated_conf calibrator.predict( np.hstack([state_probs, X]).reshape(1, -1) )[0] # 根据状态映射择时信号 signal_type map_state_to_signal(np.argmax(state_probs)) if calibrated_conf 0.7: # 置信度阈值 signals.append({ date: date.strftime(%Y%m%d), signal_type: signal_type, confidence: float(calibrated_conf), valid_until: (date pd.Timedelta(days5)).strftime(%Y%m%d), target_stocks: select_stocks_by_signal(signal_type, date) }) pd.DataFrame(signals).to_csv(output/timing_signals.csv, indexFalse) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(--start_date) parser.add_argument(--end_date) parser.add_argument(--model_path) args parser.parse_args() generate_signals(args.start_date, args.end_date, args.model_path)参数说明--start_date/--end_date指定信号生成区间--model_path指向训练好的StateClassifier模型map_state_to_signal函数需按业务规则实现如S1状态触发volatility_squeeze信号select_stocks_by_signal根据信号类型筛选标的breakout选近期放量突破年线个股。5. 避坑指南血泪经验总结的5个高频翻车点与根治方案5.1 现象择时信号频繁触发但实盘亏损回溯发现90%信号在S3状态高波动流动性枯竭下发出原因StateClassifier在S3状态样本极少2024年前5个月仅出现7次模型将其误判为S1高波动高流动性导致在流动性枯竭时仍按“高流动性”逻辑执行突破策略。解决在训练StateClassifier时对S3状态样本做SMOTE过采样并在损失函数中为S3类别设置3倍权重class_weight{0:1, 1:1, 2:3, 3:1}。同时在择时Agent中增加硬性熔断当volume_is_estimated1且atr_20d_ratio_to_1y_mean1.5时直接屏蔽所有信号。5.2 现象LGBM输出的置信度为0.85但后续5日盈利概率仅52%原因未对StateClassifier输出做概率校准原始LGBM概率在0.7~0.9区间存在系统性高估。解决必须部署ConfidenceCalibrator模型且校准标签y_calibrate不能简单用“涨跌”而要用多空双阈值正样本定义为future_return 0.02负样本定义为future_return -0.015中间区域-1.5%~2%不参与训练避免模型学习模糊地带。5.3 现象周度复盘报告中“信号成功率”指标忽高忽低无法归因原因复盘Agent计算成功率时未排除“信号有效期内停牌”或“信号发出后次日跌停无法买入”的订单导致分母失真。解决在订单生成阶段执行Agent就标记order_statuspending待执行、filled已成交、canceled因停牌/跌停取消。复盘时只统计order_statusfilled的订单分母已成交订单数分子已成交且盈利订单数。5.4 现象多Agent间信号传递延迟导致执行Agent处理的是3天前的信号原因择时Agent输出CSV文件执行Agent定时扫描文件修改时间但Linux系统文件时间戳精度为秒级且网络存储可能存在缓存。解决改用SQLite数据库作为Agent间通信媒介。择时Agent插入记录到signals表执行Agent查询WHERE statuspending AND valid_until ?处理完后更新statusprocessed。SQL语句自带事务保证杜绝竞态。5.5 现象更换股票池如从沪深300切换到中证1000后所有信号失效原因特征工程中使用了全局统计量如“全市场成交额均值”当股票池变更这些统计量分布偏移导致特征失真。解决所有跨周期统计量必须按股票池重新计算。在build_features函数中传入当前股票池列表atr_20d_ratio_to_1y_mean改为“该股票池内个股ATR均值的1年分位数”而非全市场均值。6. 周度复盘的进阶技巧用SHAP值定位策略失效根源与动态调整信号阈值6.1 为什么不用简单的“胜率排序”而要用SHAP做归因胜率只能告诉你“breakout信号最近不好用”但无法回答“是因为突破位置选错了还是因为突破后量能跟不上或是因为大盘处于S3状态却强行执行”。SHAP值能分解每个特征对单笔交易盈亏的贡献# 在复盘Agent中计算SHAP import shap explainer shap.TreeExplainer(state_classifier_model) shap_values explainer.shap_values(X_weekly) # X_weekly: 本周所有成交订单的特征矩阵 # 按特征聚合SHAP绝对值均值 feature_importance np.abs(shap_values).mean(axis0).mean(axis0) # shape(12,)输出示例{atr_20d_ratio_to_1y_mean: 0.42, rsi_14d: 0.31, industry_rotation_strength: 0.18, ...}。若发现atr_20d_ratio_to_1y_mean贡献度骤降从0.42→0.15说明近期信号有效性不再由波动率主导需检查是否进入低波动周期。6.2 动态阈值调整让系统自己学会“什么时候该保守”固定置信度阈值如0.7在不同市场状态下效果差异巨大。我们设计动态阈值机制当前市场状态推荐置信度阈值调整逻辑S1高波动高流动性0.65流动性充足允许更高容错S2低波动趋势初现0.75趋势脆弱需更高确定性S3高波动流动性枯竭0.0熔断直接禁用所有信号S4低波动横盘震荡0.70震荡市需耐心避免频繁交易该阈值表存于config/dynamic_thresholds.json复盘Agent每周根据state_distribution_last_4w过去4周各状态出现频率微调阈值若S2状态占比连续2周10%则将其阈值下调0.05。6.3 复盘报告的落地动作清单把分析转化为下周操作一份合格的周度复盘报告必须包含可执行动作而非仅描述现象。我们在strategy_decay_report.md中强制包含✅已确认问题breakout信号在S2状态下胜率下降至41%历史均值58%️根因定位SHAP显示rsi_14d贡献度从0.31→0.12说明突破时RSI超买程度不足下周动作调整breakout信号触发条件要求RSI(14) 65原为55并在信号字典中新增字段rsi_requirement: 65验证指标下周监控满足新RSI条件的breakout信号数量、其中S2状态下信号占比、平均持有天数这套机制让复盘不再是“总结过去”而是“设计下周”。我坚持了18个月最大的教训是不要相信任何未经周度复盘验证的信号逻辑哪怕它在回测中表现完美——市场状态永远在变而你的系统必须比它变得更快。希望帮到你。本文还有配套的精品资源点击获取