克隆策略

数据准备函数

In [10]:
def prepare(context):
    # 加载原始数据
    stock_raw_data = D.history_data(context.instruments, context.start_date, context.end_date, ['close','low'])
    # 包含多个周期均线值的股票数据
    stock_ma_data = stock_raw_data.groupby('instrument').apply(ma_calculate)
    # 每日买入股票的数据框
    context.daily_stock_to_buy= stock_ma_data.groupby('date').apply(open_pos_con)
    # 每日卖出股票的数据框
    context.daily_stock_to_sell= stock_ma_data.groupby('date').apply(close_pos_con)

# 计算多个周期均线的函数
def ma_calculate(df):
    ma_list = [5,10,20,40,120]
    for ma_len in ma_list:
        df['ma_'+str(ma_len)] = df['close'].rolling( ma_len).mean()
    return df

# 函数:求满足开仓条件的股票列表
def open_pos_con(df):
    return list(df[(df['ma_5']>df['ma_10'])&(df['ma_10']>df['ma_20'])&(df['ma_20']>df['ma_40'])&(df['ma_40']>df['ma_120'])&(df['low']<df['ma_10'])].instrument)

# 函数:求满足平仓条件的股票列表
def close_pos_con(df):
    return list(df[df['ma_5']<df['ma_40']].instrument)

策略逻辑主体函数

In [11]:
# 初始化虚拟账户状态,只在第一个交易日运行
def initialize(context):
    # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
    context.num_stock = 100 # 最多同时持有100只股票
    
# 策略交易逻辑,每个交易日运行一次
def handle_data(context, data):
    date = data.current_dt.strftime('%Y-%m-%d')  # 日期
    buy_stock = context.daily_stock_to_buy[date]  # 当日符合买入条件的股票
    sell_stock = context.daily_stock_to_sell[date]  # 当日符合卖出条件的股票
    weight = 1/context.num_stock   # 等权重配置
    stock_hold_num = len(context.portfolio.positions)  # 目前持有的股票数量
    remain_num = context.num_stock - stock_hold_num   # 还可以买入的股票数量,需要把卖出的股票加回来
    # 初始化当日买入订单的数量为0 
    order_count = 0
    # 买入股票
    for i in buy_stock:
        # 如果发送买入订单的股票数量已经超过了还可以买入的股票数量,那么应退出for循环
        if order_count >= remain_num:
            break
        # 对于没有买入的股票且可以交易的股票,应买入
        if context.portfolio.positions[context.symbol(i)].amount == 0 and data.can_trade(context.symbol(i)):
            order_target_percent(context.symbol(i), weight)
            order_count += 1  # 统计一下当天股票买入数量
    # 卖出股票
    for j in sell_stock:
        if context.portfolio.positions[context.symbol(j)].amount > 0 and data.can_trade(context.symbol(j)):
            order_target_percent(context.symbol(j), 0)

策略回测接口

In [12]:
# 策略回测接口: https://bigquant.com/docs/strategy_backtest.html
m = M.trade.v3(
    instruments=D.instruments(market='CN_STOCK_A'),
    start_date='2013-01-01',
    end_date='2015-01-21',
    prepare=prepare, # 数据准备函数
    initialize=initialize, # 初始化函数
    handle_data=handle_data, # 策略主体函数
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=1000000,
    benchmark='000300.INDX',
)
  • 收益率79.9%
  • 年化收益率34.76%
  • 基准收益率40.66%
  • 阿尔法0.22
  • 贝塔0.52
  • 夏普比率1.45
  • 胜率0.42
  • 盈亏比-2.97
  • 收益波动率19.88%
  • 信息比率0.04
  • 最大回撤15.68%
bigcharts-data-start/{"__type":"tabs","__id":"bigchart-1dd74ab4d24b49aaacd78814fcda006a"}/bigcharts-data-end