克隆策略
In [2]:
# 本代码由可视化策略环境自动生成 2021年8月8日 19:51
# 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
class conf:
    start_date = '2014-01-01'
    split_date = '2019-12-31'
    start_trade = '2020-01-01'
    end_date='2021-07-30'

    
    features1 = [
        'volume_0/volume_1',
        'daily_return_1',
        'return_10',
        'return_20',
        'avg_amount_5',
        'avg_amount_20',
        'avg_turn_5',
        'pb_lf_0',
        'mf_net_amount_main_0',
        'rank_avg_mf_net_amount_5',
        'rank_return_10', 
        'swing_volatility_10_0/swing_volatility_60_0'
    ]
    extra_fields = ['st_status_0',       
                    'price_limit_status_0',
                   ]
    
m1 = M.instruments.v2(
    start_date=conf.start_date,
    end_date=conf.split_date,
    market='CN_STOCK_A',
    instrument_list='',
    max_count=0
)

m2 = M.advanced_auto_labeler.v2(
    instruments=m1.data,
    label_expr="""# #号开始的表示注释
# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
# 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html
#   添加benchmark_前缀,可使用对应的benchmark数据
# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_

# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
shift(close, -5) / shift(open, -1)

# 极值处理:用1%和99%分位的值做clip
clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))

# 将分数映射到分类,这里使用20个分类
all_wbins(label, 20)

# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
where(shift(high, -1) == shift(low, -1), NaN, label)
""",
    start_date='',
    end_date='',
    benchmark='000300.SHA',
    drop_na_label=True,
    cast_label_int=True
)
m33 = M.input_features.v1(
    features=conf.features1
)

m3 = M.input_features.v1(
    features=conf.features1+conf.extra_fields
)



m4 = M.general_feature_extractor.v6(
    instruments=m1.data,
    features=m3.data,
    start_date='',
    end_date='',
    before_start_days=360
)

m5 = M.derived_feature_extractor.v2(
    input_data=m4.data,
    features=m3.data,
    date_col='date',
    instrument_col='instrument'
)

m7 = M.join.v3(
    data1=m2.data,
    data2=m5.data,
    on='date,instrument',
    how='inner',
    sort=False
)

# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m15_run_bigquant_run(input_1, input_2, input_3):
    # 示例代码如下。在这里编写您的代码

    df = input_1.read_df()
    ins= m1.data.read_pickle()['instruments']
    start= m1.data.read_pickle()['start_date']
    end= m1.data.read_pickle()['end_date']
    
    df1 = D.features(ins, start, end, fields=['mf_net_pct_main_0','market_cap_float_0'])#,'mf_net_amount_0'

    df_final=pd.merge(df,df1,on=['date','instrument'])
    df_final = df_final[df_final['mf_net_pct_main_0'] > 0.1]
    df_final = df_final[df_final['price_limit_status_0'] == 2]
    df_final = df_final[df_final['market_cap_float_0'] < 10000000000]

    
    print('-----------------------------------',len(df_final))
    data_1 = DataSource.write_df(df_final)  

    return Outputs(data_1=data_1, data_2=None, data_3=None)

m15 = M.cached.v3(
    input_1=m7.data,
    run=m15_run_bigquant_run
)

m13 = M.dropnan.v1(
    input_data=m15.data_1
)

m6 = M.stock_ranker_train.v5(
    training_ds=m13.data,
    features=m33.data,
    learning_algorithm='排序',
    number_of_leaves=30,
    minimum_docs_per_leaf=1000,
    number_of_trees=20,
    learning_rate=0.1,
    max_bins=1023,
    feature_fraction=1,
    m_lazy_run=False
)

m9 = M.instruments.v2(
    start_date=T.live_run_param('trading_date', conf.start_trade),
    end_date=T.live_run_param('trading_date', conf.end_date),
    market='CN_STOCK_A',
    instrument_list="""600000.SHA
600016.SHA
600019.SHA
600028.SHA
600029.SHA
600030.SHA
600036.SHA
600048.SHA
600050.SHA
600104.SHA
600111.SHA
600309.SHA
600340.SHA
600518.SHA
600519.SHA
600547.SHA
600606.SHA
600837.SHA
600887.SHA
600919.SHA
600958.SHA
600999.SHA
601006.SHA
601088.SHA
601166.SHA
601169.SHA
601186.SHA
601211.SHA
601229.SHA
601288.SHA
601318.SHA
601328.SHA
601336.SHA
601390.SHA
601398.SHA
601601.SHA
601628.SHA
601668.SHA
601669.SHA
601688.SHA
601766.SHA
601800.SHA
601818.SHA
601857.SHA
601878.SHA
601881.SHA
601985.SHA
601988.SHA
601989.SHA
603993.SHA""",
    max_count=0
)

