BigQuant平台学习第三篇:如何开发AI策略(下)

机器学习
回测
标签: #<Tag:0x00007f61f44209c0> #<Tag:0x00007f61f4420858>

(华尔街的猫) #1

在系列文章“BigQuant平台学习第二篇:如何开发AI策略(上)”中我们介绍了如何使用机器学习算法预测股票收益率,因此可以获得每日推荐买入哪些股票,但我们并不知道这些股票是否会带来超额收益,因此我们需要借助BigQuant回测引擎进行历史回测(参看:“BigQuant平台学习第一篇:BigQuant的回测机制”)。

通过回测我们发现该机器学习算法完全跑赢沪深300基准指数,具有超额收益,是一个正收益系统。

完整策略和回测结果如下,小伙伴可以 克隆策略到自己的私人账户:

克隆策略

1. 策略参数

In [1]:
class conf:
    start_date='2014-01-01'
    end_date='2017-02-17'
    instruments = D.instruments(start_date, end_date)
    # 标注规则请参考:"BigQuant平台学习第二篇:如何开发AI策略(上)"
    label_expr = ['(return - benchmark_return) * 100', 'where(label > {0}, \
                  {0}, where(label < -{0}, -{0}, label)) + {0}'.format(20)]
    hold_days = 10
    benchmark = '000300.SHA'
    # 选取特征
    features = ['high_10-low_0','volume_10','amount_10','turn_10','market_cap_0']
    # 每日买入排序前五的股票
    stock_count = 5
    # 等权重买入
    stock_weights = [ 1/5 for i in range(5) ]

2. 模型训练和预测

In [2]:
# 注释请参考:“BigQuant平台学习第二篇:如何开发AI策略(上)”
m1 = M.fast_auto_labeler.v4(instruments=conf.instruments, start_date=conf.start_date, 
                            end_date=conf.end_date,
                            label_expr=conf.label_expr,
                            hold_days=conf.hold_days, benchmark='000300.SHA', 
                            sell_at='open', buy_at='open')
m2 = M.general_feature_extractor.v4(instruments=conf.instruments,
                            start_date=conf.start_date, end_date=conf.end_date,
                            features=conf.features)
m3 = M.transform.v1(data=m2.data, transforms=T.get_stock_ranker_default_transforms(),
                            drop_null=True, astype='int32', 
                            except_columns=['date', 'instrument'])
m4 = M.join.v1(data1=m1.data, data2=m3.data, on=['date', 'instrument'], sort=True)
m5_training = M.filter.v1(data=m4.data, expr='date < "2016-01-02"')
m5_training_test = M.filter.v1(data=m4.data, expr='"2012-01-01" <= date < "2016-01-01"')
m5_evaluation = M.filter.v1(data=m4.data, expr='"2016-01-01" <= date')
m6 = M.stock_ranker_train.v1(
         training_ds=m5_training.data, test_ds=m5_training_test.data,
         features=conf.features,number_of_leaves=30, minimum_docs_per_leaf=1000,
         number_of_trees=20, learning_rate=0.1)
m7 = M.stock_ranker_predict.v1(model_id=m6.model_id, data=m5_evaluation.data)
[2017-04-04 11:18:12.770411] INFO: bigquant: fast_auto_labeler.v4 start ..
[2017-04-04 11:18:12.801386] INFO: bigquant: hit cache
[2017-04-04 11:18:12.824158] INFO: bigquant: fast_auto_labeler.v4 end [0.053827s].
[2017-04-04 11:18:12.839671] INFO: bigquant: general_feature_extractor.v4 start ..
[2017-04-04 11:18:12.845245] INFO: bigquant: hit cache
[2017-04-04 11:18:12.846447] INFO: bigquant: general_feature_extractor.v4 end [0.006779s].
[2017-04-04 11:18:12.858854] INFO: bigquant: transform.v1 start ..
[2017-04-04 11:18:12.860722] INFO: bigquant: hit cache
[2017-04-04 11:18:12.862916] INFO: bigquant: transform.v1 end [0.004046s].
[2017-04-04 11:18:12.875246] INFO: bigquant: join.v1 start ..
[2017-04-04 11:18:12.877211] INFO: bigquant: hit cache
[2017-04-04 11:18:12.879218] INFO: bigquant: join.v1 end [0.00397s].
[2017-04-04 11:18:12.888868] INFO: bigquant: filter.v1 start ..
[2017-04-04 11:18:12.893190] INFO: bigquant: hit cache
[2017-04-04 11:18:12.894381] INFO: bigquant: filter.v1 end [0.005513s].
[2017-04-04 11:18:12.900298] INFO: bigquant: filter.v1 start ..
[2017-04-04 11:18:12.902225] INFO: bigquant: hit cache
[2017-04-04 11:18:12.903563] INFO: bigquant: filter.v1 end [0.003261s].
[2017-04-04 11:18:12.909840] INFO: bigquant: filter.v1 start ..
[2017-04-04 11:18:12.911733] INFO: bigquant: hit cache
[2017-04-04 11:18:12.913019] INFO: bigquant: filter.v1 end [0.003191s].
[2017-04-04 11:18:12.974746] INFO: bigquant: stock_ranker_train.v1 start ..
[2017-04-04 11:18:12.977426] INFO: bigquant: hit cache
[2017-04-04 11:18:12.978558] INFO: bigquant: stock_ranker_train.v1 end [0.00382s].
[2017-04-04 11:18:12.988745] INFO: bigquant: stock_ranker_predict.v1 start ..
[2017-04-04 11:18:12.991707] INFO: bigquant: hit cache
[2017-04-04 11:18:12.992942] INFO: bigquant: stock_ranker_predict.v1 end [0.004193s].

