Open Source, Open Future!
  menu
118 文章
ღゝ◡╹)ノ❤️

第7篇:项目复盘与技术总结

上一篇: 第6篇:回测系统

这是系列的最后一篇。前面5篇讲了具体实现,这篇回过头来看看整个项目,总结一下技术栈、核心成果、踩过的坑,以及一些思考。

一、写在前面

最初做这个项目,是因为DeepSeek火了。顺着了解到DeepSeek背后是幻方量化,又顺着了解到量化交易这个领域。研究了一下发现,量化交易涉及预测、优化、数据处理这些我感兴趣的方向,就想自己动手试试。

从零开始,搭出了一个量化交易系统。虽然做出来的东西肯定不能和专业机构比,但至少把整个技术链路跑通了,也算理解了量化系统是怎么运作的。

二、技术架构总览

2.1 五层架构

┌─────────────────────────────────┐
│  5. 回测验证                     │  验证策略效果
│     - 夏普比率 0.47              │
│     - 年化收益 12.15%            │
├─────────────────────────────────┤
│  4. 运筹优化 (核心)              │  决策买什么、买多少
│     - OR-Tools 线性规划          │
│     - 整数规划、二次规划          │
├─────────────────────────────────┤
│  3. 预测模型                     │  预测涨跌
│     - LightGBM                   │
│     - RankIC 0.037               │
├─────────────────────────────────┤
│  2. 特征工程                     │  提取信息
│     - 39个技术指标               │
│     - 6大类特征                  │
├─────────────────────────────────┤
│  1. 数据获取                     │  原始数据
│     - Tushare                    │
│     - 800只股票,10年数据        │
└─────────────────────────────────┘

2.2 技术栈

模块技术核心库
数据获取PythonTushare, Pandas
特征工程时间序列处理Pandas, NumPy
预测模型机器学习LightGBM, Scikit-learn
运筹优化线性规划OR-Tools, CVXPY
回测验证金融分析Pandas, Matplotlib

2.3 代码结构

量化/
├── src/
│   ├── data_loader.py      (245行) - 数据获取与清洗
│   ├── feature_engine.py   (315行) - 特征工程
│   ├── predictor.py        (321行) - 预测模型
│   ├── optimizer.py        (406行) - 运筹优化
│   └── backtest.py         (304行) - 回测系统
├── data/                   数据目录
├── results/                结果输出
└── main.py                 主流程

三、核心成果

3.1 数据处理

原始数据

  • 沪深300 + 中证500,共800只股票
  • 时间跨度:2015-01-05 到 2024-12-31(10年)
  • 原始记录:约160万条

清洗后数据

  • 有效记录:约158万条
  • 删除缺失值、停牌数据、异常值

特征数量

  • 收益率特征:4个
  • 移动平均特征:8个
  • 波动率特征:6个
  • 动量指标:4个
  • 成交量特征:6个
  • 价格位置特征:3个
  • 滞后特征:8个
  • 总计:39个特征

3.2 预测模型表现

LightGBM价格预测

  • RankIC:0.037(超过0.03有效阈值)
  • ICIR:0.24(信号持续稳定)
  • 方向准确率:58.19%(vs 随机50%)
  • MAE(平均绝对误差):0.020(2%)
  • R²:0.152
  • 训练时间:6秒

特征重要性Top 5

  1. return_1d(昨天涨跌幅)
  2. return_5d(5日涨跌幅)
  3. macd(趋势指标)
  4. close_to_ma_5(价格偏离5日线)
  5. rsi(相对强弱指标)

3.3 运筹优化效果

线性规划

  • 求解时间:<1秒
  • 预算10万,投资9万
  • 预期收益率:2.10%

整数规划

  • 求解时间:约2秒
  • 资金使用率:99.20%
  • 满足整手交易约束

Markowitz优化

  • 夏普比率:0.0658
  • 平衡收益和风险

3.4 回测结果

策略表现(2015-2024,10年):

  • 总收益率:18.67%
  • 年化收益率:12.15%
  • 波动率:19.45%
  • 夏普比率:0.4708
  • 最大回撤:-12.21%
  • 胜率:57.89%

vs 买入持有

  • 年化收益提升:+3.92%
  • 夏普比率提升:+70%
  • 最大回撤降低:-3.13%
  • 最大回撤降低:-3.13%

四、技术亮点

4.1 预测能力

时间序列特征构建

  • 多周期收益率(1、5、10、20日)
  • 滚动统计(均值、标准差)
  • 技术指标(RSI、MACD等)

LightGBM优势

  • 训练速度快(8秒 vs LSTM的1小时)
  • 效果好(方向准确率58%)
  • 可解释性强(特征重要性)

关键技术

  • GroupBy按股票分组计算
  • shift(-1)构建目标变量
  • TimeSeriesSplit交叉验证

4.2 运筹优化能力(核心)

OR-Tools应用

  • 线性规划:资金配置优化
  • 整数规划:整手买入约束
  • 多约束处理:预算、仓位、行业限制

建模能力

# 决策变量
x = [solver.NumVar(0, max_limit, f'x_{i}') for i in range(n)]

