问题描述
连基本的历史数据都无法保证数据正确。
举个例子,比如 煤炭ETF 515220,
在4月12日进行的除权,1股变2股,因此,所以4月12日之后的价格会是原来的1/2,如果做前复权,那么前面的价格也都是要根据当前的价格做复权处理。
结果国盛的ptrade的历史数据,取的是前复权数据,前复权数据,(重点强调),在4月12日的的时候就出现了断崖。也就是没有做复权的处理。
测试代码很简单:
def initialize(context):
run_daily(context, event, '09:38')
def handle_data(context, data):
pass
def event(context):
his60 = get_history(60, '1d', ['close'], ['515220.SS'], fq='pre', include=False)
print(his60)
运行时间改成任意的就行。
获取历史数据用
get_history,取过去60天的前复权的数据。 然后就是断崖的数据。 已经确定是国盛的ptrade数据问题。因为我用上面的代码,在东莞证券,国金证券,湘财证券的ptrade上运行,均能得到正确的数据。
解决方案
问题现象分析
在 Ptrade 量化交易平台中,调用 get_history 接口并设置 fq='pre'(前复权)时,如果发现某只标的(如 ETF 515220)在除权除息日(如 1股拆2股)前后出现价格“断崖”,说明底层数据源的复权因子未及时更新或缺失。
由于 Ptrade 是各家券商独立私有化部署的,底层行情数据源(如聚源、恒生等)由各券商自行维护。这就是为什么同一段代码在东莞、国金、湘财证券的 Ptrade 上运行正常,而在国盛证券上出现异常的原因。
解决方案与应对策略
面对券商端的数据源问题,量化交易者可以采取以下几种策略来解决或规避:
1. 终极解决:向券商技术支持报备
这是最根本的解决方法。请将您的测试代码和异常结果截图,直接反馈给国盛证券的客户经理或 Ptrade 专属技术支持群。明确指出:“标的 515220.SS 在4月12日除权,get_history 接口 fq='pre' 参数未生效,复权因子缺失”。通常券商会在服务端重新拉取或修复数据。
2. 代码级规避:使用 get_stock_exrights 手动校验或复权
在等待券商修复期间,或者为了增强策略的健壮性,可以使用 Ptrade 提供的 get_stock_exrights 接口获取除权除息信息,手动判断是否发生了除权,或者自行计算复权价格。
API 接口说明:
get_stock_exrights(stock_code, date=None)
返回包含 exer_forward_a(前复权除权因子A)和 exer_forward_b(前复权除权因子B)的 DataFrame。前复权价格计算公式:前复权价格 = A * 价格 + B。
手动复权/校验示例代码:
def initialize(context):
g.security = '515220.SS'
set_universe(g.security)
run_daily(context, check_data_event, '09:38')
def check_data_event(context):
# 1. 获取未复权的原始数据
his_none = get_history(60, '1d', ['close'], [g.security], fq=None, include=False)
# 2. 获取券商提供的前复权数据
his_pre = get_history(60, '1d', ['close'], [g.security], fq='pre', include=False)
# 3. 获取除权除息信息
exrights_info = get_stock_exrights(g.security)
if exrights_info is not None and not exrights_info.empty:
log.info(f"发现 {g.security} 的除权除息记录:\n{exrights_info}")
# 如果发现 his_pre 存在断崖,可以利用 exrights_info 中的 exer_forward_a 和 exer_forward_b 对 his_none 进行手动复权计算
else:
log.warning(f"未获取到 {g.security} 的除权除息记录,请检查券商数据源!")
def handle_data(context, data):
pass
3. 交叉验证:尝试使用 get_price 接口
Ptrade 提供了两个获取历史数据的接口:get_history 和 get_price。有时底层数据表不同,某一个接口的数据可能正常。您可以尝试替换为 get_price 进行测试:
def event(context):
# 尝试使用 get_price 获取前复权数据
price_df = get_price('515220.SS', count=60, frequency='1d', fields=['close'], fq='pre')
print("get_price 返回数据:\n", price_df)
总结
量化策略对数据的准确性要求极高。在实盘或回测前,编写一段数据质量校验脚本(如对比近期价格波动率是否异常放大,或对比 fq=None 与 fq='pre' 的差异)是非常必要的。这能有效防止因券商数据源“断崖”导致的策略误触发(如误判为暴跌而止损)。