确保回测和仿真一致的方案
如果特征列表(查看特征列表m1)包含跨多天表达式因子(比如跨20天). 会导致 回测 和 仿真 差异.
在回测中, 由于区间足够大, 在区间右端(时间最近的这端), 衍生因子都是非Nan值
在仿真中, 区间就是一天, 用于计算衍生因子的天数仅有 120个自然日. 可能由于长期停牌,导致实际120天内的实际交易日<20, 进而可能导致nan值
首先,在基础特征抽取m3中配置: 向前取数据天数120,
然后, 写一个自定义模块m4, 计算出所有股票每天的最近120个自然日中的交易日数(及非停牌数).
上步实际上是获得一个因子: u_trade_num_in_n120
在实际应用时, 只要对u_trade_num_in_n120进行过滤, 比如: u_trade_num_in_n120>20
# 本代码由可视化策略环境自动生成 2018年1月30日 10:39
# 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
m1 = M.input_features.v1(
features="""
ts_min(low_0,20)/adjust_factor_0
ts_max(high_0,20)/adjust_factor_0
"""
)
m2 = M.instruments.v2(
start_date='2016-01-01',
end_date='2018-01-29',
market='CN_STOCK_A',
instrument_list='',
max_count=0
)
m3 = M.general_feature_extractor.v6(
instruments=m2.data,
features=m1.data,
start_date='',
end_date='',
before_start_days=120
)
# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m4_run_bigquant_run(input_1, input_2, input_3):
'''
计算最近120个自然日中, 各股票的交易日统计
input_1 基础因子数据
input_2 空
input_3 空
'''
# 原始输入
df = input_1.read_df()
# 双索引化, 并标注交易日
dff = df[['date','instrument']].set_index(['date','instrument'])
dff["flag"] = 1
# 双索引 => 行索引 + 列索引, 将nan值标记为非交易日
tmp_df = dff['flag'].unstack().fillna(0)
# 标注最近120自然日的起始日
tmp_df["start_date"] = list(map(lambda x: x-datetime.timedelta(120), tmp_df.index))
# 计算最近120个自然日中, 各股票的交易日统计, 然后转换成双索引Series
def func(xs):
return tmp_df[(tmp_df.index>=xs.start_date)&(tmp_df.index<=xs.name)].iloc[:,:-1].sum()
tmp_df = tmp_df.apply(func,axis=1).stack()
# 合并交易日数(最近120自然日) 顺便过滤掉停牌日, 并且保持原有排序
dff["u_trade_num_in_n120"] = tmp_df
# 去除双索引 恢复成与df类似的结构
dff = dff["u_trade_num_in_n120"].reset_index(['date','instrument'])
# 合并老&新因子
df = pd.merge(df,dff,on=['date','instrument'])
# 输出
data_1 = DataSource.write_df(df)
return Outputs(data_1=data_1, data_2=None, data_3=None)
m4 = M.cached.v3(
input_1=m3.data,
run=m4_run_bigquant_run
)
m5 = M.derived_feature_extractor.v2(
input_data=m4.data_1,
features=m1.data,
date_col='date',
instrument_col='instrument'
)
m5.data.read_df().tail(10)