# 目标函数
max: sum(x[i] * expected_return[i])

# 约束条件
s.t. sum(x) <= budget
     x[i] <= max_position

技术通用性

  • 同样的框架可用于快递运力调度
  • 代码改动量<10%

4.3 数据工程能力

数据清洗

  • 三层过滤(缺失值、停牌、异常值)
  • 阈值选择有依据(30%涨跌幅)
  • 不填充,宁可删除

特征工程

  • 6大类特征,覆盖全面
  • 每类特征都有金融意义
  • 避免数据泄露

质量控制

  • 每步都有数据验证
  • 详细日志输出
  • 可视化分析

4.4 工程实践

模块化设计

  • 每个模块职责单一
  • 可独立运行和测试
  • 易于扩展

容错机制

  • 异常处理
  • 数据验证
  • 降级策略

文档完善

  • 每个函数都有docstring
  • 关键参数都有注释
  • README说明清楚

五、踩过的坑(汇总)

5.1 数据处理的坑

坑1:忘记排序

# 错误:API返回的数据可能无序
df = ak.stock_zh_a_hist(...)

# 正确:必须排序
df = df.sort_values('date').reset_index(drop=True)

影响:计算收益率时结果全错。

坑2:没有分组计算

# 错误:不同股票数据混在一起
df['ma_20'] = df['close'].rolling(20).mean()

# 正确:按股票分组
df['ma_20'] = df.groupby('symbol')['close'].transform(
    lambda x: x.rolling(20).mean()
)

影响:茅台的均线用到了五粮液的数据。

坑3:数据泄露

# 错误:用的是过去
df['target'] = df['close'].pct_change(1)

# 正确:用shift(-1)取未来
df['target'] = df.groupby('symbol')['close'].shift(-1) / df['close'] - 1

影响:准确率虚高(65% → 58%)。

5.2 模型训练的坑

坑4:随机分割时间序列

# 错误:会用未来预测过去
train_test_split(X, y, shuffle=True)

# 正确:按时间顺序分割
split_idx = int(len(X) * 0.8)
X_train, X_test = X[:split_idx], X[split_idx:]

影响:测试结果不可信。

坑5:参数没调好

# 默认参数容易过拟合
model = lgb.LGBMRegressor()  # 训练集68%,测试集51%

# 调整参数后
model = lgb.LGBMRegressor(
    learning_rate=0.05,
    max_depth=5,
    bagging_fraction=0.8
)  # 训练集60%,测试集58%

影响:过拟合严重。

坑6:对树模型做标准化

# 多余:树模型不需要标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)

影响:增加计算量,没有帮助。

5.3 优化求解的坑

坑7:约束条件冲突

# 错误:5只股票×2万 = 10万刚好,但如果有股票不买就冲突了
solver.Add(sum(x) == budget)
solver.Add(x[i] <= 20000)

# 正确:改成 <=
solver.Add(sum(x) <= budget)

影响:求解失败。

坑8:单位不一致

# 收益率太小,金额太大,数值不稳定
objective.SetCoefficient(x[i], 0.025)  # 2.5%

# 改成统一量级
objective.SetCoefficient(x[i], 0.025 * 1000)

影响:求解器可能不收敛。

5.4 回测的坑

坑9:没有shift信号

# 错误:用今天的信号对应今天的收益(未来函数)
df['strategy_return'] = df['signal'] * df['actual_return']

# 正确:用昨天的信号
df['strategy_return'] = df['signal'].shift(1) * df['actual_return']

影响:回测结果虚高。

坑10:没考虑成本

# 理想化:不考虑手续费和滑点
# 实际:每次交易约0.15%成本

# 年化收益:12.15% → 9.83%(差2%多)

影响:实盘收益远低于回测。

六、可以改进的地方

6.1 数据层面

数据量太少

现状:5只股票,3年数据,3330条样本。

问题:

  • 样本量偏少,容易过拟合
  • 行业覆盖不够(只有白酒+金融)
  • 缺少极端行情数据(比如2015牛市)

改进方向:

  • 扩展到50只股票(覆盖主要行业)
  • 延长到5-10年数据
  • 加入宏观数据(GDP、利率等)

特征还能优化

现状:39个特征,有些相关性很高。

问题:

  • 有冗余特征(ma_20和ma_30相关性0.95)
  • 缺少基本面特征(PE、ROE等)
  • 没有另类数据(新闻情感、社交媒体等)

改进方向:

  • 特征选择,删除冗余
  • 加入基本面因子
  • 尝试深度学习自动提取特征

6.2 模型层面

模型还比较简单

现状:单一的LightGBM模型。

问题:

  • 没有集成多个模型
  • 没有在线学习(模型是静态的)
  • 缺少模型置信度评估

改进方向:

  • 模型集成(LightGBM + XGBoost + LSTM)
  • 滚动训练(定期用新数据重新训练)
  • 输出预测的置信区间

参数调优不够充分

现状:手动试了几组参数。

问题:

  • 没有系统地做超参数搜索
  • 可能还有更优的参数组合

改进方向:

  • 网格搜索或贝叶斯优化
  • 自动化调参

6.3 策略层面

5. 风险控制不够

