Compare commits
3 Commits
ca4f8095ca
...
5f7537a01d
| Author | SHA1 | Date |
|---|---|---|
|
|
5f7537a01d | |
|
|
b03a8f7dda | |
|
|
a9e1399cdc |
|
|
@ -0,0 +1,723 @@
|
|||
第1章 DeepSeek、Python与量化交易概述
|
||||
|
||||
1.1 DeepSeek介绍
|
||||
|
||||
1.1.1 DeepSeek模型家族
|
||||
|
||||
1.1.2 DeepSeek的优势
|
||||
|
||||
1.1.3 DeepSeek的应用领域
|
||||
|
||||
1.2 如何使用DeepSeek
|
||||
|
||||
1.2.1 使用网页版DeepSeek
|
||||
|
||||
1.2.2 下载DeepSeek手机App
|
||||
|
||||
1.3 Python编程在量化交易中的重要性和优势
|
||||
|
||||
1.4 DeepSeek+Python赋能量化交易
|
||||
|
||||
1.5 本章总结
|
||||
|
||||
第2章 量化交易Python语言基础
|
||||
|
||||
2.1 Python解释器
|
||||
|
||||
2.2 IDE
|
||||
|
||||
2.2.1 安装PyCharm
|
||||
|
||||
2.2.2 安装Jupyter Notebook
|
||||
|
||||
2.2.3 启动Jupyter Notebook
|
||||
|
||||
2.3 第一个Python程序
|
||||
|
||||
2.3.1 编写脚本文件运行第一个Python程序
|
||||
|
||||
2.3.2 使用PyCharm编写和运行Python程序
|
||||
|
||||
2.3.3 使用Jupyter Notebook编写和运行Python程序
|
||||
|
||||
2.4 Python语法基础
|
||||
|
||||
2.4.1 标识符
|
||||
|
||||
2.4.2 关键字
|
||||
|
||||
2.4.3 变量
|
||||
|
||||
2.4.4 语句
|
||||
|
||||
2.4.5 代码块
|
||||
|
||||
2.4.6 模块
|
||||
|
||||
2.5 运算符
|
||||
|
||||
2.5.1 算术运算符
|
||||
|
||||
2.5.2 关系运算符
|
||||
|
||||
2.5.3 逻辑运算符
|
||||
|
||||
2.5.4 赋值运算符
|
||||
|
||||
2.6 数据类型
|
||||
|
||||
2.6.1 数字类型
|
||||
|
||||
2.6.2 列表
|
||||
|
||||
2.6.3 元组
|
||||
|
||||
2.6.4 集合
|
||||
|
||||
2.6.5 字典
|
||||
|
||||
2.7 字符串
|
||||
|
||||
2.7.1 字符串的创建
|
||||
|
||||
2.7.2 字符转义
|
||||
|
||||
2.7.3 字符串格式化
|
||||
|
||||
2.7.4 数字格式化
|
||||
|
||||
2.8 控制语句
|
||||
|
||||
2.8.1 分支语句
|
||||
|
||||
2.8.2 循环语句
|
||||
|
||||
2.8.3 跳转语句
|
||||
|
||||
2.9 函数
|
||||
|
||||
2.9.1 定义函数
|
||||
|
||||
2.9.2 调用函数
|
||||
|
||||
2.9.3 带参数的函数
|
||||
|
||||
2.9.4 带返回值的函数
|
||||
|
||||
2.9.5 默认参数
|
||||
|
||||
2.9.6 可变参数
|
||||
|
||||
2.9.7 lambda函数
|
||||
|
||||
2.9.8 使用filter()和map()函数进行数据处理
|
||||
|
||||
2.10 类
|
||||
|
||||
2.10.1 实例变量和构造函数
|
||||
|
||||
2.10.2 实例方法
|
||||
|
||||
2.11 文件操作
|
||||
|
||||
2.12 异常处理
|
||||
|
||||
2.12.1 捕获异常
|
||||
|
||||
2.12.2 释放资源
|
||||
|
||||
2.13 多线程
|
||||
|
||||
2.13.1 创建线程
|
||||
|
||||
2.13.2 等待线程结束
|
||||
|
||||
2.14 本章总结
|
||||
|
||||
第3章 Python量化基础工具库
|
||||
|
||||
3.1 NumPy
|
||||
|
||||
3.1.1 为什么选择NumPy
|
||||
|
||||
3.1.2 安装NumPy
|
||||
|
||||
3.2 创建数组
|
||||
|
||||
3.2.1 从Python列表创建一维数组
|
||||
|
||||
3.2.2 指定数组的数据类型
|
||||
|
||||
3.2.3 更多创建一维数组的方式
|
||||
|
||||
3.2.4 arange()函数
|
||||
|
||||
3.2.5 等差数列与linspace()函数
|
||||
|
||||
3.2.6 等比数列与logspace()函数
|
||||
|
||||
3.3 二维数组
|
||||
|
||||
3.4 更多创建二维数组的方式
|
||||
|
||||
3.4.1 使用ones()函数
|
||||
|
||||
3.4.2 使用zeros()函数
|
||||
|
||||
3.4.3 使用empty()函数
|
||||
|
||||
3.4.4 使用full()函数
|
||||
|
||||
3.4.5 使用identity()函数
|
||||
|
||||
3.5 数组的属性
|
||||
|
||||
3.6 数组的轴
|
||||
|
||||
3.6.1 轴的概念
|
||||
|
||||
3.6.2 轴的应用
|
||||
|
||||
3.6.3 轴的应用示例
|
||||
|
||||
3.7 三维数组
|
||||
|
||||
3.7.1 三维数组的结构
|
||||
|
||||
3.7.2 创建三维数组
|
||||
|
||||
3.8 访问数组
|
||||
|
||||
3.8.1 索引访问
|
||||
|
||||
3.8.2 切片访问
|
||||
|
||||
3.8.3 布尔索引
|
||||
|
||||
3.8.4 花式索引
|
||||
|
||||
3.9 Pandas
|
||||
|
||||
3.9.1 为什么选择Pandas
|
||||
|
||||
3.9.2 安装Pandas
|
||||
|
||||
3.10 Series数据结构
|
||||
|
||||
3.10.1 理解Series数据结构
|
||||
|
||||
3.10.2 创建Series对象
|
||||
|
||||
3.10.3 访问Series数据
|
||||
|
||||
3.10.4 通过切片访问Series数据
|
||||
|
||||
3.11 DataFrame数据结构
|
||||
|
||||
3.12 访问DataFrame数据
|
||||
|
||||
3.12.1 列访问
|
||||
|
||||
3.12.2 行访问
|
||||
|
||||
3.12.3 切片访问
|
||||
|
||||
3.13 读写数据
|
||||
|
||||
3.13.1 读取CSV文件数据
|
||||
|
||||
3.13.2 实战案例1:从CSV文件读取货币供应量数据
|
||||
|
||||
3.13.3 写入数据到CSV文件
|
||||
|
||||
3.13.4 实战案例2:将银行账户交易记录写入CSV文件
|
||||
|
||||
3.13.5 读取Excel文件数据
|
||||
|
||||
3.13.6 实战案例3:从Excel文件中读取货币供应量月度数据
|
||||
|
||||
3.13.7 读取数据库
|
||||
|
||||
3.13.8 实战案例4:从数据库中读取银行账户交易记录数据
|
||||
|
||||
3.14 本章总结
|
||||
|
||||
第4章 量化交易Python语言基础
|
||||
|
||||
4.1 量化交易可视化库
|
||||
|
||||
4.2 使用Matplotlib绘制图表
|
||||
|
||||
4.2.1 安装Matplotlib
|
||||
|
||||
4.2.2 图表基本构成要素
|
||||
|
||||
4.2.3 绘制折线图
|
||||
|
||||
4.2.4 绘制柱状图
|
||||
|
||||
4.2.5 绘制饼图
|
||||
|
||||
4.2.6 绘制散点图
|
||||
|
||||
4.3 使用Seaborn绘制图表
|
||||
|
||||
4.3.1 Seaborn内置数据集
|
||||
|
||||
4.3.2 Seaborn图表主题
|
||||
|
||||
4.3.3 柱状图
|
||||
|
||||
4.3.4 直方图
|
||||
|
||||
4.3.5 箱线图
|
||||
|
||||
4.3.6 小提琴图
|
||||
|
||||
4.3.7 热力图
|
||||
|
||||
4.4 时间序列可视化
|
||||
|
||||
4.4.1 实战案例5:使用Matplotlib绘制英伟达股票历史成交量折线图
|
||||
|
||||
4.4.2 实战案例6:绘制英伟达股票OHLC折线图
|
||||
|
||||
4.4.3 K线图
|
||||
|
||||
4.4.4 绘制K线图
|
||||
|
||||
4.4.5 实战案例7:绘制英伟达股票K线图
|
||||
|
||||
4.4.6 实战案例8:使用Seaborn绘制英伟达股票历史成交量折线图
|
||||
|
||||
4.5 本章总结
|
||||
|
||||
第5章 数据采集与分析
|
||||
|
||||
5.1 数据采集概述
|
||||
|
||||
5.1.1 数据采集的基本步骤
|
||||
|
||||
5.1.2 数据采集技术和工具
|
||||
|
||||
5.2 网页数据采集
|
||||
|
||||
5.2.1 使用urllib爬取网页数据
|
||||
|
||||
5.2.2 实战案例9:爬取苹果股票数据
|
||||
|
||||
5.2.3 解析数据
|
||||
|
||||
5.2.4 使用BeautifulSoup
|
||||
|
||||
5.2.5 实战案例10:解析苹果股票数据
|
||||
|
||||
5.2.6 使用Selenium爬取网页数据
|
||||
|
||||
5.2.7 实战案例11:使用Selenium爬取中国石油股票数据
|
||||
|
||||
5.2.8 实战案例12:使用Selenium解析HTML数据
|
||||
|
||||
5.2.9 借助DeepSeek爬取网页数据
|
||||
|
||||
5.3 API调用采集数据
|
||||
|
||||
5.3.1 常见的金融数据API
|
||||
|
||||
5.3.2 使用Tushare API采集数据
|
||||
|
||||
5.3.3 实战案例13:使用Tushare API获取中国石油股票数据
|
||||
|
||||
5.4 数据清洗
|
||||
|
||||
5.4.1 实战案例14:ABC股票数据清洗
|
||||
|
||||
5.4.2 处理股票数据类型不一致问题
|
||||
|
||||
5.4.3 处理股票数据异常值
|
||||
|
||||
5.4.4 DeepSeek助力数据清洗
|
||||
|
||||
5.4.5 实战案例15:使用DeepSeek清洗特斯拉股票数据
|
||||
|
||||
5.5 统计分析
|
||||
|
||||
5.5.1 DeepSeek辅助统计分析
|
||||
|
||||
5.5.2 相关性分析
|
||||
|
||||
5.5.3 实战案例16:股票行业相关性分析
|
||||
|
||||
5.5.4 统计描述和摘要
|
||||
|
||||
5.5.5 实战案例17:苹果股票数据统计描述和摘要分析
|
||||
|
||||
5.6 本章总结
|
||||
|
||||
第6章 量化交易基础
|
||||
|
||||
6.1 量化交易概述
|
||||
|
||||
6.2 金融市场和交易品种概述
|
||||
|
||||
6.3 技术分析和基本面分析基础
|
||||
|
||||
6.3.1 技术分析
|
||||
|
||||
6.3.2 基本面分析
|
||||
|
||||
6.4 量化交易策略概述
|
||||
|
||||
6.5 本章总结
|
||||
|
||||
第7章 DeepSeek与量化交易结合
|
||||
|
||||
7.1 DeepSeek辅助技术分析
|
||||
|
||||
7.1.1 DeepSeek 在技术分析中的主要应用
|
||||
|
||||
7.1.2 实战案例18:利用DeepSeek对000001.SZ股票进行技术分析
|
||||
|
||||
7.2 DeepSeek辅助基本面分析
|
||||
|
||||
7.2.1 DeepSeek在基本面分析中的应用
|
||||
|
||||
7.2.2 实战案例19:利用DeepSeek对某上市公司公告进行解析
|
||||
|
||||
7.3 DeepSeek在市场情报分析中的应用
|
||||
|
||||
7.3.1 实战案例20:利用DeepSeek对“央行发布降息25个基点”消息进行分析
|
||||
|
||||
7.3.2 实战案例21:利用DeepSeek对“重大项目获得批复,股价大涨20%”消息进行分析
|
||||
|
||||
7.4 DeepSeek在交易决策支持中的应用
|
||||
|
||||
7.4.1 实战案例22:某科技型上市公司获大单,DeepSeek提出交易决策建议
|
||||
|
||||
7.4.2 实战案例23:某新能源概念股获多项利好,DeepSeek交易建议
|
||||
|
||||
7.5 使用DeepSeek进行市场预测和趋势识别
|
||||
|
||||
7.5.1 实战案例24:DeepSeek预测某城市商业地产市场面临调整
|
||||
|
||||
7.5.2 实战案例25:DeepSeek用于预测“新能源汽车补贴退坡”的影响
|
||||
|
||||
7.6 本章总结
|
||||
|
||||
第8章 趋势跟踪策略与DeepSeek智能增强
|
||||
|
||||
8.1 趋势跟踪策略概述
|
||||
|
||||
8.1.1 趋势跟踪和交易决策中一些主要概念
|
||||
|
||||
8.1.2 使用移动平均线进行分析
|
||||
|
||||
8.2 使用DeepSeek辅助趋势跟踪策略决策过程
|
||||
|
||||
8.3 实战案例26:使用DeepSeek辅助移动平均线策略分析微软股票
|
||||
|
||||
8.3.1 步骤1:数据采集和加载数据
|
||||
|
||||
8.3.2 步骤2:计算移动平均线
|
||||
|
||||
8.3.3 步骤3:初始策略规则的制定
|
||||
|
||||
8.3.4 步骤4:生成买入和卖出信号
|
||||
|
||||
8.3.5 步骤5:DeepSeek赋能模拟回测验证策略
|
||||
|
||||
8.3.6 步骤6:绘制K线图和信号
|
||||
|
||||
8.3.7 步骤7:DeepSeek辅助优化策略
|
||||
|
||||
8.4 本章总结
|
||||
|
||||
第9章 动量策略与DeepSeek智能辅助决策
|
||||
|
||||
9.1 动量策略概述
|
||||
|
||||
9.1.1 动量策略中的一些主要概念
|
||||
|
||||
9.1.2 动量策略的优缺点
|
||||
|
||||
9.2 相对强弱指标
|
||||
|
||||
9.3 使用DeepSeek辅助动量策略决策
|
||||
|
||||
9.4 实战案例27:使用DeepSeek辅助中国铝业股票价格和RSI交易信号分析
|
||||
|
||||
9.4.1 步骤1:数据采集与预处理
|
||||
|
||||
9.4.2 步骤2:计算RSI
|
||||
|
||||
9.4.3 步骤3:初始策略规则的制定
|
||||
|
||||
9.4.4 步骤4:生成买入和卖出信号
|
||||
|
||||
9.4.5 步骤5:绘制RSI曲线与交易信号
|
||||
|
||||
9.4.6 步骤6:DeepSeek赋能模拟回测验证策略
|
||||
|
||||
9.4.7 步骤7:DeepSeek辅助优化策略
|
||||
|
||||
9.5 本章总结
|
||||
|
||||
第10章 海龟交易策略
|
||||
|
||||
10.1 海龟交易策略的诞生与基础概念
|
||||
|
||||
10.1.1 海龟交易策略的起源故事
|
||||
|
||||
10.1.2 海龟交易策略的核心原则
|
||||
|
||||
10.1.3 海龟交易策略的一些主要概念
|
||||
|
||||
10.1.4 海龟交易策略的实施过程
|
||||
|
||||
10.2 使用DeepSeek辅助实施海龟交易策略
|
||||
|
||||
10.3 实战案例28:借助DeepSeek推进海龟交易策略落地——以中国石油股票交易为例
|
||||
|
||||
10.3.1 步骤1:数据获取和准备
|
||||
|
||||
10.3.2 步骤2:封装海龟交易策略函数
|
||||
|
||||
10.3.3 步骤3:回测策略
|
||||
|
||||
10.3.4 步骤4:回测的可视化分析
|
||||
|
||||
10.3.5 步骤5:DeepSeek辅助优化策略
|
||||
|
||||
10.4 本章总结
|
||||
|
||||
第11章 借助DeepSeek构建与优化高频交易策略
|
||||
|
||||
11.1 高频交易策略概述
|
||||
|
||||
11.1.1 高频交易的特点
|
||||
|
||||
11.1.2 高频交易策略中的一些主要概念
|
||||
|
||||
11.1.3 实施高频交易策略
|
||||
|
||||
11.1.4 高频交易策略中常见的策略
|
||||
|
||||
11.1.5 高频交易策略的技术和设施层面问题
|
||||
|
||||
11.2 使用DeepSeek辅助实施高频交易策略
|
||||
|
||||
11.3 实战案例29:利用DeepSeek辅助实施高频交易策略并优化股票投资回报——以比亚
|
||||
|
||||
迪股票为例
|
||||
|
||||
11.3.1 步骤1:DeepSeek辅助制定策略
|
||||
|
||||
11.3.2 步骤2:DeepSeek辅助选择交易平台和技术手段
|
||||
|
||||
11.3.3 步骤3:DeepSeek辅助撰写交易算法
|
||||
|
||||
11.4 构建高频交易框架
|
||||
|
||||
11.4.1 高频交易框架的核心组件
|
||||
|
||||
11.4.2 高频交易框架的实现步骤
|
||||
|
||||
11.4.3 实战案例30:基本高频交易框架实现
|
||||
|
||||
11.5 实战案例31:基于配对交易策略的高频交易实施过程
|
||||
|
||||
11.6 实战案例32:DeepSeek辅助HTF框架下的动量策略——以苹果股票为例
|
||||
|
||||
11.7 DeepSeek辅助实现其他编程语言的BHTF策略
|
||||
|
||||
11.8 本章总结
|
||||
|
||||
第12章 利用DeepSeek实施套利交易策略
|
||||
|
||||
12.1 套利策略概述
|
||||
|
||||
12.1.1 套利策略的基本定义
|
||||
|
||||
12.1.2 套利策略的类型
|
||||
|
||||
12.1.3 套利策略中的一些主要概念
|
||||
|
||||
12.2 实施套利交易策略
|
||||
|
||||
12.3 使用DeepSeek辅助实施套利交易策略
|
||||
|
||||
12.4 套利交易策略案例分析
|
||||
|
||||
12.4.1 实战案例33:股票A跨市场套利
|
||||
|
||||
12.4.2 实战案例34:利用美元与欧元汇率差异套利
|
||||
|
||||
12.4.3 实战案例35:同行业相对值套利策略
|
||||
|
||||
12.5 实战案例36:中国石化股票和中国石油股票配对交易套利
|
||||
|
||||
12.5.1 步骤1:清洗数据
|
||||
|
||||
12.5.2 步骤2:读取股票数据
|
||||
|
||||
12.5.3 步骤3:两只股票的相关性分析
|
||||
|
||||
12.5.4 步骤4:使用DeepSeek对相关性进行分析
|
||||
|
||||
12.5.5 步骤5:回测股票历史数据
|
||||
|
||||
12.5.6 步骤6:使用DeepSeek对回测结果进行分析
|
||||
|
||||
12.5.7 步骤7:使用DeepSeek优化策略
|
||||
|
||||
12.6 本章总结
|
||||
|
||||
第13章 基于机器学习与DeepSeek优化的量化交易策略
|
||||
|
||||
13.1 机器学习策略中的一些主要概念
|
||||
|
||||
13.2 机器学习策略分类
|
||||
|
||||
13.3 分类策略
|
||||
|
||||
13.3.1 Python机器学习库
|
||||
|
||||
13.3.2 机器学习策略实施过程
|
||||
|
||||
13.4 实战案例37:使用分类策略预测英伟达股票走势
|
||||
|
||||
13.4.1 步骤1:数据准备和处理
|
||||
|
||||
13.4.2 步骤2:模型训练
|
||||
|
||||
13.4.3 步骤3:使用DeepSeek进行模型评估
|
||||
|
||||
13.4.4 步骤4:使用DeepSeek进行模型优化
|
||||
|
||||
13.4.5 步骤5:预测股票走势
|
||||
|
||||
13.5 实战案例38:使用回归策略预测英伟达股票走势
|
||||
|
||||
13.5.1 步骤1:数据准备和处理
|
||||
|
||||
13.5.2 步骤2:模型训练
|
||||
|
||||
13.5.3 步骤3:预测股票走势
|
||||
|
||||
13.5.4 步骤4:使用DeepSeek进行模型评估
|
||||
|
||||
13.5.5 步骤5:使用DeepSeek进行模型优化
|
||||
|
||||
13.5.6 步骤6:使用优化后的模型再次预测股票走势
|
||||
|
||||
13.6 实战案例39:LSTM预测比特币价格趋势
|
||||
|
||||
13.6.1 步骤1:加载和清洗数据
|
||||
|
||||
13.6.2 步骤2:模型训练
|
||||
|
||||
13.6.3 步骤3:可视化结果
|
||||
|
||||
13.6.4 步骤4:使用DeepSeek进行模型评估
|
||||
|
||||
13.6.5 步骤5:使用DeepSeek优化模型
|
||||
|
||||
13.6.6 步骤6:比特币价格预测
|
||||
|
||||
13.7 本章总结
|
||||
|
||||
第14章 量化交易回测框架与DeepSeek优化
|
||||
|
||||
14.1 再谈回测
|
||||
|
||||
14.1.1 回测的基本流程
|
||||
|
||||
14.1.2 常见回测框架
|
||||
|
||||
14.2 Backtrader框架
|
||||
|
||||
14.2.1 Backtrader使用流程
|
||||
|
||||
14.2.2 实战案例40:使用Backtrader回测苹果股票的双均线策略
|
||||
|
||||
14.2.3 DeepSeek辅助优化Backtrader参数双均线策略
|
||||
|
||||
14.3 本章总结
|
||||
|
||||
第15章 利用DeepSeek提高量化交易的风险管理效能
|
||||
|
||||
15.1 风险管理工具和方法
|
||||
|
||||
15.1.1 止损与止盈策略
|
||||
|
||||
15.1.2 实战案例41:基于移动平均线的固定止损+固定止盈策略
|
||||
|
||||
15.1.3 实战案例42:移动止损和移动止盈策略
|
||||
|
||||
15.1.4 头寸管理
|
||||
|
||||
15.1.5 实战案例43:基于波动率的动态头寸管理策略——以特斯拉股票为例
|
||||
|
||||
15.1.6 投资组合分散
|
||||
|
||||
15.1.7 实战案例44:股票与黄金的风险分散投资策略
|
||||
|
||||
15.1.8 对冲策略
|
||||
|
||||
15.1.9 实战案例45:对冲策略——股票与债券的对冲组合
|
||||
|
||||
15.2 使用DeepSeek辅助量化交易风险管理
|
||||
|
||||
15.2.1 风险识别
|
||||
|
||||
15.2.2 实战案例46:DeepSeek智能监控应对市场动荡
|
||||
|
||||
15.2.3 风险评估
|
||||
|
||||
15.2.4 实战案例47:基于DeepSeek的科技股投资组合的风险评估
|
||||
|
||||
15.2.5 风险控制
|
||||
|
||||
15.2.6 实战案例48:应对银行业危机的风险控制
|
||||
|
||||
15.3 本章总结
|
||||
|
||||
第16章 AI+量化交易的未来:DeepSeek API调用与AI智能体赋能
|
||||
|
||||
16.1 DeepSeek API调用
|
||||
|
||||
16.1.1 DeepSeek RESTful API接口
|
||||
|
||||
16.1.2 调用DeepSeek API接口的基本流程
|
||||
|
||||
16.1.3 实战案例49:调用DeepSeek API获取财经新闻简报
|
||||
|
||||
16.1.4 实战案例50:使用Tushare API+DeepSeek API分析股票数据简报
|
||||
|
||||
16.2 智能体在量化交易中的应用
|
||||
|
||||
16.2.1 智能体介绍简报
|
||||
|
||||
16.2.2 扣子智能体平台
|
||||
|
||||
16.3 实战案例51:实现“财经新闻快报”智能体
|
||||
|
||||
16.3.1 步骤1:创建智能体
|
||||
|
||||
16.3.2 步骤2:创建工作流
|
||||
|
||||
16.3.3 步骤3:添加节点
|
||||
|
||||
16.3.4 步骤4:试运行
|
||||
|
||||
16.3.5 步骤5:发布
|
||||
|
||||
16.3.6 步骤6:实时测试
|
||||
|
||||
16.4 智能体与量化交易现状和未来发展
|
||||
|
||||
16.4.1 当前状况
|
||||
|
||||
16.4.2 未来展望
|
||||
|
||||
16.5 本章总结
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
============================================================
|
||||
数据质量报告 / Data Quality Report
|
||||
生成时间: 2026-06-07T16:05:29.175368
|
||||
数据源: AKShare (fund_etf_hist_em)
|
||||
============================================================
|
||||
|
||||
159995 (芯片ETF):
|
||||
日期范围: 2021-02-04 ~ 2025-05-30 (1043 天)
|
||||
原始缺失: 265 天 (17.1%)
|
||||
日均收益率: +0.000172
|
||||
日波动率: 0.021145
|
||||
最大日涨幅: +10.01%
|
||||
最大日跌幅: -9.05%
|
||||
|
||||
159819 (人工智能ETF):
|
||||
日期范围: 2021-02-04 ~ 2025-05-30 (1043 天)
|
||||
原始缺失: 421 天 (27.1%)
|
||||
日均收益率: +0.000163
|
||||
日波动率: 0.019471
|
||||
最大日涨幅: +10.07%
|
||||
最大日跌幅: -9.95%
|
||||
|
||||
516160 (新能源ETF):
|
||||
日期范围: 2021-02-04 ~ 2025-05-30 (1043 天)
|
||||
原始缺失: 510 天 (32.8%)
|
||||
日均收益率: -0.000343
|
||||
日波动率: 0.020161
|
||||
最大日涨幅: +10.07%
|
||||
最大日跌幅: -9.98%
|
||||
|
||||
159928 (消费ETF):
|
||||
日期范围: 2021-02-04 ~ 2025-05-30 (1043 天)
|
||||
原始缺失: 0 天 (0.0%)
|
||||
日均收益率: -0.000380
|
||||
日波动率: 0.015514
|
||||
最大日涨幅: +10.01%
|
||||
最大日跌幅: -9.94%
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,465 @@
|
|||
# =============================================================================
|
||||
# Real Data Acquisition Demo — AKShare
|
||||
# 真实数据获取演示 — AKShare 版
|
||||
# =============================================================================
|
||||
#
|
||||
# AKShare 是一个完全免费的开源金融数据接口,无需注册、无需 Token。
|
||||
# 覆盖 A 股/港股/美股/期货/外汇/宏观经济等数据,是目前个人投资者
|
||||
# 最实用的免费数据源。
|
||||
#
|
||||
# Prerequisites / 安装:
|
||||
# pip install akshare pandas numpy matplotlib
|
||||
#
|
||||
# Topics covered / 涵盖主题:
|
||||
# §1 AKShare 简介与基本用法
|
||||
# §2 获取 A 股行业 ETF 日线数据(轮动策略核心输入)
|
||||
# §3 获取宽基指数数据(沪深300 / 中证500)
|
||||
# §4 获取北向资金数据(情绪因子数据源)
|
||||
# §5 获取融资融券数据(杠杆情绪数据源)
|
||||
# §6 真实数据的清洗陷阱(与合成数据的关键差异)
|
||||
# §7 数据存储:构建本地研究数据库
|
||||
# §8 数据质量报告生成
|
||||
# =============================================================================
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
import time
|
||||
import os
|
||||
|
||||
# ── 绕过系统代理,直连东方财富 ──
|
||||
# macOS 上的 Clash/小火箭等代理工具的出口 IP 容易被东方财富反爬封禁。
|
||||
# 设置环境变量让 requests 库对 eastmoney.com 不走代理。
|
||||
os.environ["NO_PROXY"] = os.environ.get("NO_PROXY", "") + ",eastmoney.com,eastmoneyfutures.com,10jqka.com.cn"
|
||||
os.environ["no_proxy"] = os.environ["NO_PROXY"]
|
||||
|
||||
# ── 检查 akshare 是否安装 ──
|
||||
try:
|
||||
import akshare as ak
|
||||
print(f"✓ AKShare 版本: {ak.__version__}")
|
||||
except ImportError:
|
||||
print("❌ AKShare 未安装。请在 trading conda 环境中执行:")
|
||||
print(" conda activate trading")
|
||||
print(" pip install akshare")
|
||||
raise
|
||||
|
||||
print("=" * 68)
|
||||
print(" 真实数据获取演示 — AKShare 版")
|
||||
print(" Real Data Acquisition Demo with AKShare")
|
||||
print("=" * 68)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §1 AKShare 简介与基本用法
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# AKShare 特点:
|
||||
# • 完全免费,无需注册
|
||||
# • 数据来源于东方财富、新浪财经、交易所等公开接口
|
||||
# • 函数名遵循 fund_xxx / stock_xxx / macro_xxx 等命名规范
|
||||
# • 每次调用触发一次 HTTP 请求,批量获取需注意频率
|
||||
#
|
||||
# 基本用法:
|
||||
# df = ak.function_name(param1=value1, param2=value2)
|
||||
# → 返回 pandas DataFrame
|
||||
#
|
||||
# 文档: https://akshare.akfamily.xyz/
|
||||
|
||||
print("\n[§1] AKShare 简介")
|
||||
print(f" 数据接口数量: 数千个 (覆盖股票/基金/期货/外汇/宏观/另类)")
|
||||
print(f" 数据来源: 东方财富、新浪财经、交易所公开接口等")
|
||||
print(f" 费用: 完全免费")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §2 获取 A 股行业 ETF 日线数据
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 这是 demo_07 (ETF 轮动策略) 的真实数据替代方案。
|
||||
# 下面获取的 ETF 代码与 demo_07 的 ETF_UNIVERSE 一一对应。
|
||||
#
|
||||
# AKShare 接口: fund_etf_hist_em()
|
||||
# symbol — ETF 代码 (如 "159995")
|
||||
# period — "daily" / "weekly" / "monthly"
|
||||
# start_date / end_date — "YYYYMMDD" 格式
|
||||
# adjust — "" (不复权) / "qfq" (前复权) / "hfq" (后复权)
|
||||
# ETF 通常用 "" 或 "qfq"
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§2] 获取行业 ETF 日线数据")
|
||||
|
||||
# A 股行业 ETF 池 — 与 demo_07 对应
|
||||
ETF_UNIVERSE = {
|
||||
"159995": "芯片ETF",
|
||||
"159819": "人工智能ETF",
|
||||
"516160": "新能源ETF",
|
||||
"159928": "消费ETF",
|
||||
"512170": "医疗ETF",
|
||||
"512880": "证券ETF",
|
||||
# 宽基 ETF (新增)
|
||||
"510300": "沪深300ETF",
|
||||
"510500": "中证500ETF",
|
||||
# 国债 ETF (避险资产)
|
||||
"511010": "国债ETF",
|
||||
}
|
||||
|
||||
START_DATE = "20190101"
|
||||
END_DATE = "20250601"
|
||||
|
||||
# ── 安全获取单只 ETF 数据 (带重试和限速) ──
|
||||
def fetch_etf_safe(code: str, start: str, end: str, max_retries: int = 3):
|
||||
"""
|
||||
安全获取 ETF 日线数据,失败时自动重试并控制请求频率。
|
||||
网络抖动或东方财富接口偶发不稳定时非常必要。
|
||||
"""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
df = ak.fund_etf_hist_em(
|
||||
symbol=code,
|
||||
period="daily",
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
adjust="qfq", # 前复权
|
||||
)
|
||||
return df
|
||||
except Exception as e:
|
||||
err_msg = str(e)
|
||||
if "ProxyError" in err_msg or "RemoteDisconnected" in err_msg:
|
||||
wait = (attempt + 1) * 5 # 代理/连接问题,等更久
|
||||
print(f"\n ⚠ {code} 连接被拒绝 (代理/反爬),{wait}s 后重试...")
|
||||
else:
|
||||
wait = 2.0
|
||||
print(f"\n ⚠ {code} 第 {attempt+1} 次获取失败: {e}")
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(wait)
|
||||
print(f"\n ✗ {code} 全部 {max_retries} 次获取失败,跳过")
|
||||
return None
|
||||
|
||||
|
||||
etf_data = {}
|
||||
for i, (code, name) in enumerate(ETF_UNIVERSE.items()):
|
||||
if i > 0:
|
||||
# 请求间隔 + 随机抖动,避免触发东方财富反爬
|
||||
time.sleep(2.0 + np.random.uniform(0, 1.5))
|
||||
print(f" 获取 {code} ({name})...", end=" ")
|
||||
df = fetch_etf_safe(code, START_DATE, END_DATE)
|
||||
if df is not None:
|
||||
etf_data[code] = df
|
||||
print(f"{len(df)} 行, {df['日期'].iloc[0]} ~ {df['日期'].iloc[-1]}")
|
||||
else:
|
||||
print("失败 ✗")
|
||||
|
||||
print(f"\n 成功获取: {len(etf_data)} / {len(ETF_UNIVERSE)} 只 ETF")
|
||||
|
||||
# ── 构建价格面板 (Multi-Asset Price Panel) ──
|
||||
# 这是最关键的步骤:将多只 ETF 的收盘价对齐到统一的日期轴上。
|
||||
# 真实数据中,不同 ETF 可能有不同的上市日期和停牌日期,
|
||||
# 对齐方式的选择直接影响后续所有分析。
|
||||
|
||||
if etf_data:
|
||||
price_panel = pd.DataFrame()
|
||||
for code, df in etf_data.items():
|
||||
# 设置日期索引,提取收盘价
|
||||
df_indexed = df.set_index("日期")["收盘"].copy()
|
||||
df_indexed.name = code
|
||||
price_panel = pd.concat([price_panel, df_indexed], axis=1)
|
||||
|
||||
# 确保日期索引排序
|
||||
price_panel.index = pd.to_datetime(price_panel.index)
|
||||
price_panel = price_panel.sort_index()
|
||||
|
||||
print(f"\n 价格面板: {price_panel.shape[0]} 个交易日 × {price_panel.shape[1]} 只 ETF")
|
||||
print(f" 日期范围: {price_panel.index[0].date()} ~ {price_panel.index[-1].date()}")
|
||||
print(f" 各 ETF 起止日期:")
|
||||
for col in price_panel.columns:
|
||||
valid = price_panel[col].dropna()
|
||||
if len(valid) > 0:
|
||||
print(f" {col} ({ETF_UNIVERSE.get(col, '?')}): {valid.index[0].date()} ~ {valid.index[-1].date()}, {len(valid)} 天")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §3 获取宽基指数数据
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# AKShare 接口: stock_zh_index_daily()
|
||||
# symbol — 指数代码:
|
||||
# "sh000300" → 沪深300
|
||||
# "sh000905" → 中证500
|
||||
# "sz399006" → 创业板指
|
||||
# "sh000016" → 上证50
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§3] 获取宽基指数数据")
|
||||
|
||||
INDEX_CODES = {
|
||||
"sh000300": "沪深300",
|
||||
"sh000905": "中证500",
|
||||
"sz399006": "创业板指",
|
||||
"sh000016": "上证50",
|
||||
}
|
||||
|
||||
index_data = {}
|
||||
for symbol, name in INDEX_CODES.items():
|
||||
print(f" 获取 {symbol} ({name})...", end=" ")
|
||||
try:
|
||||
df = ak.stock_zh_index_daily(symbol=symbol)
|
||||
index_data[symbol] = df
|
||||
print(f"{len(df)} 行, {df['date'].iloc[0]} ~ {df['date'].iloc[-1]}")
|
||||
time.sleep(0.3)
|
||||
except Exception as e:
|
||||
print(f"失败: {e}")
|
||||
|
||||
|
||||
# ── 计算指数滚动估值参考 (PE/PB 分位数需另接接口,此处展示收益基座) ──
|
||||
if index_data:
|
||||
# 对齐为面板
|
||||
index_panel = pd.DataFrame()
|
||||
for sym, df in index_data.items():
|
||||
s = df.set_index("date")["close"].copy()
|
||||
s.name = sym
|
||||
index_panel = pd.concat([index_panel, s], axis=1)
|
||||
index_panel.index = pd.to_datetime(index_panel.index)
|
||||
index_panel = index_panel.sort_index()
|
||||
|
||||
# 计算滚动年化收益 (252 日)
|
||||
rolling_ret = index_panel.pct_change(252).dropna()
|
||||
if len(rolling_ret) > 0:
|
||||
print(f"\n 最新滚动年化收益 ({rolling_ret.index[-1].date()}):")
|
||||
for col in rolling_ret.columns:
|
||||
name = INDEX_CODES.get(col, col)
|
||||
val = rolling_ret[col].iloc[-1]
|
||||
print(f" {name}: {val:+.2%}")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §4 获取北向资金数据(关键情绪因子数据源)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 北向资金 (North-bound Capital Flow) 指通过沪深港通从香港流入 A 股
|
||||
# 的外资。净买入额被视为外资对 A 股情绪的"投票机"。
|
||||
#
|
||||
# AKShare 接口: stock_hsgt_hist_em() → 沪深港通历史资金流向
|
||||
# stock_hsgt_north_net_flow_in_em() → 北向净流入
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§4] 获取北向资金数据")
|
||||
|
||||
try:
|
||||
# 北向资金: stock_hsgt_hist_em 获取沪股通/深股通历史资金流向
|
||||
for market, label in [("沪股通", "沪股通(北向)"), ("深股通", "深股通(北向)")]:
|
||||
try:
|
||||
hsgt = ak.stock_hsgt_hist_em(symbol=market)
|
||||
if hsgt is not None and len(hsgt) > 0:
|
||||
print(f" {label}: {hsgt.shape}")
|
||||
print(f" 列名: {list(hsgt.columns)}")
|
||||
print(f" 最新 3 行:\n{hsgt.tail(3)}")
|
||||
time.sleep(1.5) # 避免触发反爬
|
||||
except Exception as e:
|
||||
print(f" {label} 获取失败: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" 北向资金获取失败: {e}")
|
||||
print(f" 提示: AKShare 接口可能已更新,请查阅最新文档")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §5 获取融资融券数据(杠杆情绪数据源)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 融资余额 (Margin Balance) 反映散户借钱买股的意愿。
|
||||
# 融资余额大幅上升 → 散户看多情绪高涨(注意:极端值往往是反向指标)
|
||||
# 融资余额骤降 → 恐慌去杠杆,市场底部特征之一
|
||||
#
|
||||
# AKShare 接口: stock_margin_sz() / stock_margin_sh() → 深圳/上海融资融券明细
|
||||
# stock_margin_detail_sse() → 上交所融资融券汇总
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§5] 获取融资融券数据")
|
||||
|
||||
try:
|
||||
# 上交所融资融券汇总 (日频)
|
||||
# stock_margin_sse: 历史序列 (start_date/end_date)
|
||||
# stock_margin_detail_sse: 单日快照 (date='YYYYMMDD')
|
||||
margin_sse = ak.stock_margin_sse(start_date="20240101", end_date="20250601")
|
||||
if margin_sse is not None and len(margin_sse) > 0:
|
||||
print(f" 上交所融资融券: {margin_sse.shape}")
|
||||
print(f" 列名: {list(margin_sse.columns)}")
|
||||
print(f" 最新数据:\n{margin_sse.tail(3)}")
|
||||
else:
|
||||
print(" 未获取到融资融券数据")
|
||||
|
||||
except Exception as e:
|
||||
print(f" 融资融券获取失败: {e}")
|
||||
print(f" 说明: 此接口可能需要特定参数格式,请查阅文档")
|
||||
print(f" 备选: 可直接使用东方财富网页爬取")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §6 真实数据的清洗陷阱
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 合成数据 (Demo 系列的 GBM/Factor Model) 没有这些问题:
|
||||
# ① 不同标的上市日期不同 → 面板前段大量 NaN
|
||||
# ② 停牌 (suspension) → 面板中间出现 NaN 缺口
|
||||
# ③ 涨跌停日 → 价格"真实"但无法成交
|
||||
# ④ ETF 分红/拆分 → 不复权价格存在跳跃
|
||||
# ⑤ 数据源异常 → 极少数日期的 OHLC 数据错乱
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§6] 真实数据清洗演示")
|
||||
|
||||
if etf_data:
|
||||
# ── 6-A: 缺失值分析 ──
|
||||
print(f"\n 6-A 缺失值分析:")
|
||||
missing_pct = price_panel.isna().mean().sort_values(ascending=False)
|
||||
for code in missing_pct.index[:5]:
|
||||
pct = missing_pct[code]
|
||||
name = ETF_UNIVERSE.get(code, code)
|
||||
print(f" {code} {name}: {pct:.1%} 缺失")
|
||||
|
||||
# ── 6-B: 前向填充 (仅 ffill, 禁止 bfill!) ──
|
||||
# bfill 会用"未来还没发生的数据"填补今天的空值 → Look-Ahead Bias
|
||||
print(f"\n 6-B 缺失值处理 (ffill only):")
|
||||
missing_before = price_panel.isna().sum().sum()
|
||||
clean_prices = price_panel.ffill() # 步骤1: 前向填充
|
||||
# 步骤2: 丢弃早期所有标的都 NaN 的行(通常是面板最前面)
|
||||
clean_prices = clean_prices.dropna(how='any')
|
||||
missing_after = clean_prices.isna().sum().sum()
|
||||
print(f" 填充前 NaN: {missing_before} → 填充后 NaN: {missing_after}")
|
||||
print(f" 丢弃了 {len(price_panel) - len(clean_prices)} 个早期交易日")
|
||||
|
||||
# ── 6-C: 收益率计算与异常值标记 ──
|
||||
print(f"\n 6-C 收益率与涨跌停标记:")
|
||||
returns = clean_prices.pct_change()
|
||||
|
||||
# 涨跌停检测: A 股 ETF 理论涨跌停 ±10%
|
||||
LIMIT_PCT = 0.10
|
||||
limit_up = (returns >= LIMIT_PCT - 0.002).sum()
|
||||
limit_down = (returns <= -LIMIT_PCT + 0.002).sum()
|
||||
for code in returns.columns[:5]:
|
||||
up = limit_up[code]
|
||||
dn = limit_down[code]
|
||||
if up > 0 or dn > 0:
|
||||
name = ETF_UNIVERSE.get(code, code)
|
||||
print(f" {code} {name}: 涨停 {up} 天, 跌停 {dn} 天")
|
||||
|
||||
# ── 6-D: 数据连续性检查 ──
|
||||
print(f"\n 6-D 数据连续性检查:")
|
||||
date_gaps = 0
|
||||
for col in clean_prices.columns:
|
||||
ser = clean_prices[col].dropna()
|
||||
if len(ser) < 2:
|
||||
continue
|
||||
# 检查自然日连续性 → 非交易日(周末/假日)是正常的
|
||||
trading_gaps = ser.index.to_series().diff().dt.days
|
||||
long_gaps = trading_gaps[trading_gaps > 7] # 连续停牌 > 7 天
|
||||
if len(long_gaps) > 0:
|
||||
name = ETF_UNIVERSE.get(col, col)
|
||||
print(f" {col} {name}: {len(long_gaps)} 次连续停牌 > 7 天")
|
||||
date_gaps += len(long_gaps)
|
||||
if date_gaps == 0:
|
||||
print(f" 所有 ETF 无连续停牌 > 7 天 ✓")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §7 数据存储:构建本地研究数据库
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 存储原则是"存原始数据 + 存清洗后数据",不要只存一个。
|
||||
# 原因: 你以后可能想换一种清洗方式,而原始数据丢了就回不去了。
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§7] 数据存储")
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
|
||||
if etf_data:
|
||||
# 保存清洗后的价格面板 (研究级)
|
||||
clean_path = os.path.join(DATA_DIR, "etf_price_panel_clean.csv")
|
||||
clean_prices.to_csv(clean_path)
|
||||
print(f" ✓ 清洗后价格面板 → {clean_path}")
|
||||
|
||||
# 保存收益率面板
|
||||
returns_path = os.path.join(DATA_DIR, "etf_returns_panel.csv")
|
||||
returns.to_csv(returns_path)
|
||||
print(f" ✓ 收益率面板 → {returns_path}")
|
||||
|
||||
if index_data and len(index_panel) > 0:
|
||||
index_path = os.path.join(DATA_DIR, "index_prices.csv")
|
||||
index_panel.to_csv(index_path)
|
||||
print(f" ✓ 指数价格 → {index_path}")
|
||||
|
||||
print(f"\n 数据目录: {DATA_DIR}")
|
||||
print(f" 文件列表: {os.listdir(DATA_DIR) if os.path.exists(DATA_DIR) else '无'}")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §8 数据质量报告
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 每次拉取数据后,生成一份质量报告,记录:
|
||||
# - 各标的覆盖日期范围
|
||||
# - 缺失值比例
|
||||
# - 极端收益率事件
|
||||
# - 数据拉取时间戳
|
||||
# 这对后期回溯调试非常有用——"我用的数据是哪天拉的?有什么已知缺陷?"
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§8] 数据质量报告")
|
||||
|
||||
if etf_data:
|
||||
report_lines = []
|
||||
report_lines.append("=" * 60)
|
||||
report_lines.append("数据质量报告 / Data Quality Report")
|
||||
report_lines.append(f"生成时间: {datetime.now().isoformat()}")
|
||||
report_lines.append(f"数据源: AKShare (fund_etf_hist_em)")
|
||||
report_lines.append("=" * 60)
|
||||
|
||||
for code in clean_prices.columns:
|
||||
name = ETF_UNIVERSE.get(code, code)
|
||||
ser = clean_prices[code].dropna()
|
||||
ret_ser = returns[code].dropna()
|
||||
n = len(ser)
|
||||
missing_input = price_panel[code].isna().sum()
|
||||
|
||||
report_lines.append(
|
||||
f"\n{code} ({name}):"
|
||||
f"\n 日期范围: {ser.index[0].date()} ~ {ser.index[-1].date()} ({n} 天)"
|
||||
f"\n 原始缺失: {missing_input} 天 ({missing_input/len(price_panel):.1%})"
|
||||
f"\n 日均收益率: {ret_ser.mean():+.6f}"
|
||||
f"\n 日波动率: {ret_ser.std():.6f}"
|
||||
f"\n 最大日涨幅: {ret_ser.max():+.2%}"
|
||||
f"\n 最大日跌幅: {ret_ser.min():+.2%}"
|
||||
)
|
||||
|
||||
# 打印报告
|
||||
report_text = "\n".join(report_lines)
|
||||
print(report_text)
|
||||
|
||||
# 保存报告
|
||||
report_path = os.path.join(DATA_DIR, "data_quality_report.txt")
|
||||
with open(report_path, "w", encoding="utf-8") as f:
|
||||
f.write(report_text)
|
||||
print(f"\n ✓ 质量报告已保存 → {report_path}")
|
||||
|
||||
|
||||
print("\n" + "=" * 68)
|
||||
print(" ✓ AKShare 数据获取 Demo 完成")
|
||||
print("=" * 68)
|
||||
print(f"""
|
||||
关键收获:
|
||||
1. AKShare 完全免费,覆盖 ETF / 指数 / 资金流向 / 融资融券
|
||||
2. 真实数据需要处理: 上市日期不一致、停牌缺口、涨跌停标记
|
||||
3. 填充缺失值只用 ffill() —— bfill() 会引入 Look-Ahead Bias
|
||||
4. 数据存储时同时保留"原始"和"清洗后"两个版本
|
||||
5. 每次拉取数据都应生成质量报告,记录已知缺陷
|
||||
|
||||
下一步: 将清洗后的 ETF 价格面板替换 demo_07 的合成数据,
|
||||
重新运行 ETF 轮动策略回测,观察真实数据下的策略表现。
|
||||
""")
|
||||
|
|
@ -0,0 +1,619 @@
|
|||
# =============================================================================
|
||||
# Real Data Acquisition Demo — Tushare Pro
|
||||
# 真实数据获取演示 — Tushare Pro 版
|
||||
# =============================================================================
|
||||
#
|
||||
# Tushare Pro 是国内最成熟的金融数据 API 之一,数据质量和稳定性
|
||||
# 优于 AKShare,适合策略验证通过后切换到生产级数据。
|
||||
#
|
||||
# 与 AKShare 的核心差异:
|
||||
# • 需要注册获取 Token (免费注册,基础接口免费)
|
||||
# • 积分系统: 注册送 120 分,部分接口需要更高积分
|
||||
# • 股票代码格式: "000001.SZ" (而非纯数字)
|
||||
# • 数据质量更高、接口更稳定
|
||||
# • 支持基本面数据 (PE/PB/ROE) 和因子数据
|
||||
#
|
||||
# Prerequisites / 前置准备:
|
||||
# 1. 注册 Tushare: https://tushare.pro/register
|
||||
# 2. 获取 Token: 登录后 → 个人主页 → 接口 Token
|
||||
# 3. 安装: pip install tushare pandas numpy
|
||||
#
|
||||
# Topics covered / 涵盖主题:
|
||||
# §1 Tushare 注册与 Token 配置
|
||||
# §2 获取 A 股个股日线数据
|
||||
# §3 获取指数日线数据
|
||||
# §4 获取股票基础信息 (上市日期/行业/市值)
|
||||
# §5 获取财务数据 (PE/PB/ROE — 价值因子的数据源)
|
||||
# §6 获取指数成分股权重 (组合优化的输入)
|
||||
# §7 获取行业分类 (申万行业)
|
||||
# §8 数据清洗与对齐
|
||||
# §9 构建本地数据库
|
||||
# §10 AKShare vs Tushare 对比总结
|
||||
# =============================================================================
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
# ── 检查 tushare 是否安装 ──
|
||||
try:
|
||||
import tushare as ts
|
||||
print(f"✓ Tushare 版本: {ts.__version__}")
|
||||
except ImportError:
|
||||
print("❌ Tushare 未安装。请在 trading conda 环境中执行:")
|
||||
print(" conda activate trading")
|
||||
print(" pip install tushare")
|
||||
raise
|
||||
|
||||
print("=" * 68)
|
||||
print(" 真实数据获取演示 — Tushare Pro 版")
|
||||
print(" Real Data Acquisition Demo with Tushare Pro")
|
||||
print("=" * 68)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §1 Tushare 注册与 Token 配置
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 使用步骤:
|
||||
# 1. 访问 https://tushare.pro/register 注册 (用手机号即可)
|
||||
# 2. 登录后 → 个人主页 → 接口 Token → 复制那一长串字符
|
||||
# 3. 把 Token 粘贴到下面 (或设置环境变量 TUSHARE_TOKEN)
|
||||
#
|
||||
# 积分说明:
|
||||
# 注册: 120 分 (基础接口可用)
|
||||
# 完善个人信息: +20 分
|
||||
# 推荐他人注册: 各 +50 分
|
||||
# 捐赠: 200 RMB = 3000 分 (解锁全部接口)
|
||||
#
|
||||
# 日常使用建议:
|
||||
# - 将 Token 存为环境变量而非硬编码在代码中
|
||||
# - 每个接口都标注所需最低积分,避免超限调用
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§1] Tushare Token 配置")
|
||||
|
||||
TUSHARE_TOKEN = os.environ.get("TUSHARE_TOKEN", "")
|
||||
|
||||
if not TUSHARE_TOKEN:
|
||||
print(" ⚠ 未检测到 TUSHARE_TOKEN 环境变量")
|
||||
print(" ── 获取 Token 的步骤 ──")
|
||||
print(" 1. 访问 https://tushare.pro/register 注册")
|
||||
print(" 2. 登录后进入个人主页 → 接口 Token")
|
||||
print(" 3. 复制 Token 后,设置环境变量:")
|
||||
print(" export TUSHARE_TOKEN='你的token'")
|
||||
print()
|
||||
print(" 或者直接在下方代码中填入 (仅本地测试用):")
|
||||
print(' TUSHARE_TOKEN = "你的token"')
|
||||
print()
|
||||
print(" ⚠ 本 Demo 将继续运行,但数据获取部分会跳过或使用模拟数据")
|
||||
print(" 您仍然可以看到完整的代码结构和数据清洗逻辑。")
|
||||
print()
|
||||
|
||||
# 尝试初始化 Pro API
|
||||
PRO = None
|
||||
TOKEN_VALID = False
|
||||
if TUSHARE_TOKEN:
|
||||
try:
|
||||
PRO = ts.pro_api(TUSHARE_TOKEN)
|
||||
# 用最简单接口测试 Token 是否有效
|
||||
test = PRO.trade_cal(exchange='SSE', start_date='20250601', end_date='20250605')
|
||||
TOKEN_VALID = len(test) > 0
|
||||
print(f" ✓ Token 验证成功")
|
||||
print(f" ✓ Pro API 就绪")
|
||||
except Exception as e:
|
||||
print(f" ✗ Token 验证失败: {e}")
|
||||
else:
|
||||
print(f" - Token 未设置,跳过远程数据获取")
|
||||
print(f" - 代码结构完整,可阅读学习流程逻辑")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §2 获取 A 股个股日线数据
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 接口: pro.daily()
|
||||
# 所需积分: 120 分 (注册即送)
|
||||
# 每日调用上限: 200 次
|
||||
# 单次最多返回: 约 5000 条记录
|
||||
#
|
||||
# 参数:
|
||||
# ts_code — 股票代码 "000001.SZ" / "600000.SH"
|
||||
# trade_date— 交易日期 "YYYYMMDD"
|
||||
# start_date/end_date — 日期范围
|
||||
#
|
||||
# 注意: Tushare 的日期格式是 "YYYYMMDD" (无连字符)
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§2] 获取个股日线数据")
|
||||
|
||||
# ── 构建 A 股代表性标的池 ──
|
||||
STOCK_POOL = {
|
||||
"000001.SZ": "平安银行",
|
||||
"000002.SZ": "万科A",
|
||||
"000858.SZ": "五粮液",
|
||||
"600519.SH": "贵州茅台",
|
||||
"600036.SH": "招商银行",
|
||||
"600276.SH": "恒瑞医药",
|
||||
"300750.SZ": "宁德时代",
|
||||
"601318.SH": "中国平安",
|
||||
}
|
||||
|
||||
# ── 日期范围转换 ──
|
||||
# Demo 系列用 "YYYY-MM-DD",Tushare 用 "YYYYMMDD"
|
||||
START_DATE = "20190101"
|
||||
END_DATE = "20250601"
|
||||
|
||||
|
||||
def fetch_daily_safe(pro, ts_code, start, end, max_retries=3):
|
||||
"""
|
||||
安全获取个股日线数据。
|
||||
|
||||
Tushare 每次调用返回约 5000 条,单只股票 6 年约 1500 个交易日,
|
||||
一次调用即可覆盖。如果有更多股票/更长区间,需要分多次调用并拼接。
|
||||
"""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
df = pro.daily(
|
||||
ts_code=ts_code,
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
fields='ts_code,trade_date,open,high,low,close,pre_close,'
|
||||
'change,pct_chg,vol,amount'
|
||||
)
|
||||
time.sleep(0.3) # 频率控制: Tushare 每分钟上限约 200 次
|
||||
return df
|
||||
except Exception as e:
|
||||
print(f" ⚠ {ts_code} 第 {attempt+1} 次失败: {e}")
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(2.0)
|
||||
return None
|
||||
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
stock_daily_data = {}
|
||||
for code, name in STOCK_POOL.items():
|
||||
print(f" 获取 {code} ({name})...", end=" ")
|
||||
df = fetch_daily_safe(PRO, code, START_DATE, END_DATE)
|
||||
if df is not None and len(df) > 0:
|
||||
stock_daily_data[code] = df
|
||||
print(f"{len(df)} 行, {df['trade_date'].iloc[-1]} ~ {df['trade_date'].iloc[0]}")
|
||||
else:
|
||||
print("无数据")
|
||||
|
||||
if stock_daily_data:
|
||||
# ── 构建价格面板 ──
|
||||
stock_price_panel = pd.DataFrame()
|
||||
for code, df in stock_daily_data.items():
|
||||
# Tushare 返回的 trade_date 是 YYYYMMDD 格式
|
||||
df = df.copy()
|
||||
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
|
||||
df = df.sort_values('trade_date')
|
||||
s = df.set_index('trade_date')['close'].copy()
|
||||
s.name = code
|
||||
stock_price_panel = pd.concat([stock_price_panel, s], axis=1)
|
||||
|
||||
print(f"\n 个股价格面板: {stock_price_panel.shape}")
|
||||
# 展示最新 3 行
|
||||
print(f" 最新 3 个交易日:")
|
||||
print(stock_price_panel.tail(3).to_string())
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
print(f" 演示: 如果 Token 有效,会拉取以下 {len(STOCK_POOL)} 只股票的数据")
|
||||
for code, name in STOCK_POOL.items():
|
||||
print(f" {code} ({name})")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §3 获取指数日线数据
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 接口: pro.index_daily()
|
||||
# 所需积分: 120 分
|
||||
#
|
||||
# 指数代码:
|
||||
# 000300.SH — 沪深300
|
||||
# 000905.SH — 中证500
|
||||
# 000016.SH — 上证50
|
||||
# 399006.SZ — 创业板指
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§3] 获取指数日线数据")
|
||||
|
||||
INDEX_CODES = {
|
||||
"000300.SH": "沪深300",
|
||||
"000905.SH": "中证500",
|
||||
"000016.SH": "上证50",
|
||||
"399006.SZ": "创业板指",
|
||||
}
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
index_data = {}
|
||||
for code, name in INDEX_CODES.items():
|
||||
print(f" 获取 {code} ({name})...", end=" ")
|
||||
try:
|
||||
df = PRO.index_daily(
|
||||
ts_code=code,
|
||||
start_date=START_DATE,
|
||||
end_date=END_DATE,
|
||||
fields='ts_code,trade_date,close,open,high,low,vol,amount,pct_chg'
|
||||
)
|
||||
time.sleep(0.3)
|
||||
if df is not None and len(df) > 0:
|
||||
index_data[code] = df
|
||||
print(f"{len(df)} 行")
|
||||
else:
|
||||
print("无数据")
|
||||
except Exception as e:
|
||||
print(f"失败: {e}")
|
||||
|
||||
if index_data:
|
||||
index_panel = pd.DataFrame()
|
||||
for code, df in index_data.items():
|
||||
df = df.copy()
|
||||
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
|
||||
df = df.sort_values('trade_date')
|
||||
s = df.set_index('trade_date')['close']
|
||||
s.name = code
|
||||
index_panel = pd.concat([index_panel, s], axis=1)
|
||||
|
||||
print(f"\n 指数面板: {index_panel.shape}")
|
||||
# 年化收益对比
|
||||
ann_rets = (index_panel.iloc[-1] / index_panel.iloc[0]) ** (252.0 / len(index_panel)) - 1
|
||||
print(" 年化收益率 (CAGR):")
|
||||
for code, val in ann_rets.items():
|
||||
name = INDEX_CODES.get(code, code)
|
||||
print(f" {name}: {val:+.2%}")
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §4 获取股票基础信息
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 接口: pro.stock_basic()
|
||||
# 所需积分: 120 分
|
||||
# 功能: 获取股票列表,包含股票代码、名称、上市日期、退市日期、行业、地区等
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§4] 获取股票基础信息")
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
try:
|
||||
# 获取沪深两市全部 A 股列表
|
||||
stock_basic = PRO.stock_basic(
|
||||
exchange='',
|
||||
list_status='L', # L=上市, D=退市, P=暂停上市
|
||||
fields='ts_code,symbol,name,area,industry,market,list_date,'
|
||||
'delist_date,curr_type,list_status,enname'
|
||||
)
|
||||
if stock_basic is not None and len(stock_basic) > 0:
|
||||
print(f" 当前上市股票: {len(stock_basic)} 只")
|
||||
|
||||
# 退市股票 (用于幸存者偏差检查!)
|
||||
# 如果只拉当前上市股票,回测会漏掉已退市的垃圾公司
|
||||
# → 幸存者偏差 (Survivorship Bias) ← 这是实盘最大的坑之一
|
||||
delisted = PRO.stock_basic(
|
||||
exchange='',
|
||||
list_status='D', # 退市
|
||||
fields='ts_code,symbol,name,list_date,delist_date'
|
||||
)
|
||||
if delisted is not None and len(delisted) > 0:
|
||||
print(f" 历史退市股票: {len(delisted)} 只 ← 回测必须包含!")
|
||||
print(f" 退市样本 (前 5 只):")
|
||||
for _, row in delisted.head(5).iterrows():
|
||||
print(f" {row['ts_code']} {row['name']} "
|
||||
f"{row['list_date']} ~ {row['delist_date']}")
|
||||
|
||||
# 行业分布
|
||||
if 'industry' in stock_basic.columns:
|
||||
industry_counts = stock_basic['industry'].value_counts().head(10)
|
||||
print(f"\n 行业分布 Top 10:")
|
||||
for ind, cnt in industry_counts.items():
|
||||
print(f" {ind}: {cnt} 只")
|
||||
|
||||
except Exception as e:
|
||||
print(f" 获取失败: {e}")
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
print(" 提示: stock_basic() 可获取全市场股票列表和退市记录")
|
||||
print(" 退市数据对消除幸存者偏差至关重要")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §5 获取财务数据 (价值因子的数据源)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 这是 Tushare 相比 AKShare 最大的优势领域 ——
|
||||
# AKShare 也有部分财务接口,但覆盖度和稳定性不如 Tushare。
|
||||
#
|
||||
# 接口: pro.daily_basic() — 每日指标
|
||||
# 所需积分: 300 分 (需升级)
|
||||
# 字段: pe, pe_ttm, pb, ps, ps_ttm, dv_ratio, total_share, float_share,
|
||||
# total_mv, circ_mv
|
||||
#
|
||||
# 接口: pro.fina_indicator() — 财务指标
|
||||
# 所需积分: 600 分 (需进一步升级)
|
||||
# 字段: roe, roa, grossprofit_margin, netprofit_margin, debt_to_assets 等
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§5] 获取财务数据")
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
try:
|
||||
# daily_basic: 日频估值指标 (PE/PB/市值)
|
||||
daily_basic = PRO.daily_basic(
|
||||
ts_code='000001.SZ',
|
||||
start_date='20240101',
|
||||
end_date='20250601',
|
||||
fields='ts_code,trade_date,close,pe,pe_ttm,pb,ps,total_mv,circ_mv'
|
||||
)
|
||||
if daily_basic is not None and len(daily_basic) > 0:
|
||||
print(f" 平安银行 (000001.SZ) 日频估值: {len(daily_basic)} 行")
|
||||
print(f" 字段: {list(daily_basic.columns)}")
|
||||
print(f" 最新 PE_TTM / PB / 市值:")
|
||||
latest = daily_basic.iloc[0]
|
||||
print(f" PE(TTM): {latest.get('pe_ttm', 'N/A')}")
|
||||
print(f" PB: {latest.get('pb', 'N/A')}")
|
||||
print(f" 总市值: {latest.get('total_mv', 'N/A')} 万元")
|
||||
print(f"\n ⚠ 注意: 如果返回的 pe_ttm 都是 NaN, 说明积分不足 (需 300 分)")
|
||||
else:
|
||||
print(" 未获取到数据 (积分可能不足)")
|
||||
|
||||
except Exception as e:
|
||||
print(f" 获取失败: {e}")
|
||||
print(f" 提示: daily_basic 需要 300 积分,注册仅送 120 分")
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
print(" 提示: Tushare 的 daily_basic() 和 fina_indicator() 可获取")
|
||||
print(" PE/PB/ROE/ROA/毛利率/资产负债率等基本面数据")
|
||||
print(" 这些都是价值因子 (Value Factor) 的核心输入")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §6 获取指数成分股权重
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 接口: pro.index_weight() — 指数成分股权重
|
||||
# 所需积分: 120 分
|
||||
# 用途: 组合优化 (Black-Litterman 的市场均衡权重)
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§6] 获取指数成分股权重")
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
try:
|
||||
# 沪深300 成分股权重 (每月更新)
|
||||
index_weights = PRO.index_weight(
|
||||
index_code='000300.SH',
|
||||
start_date='20240101',
|
||||
end_date='20250601',
|
||||
)
|
||||
if index_weights is not None and len(index_weights) > 0:
|
||||
print(f" 沪深300 成分股权重: {len(index_weights)} 条记录")
|
||||
print(f" 字段: {list(index_weights.columns)}")
|
||||
# 最新一期 Top 10
|
||||
latest_date = index_weights['trade_date'].max() if 'trade_date' in index_weights.columns else None
|
||||
if latest_date is not None:
|
||||
latest_weights = index_weights[
|
||||
index_weights['trade_date'] == latest_date
|
||||
].nlargest(10, 'weight') if 'weight' in index_weights.columns else None
|
||||
if latest_weights is not None and len(latest_weights) > 0:
|
||||
print(f"\n {latest_date} 前 10 大权重股:")
|
||||
for _, row in latest_weights.iterrows():
|
||||
print(f" {row['con_code']} {row.get('con_name', '')}: "
|
||||
f"{row['weight']:.2%}")
|
||||
else:
|
||||
print(" 未获取到数据")
|
||||
except Exception as e:
|
||||
print(f" 获取失败: {e}")
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
print(" 提示: index_weight() 可获取沪深300/中证500等指数的成分股权重")
|
||||
print(" 这是 Black-Litterman 模型市场均衡组合的必需输入")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §7 获取行业分类 (申万行业)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# 申万行业分类是中国 A 股投研最常用的行业分类标准。
|
||||
# 在组合优化中 (demo_05), 行业约束需要知道每只股票属于哪个行业。
|
||||
#
|
||||
# 接口: pro.index_classify() — 申万行业分类
|
||||
# 所需积分: 120 分
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§7] 获取行业分类")
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
try:
|
||||
# 获取申万一级行业分类 (level='L1')
|
||||
sw_classify = PRO.index_classify(
|
||||
level='L1',
|
||||
src='SW2021' # 申万2021版行业分类
|
||||
)
|
||||
if sw_classify is not None and len(sw_classify) > 0:
|
||||
print(f" 申万一级行业: {sw_classify['industry_name'].nunique()} 个")
|
||||
print(f" 各行业成分股数量 Top 10:")
|
||||
industry_counts = sw_classify.groupby('industry_name').size().sort_values(ascending=False)
|
||||
for name, cnt in industry_counts.head(10).items():
|
||||
print(f" {name}: {cnt} 只")
|
||||
else:
|
||||
print(" 未获取到数据 (接口可能已变更)")
|
||||
except Exception as e:
|
||||
print(f" 获取失败: {e}")
|
||||
print(f" 提示: 申万行业分类接口可能已更新,建议查阅最新文档")
|
||||
else:
|
||||
print(" (跳过 — Token 未配置)")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §8 数据清洗与对齐 (Tushare 特有)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§8] 数据清洗与对齐")
|
||||
|
||||
if TOKEN_VALID and PRO and 'stock_daily_data' in dir() and stock_daily_data:
|
||||
# ── 缺失值分析 ──
|
||||
missing = stock_price_panel.isna().sum()
|
||||
print(f" 各标的缺失天数:")
|
||||
for code, cnt in missing.items():
|
||||
name = STOCK_POOL.get(code, code)
|
||||
print(f" {code} ({name}): {cnt} 天 ({cnt/len(stock_price_panel):.1%})")
|
||||
|
||||
# ── ffill + 丢弃行首 ──
|
||||
clean_prices = stock_price_panel.ffill().dropna(how='any')
|
||||
print(f"\n 清洗前: {stock_price_panel.shape[0]} 天")
|
||||
print(f" 清洗后: {clean_prices.shape[0]} 天 (丢弃 {stock_price_panel.shape[0] - clean_prices.shape[0]} 天)")
|
||||
|
||||
# ── 收益率面板 ──
|
||||
returns = clean_prices.pct_change().dropna()
|
||||
print(f" 收益率面板: {returns.shape}")
|
||||
|
||||
# ── 相关性矩阵 ──
|
||||
corr = returns.corr()
|
||||
print(f"\n 收益率相关性 (仅展示对角外最高相关的 3 对):")
|
||||
corr_unstack = corr.where(
|
||||
~np.eye(len(corr), dtype=bool)
|
||||
).unstack().dropna()
|
||||
top_pairs = corr_unstack.abs().nlargest(6)
|
||||
for (s1, s2), val in top_pairs.items():
|
||||
print(f" {s1} ↔ {s2}: {val:+.3f}")
|
||||
else:
|
||||
print(" (跳过 — 无数据可清洗)")
|
||||
print(" 提示: 清洗流程与 demo_akshare_data.py 相同,核心原则:")
|
||||
print(" 1. 只用 ffill(), 禁止 bfill()")
|
||||
print(" 2. 填充后 dropna(how='any') 丢弃仍有 NaN 的行")
|
||||
print(" 3. pct_change() 后再 dropna() 得到收益率面板")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §9 构建本地数据库
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# =============================================================================
|
||||
|
||||
print("\n[§9] 构建本地数据库")
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), "data", "tushare")
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
|
||||
if TOKEN_VALID and PRO:
|
||||
saved_files = []
|
||||
|
||||
if 'stock_daily_data' in dir() and stock_daily_data:
|
||||
# 保存清洗后价格面板
|
||||
clean_path = os.path.join(DATA_DIR, "stock_price_clean.csv")
|
||||
clean_prices.to_csv(clean_path)
|
||||
saved_files.append(clean_path)
|
||||
|
||||
# 保存收益率
|
||||
ret_path = os.path.join(DATA_DIR, "stock_returns.csv")
|
||||
returns.to_csv(ret_path)
|
||||
saved_files.append(ret_path)
|
||||
|
||||
if 'index_panel' in dir() and len(index_panel) > 0:
|
||||
idx_path = os.path.join(DATA_DIR, "index_prices.csv")
|
||||
index_panel.to_csv(idx_path)
|
||||
saved_files.append(idx_path)
|
||||
|
||||
# 保存拉取元信息
|
||||
meta_path = os.path.join(DATA_DIR, "fetch_metadata.txt")
|
||||
with open(meta_path, "w", encoding="utf-8") as f:
|
||||
f.write(f"数据源: Tushare Pro\n")
|
||||
f.write(f"拉取时间: {datetime.now().isoformat()}\n")
|
||||
f.write(f"数据范围: {START_DATE} ~ {END_DATE}\n")
|
||||
f.write(f"标的数量: {len(STOCK_POOL)} 只个股, {len(INDEX_CODES)} 个指数\n")
|
||||
saved_files.append(meta_path)
|
||||
|
||||
for f in saved_files:
|
||||
print(f" ✓ {f}")
|
||||
|
||||
print(f"\n 数据目录: {DATA_DIR}")
|
||||
print(f" 文件列表: {os.listdir(DATA_DIR) if os.path.exists(DATA_DIR) else '无'}")
|
||||
else:
|
||||
print(" (跳过 — 无数据可保存)")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# §10 AKShare vs Tushare 对比总结
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# =============================================================================
|
||||
|
||||
print("\n" + "=" * 68)
|
||||
print(" §10 AKShare vs Tushare 对比总结")
|
||||
print("=" * 68)
|
||||
|
||||
print("""
|
||||
┌───────────────────┬─────────────────────┬─────────────────────┐
|
||||
│ 维度 │ AKShare │ Tushare Pro │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 费用 │ 完全免费 │ 基础免费(120分) │
|
||||
│ │ │ 高级需积分/捐赠 │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 注册 │ 不需要 │ 需要手机号注册 │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 数据覆盖 │ 极广 (股/基/期/外/ │ 聚焦 A 股/指数/ │
|
||||
│ │ 宏/另类/舆情等) │ 基金/财务/因子 │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 数据稳定性 │ 中等 (依赖爬虫, │ 高 (独立数据源, │
|
||||
│ │ 接口偶发变更) │ 专业维护) │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 基本面数据 │ 有限 (PE/PB 基本) │ 丰富 (PE/PB/ROE/ │
|
||||
│ │ │ 财务报表等) │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 退市股票数据 │ 获取较难 │ stock_basic() 直接 │
|
||||
│ │ │ 包含退市记录 │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 因子数据 │ 无 │ 有 (Barra 风格因子) │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 股票代码格式 │ "000001" (纯数字) │ "000001.SZ" (含市场)│
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 调用频率限制 │ 无硬限制 (建议礼貌) │ 有 (按积分等级) │
|
||||
├───────────────────┼─────────────────────┼─────────────────────┤
|
||||
│ 最佳使用场景 │ 研究探索、快速验证 │ 策略验证通过后的 │
|
||||
│ │ 数据覆盖第一选择 │ 生产级数据源 │
|
||||
└───────────────────┴─────────────────────┴─────────────────────┘
|
||||
|
||||
推荐路径:
|
||||
① 研究阶段 → AKShare (零成本、快速验证想法)
|
||||
② 策略定型 → Tushare (数据质量更高、接口更稳定)
|
||||
③ 实盘运行 → Tushare + 本地缓存数据库 (减少 API 依赖)
|
||||
|
||||
关键提醒:
|
||||
• AKShare 接口偶尔变更,升级版本前记得检查 changelog
|
||||
• Tushare 积分用完会拒绝请求,注意剩余调用次数
|
||||
• 两个数据源的收盘价可能存在微小差异 (取整/复权方式)
|
||||
回测结果因此会有细微不同,这是正常的
|
||||
• 长期存储请用 Parquet 格式 (比 CSV 更快更省空间):
|
||||
df.to_parquet("data.parquet")
|
||||
df = pd.read_parquet("data.parquet")
|
||||
""")
|
||||
|
||||
print("=" * 68)
|
||||
print(" ✓ Tushare Pro 数据获取 Demo 完成")
|
||||
print("=" * 68)
|
||||
print(f"""
|
||||
关键收获:
|
||||
1. Tushare 需要 Token (免费注册),积分系统决定可用接口范围
|
||||
2. 股票代码格式为 "000001.SZ" / "600000.SH" (含交易所后缀)
|
||||
3. Tushare 最大优势: 财务数据 (PE/PB/ROE) + 退市数据 + 稳定性
|
||||
4. daily_basic() 和 fina_indicator() 是价值因子的核心数据源
|
||||
5. index_weight() 提供 Black-Litterman 所需的市场权重
|
||||
6. stock_basic(list_status='D') 是消除幸存者偏差的关键
|
||||
7. 研究阶段用 AKShare,定型后用 Tushare 生产化
|
||||
|
||||
下一步:
|
||||
- 将 Tushare 拉取的数据写入 demo_04 (Alpha 因子),
|
||||
用真实 PE/PB/ROE 替代合成因子
|
||||
- 用真实退市记录修正回测的幸存者偏差
|
||||
""")
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
> **定位**:本文档基于对整个 Demo 系列的代码审计和策略评估,为个人投资者回答三个核心问题——做什么策略、怎么做策略、用什么平台做。
|
||||
> **前置阅读**:建议已通读完 7 篇 Demo 后阅读本文。
|
||||
> **目标读者**:有 Python 基础的量化入门者,关注 A 股实操。
|
||||
> **附注**:文末附录 B 对比了市面上典型量化入门书(如《DeepSeek+Python 量化交易》)与本 Demo 系列的差异,帮读者理解"为什么有些书看起来厚但学不到东西"。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -14,8 +15,13 @@
|
|||
3. [个人投资者的现实策略频谱](#3-个人投资者的现实策略频谱)
|
||||
4. [中低频策略的核心范式](#4-中低频策略的核心范式)
|
||||
5. [情绪因子与突发事件量化](#5-情绪因子与突发事件量化)
|
||||
- 5.3 [LLM 辅助量化分析:两个务实场景](#53-llm-辅助量化分析两个务实场景)
|
||||
6. [从 Demo 到实盘:平台与工具链](#6-从-demo-到实盘平台与工具链)
|
||||
- 6.3 [真实数据接入](#63-真实数据接入合成数据的第一个暴击)
|
||||
- 6.4 [风控层详解:Demo 系列最大的盲区](#64-风控层详解demo-系列最大的盲区)
|
||||
7. [推荐学习与实践路径](#7-推荐学习与实践路径)
|
||||
附录 A:[关键术语速查](#附录-a关键术语速查)
|
||||
附录 B:[市面入门书 vs 本 Demo 系列](#附录-b市面入门书-vs-本-demo-系列以deepseekpython-量化交易为例)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -174,6 +180,64 @@ Demo 中用的价格/成交量/波动率都是"硬数据",但"软数据"在很
|
|||
|
||||
3. **文本情绪监控**:用大模型对财经新闻标题做情感分析,构建日频情绪指数。当前有大模型后门槛大幅降低——可以用本地模型批量打分。属于"另类数据因子"的范畴,初期可选。
|
||||
|
||||
### 5.3 LLM 辅助量化分析:两个务实场景
|
||||
|
||||
现有 Demo 系列完全没有触及 LLM(大语言模型)在量化中的应用。这不是让你用 ChatGPT 预测股价——那是玄学。以下两个场景是 LLM 在量化中真正有实用价值的方向,也是市面 AI 量化书籍(如《DeepSeek+Python 量化交易》)中为数不多的值得关注的内容。
|
||||
|
||||
**场景一:非结构化信息 → 结构化情绪因子**
|
||||
|
||||
传统量价因子(动量、波动率、流动性)是 Demo 4 的核心,但市场情绪信息大多藏在文本里——财经新闻、公告、研报、社交媒体。LLM 让个人投资者也能批量处理这类非结构化数据:
|
||||
|
||||
```
|
||||
工作流:
|
||||
每日收盘后
|
||||
→ 用 AKShare/Tushare 获取当日财经新闻标题列表
|
||||
→ 批量送 LLM
|
||||
prompt: "以下是一条财经新闻,请判断它对A股市场
|
||||
的情绪影响:看多/中性/看空。只回复一个词。"
|
||||
→ 汇总当日 "看多率 − 看空率" 作为情绪因子原始值
|
||||
→ 做滚动标准化(Z-score),得到日频情绪因子
|
||||
```
|
||||
|
||||
注意事项:
|
||||
- 用本地模型(Ollama + Qwen/Llama 等 7B 级模型)可以零成本跑,速度足够覆盖日频
|
||||
- 情感分类只用标题即可(延迟低、成本低),全文分析留到需要深度解读的场景
|
||||
- 情绪因子的 IC 通常较低(0.02-0.04),但与传统量价因子相关性低,合成后能提升 ICIR
|
||||
- 需要小心 Look-Ahead:如果你用 LLM 解读盘后新闻,信号只能在次日使用
|
||||
|
||||
**场景二:回测报告的自动解读**
|
||||
|
||||
你跑完回测得到一串绩效数字(Sharpe 1.2, MaxDD -18%, Calmar 0.8...),这些数字真正意味着什么?LLM 可以做有价值的"翻译":
|
||||
|
||||
```
|
||||
Prompt 示例:
|
||||
"以下是一个ETF轮动策略的回测绩效:
|
||||
- 夏普比率:1.15
|
||||
- 最大回撤:-22.3%,发生在 2022年3月
|
||||
- 月度胜率:58%
|
||||
- 年化收益率:13.2%
|
||||
- 换手率:月均 35%
|
||||
|
||||
请分析:
|
||||
1. 这些指标的整体评价
|
||||
2. 最大回撤发生在什么市场环境下(提示:2022年3月 A股处于什么阶段)
|
||||
3. 这个策略最可能在什么市场环境下失效
|
||||
4. 实盘中需要额外关注的风险点"
|
||||
```
|
||||
|
||||
这比你自己盯着一串数字琢磨半小时有效得多。关键是——LLM 不是替你决策,而是帮你更全面地**理解**你的策略在历史上的行为特征。
|
||||
|
||||
**LLM 在量化中的定位边界**
|
||||
|
||||
| 能用 LLM 做的 | 不该用 LLM 做的 |
|
||||
|--------------|----------------|
|
||||
| 文本情感 → 因子值 | "帮我写一个稳赚的策略" |
|
||||
| 回测报告解读 | 直接预测股价涨跌方向 |
|
||||
| 代码辅助与调试 | 替代回测(LLM 不知道数据里的陷阱) |
|
||||
| 参数优化建议(需结合回测验证) | 直接给调仓决策(你才是最终负责人) |
|
||||
|
||||
> **一句话**:LLM 是研究助理,不是交易员。它可以帮你从文本中提取信号、帮你理解回测结果、帮你写代码——但最终的策略逻辑、风险控制和执行纪律,必须是你自己理解并负责的。
|
||||
|
||||
---
|
||||
|
||||
## 6. 从 Demo 到实盘:平台与工具链
|
||||
|
|
@ -242,6 +306,94 @@ Demo 代码在本地跑跑看图表是"研究阶段"。实盘涉及三个层次
|
|||
| 8. 参数稳健性检验 | 对 top_k、回望期、再平衡频率做敏感性分析 | 建议 |
|
||||
| 9. 绩效归因 | Brinson 归因 / 因子归因,确认收益来源 | 进阶 |
|
||||
|
||||
以下对其中两项(数据接入 + 风控层)展开详细说明,因为它们是 Demo 到实盘跨度最大的两步,也是市面量化入门书(如《DeepSeek+Python 量化交易》)几乎不涉及的内容。
|
||||
|
||||
### 6.3 真实数据接入:合成数据的第一个"暴击"
|
||||
|
||||
现有 Demo 全部使用合成数据(GBM / 因子模型生成),好处是零门槛运行,但切换到真实数据时会遇到以下几类合成数据没有的问题:
|
||||
|
||||
**问题 1:停牌导致的日期错位**
|
||||
|
||||
真实 A 股数据中,不同标的停牌日期不同。直接 `pd.concat` 多个标的的收盘价会得到参差不齐的日期索引。关键是只做 ffill(向前填充),**禁止 bfill**——bfill 会用"复牌后的未来价格"填补停牌前的 NaN,这是典型的 Look-Ahead Bias。
|
||||
|
||||
```
|
||||
正确做法:
|
||||
price_panel = price_panel.ffill() # 只看向历史
|
||||
price_panel = price_panel.dropna(how='any') # 仍有 NaN 的行丢弃
|
||||
```
|
||||
|
||||
**问题 2:ETF 净值 vs 市价的差异**
|
||||
|
||||
ETF 有两个价格——IOPV(实时估算净值)和市价。Demo 7 的轮动策略用收盘价回测是合理的,但实盘中 ETF 可能出现折溢价(市价显著偏离净值),这在极端行情下会影响实际成交价格。实盘代码应该用市价做信号计算和回测,但需要理解 ETF 的折溢价风险。
|
||||
|
||||
**问题 3:数据源的选择**
|
||||
|
||||
| 数据源 | 优势 | 劣势 |
|
||||
|--------|------|------|
|
||||
| AKShare | 免费、覆盖面广、更新及时 | API 偶尔不稳定,部分接口可能变更 |
|
||||
| Tushare Pro | 稳定、文档全、数据质量高 | 需要积分(部分接口收费) |
|
||||
| Baostock | 免费、无需注册 | 更新慢、覆盖面有限 |
|
||||
| 聚宽/米筐数据 | 清洗过、质量最高 | 绑定平台,本地使用受限 |
|
||||
|
||||
推荐初次尝试用 AKShare(零成本),策略验证通过后切到 Tushare Pro(稳定性更好)。
|
||||
|
||||
### 6.4 风控层详解:Demo 系列最大的盲区
|
||||
|
||||
现有 7 篇 Demo 的风险管理几乎只有"最大回撤"这个**事后统计指标**。实盘中,风控必须是一个**事前和事中的执行层**——在亏损发生之前或初期就介入。以下三种风控手段是个人投资者最容易落地且效果最显著的。
|
||||
|
||||
**手段一:波动率缩放仓位(Volatility Targeting)**
|
||||
|
||||
这是最简单、最有效、但对策略绩效改善最大的手段。核心思想:当市场最近很"颠簸"(波动率放大),自动减小仓位;当市场平稳,正常仓位。
|
||||
|
||||
```
|
||||
核心公式:
|
||||
目标仓位 = 基础仓位 × (目标波动率 / 近期已实现波动率)
|
||||
|
||||
示例:
|
||||
基础仓位 = 100%(满仓)
|
||||
目标波动率 = 15%(年化,你愿意承受的风险水平)
|
||||
近期已实现波动率 = 30%(过去 20 日年化) → 仓位 = 100% × 15/30 = 50%
|
||||
近期已实现波动率 = 10% → 仓位 = 100% × 15/10 = 150%(需设上限)
|
||||
|
||||
实现要点:
|
||||
- 波动率窗口:20-60 个交易日,太短不稳定,太长反应慢
|
||||
- 仓位上下限:通常设 [30%, 150%] 或 [50%, 100%](不做杠杆)
|
||||
- 更新频率:每日计算但每周调一次即可(避免过度交易)
|
||||
- A 股限制:融资账户最高杠杆 1:1,普通账户无法做空
|
||||
```
|
||||
|
||||
这个手段的妙处在于:它不预测市场方向,只根据"当前有多危险"来调整暴露——是纯粹的防守动作,不会引入新的预测误差。
|
||||
|
||||
**手段二:硬止损(Hard Stop-Loss)**
|
||||
|
||||
现有 Demo 的策略出场完全依赖信号(金叉进/死叉出),这在实盘中是不够的。信号可能迟迟不来,而你的亏损已经超出了可承受范围。
|
||||
|
||||
```
|
||||
简单止损规则:
|
||||
- 单笔交易止损:持仓亏损超过 -X%(如 -8%或 -15%)→ 无条件平仓
|
||||
- 月度最大亏损:当月累计亏损超过 -Y% → 暂停交易,下月再评估
|
||||
- 连续亏损暂停:连续 Z 笔交易亏损 → 暂停,人工审查策略是否失效
|
||||
|
||||
参数建议(个人投资者):
|
||||
- 趋势策略(如动量轮动): X=12-15%,Y=8-10%,Z=4
|
||||
- 均值回归策略(如 RSI): X=5-8%, Y=5-8%, Z=5
|
||||
```
|
||||
|
||||
**手段三:最大回撤熔断**
|
||||
|
||||
这是一个组合层面的保护:如果账户从历史最高点回撤超过一定幅度,自动进入"防御模式"。
|
||||
|
||||
```
|
||||
实现逻辑:
|
||||
if 当前回撤(从历史最高净值算起) < -25%:
|
||||
强制减仓至 30%
|
||||
暂停新开仓
|
||||
发送告警 → "策略触发最大回撤熔断,净值从峰值回撤 xx%,已自动减仓"
|
||||
# 回撤恢复到 -15% 以内再恢复交易
|
||||
```
|
||||
|
||||
这三种手段的组合使用,能把你从"策略失效了才发现"的被动状态,变成"有明确规则控制损失"的主动状态。Demo 系列没有覆盖这些,但它们在实盘中比多找到 0.1 的夏普更重要。
|
||||
|
||||
---
|
||||
|
||||
## 7. 推荐学习与实践路径
|
||||
|
|
@ -282,7 +434,7 @@ Demo 给你的是知识地图,不是提款机密码。实盘中最重要的是
|
|||
|
||||
---
|
||||
|
||||
## 附录:关键术语速查
|
||||
## 附录 A:关键术语速查
|
||||
|
||||
| 术语 | 英文 | 含义 |
|
||||
|------|------|------|
|
||||
|
|
@ -294,3 +446,58 @@ Demo 给你的是知识地图,不是提款机密码。实盘中最重要的是
|
|||
| 前视偏差 | Look-Ahead Bias | 用"未来数据"做回测决策导致的虚假高收益 |
|
||||
| 幸存者偏差 | Survivorship Bias | 只用当前存活的股票回测,忽略了已退市的股票 |
|
||||
| 风格漂移 | Style Drift | 策略实际持仓偏离了其宣称的投资风格 |
|
||||
|
||||
---
|
||||
|
||||
## 附录 B:市面入门书 vs 本 Demo 系列——以《DeepSeek+Python 量化交易》为例
|
||||
|
||||
市面上很多量化交易入门书看起来很厚(三四百页、几十个案例),但读完往往发现"好像学了很多,又好像什么都没学到"。这里以《DeepSeek+Python 量化交易》(16 章、51 个实战案例)作为典型标本,拆解为什么会有这种感觉,以及它和本 Demo 系列的真实差距。
|
||||
|
||||
### 全书结构
|
||||
|
||||
| 板块 | 章节 | 内容 |
|
||||
|------|------|------|
|
||||
| Python 基础 | 第 1-5 章 | Python 语法、NumPy/Pandas/Matplotlib、网页爬虫 + Tushare API |
|
||||
| 策略入门 | 第 6-10 章 | 量化概念、DeepSeek 辅助分析(技术/基本面/消息)、双均线/RSI/海龟策略 |
|
||||
| 进阶策略 | 第 11-13 章 | 高频交易(概念层)、套利策略、机器学习预测(分类/回归/LSTM) |
|
||||
| 工程与风控 | 第 14-16 章 | Backtrader 回测、止损止盈/头寸管理/对冲、DeepSeek API + 智能体 |
|
||||
|
||||
### 它的定位
|
||||
|
||||
一本**面向绝对零基础读者的量化交易科普 + DeepSeek 使用指南**。目标读者是"刚学会 Python 甚至还没学 Python 的人"。全书 51 个案例覆盖面极广,但每个案例的深度有限——典型模式是:"拉数据 → 套一个经典公式 → 画图 → 把结果扔给 DeepSeek 解读 → DeepSeek 给优化建议"。
|
||||
|
||||
### 它有价值的部分
|
||||
|
||||
书中真正值得关注的内容集中在三个 Demo 系列没有覆盖的方向:
|
||||
|
||||
1. **真实数据接入(第 5 章)**:用 Tushare API 拉取 A 股真实数据的流程,虽然讲得浅,但方向对——这是 Demo 到实盘的第一道坎
|
||||
2. **风险管理工具(第 15 章)**:止损止盈、波动率头寸管理、对冲组合——这些是 Demo 系列最大盲区,详见本文 §6.4
|
||||
3. **LLM 辅助分析(第 7、16 章)**:用 LLM 处理非结构化信息(公告解读、新闻情绪、策略回测解读)——这是这本书唯一真正的差异化内容,详见本文 §5.3
|
||||
|
||||
### 它的问题
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| 策略覆盖面过时 | 双均线 + RSI + 海龟是 1980-1990 年代的经典。现代量化核心——因子模型、截面选股、组合优化——完全没有涉及 |
|
||||
| 高频章节名不副实 | 第 11 章名为"高频交易",实际是概念科普 + 一个比亚迪案例。真正的高频涉及 colocation/FPGA/市场微观结构,书中完全无法覆盖——这会误导读者以为"写个 Python 脚本就是高频交易" |
|
||||
| 深度学习案例浮于表面 | LSTM 预测股价只用一个案例,无时间序列交叉验证、无样本外泛化讨论——容易让初学者产生"跑个模型就能预测股价"的危险错觉 |
|
||||
| DeepSeek 角色被过度包装 | 书中几乎每个案例都以"DeepSeek 辅助优化"结尾。但 LLM 对量化策略的优化能力完全取决于 prompt 质量和用户自身的判断力——书中没有讨论这个根本局限 |
|
||||
| 回测严谨性近乎为零 | 不涉及过拟合检测、前视偏差、幸存者偏差、参数敏感性——而本 Demo 系列的事件驱动回测和滚动前向验证专门解决了这些问题 |
|
||||
| 无 A 股特有规则的系统讨论 | 涨跌停、T+1、融券限制、印花税——这些在本 Demo 系列的 `doc_06` 和 `doc_07` 中有专门覆盖,书中几乎没有 |
|
||||
|
||||
### 两种学习路径的对比
|
||||
|
||||
| 维度 | 《DeepSeek+Python量化交易》 | 本 Demo 系列 |
|
||||
|------|---------------------------|-------------|
|
||||
| 目标读者 | 零基础(从 Python 安装开始) | 有 Python 基础,缺少量化方法论 |
|
||||
| 学习方式 | 广度优先 — 51 个案例快速扫一遍 | 深度优先 — 5-7 个主题层层递进 |
|
||||
| 策略类型 | 经典技术指标策略(均线/RSI/海龟) | 因子模型 + 截面选股 + 组合优化 |
|
||||
| 回测方法论 | 仅 Backtrader 基本使用 | 向量化 → 事件驱动 → 前向验证,完整链条 |
|
||||
| 学术严谨性 | 较低 — 不涉及 IC/ICIR/因子预处理 | 较高 — IC 分析、去极值/Z-score/中性化、Ledoit-Wolf |
|
||||
| A 股实操 | 无系统讨论 | 实盘指南(doc_06)+ ETF 轮动策略(doc_07) |
|
||||
| AI 角色 | DeepSeek 贯穿全书,定位为"策略顾问" | 无 AI 依赖,本文 §5.3 补充了 LLM 的务实用法 |
|
||||
| 代码复杂度 | 简单脚本级别 | 类 + 函数封装,模拟生产级结构 |
|
||||
|
||||
### 一句话总结
|
||||
|
||||
这本书能让你从"完全不会 Python"跑到"能跑通第一个策略脚本",但从"跑通脚本"到"独立做量化交易"所需的系统知识——因子研究、稳健回测、组合构建、风险控制、A 股实盘陷阱——它几乎没有涉及。而这些东西恰好是本 Demo 系列所覆盖的。两套内容存在一定的互补性:**用那本书学会 Python 基础,用这套 Demo 学会量化方法论。**
|
||||
|
|
|
|||
|
|
@ -2,3 +2,6 @@ numpy
|
|||
pandas
|
||||
matplotlib
|
||||
scipy
|
||||
scikit-learn
|
||||
akshare
|
||||
tushare
|
||||
Loading…
Reference in New Issue