3. 回测主体函数

In [3]:
def initialize(context):
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
    # 记录持仓中每只股票买入时候的日期索引
    context.holds = {}
    # 获取模型预测结果
    context.ranker_prediction = m7.predictions.read_hdf()
    
def handle_data(context, data):
    
    # 当天推荐买入的股票
    ranker_prediction = context.ranker_prediction[context.ranker_prediction.date
                                == data.current_dt.strftime('%Y-%m-%d')]

    # 每日买股票的资金是均等的
    cash_avg = context.portfolio.portfolio_value / context.options['hold_days']  
    # 每日买入金额
    cash_for_buy = min(context.portfolio.cash,  cash_avg)
    # 持仓
    current_positions = context.perf_tracker.position_tracker.positions
    
     # 今日卖出:根据持仓期今日卖出的股票:
    sell_stock = {}
    for equity, position in current_positions.items():
        if position.amount <= 0:
            continue
        # context.trading_day_index为日期索引,第一天为0,依次类推
        _hold_days = context.trading_day_index - context.holds[equity.symbol]
        to_sell = _hold_days >= context.options['hold_days'] # 持仓期是否超过10天
        if to_sell:
            # 超过10天就卖出股票
            context.order_target(context.symbol(equity.symbol), 0)
    
   
    # 今日买入:等权重分配资金
    buy_cash_weights = context.options['weights']
    # 买入股票的列表
    buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
    # 依次买入股票
    for i, instrument in enumerate(buy_instruments):
        cash = cash_for_buy * buy_cash_weights[i]
        if cash > 100:
            context.order_value(context.symbol(instrument), cash)
            # 买入股票的时候记录日期索引
            context.holds[instrument] = context.trading_day_index

4. 回测接口

In [4]:
m8=M.backtest.v5(
    instruments=m7.instruments,
    start_date=m7.start_date,
    end_date=m7.end_date,
    initialize=initialize,
    handle_data=handle_data,
    order_price_field_buy='open', # 以开盘价买入股票
    order_price_field_sell='open', # 以开盘价卖出股票
    capital_base=500000, # 初始资金50万
    benchmark='000300.SHA', # 以沪深300为比较基准 
    options={ 'hold_days': conf.hold_days, 'weights': conf.stock_weights} # 传入相关参数
    )
[2017-04-04 11:18:13.111065] INFO: bigquant: backtest.v5 start ..
[2017-04-04 11:19:26.456111] INFO: Performance: Simulated 262 trading days out of 262.
[2017-04-04 11:19:26.459112] INFO: Performance: first open: 2016-01-04 14:30:00+00:00
[2017-04-04 11:19:26.460744] INFO: Performance: last close: 2017-01-26 20:00:00+00:00
[2017-04-04 11:19:27.034436] INFO: bigquant: ir base: 0.2106835813071899
  • 收益率41.73%
  • 年化收益率39.86%
  • 基准收益率-9.19%
  • 阿尔法0.24
  • 贝塔0.94
  • 夏普比率1.35
  • 收益波动率29.22%
  • 信息比率2.48
  • 最大回撤15.39%
  • 盈/亏次数231/144
  • 盈/亏利润率+8.63%/-6.61%
[2017-04-04 11:19:27.522831] INFO: bigquant: backtest.v5 end [74.411739s].

(路飞) #2

受益匪浅


(frog) #3

人工智能量化交易势在必行啊


(kaoya) #4

楼主好贴,让我们开发策略更容易啦


(小Q) #5

期待更多好的文章