m10 = M.general_feature_extractor.v6(
    instruments=m9.data,
    features=m3.data,
    start_date='',
    end_date='',
    before_start_days=360
)

m11 = M.derived_feature_extractor.v2(
    input_data=m10.data,
    features=m3.data,
    date_col='date',
    instrument_col='instrument'
)

# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m16_run_bigquant_run(input_1, input_2, input_3):
    # 示例代码如下。在这里编写您的代码

    df = input_1.read_df()
    ins= m9.data.read_pickle()['instruments']
    start= m9.data.read_pickle()['start_date']
    end= m9.data.read_pickle()['end_date']
    df1 = D.features(ins, start, end, fields=['mf_net_pct_main_0','market_cap_float_0'])#,'mf_net_amount_0'

    
    df_final=pd.merge(df,df1,on=['date','instrument'])
    df_final = df_final[df_final['mf_net_pct_main_0'] > 0.1]
    df_final = df_final[df_final['price_limit_status_0'] == 2]
    df_final = df_final[df_final['market_cap_float_0'] < 10000000000]
    df_final = df_final[df_final['st_status_0'] == 0]
    print('-----------------------------------',len(df_final))
    data_1 = DataSource.write_df(df_final)


    return Outputs(data_1=data_1, data_2=None, data_3=None)
m16 = M.cached.v3(
    input_1=m11.data,
    run=m16_run_bigquant_run
)

m14 = M.dropnan.v1(
    input_data=m16.data_1
)

m8 = M.stock_ranker_predict.v5(
    model=m6.model,
    data=m14.data,
    m_lazy_run=False
)

# 回测引擎:每日数据处理函数,每天执行一次
def m12_handle_data_bigquant_run(context, data):
     
    # 按日期过滤得到今日的预测数据
    ranker_prediction = context.ranker_prediction[
        context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]

    # 1. 资金分配
    # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金
    # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)
    is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)
    cash_avg = context.portfolio.portfolio_value / context.options['hold_days']
    cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)
    cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)
    positions = {e.symbol: p.amount * p.last_sale_price
                 for e, p in context.perf_tracker.position_tracker.positions.items()}

    # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰
    if not is_staging and cash_for_sell > 0:
        equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}
        instruments = []
        for x in equities :
            if not context.has_unfinished_sell_order(equities[x]):
                instruments.append(x)
                
        for instrument in instruments:
            context.order_target(context.symbol(instrument), 0)
            cash_for_sell -= positions[instrument]
            if cash_for_sell <= 0:
                break

    # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票
    buy_cash_weights = context.stock_weights
    buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
    max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
    for i, instrument in enumerate(buy_instruments):
        cash = cash_for_buy * buy_cash_weights[i]
        if cash > max_cash_per_instrument - positions.get(instrument, 0):
            # 确保股票持仓量不会超过每次股票最大的占用资金量
            cash = max_cash_per_instrument - positions.get(instrument, 0)
        if cash > 0:
            current_price = data.current(context.symbol(instrument), 'price')
            amount = math.floor(cash / current_price - cash / current_price % 100)
            context.order(context.symbol(instrument), amount)

# 回测引擎:准备数据,只执行一次
def m12_prepare_bigquant_run(context):
    pass

# 回测引擎:初始化函数,只执行一次
def m12_initialize_bigquant_run(context):
    # 加载预测数据
    context.ranker_prediction = context.options['data'].read_df()

    # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=3))
    # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
    # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
    stock_count = 1
    # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
    context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
    # 设置每只股票占用的最大资金比例
    context.max_cash_per_instrument = 0.8
    context.options['hold_days'] = 1

m12 = M.trade.v3(
    instruments=m9.data,
    options_data=m8.predictions,
    start_date='',
    end_date='',
    handle_data=m12_handle_data_bigquant_run,
    prepare=m12_prepare_bigquant_run,
    initialize=m12_initialize_bigquant_run,
    volume_limit=0.025,
    order_price_field_buy='open',
    order_price_field_sell='close',
    capital_base=100000, 
    benchmark='000300.SHA',
    auto_cancel_non_tradable_orders=True,
    data_frequency='daily',
    price_type='后复权',
    plot_charts=True,
    backtest_only=False,
    amount_integer=False
)
----------------------------------- 170436
设置测试数据集,查看训练迭代过程的NDCG
bigcharts-data-start/{"__type":"tabs","__id":"bigchart-9e2d75524d7e4f06b5eb8f2e6a0dd05b"}/bigcharts-data-end
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-2-face2f6cf367> in <module>
    235 )
    236 
--> 237 m14 = M.dropnan.v1(
    238     input_data=m16.data_1
    239 )

Exception: no data left after dropnan