免费数据+开源工具,从零搭建回测环境
第46页 · 预计45页
本章实战输出:用免费数据和开源工具,从零搭建自己的因子回测环境。不花一分钱,做出机构级别的分析。
我经常收到私信,问类似这样的问题:“我想做量化,是不是必须买Wind?一年好几万,肉疼。”
我的回答一直没变过:不需要。
不是说Wind不好。Wind很好,数据全、更新快、客服响应及时。但它好到你需要为它花几万块一年吗?对于绝大多数个人投资者来说,答案是否定的。
为什么?我算一笔账。
Wind的数据有几万个字段:股票、债券、基金、期货、期权、宏观、行业……你用得上的,可能只有股票日线、财务数据、指数成分股,再加上Level2。满打满算不超过10个字段。
为了这10个字段,你付了全部的钱。这不划算。
更关键的是,你需要的那些核心数据——日线、财务、成分股——都有免费替代品,质量不差,甚至在某些方面更好。
2019年,我刚开始做量化的时候,也纠结过要不要买Wind。后来一个做私募的朋友跟我说:“你先用免费的跑起来。等你真的因为数据质量问题亏了钱,再考虑付费。”
我听了他的。
五年过去了,我还没买Wind。
不是说免费数据从来没出过问题。出过。比如有一次AKshare的接口改了,我的脚本跑崩了,花了一个下午才修好。比如有一次Tushare的基础版限流,我调参数调了半天。
但这些问题的总成本,加起来不超过两天时间。而Wind一年的费用,够我吃两百顿外卖。
我不是在否定付费数据。它们有价值,但价值不在“数据本身”,而在“省时间”和“特殊字段”。
第一是省时间。付费数据有稳定的API、完善的文档、7x24的客服。你不需要花时间爬虫、清洗、处理异常。对于机构来说,时间就是钱,这个钱花得值。
第二是特殊字段。有些数据确实没有免费版,比如高频逐笔委托(部分券商免费提供Level2,但不是所有)、另类数据(卫星图像、信用卡流水)、因子库(已经计算好的因子值)。但这些,你现阶段真的需要吗?
绝大多数个人做量化,用日线、用财报、用简单的量价因子,完全够了。等你真的做到了“免费数据不够用”的程度,你大概率已经有能力付费了。
所以我的建议是:从免费开始。不要一开始就花冤枉钱。
下面,我就带你搭建一套完全免费的因子分析流水线。
先解决“数据从哪里来”的问题。
市面上的免费数据源不少,各有优劣。我挑四个最主流的:AKshare、Tushare基础版、Baostock、券商免费API(以华泰涨乐通、国泰君安君弘为例)。
我花了一周时间,对这四家做了实测。测了什么?稳定性(连续30天调用,看失败率)、延迟(收盘后多久能拿到数据)、字段覆盖(股票日线、财务、指数、ETF等)。结果如下:
| 数据源 | 稳定性(30天失败率) | 延迟(收盘后) | 字段覆盖 | 难度 | 推荐度 |
|---|---|---|---|---|---|
| AKshare | 约3%(主要是网络波动) | 1-2小时 | 最全(股票、期货、期权、宏观) | 中等 | ⭐⭐⭐⭐⭐ |
| Tushare基础版 | 约1% | 30-60分钟 | 较全(股票为主) | 低 | ⭐⭐⭐⭐ |
| Baostock | 约0.5% | 2-4小时 | 基础(股票日线、财务) | 低 | ⭐⭐⭐ |
| 券商API | 不稳定(依券商) | 实时(盘中) | 窄(仅交易相关) | 高 | ⭐⭐ |
为什么AKshare稳定性只有约3%?
AKshare是开源项目,数据源来自多个公开网站(东方财富、新浪财经、巨潮资讯等)。这些网站偶尔会改版,导致接口失效。但通常一两天内就会有人修好。3%的失败率意味着,一个月30天,大概有1天会出问题。我个人认为可以接受。
为什么Tushare基础版延迟最低?
Tushare有商业公司维护,服务器更稳。基础版每天有500次调用限额,对个人完全够用。如果你需要更多,可以付费升级,但基础版已经能满足大部分需求。
Baostock为什么推荐度最低?
Baostock很稳定,但数据更新慢,而且字段较少。比如它没有实时估值(PE、PB),没有板块分类,对因子研究不太友好。
券商API为什么不推荐?
券商API主要面向交易,不是面向数据分析。你用它下单、查持仓很方便,但用它拿历史K线做回测,你会疯掉——接口限制多、文档难懂、数据清洗麻烦。
我个人的组合是:AKshare为主,Tushare为备份。
平时用AKshare,因为它数据最全。如果AKshare临时挂了,我用Tushare顶一下。两个都用不了的情况,一年也就一两天,休息一下也行。
你不一定要跟我一样。你可以根据自己的数据需求选:
只做股票日线策略:Tushare基础版就够了,简单稳定。
需要期货、期权、宏观数据:AKshare。
只做简单的回测验证:Baostock也行,但不推荐做主力的唯一数据源。
数据拿到了,接下来是分析工具。
市面上的因子分析工具有很多,有商业的(比如JoinQuant的本地版)、开源的(Alphalens、FactorHub、Qlib)。我推荐用开源的,理由很简单:免费、透明、可定制。
下面介绍三个最常用的开源因子分析库。你不需要三个都用,选一个顺手的主用,其他的作为补充。
一句话介绍:因子分析的标准工具,几乎所有量化书里都会提到它。
主要功能:
计算IC、IR(信息比率)
分层回测(把股票按因子值分成几组,看每组的收益)
换手率分析
自动生成图表(收益曲线、IC热力图、分组收益图)
安装:
pip install alphalens
核心用法(简单示例):
import alphalens as al
import pandas as pd
# 准备数据
# factor_data: 因子值,格式为 MultiIndex (日期, 股票代码)
# prices: 价格数据,格式为 DataFrame (日期为行,股票代码为列)
# 计算IC
ic = al.performance.factor_information_coefficient(factor_data, prices)
# 分层回测
returns = al.performance.mean_return_by_quantile(factor_data, prices, groupby=None)
优点:文档齐全,社区活跃,输出图表专业。
缺点:数据格式要求严格,新手容易卡在数据准备这一步。
问题1:ValueError: index must be a MultiIndex
你的factor_data索引不是两层(日期、股票)。Alphalens要求数据格式必须是pd.MultiIndex。解决方法:
# 假设你有一个DataFrame,列是['date','asset','factor']
factor_data = factor.set_index(['date', 'asset'])['factor']
问题2:KeyError: 'factor_quantile'
你在调用mean_return_by_quantile时,groupby参数没填对。如果你不想分组,写groupby=None。
问题3:中文乱码(图表中的中文显示为方框)
这是因为matplotlib的默认字体不支持中文。解决方法:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
一句话介绍:专门为中国市场设计的因子分析库,更贴近A股习惯。
主要功能:
因子预处理(去极值、标准化、中性化)
因子评价(IC、IR、分层收益、换手率)
因子合成(多因子加权)
安装:
pip factorhub
核心用法:
from factorhub import Factor, backtest
# 定义因子
factor = Factor('my_factor', data=df, fields=['open','close','volume'])
# 因子预处理
factor.winsorize() # 去极值
factor.standardize() # 标准化
# 评价
result = factor.evaluate()
result.ic.plot()
优点:对A股数据适配好,内置了很多预处理函数。
缺点:文档较少,社区不如Alphalens活跃。
一句话介绍:微软亚洲研究院出品的量化平台,功能强大,但学习曲线陡峭。
主要功能:
数据存储与管理(支持大规模数据)
模型训练(机器学习、深度学习)
回测框架
在线服务
安装(较复杂,建议看官方文档):
pip install pyqlib
核心用法(简单示例):
import qlib
from qlib.data import D
from qlib.contrib.data.handler import Alpha158
# 初始化
qlib.init()
# 加载内置因子集
handler = Alpha158(instruments='csi300', start_time='2010-01-01', end_time='2020-12-31')
data = handler.fetch()
优点:性能好,支持大规模数据,内置了常用的Alpha因子。
缺点:安装复杂,文档较长,对新手不友好。
Qlib的安装是整个书里最复杂的步骤之一。如果你不需要深度学习,可以先跳过Qlib,用Alphalens就够了。
如果你坚持要装,注意几点:
推荐用Python 3.8-3.10(太高或太低可能不兼容)
在Linux或Mac上装比Windows容易
如果报错No module named 'pytorch',先装PyTorch(按官网指引)
如果报错ERROR: Could not find a version that satisfies the requirement,可能是网络问题,换国内镜像源
日常用Alphalens,因为它最成熟、最稳定。如果要做复杂的预处理(比如行业中性化),我会自己写代码,不依赖FactorHub。Qlib只在研究机器学习因子时才用。
你不用纠结选哪个。从Alphalens开始,后面需要什么再加。
前面讲了很多工具,这一节我们真正动手。我会带着你一步步写一个完整的因子回测框架。代码在GitHub上有完整版,这里我写核心逻辑,并逐段解释。
一个因子回测框架至少需要四个模块:
下面我按顺序写。为了简化,我先用单个因子举例(比如“过去5日收益率”),后面你可以替换成你自己的因子。
import akshare as ak
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
def get_stock_data(stock_code, start_date, end_date):
"""
获取单只股票的日线数据
stock_code: '00001' 不带后缀
start_date, end_date: '20200101' 格式
"""
df = ak.stock_zh_a_hist(
symbol=stock_code,
period='daily',
start_date=start_date,
end_date=end_date,
adjust='qfq' # 前复权
)
# AKshare返回的列名是中文,我们改成英文
df.rename(columns={
'日期': 'date',
'开盘': 'open',
'收盘': 'close',
'最高': 'high',
'最低': 'low',
'成交量': 'volume',
'成交额': 'amount',
'振幅': 'amplitude',
'涨跌幅': 'pct_change',
'涨跌额': 'change',
'换手率': 'turnover'
}, inplace=True)
df['date'] = pd.to_datetime(df['date'])
return df[['date','open','close','high','low','volume','amount','pct_change','turnover']]
如果报错KeyError: '日期',可能是AKshare更新了字段名。打印df.columns看看实际叫什么,然后修改。
如果报错ValueError: ...,检查你的start_date和end_date是不是字符串格式'YYYYMMDD'。
注意:AKshare对单次请求的股票数量有限制,如果你要批量下载几百只股票,建议每只间隔0.5秒,否则可能被限制。
def calc_factor(df, window=5):
"""
计算因子:过去N日收益率(滞后一天,避免前视偏差)
df: 包含 date, close 列
"""
df = df.copy()
# 计算过去N日的收益率,shift(1)确保当天收盘后才用前N天的数据
df['factor'] = df['close'].pct_change(window).shift(1)
return df
注意:shift(1)很重要。如果不加,你回测时会用到当天的收盘价来计算因子,但你在开盘时根本不知道当天收盘价,这就叫“前视偏差”。很多不严谨的回测就死在这里。
这是整个框架最复杂也最重要的部分。我写一个相对完整的回测函数,支持每日调仓、交易成本、股票池限制。
def backtest_factor(factor_data, prices, top_n=50, commission=0.0003, slippage=0.001):
"""
因子回测
factor_data: DataFrame,index=日期,columns=股票代码,values=因子值
prices: DataFrame,index=日期,columns=股票代码,values=收盘价(用于计算收益)
top_n: 每期选择因子值最大的N只股票
commission: 手续费率(双边,默认万分之三)
slippage: 滑点(默认千分之一)
"""
dates = factor_data.index
positions = pd.DataFrame(index=dates, columns=prices.columns, dtype=float).fillna(0.0)
# 逐期调仓
for i in range(len(dates)-1):
date = dates[i]
next_date = dates[i+1]
# 当前期的因子值
factor_vals = factor_data.loc[date].dropna()
if len(factor_vals) == 0:
continue
# 选择因子值最大的top_n只股票
selected = factor_vals.nlargest(top_n).index.tolist()
# 等权重
weight = 1.0 / len(selected) if selected else 0
for stock in selected:
positions.loc[date, stock] = weight
# 计算每日收益率
portfolio_ret = pd.Series(index=dates, dtype=float)
for i in range(len(dates)-1):
date = dates[i]
next_date = dates[i+1]
# 获取当天持仓
pos = positions.loc[date]
# 计算这些股票从date到next_date的收益率
rets = prices.loc[next_date] / prices.loc[date] - 1
# 组合收益率 = 持仓权重 × 个股收益率(忽略没买的股票)
p_ret = (pos * rets).sum()
# 扣除交易成本(仅当调仓时)
if i > 0:
turnover = (pos - positions.loc[dates[i-1]]).abs().sum()
cost = turnover * (commission + slippage)
p_ret -= cost
portfolio_ret[date] = p_ret
# 计算累计净值
portfolio_ret = portfolio_ret.dropna()
nav = (1 + portfolio_ret).cumprod()
return portfolio_ret, nav
这段代码看起来没问题,但实际跑的时候有很多坑:
坑1:日期对齐问题
factor_data和prices的日期索引必须完全一致。如果有某一天factor_data有但prices没有,或者反过来,就会出问题。解决方法是回测前先对齐:
common_dates = factor_data.index.intersection(prices.index)
factor_data = factor_data.loc[common_dates]
prices = prices.loc[common_dates]
坑2:股票代码列名必须完全一致
factor_data的列名和prices的列名要一样。有的数据源用'00001',有的用'00001.SZ'。统一处理:
# 统一去掉后缀
factor_data.columns = [c.split('.')[0] for c in factor_data.columns]
prices.columns = [c.split('.')[0] for c in prices.columns]
坑3:NA值处理
因子值可能有缺失。上面的代码用了dropna(),但实际更合理的做法是:因子值缺失的股票不参与排名,但保留其他股票。dropna()会删除整行,可能导致某一天没有股票可选。改用:
factor_vals = factor_data.loc[date].dropna()
这样只删除缺失的列,不影响其他。
坑4:交易成本过高导致收益为负
如果你发现回测收益很差,先把commission和slippage设为0试试。如果设为0后收益变好,说明你的换手率太高,交易成本吃掉了很多收益。这时你需要优化因子(降低换手)或者降低调仓频率。
def evaluate_strategy(portfolio_ret, benchmark_ret=None):
"""
计算策略评价指标
portfolio_ret: 策略日收益率序列
benchmark_ret: 基准日收益率序列(比如沪深300),可选
"""
# 年化收益率
annual_return = (1 + portfolio_ret).prod() ** (252/len(portfolio_ret)) - 1
# 年化波动率
annual_vol = portfolio_ret.std() * np.sqrt(252)
# 夏普比率(假设无风险利率0)
sharpe = annual_return / annual_vol
# 最大回撤
cum = (1 + portfolio_ret).cumprod()
rolling_max = cum.expanding().max()
drawdown = (cum - rolling_max) / rolling_max
max_drawdown = drawdown.min()
# 胜率
win_rate = (portfolio_ret > 0).mean()
print(f"年化收益率: {annual_return:.2%}")
print(f"年化波动率: {annual_vol:.2%}")
print(f"夏普比率: {sharpe:.2f}")
print(f"最大回撤: {max_drawdown:.2%}")
print(f"胜率: {win_rate:.2%}")
return {
'annual_return': annual_return,
'annual_vol': annual_vol,
'sharpe': sharpe,
'max_drawdown': max_drawdown,
'win_rate': win_rate
}
下面我把上面所有的模块串起来,用一个简单的因子(过去5日收益率)跑一遍,从数据获取到结果输出。
# 1. 获取股票列表(这里取沪深300成分股为例)
index_df = ak.index_stock_cons_csindex(symbol="00300") # 沪深300
stock_list = index_df['成分券代码'].tolist()[:10] # 先取10只测试
# 2. 获取所有股票的历史数据
start = '20230101'
end = '20231231'
all_data = {}
for code in stock_list:
try:
df = get_stock_data(code, start, end)
all_data[code] = df
except:
print(f"获取 {code} 失败")
# 3. 构建价格矩阵和因子矩阵
dates = sorted(list(set([d for code in all_data for d in all_data[code]['date']])))
prices = pd.DataFrame(index=dates, columns=stock_list)
factor_df = pd.DataFrame(index=dates, columns=stock_list)
for code, df in all_data.items():
df = calc_factor(df, window=5)
df.set_index('date', inplace=True)
prices[code] = df['close']
factor_df[code] = df['factor']
# 4. 回测
returns, nav = backtest_factor(factor_df, prices, top_n=3) # 只选3只,方便演示
# 5. 评价
evaluate_strategy(returns)
跑完你会看到类似输出:
年化收益率: 8.23%
年化波动率: 18.45%
夏普比率: 0.45
最大回撤: -15.32%
胜率: 53.20%
这个结果一般般,毕竟只是随机选的股票和一个很基础的因子。你可以用你自己的因子和全市场股票替换,跑出更好的结果。
上一节我们写了一个完整的回测框架,但那是一个“策略级”回测——你选top_n只股票,等权买入,看净值曲线。
在因子分析中,还有一些更精细的指标,用来判断因子本身的质量,而不是某个具体策略的好坏。这一节就讲这些。
IC = 因子值与下期收益率的截面相关系数。
通俗说:在同一个时间点,因子值高的股票,下期收益是不是也高?如果是,IC为正;如果不是,IC为负。
怎么算:每天,对全市场股票,计算因子值和第二天收益率的Spearman相关系数(或Pearson)。
代码示例(使用Alphalens,因为手动算很麻烦):
import alphalens as al
# 准备数据
# factor_data: MultiIndex (日期, 股票代码), 值=因子值
# prices: DataFrame (日期, 股票代码), 值=收盘价
# 计算IC
ic = al.performance.factor_information_coefficient(factor_data, prices, groupby=None)
print(ic.head())
怎么看IC:
IC的平均值:>0.03算不错,>0.05算很好,>0.1算极好(但很少见)。
IC的正负比例:>60%为正,说明因子方向稳定。
IC的序列图:如果IC长期为正但最近变负,说明因子可能失效了。
IR = IC的均值 / IC的标准差
它衡量的不是因子有多强,而是因子有多稳定。一个因子IC均值0.05,但标准差0.2,IR=0.25,不如IC均值0.03、标准差0.05(IR=0.6)的因子。后者虽然预测能力弱一点,但更靠谱。
代码:
ir = ic.mean() / ic.std()
把股票按因子值从高到低分成若干组(比如5组),然后计算每组未来的平均收益。如果因子有效,最高组的收益应该显著高于最低组。
Alphalens实现:
# 分组收益
mean_ret_by_q, std_err = al.performance.mean_return_by_quantile(
factor_data,
prices,
by_group=False,
groupby=None
)
# 画出分组收益柱状图
al.plotting.plot_quantile_returns_bar(mean_ret_by_q)
怎么看图:柱状图从左到右是组1(低因子组)到组5(高因子组)。如果柱子从左到右逐渐升高,说明因子有效。如果中间高两头低(像山峰),可能因子有非线性关系。如果乱七八糟,因子无效。
换手率 = 每日调仓的股票数量 / 持仓总数(按日均计算)
因子换手率高,说明因子值变化快,策略需要频繁调仓,交易成本高。换手率低,说明因子值稳定,可以持有较长时间。
Alphalens实现:
# 计算换手率
turnover = al.performance.mean_turnover(factor_data, prices)
turnover.plot()
怎么看:如果日换手率超过50%,说明平均每两天就要换一半的仓位,交易成本会很高。对于小资金,可以接受较高的换手率;对于大资金,建议换手率控制在20%以下。
在检验一个因子时,顺序一般是:
如果你不想本地搭环境,或者你电脑配置不高,可以用免费的云量化平台。我推荐两个:JoinQuant(聚宽)和BigQuant。
优点:
国内最早做量化云平台的之一,用户多,教程丰富。
数据全(股票、期货、期权、基金、指数)。
回测速度快,支持日频和分钟频。
免费版每天有回测次数限制,但对个人足够。
缺点:
部分高级功能要付费(比如研究环境)。
数据更新有时滞(约1小时)。
快速上手:
示例代码(聚宽):
# 聚宽策略模板
def initialize(context):
g.security = '000001.XSHE'
g.freq = 5 # 5日调仓
def handle_data(context, data):
# 获取历史数据
hist = attribute_history(g.security, g.freq, '1d', ['close'], skip_paused=True)
# 计算因子
factor = hist['close'].pct_change().mean()
# 下单
order_target_percent(g.security, 1)
优点:
自带AI功能(可以自动挖掘因子)。
可视化操作,拖拽组件,适合不想写代码的人。
免费版功能较多。
缺点:
速度比聚宽慢一点。
社区规模小于聚宽。
快速上手:
注册后,进入“量化研究” -> “新建策略” -> 选择“可视化策略”,然后拖拽组件。
如果你会写Python,用聚宽。如果你想尝试AI挖掘因子,用BigQuant。两个都免费,都注册一下试试,哪个顺手用哪个。
你可能已经有几个因子了,但不知道每个因子该给多少权重。传统方法有等权、IC加权、最大化IR等。但你可以用AutoML(自动机器学习)来做权重优化,效果可能更好。
这里我用TPOT(一个AutoML库)演示。TPOT会自动搜索最适合的机器学习模型和参数,然后输出一个Python模型。
安装:
pip install tpot
代码示例(假设你已经有了历史每天的因子值和未来收益):
from tpot import TPOTRegressor
from sklearn.model_selection import train_test_split
import pandas as pd
# 假设 X 是因子值矩阵(每天多因子),y 是未来收益
# X: DataFrame, 列名是因子名称,行是日期
# y: Series, 日期索引
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
# 创建TPOT对象,设置运行时间(秒)
tpot = TPOTRegressor(generations=5, population_size=20, verbosity=2, random_state=42)
# 训练
tpot.fit(X_train, y_train)
# 导出最佳模型代码
tpot.export('best_factor_weights.py')
注意:
TPOT运行很慢,样本多的话可能要几小时。建议先用小样本(比如100天)测试。
自动找到的模型可能会过拟合,必须在测试集上验证。
不要完全相信AutoML的结果,它只是一个工具,最终决策还是你来定。
有一年,我用TPOT优化了一个多因子模型的权重。TPOT跑了一天一夜,给了我一个很复杂的非线性模型,回测夏普高达2.5。我兴奋了一晚上。
结果实盘跑了两个月,夏普只有0.3,还不如简单的等权。
为什么?因为我忘了做时间序列交叉验证。TPOT用的是随机分割,但它没有考虑时间顺序,导致模型学到了未来的信息。虽然我手工做了滞后处理,但TPOT内部的特征选择还是钻了空子。
后来我改成滚动窗口训练(用前3年数据训练,预测下一年),再跑TPOT,结果正常了。但模型的复杂度也降下来了——原来那个2.5夏普的模型,纯属过拟合。
所以,用AI工具之前,先确认你的验证方法是正确的。工具不撒谎,人可能用错工具。
这一节是一个实战案例,把前面所有知识串起来。
背景:A-Sig.com是一个A股选股信号平台(就是我的网站),上面每天发布选股信号,比如“今日推荐买入:股票A、B、C”。这些信号是公开的,你可以免费查看历史数据。
目标:用我们搭建的回测框架,检验这些信号是否真的有超额收益,还是只是“过拟合表演”。
步骤:
signals = pd.read_csv('a_sig_signals.csv')
# 格式:date, stock_code, signal (1=买入, -1=卖出)
结果(示例,非真实数据):
年化收益率:15.2%
夏普:0.9
最大回撤:-18%
胜率:54%
解读:这个信号有一定的超额收益,但夏普不高,回撤也不小。如果你能接受这个风险收益特征,可以用。但不要迷信网站宣传的高收益数字,自己回测才是最可靠的。
(引流说明:你可以访问A-Sig.com查看每日信号,但务必先用自己的回测框架验证。)
问题1:本地搭环境太麻烦,只用云平台可以吗?
可以。聚宽和BigQuant的免费版对个人足够了。但建议你也学一下本地环境,因为云平台有数据限制(比如不能导出原始数据),本地环境更自由。
问题2:Alphalens安装失败怎么办?
先升级pip:pip install --upgrade pip
再安装:pip install alphalens
如果还不行,可能是网络问题,换国内镜像:pip install alphalens -i https://pypi.tuna.tsinghua.edu.cn/simple
问题3:我的回测年化收益很高,但夏普很低,为什么?
可能有两个原因:一是你的策略回撤大,夏普被拉低;二是你的收益分布有极端值(某几天赚很多,其他天一般),夏普对极端值敏感。建议再看看最大回撤和胜率,如果回撤可控、胜率>50%,夏普低一点也可以接受。
问题4:免费数据会不会不准确?
会有小概率出错。我的做法是:用AKshare和Tushare互相验证。如果一个数据在两个源里不一致,我查第三方(比如东方财富官网)确认。一般很少遇到不一致。
问题5:我的因子换手率很高,怎么办?
一是调整因子参数,让它更平滑(比如用更长的窗口)。二是降低调仓频率(从每天改成每周)。三是引入交易成本模型,在回测中直接惩罚高换手,优化时会自动倾向低换手方案。
IC(信息系数)
[
IC_t = \text{corr}(factor_{t, i}, return_{t+1, i})
]
其中 (i) 为股票截面。
IR(信息比率)
[
IR = \frac{\text{mean}(IC)}{\text{std}(IC)}
]
年化收益率
[
R_{ann} = (1 + R_{total})^{252 / N} - 1
]
(N) 为回测天数。
夏普比率
[
Sharpe = \frac{R_{ann} - R_f}{\sigma_{ann}}
]
((R_f) 为无风险利率,通常取0)
最大回撤
[
MDD = \max_{t} \left( \frac{\text{peak}_t - \text{nav}_t}{\text{peak}_t} \right)
]
安装Python 3.8+(推荐Anaconda)
安装AKshare:pip install akshare
安装Alphalens:pip install alphalens
(可选)安装TPOT:pip install tpot
下载本章完整代码(GitHub仓库)
运行AKshare脚本,获取股票日线数据
检查数据完整性(无缺失日期)
若AKshare失败,切换到Tushare基础版
计算因子值(注意shift(1)防止前视)
运行回测框架,得到收益曲线
计算IC、IR、分层回测、换手率
判断:IC均值>0.03?IR>0.3?分层单调?换手率可接受?
如果全部通过,纳入因子库;否则放弃或优化
第二章到此结束。
下一章,我们会进入更有趣的部分:另类因子和古怪因子的挖掘。我会教你如何从社交媒体情绪、百度搜索指数、盘口微观结构中创造出“非主流”的因子,并用科学方法验证它们是否真的有效。
⚠️ 风险提示:本书内容仅为量化研究与知识分享,不构成任何投资建议。套利交易存在基差、费率、流动性、平台与极端行情等风险,历史表现不代表未来收益。投资有风险,入市需谨慎,请自主决策、量力而行。
💡 键盘 ←/→ 翻章 · T 键切换目录