现状:只有简单的仓位限制。

问题:

  • 没有止损机制
  • 没有行业分散约束
  • 缺少极端情况的应对

改进方向:

  • 动态止损(跟踪止损)
  • 行业中性策略
  • 压力测试

6. 交易频率优化

现状:每周调仓一次。

问题:

  • 可能还不够优化
  • 没有考虑市场流动性

改进方向:

  • 根据市场波动调整频率
  • 高波动时少交易
  • 低波动时可多交易

6.4 工程层面

7. 性能还能提升

现状:单机运行,速度够用但不快。

问题:

  • 数据处理是单线程的
  • 特征计算可以并行
  • 模型训练可以用GPU

改进方向:

  • 并行处理(多进程)
  • GPU加速
  • 分布式计算(如果数据量更大)

8. 监控和告警

现状:没有自动化监控。

问题:

  • 数据异常需要人工检查
  • 模型性能下降不能及时发现

改进方向:

  • 数据质量监控
  • 模型性能监控
  • 异常告警系统

七、技术迁移详解

这套技术框架最大的价值是通用性。

7.1 量化 → 快递需求预测

模块量化场景快递场景代码改动
数据获取ak.stock_zh_a_hist()获取包裹量API数据源接口
特征工程return_1d, ma_20, rsi昨日包裹量, 7日均值, 节假日特征定义
预测模型预测股价涨跌预测包裹量目标变量
运筹优化资金配置运力调度目标函数和约束
回测验证模拟交易模拟调度评估指标

核心不变

  • 数据处理流程(清洗、特征、标准化)
  • LightGBM建模流程
  • OR-Tools优化框架
  • 交叉验证方法

需要改变

  • 业务逻辑(股票 → 包裹)
  • 评估指标(收益率 → 成本/服务水平)
  • 约束条件(预算 → 运力容量)

具体迁移示例

预测模型

# 量化:预测股价
df['target'] = df.groupby('symbol')['close'].shift(-1) / df['close'] - 1

# 快递:预测包裹量
df['target'] = df.groupby('station')['package_count'].shift(-1)

运筹优化

# 量化:资金配置
objective.SetMaximization()  # 最大化收益
solver.Add(sum(x) <= budget)  # 预算约束

# 快递:运力调度
objective.SetMinimization()  # 最小化成本
solver.Add(sum(y) >= total_demand)  # 需求约束

代码结构完全一样,只改业务参数。

7.2 其他可迁移场景

电商库存优化

  • 预测:商品销量
  • 优化:库存配置(仓库容量、运输成本)

能源调度

  • 预测:电力需求
  • 优化:发电机组配置(容量、成本)

广告投放

  • 预测:点击率
  • 优化:预算分配(ROI最大化)

八、学到的东西

8.1 技术层面

1. LightGBM真的好用

之前一直用深度学习,这次用树模型发现:

  • 表格数据上效果更好
  • 训练速度快得多
  • 可解释性强

以后遇到表格数据,优先考虑树模型。

2. OR-Tools很强大

以前觉得运筹优化很抽象,实际用起来发现很实用:

  • 建模思路清晰(目标+约束)
  • 求解速度快
  • 应用场景广

这个工具值得深入学习。

3. 数据泄露很容易犯

shift、groupby、时间序列分割,每个环节都可能泄露。

最深的体会:永远假设自己会犯错,多检查几遍。

8.2 思维层面

1. 技术真的是相通的

一开始担心量化太偏门,后来发现:

  • 预测就是预测,换个场景也一样
  • 优化就是优化,核心思想不变
  • 数据处理都是pandas那一套

学会迁移思维很重要。

2. 简单就是美

39个特征,其实20个核心特征就够了。
LightGBM默认参数,调一调也能用。
简化版回测,能说明问题就行。不要过度设计。

3. 完成比完美重要

这个项目很多地方可以做得更好,但一周时间有限。

先做出来,能跑通,再慢慢优化。

完美主义容易陷入细节,永远做不完。

九、项目价值

9.1 技术价值

  • 掌握了完整的机器学习项目流程
  • 学会了LightGBM和OR-Tools两个重要工具
  • 理解了时间序列预测的特殊性
  • 积累了数据处理和特征工程经验

9.2 通用价值

  • 证明了技术迁移的可行性
  • 建立了可复用的代码框架
  • 养成了模块化开发的习惯
  • 学会了从零到一搭建系统

9.3 个人收获

  • 从好奇到理解:知道量化交易的技术链路
  • 从理论到实践:不是纸上谈兵,真正跑通了
  • 从困惑到清晰:踩过坑之后印象更深刻

十、写在最后

这个项目前后花了一周时间,过程中踩了不少坑,但收获很大。

最大的收获不是做出了一个RankIC 0.037的模型(虽然超过了0.03的有效阈值),而是理解了整个技术链路:

  • 数据怎么获取和处理
  • 特征怎么设计
  • 模型怎么训练和评估
  • 优化怎么建模和求解
  • 策略怎么回测和验证

这些技能是通用的,换个场景照样能用。

如果你也对时间序列预测、运筹优化或量化交易感兴趣,希望这个系列对你有帮助。


系列文章目录