电梯策略

策略分享
标签: #<Tag:0x00007f61edb07538>

(njchenxin) #1

克隆策略
In [14]:
# 1. 策略基本参数

# 证券池:这里使用所有股票
instruments = D.instruments()
# 起始日期
start_date = '2016-01-01'
# 结束日期
end_date = '2017-02-28'
# 初始资金
capital_base = 1000000
# 策略比较参考标准,以沪深300为例
benchmark = '000300.INDX'
# 调仓周期(多少个交易日调仓)
rebalance_period = 22
# 每轮调仓买入的股票数量
stock_num = 30


# 2. 选择股票:为了得到更好的性能,在这里做批量计算
# 本样例策略逻辑:选取调仓当天,交易额最小的30只股票买入
# 加载数据:https://bigquant.com/docs/data_history_data.html
history_data = D.history_data(instruments, start_date, end_date, fields=['open', 'high', 'low', 'close','turn','mf_net_amount','list_date','price_limit_status','amount'])
# 过滤掉停牌股票:amount为0的数据
selected_data = history_data[history_data.amount > 0]
# 按天做聚合(groupby),对于每一天的数据,做(apply)按交易额升序排列(sort_values),并选取前30只([:stock_num])
selected_data = selected_data.groupby('date').apply(lambda df: df.sort_values('amount')[:stock_num])

# 3. 策略主体函数
# 初始化虚拟账户状态,只在第一个交易日运行
def initialize(context):
    # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))

# 策略交易逻辑,每个交易日运行一次
def handle_data(context,data):
    today = data.current_dt.strftime('%Y-%m-%d') # 交易日期

    #换手率连续增加
    def ma_calcuturn(df):
        ma_list = [5,10]
        for ma_len in ma_list:
            df['ma_'+str(ma_len)] = pd.rolling_mean(df['turn'], ma_len)
        return df
    # 包含多个周期均线值的股票数据
    stock_ma_data = history_data.groupby('instrument').apply(ma_calcuturn)
    stock_ma_data  = stock_ma_data[stock_ma_data['list_date'] < '2017-05-01']
    #剔除跌停板的股票
    stock_ma_data_limit = stock_ma_data[(stock_ma_data['price_limit_status'] == 1) & (stock_ma_data['open']==stock_ma_data['close'])]
    stock_ma_data_limit =stock_ma_data_limit.groupby('instrument').sum()
    stock_ma_data_limit.reset_index(inplace=True)

    #寻找出现放量的股票
    stock_ma_data['condition']=stock_ma_data['turn']/stock_ma_data['ma_5']>4
    stock_ma_data_row = stock_ma_data[stock_ma_data['open'] < stock_ma_data['close']]
    volume_amp_stock=stock_ma_data_row[stock_ma_data_row['condition']==True]
    volume_amp_stock = volume_amp_stock[['instrument','close']]
    #定位放量当天的收盘价
    volume_amp_stock['pre_close']=volume_amp_stock['close']
    volume_amp_stock = volume_amp_stock[['instrument','pre_close']]
    volume_amp_stock.index=volume_amp_stock['instrument']
    volume_amp_stock=volume_amp_stock['pre_close']
    
    #更新股票列表
    stock_ma_data=stock_ma_data[['instrument','close']]
    stock_ma_data.index=stock_ma_data['instrument']
    
    #合并股票列表
    HB=pd.concat([stock_ma_data,volume_amp_stock],axis=1)
    #确定当今日收盘价格低于放量当天的收盘价的股票列表
    HB=HB[HB['close']<HB['pre_close']]
    
    event=[]
    
    for i in list(HB['instrument']):
        if i in list(stock_ma_data_limit['instrument']):
            pass
        else:
            event.append(i)

    # context.trading_day_index:交易日序号,第一个交易日为0
    if context.trading_day_index % context.options['rebalance_period'] != 0:
        return

    # 调仓:卖出所有持有股票
    for equity in context.portfolio.positions:
        # 停牌的股票,将不能卖出,将在下一个调仓期处理
        if data.can_trade(equity):
            context.order_target_percent(equity, 0)

    # 调仓:买入新的股票
    instruments_to_buy = event
    if len(instruments_to_buy) == 0:
        return
    # 等量分配资金买入股票
    weight = 1.0 / len(instruments_to_buy)
    for instrument in instruments_to_buy:
        if data.can_trade(context.symbol(instrument)):
            context.order_target_percent(context.symbol(instrument), weight)

# 4. 策略回测:https://bigquant.com/docs/module_trade.html
m = M.trade.v1(
    instruments=instruments,
    start_date=start_date,
    end_date=end_date,
    initialize=initialize,
    handle_data=handle_data,
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=capital_base,
    benchmark=benchmark,
    # 传入数据给回测模块,所有回测函数里用到的数据都要从这里传入,并通过 context.options 使用,否则可能会遇到缓存问题
    options={'selected_data': selected_data, 'rebalance_period': rebalance_period}
)
[2017-06-28 22:33:12.020073] INFO: bigquant: backtest.v6 start ..
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-214c86c0d792> in <module>()
    110     benchmark=benchmark,
    111     # 传入数据给回测模块,所有回测函数里用到的数据都要从这里传入,并通过 context.options 使用,否则可能会遇到缓存问题
--> 112     options={'selected_data': selected_data, 'rebalance_period': rebalance_period}
    113 )

<ipython-input-14-214c86c0d792> in handle_data(context, data)
     65     len(stock_ma_data)
     66     #合并股票列表
---> 67     HB=pd.concat([stock_ma_data,volume_amp_stock],axis=1)
     68     HB=HB[HB['close']<HB['pre_close']]
     69 

ValueError: Shape of passed values is (3, 815167), indices imply (3, 3122)

这个策略用来选股可以,但是用传统策略来回测就报错,求大神看看

(小Q) #2

问题的关键在于,对concat函数的理解。

函数的帮助文档,请参考:帮助文档

帮助文档全是英文很费解,那就来看具体小例子,简单易明白:具体例子

stock_ma_data与volume_amp_stock 是不同长度的DataFrame,由于不太清楚你的合并目的,不知道你是想横向合并还是纵向合并,因此不知道axis到底应该是传入1还是传入0。

如果你修改下axis这个参数,应该就没有问题了。

欢迎交流!


(njchenxin) #3

1是横向拼接,0是纵向拼接。好像我想明白了。。。。。