我的策略跑了5天了,怎么没有选出来股票呢


(vinjie2018) #1

def prepare(context):
# 加载原始数据
stock_raw_data = D.history_data(context.instruments, context.start_date, context.end_date, [‘close’,‘open’,‘low’,‘high’,‘price_limit_status’,‘mf_net_pct_main’,‘mf_net_amount_l’,‘mf_net_pct_l’,‘amount’])

# 包含多个周期均线值的股票数据
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,30,60]
for ma_len in ma_list:
df[‘ma_’+str(ma_len)] = pd.rolling_mean(df[‘close’], ma_len)
df[‘zf’] = df[‘close’] / df[‘close’].shift(1) - 1.0 > 0.06
df[‘zf0’] = df[‘close’] > df[‘ma_5’].shift(20)
df[‘zf1’] = df[‘close’] - df[‘open’] > 0
df[‘zf2’] = ((df[‘open’] / df[‘close’].shift(1)) - 1.0) < 0.01
df[‘zf3’] = df[‘amount’] > df[‘amount’].shift(1)
return df

函数:求满足开仓条件的股票列表

def open_pos_con(df):
return list(df[
#(df[‘mf_net_pct_l’]>0.1)
(df[‘price_limit_status’]==3)
#&(df[‘close’]>df[‘ma_10’])
&(df[‘zf’])
#&(df[‘zf0’])
&(df[‘zf1’])
&(df[‘zf2’])
&(df[‘zf3’])
&(df[‘close’]>df[‘ma_5’])
#&(df[‘close’]>df[‘ma_20’])
#&(df[‘close’]>df[‘ma_30’])
#&(df[‘low’]<df[‘ma_5’])
#&(df[‘low’]<df[‘ma_10’])
#&(df[‘low’]<df[‘ma_20’])
#&(df[‘low’]>df[‘ma_20’])
].instrument)

函数:求满足平仓条件的股票列表

def close_pos_con(df):
return list(df[df[‘close’]<df[‘high’]].instrument)

初始化虚拟账户状态,只在第一个交易日运行

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 = 50 # 最多同时持有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)

策略回测接口: https://bigquant.com/docs/strategy_backtest.html

m = M.trade.v3(
instruments=D.instruments(market=‘CN_STOCK_A’),
#start_date=‘2018-01-01’,
#end_date=‘2018-06-22’,
prepare=prepare, # 数据准备函数
initialize=initialize, # 初始化函数
handle_data=handle_data, # 策略主体函数
# 买入订单以开盘价成交
order_price_field_buy=‘open’,
# 卖出订单以开盘价成交
order_price_field_sell=‘close’,
capital_base=1000000,
benchmark=‘000300.INDX’,
price_type=‘original’,
)


(达达) #2

请您修改一下贴子格式,在策略中点击策略链接,然后拷贝地址,粘到您的帖子中,就可以分享您的策略了,格式比较正规方便我们修改


(vinjie2018) #3
克隆策略
In [3]:
def prepare(context):
    # 加载原始数据
    stock_raw_data = D.history_data(context.instruments, context.start_date, context.end_date, ['close','turn','open','low','high','price_limit_status','mf_net_pct_main','mf_net_amount_l','mf_net_pct_l','amount'])
    
    # 包含多个周期均线值的股票数据
    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,30,60]
    for ma_len in ma_list:
        df['ma_'+str(ma_len)] = pd.rolling_mean(df['close'], ma_len)
    
    #涨幅大于6%    
    #df['Increase'] = df['close'] / df['close'].shift(1) - 1.0 > 0.06
   
    #高开小于1%
    df['open_high'] = ((df['open'] / df['close'].shift(1)) - 1.0) < 0.01
    
    #成交量放大小于6倍
    df['amount_cmp'] = ((df['amount'] / df['amount'].shift(1)) - 1.0) < 6.0
    
    #计算20天最高点和最低点的比要小于2%
    df['ma_20_highest_max'] = df['ma_20'].rolling(20).max()  
    df['ma_20_highest_min'] = df['ma_20'].rolling(20).min()
    df['is_ma_20_highest'] = ((df['ma_20_highest_max'] / df['ma_20_highest_min']) - 1.0) < 0.1
    
    #收盘价要为5日最高价
    df['highest_5'] = df['high'].rolling(5).max() 
    df['is_highest'] = df['close'] == df['highest_5']
    
    #成交量为5日内最大
    df['amount_5_highest'] = df['amount'].rolling(5).max()
    df['is_amount_5_highest'] = df['amount'] == df['amount_5_highest']
    
    df['is_turn'] = df['turn'] > 0.05
    return df

# 函数:求满足开仓条件的股票列表
def open_pos_con(df):
    return list(df[
                    #(df['mf_net_pct_l']>0.1)
                   (df['price_limit_status']==3)
                   &(df['is_turn']) 
                   &(df['open_high'])
                   &(df['amount_cmp'])   
                   &(df['is_highest'])
                   &(df['is_ma_20_highest'])
                   &(df['is_amount_5_highest'])
                   &(df['close']>df['ma_5'])
                   &(df['close']>df['ma_10'])
                   &(df['close']>df['ma_20'])
                   &(df['close']>df['ma_30'])
                    ].instrument)

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

# 初始化虚拟账户状态,只在第一个交易日运行
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 = 20 # 最多同时持有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)

# 策略回测接口: https://bigquant.com/docs/strategy_backtest.html
m = M.trade.v3(
    instruments=D.instruments(market='CN_STOCK_A'),
    start_date='2018-01-01',
    end_date='2018-06-30',
    prepare=prepare, # 数据准备函数
    initialize=initialize, # 初始化函数
    handle_data=handle_data, # 策略主体函数
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='close',
    capital_base=100004,
    benchmark='000300.INDX',
    price_type='original',
)           
            
[2018-07-01 21:53:22.875118] INFO: bigquant: backtest.v7 开始运行..
[2018-07-01 21:53:22.879823] INFO: bigquant: biglearning backtest:V7.1.0
[2018-07-01 21:54:38.179244] INFO: algo: TradingAlgorithm V1.2.1
[2018-07-01 21:55:08.936145] INFO: algo: handle_splits get splits [dt:2018-04-26 00:00:00+00:00] [asset:Equity(443 [603027.SHA]), ratio:0.9938996542088288]
[2018-07-01 21:55:08.939921] INFO: Position: position stock handle split[sid:443, orig_amount:200, new_amount:201.0, orig_cost:21.059999467616617, new_cost:20.93, ratio:0.9938996542088288, last_sale_price:21.18000110039046]
[2018-07-01 21:55:08.943670] INFO: Position: after split: asset: Equity(443 [603027.SHA]), amount: 201.0, cost_basis: 20.93,             last_sale_price: 21.309999465942383
[2018-07-01 21:55:08.945202] INFO: Position: returning cash: 4.82
[2018-07-01 21:55:09.307737] INFO: algo: handle_splits get splits [dt:2018-05-04 00:00:00+00:00] [asset:Equity(2615 [300403.SZA]), ratio:0.5488611053545247]
[2018-07-01 21:55:09.412930] INFO: algo: handle_splits get splits [dt:2018-05-07 00:00:00+00:00] [asset:Equity(1645 [300375.SZA]), ratio:0.5412401796937161]
[2018-07-01 21:55:10.733099] INFO: algo: handle_splits get splits [dt:2018-05-24 00:00:00+00:00] [asset:Equity(2801 [600711.SHA]), ratio:0.991453046886707]
[2018-07-01 21:55:10.734353] INFO: Position: position stock handle split[sid:2801, orig_amount:300, new_amount:302.0, orig_cost:11.949999809272413, new_cost:11.85, ratio:0.991453046886707, last_sale_price:11.600001404993117]
[2018-07-01 21:55:10.735194] INFO: Position: after split: asset: Equity(2801 [600711.SHA]), amount: 302.0, cost_basis: 11.85,             last_sale_price: 11.700000762939453
[2018-07-01 21:55:10.735950] INFO: Position: returning cash: 6.8
[2018-07-01 21:55:10.910236] INFO: algo: handle_splits get splits [dt:2018-05-28 00:00:00+00:00] [asset:Equity(41 [002826.SZA]), ratio:0.9970003292668443]
[2018-07-01 21:55:11.620422] INFO: algo: handle_splits get splits [dt:2018-06-07 00:00:00+00:00] [asset:Equity(439 [300689.SZA]), ratio:0.9939112537599243]
[2018-07-01 21:55:11.624871] INFO: Position: position stock handle split[sid:439, orig_amount:100, new_amount:100.0, orig_cost:43.63000106979945, new_cost:43.36, ratio:0.9939112537599243, last_sale_price:40.80999744431189]
[2018-07-01 21:55:11.626181] INFO: Position: after split: asset: Equity(439 [300689.SZA]), amount: 100.0, cost_basis: 43.36,             last_sale_price: 41.060001373291016
[2018-07-01 21:55:11.627292] INFO: Position: returning cash: 25.0
[2018-07-01 21:55:12.298964] INFO: algo: handle_splits get splits [dt:2018-06-20 00:00:00+00:00] [asset:Equity(2171 [002829.SZA]), ratio:0.999310004143541]
[2018-07-01 21:55:12.300300] INFO: Position: position stock handle split[sid:2171, orig_amount:100, new_amount:100.0, orig_cost:27.860002517849736, new_cost:27.84, ratio:0.999310004143541, last_sale_price:28.96000536866457]
[2018-07-01 21:55:12.301332] INFO: Position: after split: asset: Equity(2171 [002829.SZA]), amount: 100.0, cost_basis: 27.84,             last_sale_price: 28.98000144958496
[2018-07-01 21:55:12.302379] INFO: Position: returning cash: 2.0
[2018-07-01 21:55:12.908466] INFO: Performance: Simulated 119 trading days out of 119.
[2018-07-01 21:55:12.909750] INFO: Performance: first open: 2018-01-02 09:30:00+00:00
[2018-07-01 21:55:12.910974] INFO: Performance: last close: 2018-06-29 15:00:00+00:00
  • 收益率-13.05%
  • 年化收益率-25.64%
  • 基准收益率-12.9%
  • 阿尔法-0.25
  • 贝塔0.21
  • 夏普比率-2.16
  • 胜率0.37
  • 盈亏比1.37
  • 收益波动率14.57%
  • 信息比率-0.0
  • 最大回撤15.74%
[2018-07-01 21:55:14.133795] INFO: bigquant: backtest.v7 运行完成[111.258733s].

(vinjie2018) #4

测试没有问题,为什么开始交易后,5天都没有交易记录呢?


(达达) #5

#计算20天最高点和最低点的比要小于2%
这一条就注定了20天后才会有这个指标值,因此前20天都因为等待这个值的计算结果导致没有交易
另外,希望您尽量用可视化,比如说您有6个过滤条件您完全可以用因子实现

price_limit_status_0
mean(close_0,5)
mean(close_0,10)
mean(close_0,20)
mean(close_0,30)
open_0/close_1-1
amount_0/amount_1-1
ts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1
where(close_0==ts_max(high_0,5),1,0)
where(amount_0==ts_max(amount_0,5),1,0)
where(turn_0>0.05,1,0)

这些因子就是您要计算的条件嘛~
然后过滤一下

    # 加载历史数据
    raw_data = context.options['data'].read_df()

    #生成每日买入股票
    daily_buy_stock=raw_data[(raw_data['open_0/close_1-1']<0.01) &
                          (raw_data['amount_0/amount_1-1']<6) &
                          (raw_data['ts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1']<0.02) &
                          (raw_data['where(close_0==ts_max(high_0,5),1,0)']>0) &
                          (raw_data['where(amount==ts_max(amount,5),1,0)']>0) &
                          (raw_data['where(turn_0>0.05,1,0)']>0) &
                          (raw_data['close_0']>raw_data['mean(close_0,5)']) &
                          (raw_data['close_0']>raw_data['mean(close_0,10)']) &
                          (raw_data['close_0']>raw_data['mean(close_0,20)']) &
                          (raw_data['close_0']>raw_data['mean(close_0,30)']) & 
                          (raw_data['price_limit_status_0']==3)
                         ]

利用可视化和表达式引擎可以轻松实现您的想法
按您的想法修改了策略

克隆策略

    {"Description":"实验创建于2018/6/27","Summary":"","Graph":{"EdgesInternal":[{"DestinationInputPortId":"-64:instruments","SourceOutputPortId":"-51:data"},{"DestinationInputPortId":"-84:instruments","SourceOutputPortId":"-51:data"},{"DestinationInputPortId":"-64:features","SourceOutputPortId":"-59:data"},{"DestinationInputPortId":"-71:features","SourceOutputPortId":"-59:data"},{"DestinationInputPortId":"-71:input_data","SourceOutputPortId":"-64:data"},{"DestinationInputPortId":"-84:options_data","SourceOutputPortId":"-71:data"}],"ModuleNodes":[{"Id":"-51","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"2018-06-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"-51"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-51","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":1,"Comment":"","CommentCollapsed":true},{"Id":"-59","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"\n# #号开始的表示注释\n# 多个特征,每行一个,可以包含基础特征和衍生特征\nprice_limit_status_0\nadjust_factor_0\nmean(close_0,5)\nmean(close_0,10)\nmean(close_0,20)\nmean(close_0,30)\nopen_0/close_1-1\namount_0/amount_1-1\nts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1\nwhere(close_0==ts_max(high_0,5),1,0)\nwhere(amount_0==ts_max(amount_0,5),1,0)\nwhere(turn_0>0.05,1,0)\n\n\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"-59"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-59","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":2,"Comment":"","CommentCollapsed":true},{"Id":"-64","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v6","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":"60","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-64"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-64"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-64","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":3,"Comment":"","CommentCollapsed":true},{"Id":"-71","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v2","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-71"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-71"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-71","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":4,"Comment":"","CommentCollapsed":true},{"Id":"-84","ModuleId":"BigQuantSpace.trade.trade-v3","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"handle_data","Value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n date = data.current_dt.strftime('%Y-%m-%d') # 日期 \n weight = 1/context.num_stock # 等权重配置\n stock_hold_num = len(context.portfolio.positions) # 目前持有的股票数量\n remain_num = context.num_stock - stock_hold_num # 还可以买入的股票数量,需要把卖出的股票加回来\n\n #如果今天有满足卖出条件的股票 \n if date in list(context.daily_stock_to_buy.index):\n sell_stock = context.daily_stock_to_sell.ix[date] # 当日符合卖出条件的股票\n # 卖出股票\n for j in sell_stock:\n if context.portfolio.positions[context.symbol(j)].amount > 0 and data.can_trade(context.symbol(j)):\n order_target_percent(context.symbol(j), 0)\n #每卖出1个股票就可以多买一只股票\n remain_num=remain_num+1\n\n # 初始化当日买入订单的数量为0 \n order_count = 0 \n #如果今天有满足买入条件的股票 \n if date in list(context.daily_stock_to_buy.index):\n buy_stock = context.daily_stock_to_buy.ix[date] # 当日符合买入条件的股票\n # 买入股票\n for i in buy_stock:\n # 如果发送买入订单的股票数量已经超过了还可以买入的股票数量,那么应退出for循环\n if order_count >= remain_num:\n break\n # 对于没有买入的股票且可以交易的股票,应买入\n if context.portfolio.positions[context.symbol(i)].amount == 0 and data.can_trade(context.symbol(i)):\n order_target_percent(context.symbol(i), weight)\n order_count += 1 # 统计一下当天股票买入数量\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"prepare","Value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n # 加载历史数据\n raw_data = context.options['data'].read_df()\n #更改日期格式为字符串。便于在handle中按日期筛选\n raw_data['date']= raw_data['date'].apply(lambda x:x.strftime('%Y-%m-%d'))\n #生成每日买入股票\n daily_buy_stock=raw_data[(raw_data['open_0/close_1-1']<0.01) &\n (raw_data['amount_0/amount_1-1']<6) &\n (raw_data['ts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1']<0.02) &\n (raw_data['where(close_0==ts_max(high_0,5),1,0)']>0) &\n (raw_data['where(amount_0==ts_max(amount_0,5),1,0)']>0) &\n (raw_data['where(turn_0>0.05,1,0)']>0) &\n (raw_data['close_0']>raw_data['mean(close_0,5)']) &\n (raw_data['close_0']>raw_data['mean(close_0,10)']) &\n (raw_data['close_0']>raw_data['mean(close_0,20)']) &\n (raw_data['close_0']>raw_data['mean(close_0,30)']) & \n (raw_data['price_limit_status_0']==3)\n ]\n \n # 生成每日卖出股票 后复权数据除以除权因子是真实价格\n daily_sell_stock=raw_data[raw_data['close_0']/raw_data['adjust_factor_0']>0] \n \n # 每日买入股票的数据框\n context.daily_stock_to_buy= daily_buy_stock.groupby('date').apply(lambda x:list(x.instrument))\n # 每日卖出股票的数据框.set_index('date')\n context.daily_stock_to_sell=daily_sell_stock.groupby('date').apply(lambda x:list(x.instrument))\n \n \n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"initialize","Value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n context.num_stock = 20 # 最多同时持有20只股票\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_trading_start","Value":"# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。\ndef bigquant_run(context, data):\n pass\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"volume_limit","Value":0.025,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_buy","Value":"open","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_sell","Value":"close","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"capital_base","Value":1000000,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"auto_cancel_non_tradable_orders","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"data_frequency","Value":"daily","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"price_type","Value":"后复权","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"plot_charts","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"backtest_only","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"amount_integer","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-84"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"options_data","NodeId":"-84"}],"OutputPortsInternal":[{"Name":"raw_perf","NodeId":"-84","OutputType":null}],"UsePreviousResults":false,"moduleIdForCode":6,"Comment":"","CommentCollapsed":true}],"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions><NodePosition Node='-51' Position='81,121,200,200'/><NodePosition Node='-59' Position='448,123,200,200'/><NodePosition Node='-64' Position='257,238,200,200'/><NodePosition Node='-71' Position='239,338,200,200'/><NodePosition Node='-84' Position='218,523,200,200'/></NodePositions><NodeGroups /></DataV1>"},"IsDraft":true,"ParentExperimentId":null,"WebService":{"IsWebServiceExperiment":false,"Inputs":[],"Outputs":[],"Parameters":[{"Name":"交易日期","Value":"","ParameterDefinition":{"Name":"交易日期","FriendlyName":"交易日期","DefaultValue":"","ParameterType":"String","HasDefaultValue":true,"IsOptional":true,"ParameterRules":[],"HasRules":false,"MarkupType":0,"CredentialDescriptor":null}}],"WebServiceGroupId":null,"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions></NodePositions><NodeGroups /></DataV1>"},"DisableNodesUpdate":false,"Category":"user","Tags":[],"IsPartialRun":true}
    In [29]:
    # 本代码由可视化策略环境自动生成 2018年7月7日 11:56
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    m1 = M.instruments.v2(
        start_date='2018-01-01',
        end_date='2018-06-01',
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    
    m2 = M.input_features.v1(
        features="""
    # #号开始的表示注释
    # 多个特征,每行一个,可以包含基础特征和衍生特征
    price_limit_status_0
    adjust_factor_0
    mean(close_0,5)
    mean(close_0,10)
    mean(close_0,20)
    mean(close_0,30)
    open_0/close_1-1
    amount_0/amount_1-1
    ts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1
    where(close_0==ts_max(high_0,5),1,0)
    where(amount_0==ts_max(amount_0,5),1,0)
    where(turn_0>0.05,1,0)
    
    
    """
    )
    
    m3 = M.general_feature_extractor.v6(
        instruments=m1.data,
        features=m2.data,
        start_date='',
        end_date='',
        before_start_days=60
    )
    
    m4 = M.derived_feature_extractor.v2(
        input_data=m3.data,
        features=m2.data,
        date_col='date',
        instrument_col='instrument',
        user_functions={}
    )
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m6_handle_data_bigquant_run(context, data):
        date = data.current_dt.strftime('%Y-%m-%d')  # 日期 
        weight = 1/context.num_stock   # 等权重配置
        stock_hold_num = len(context.portfolio.positions)  # 目前持有的股票数量
        remain_num = context.num_stock - stock_hold_num   # 还可以买入的股票数量,需要把卖出的股票加回来
    
        #如果今天有满足卖出条件的股票 
        if date in list(context.daily_stock_to_buy.index):
            sell_stock = context.daily_stock_to_sell.ix[date]  # 当日符合卖出条件的股票
            # 卖出股票
            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)
                    #每卖出1个股票就可以多买一只股票
                    remain_num=remain_num+1
    
        # 初始化当日买入订单的数量为0 
        order_count = 0            
        #如果今天有满足买入条件的股票        
        if date in list(context.daily_stock_to_buy.index):
            buy_stock = context.daily_stock_to_buy.ix[date]  # 当日符合买入条件的股票
            # 买入股票
            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  # 统计一下当天股票买入数量
    
    # 回测引擎:准备数据,只执行一次
    def m6_prepare_bigquant_run(context):
        # 加载历史数据
        raw_data = context.options['data'].read_df()
        #更改日期格式为字符串。便于在handle中按日期筛选
        raw_data['date']= raw_data['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
        #生成每日买入股票
        daily_buy_stock=raw_data[(raw_data['open_0/close_1-1']<0.01) &
                              (raw_data['amount_0/amount_1-1']<6) &
                              (raw_data['ts_max(mean(close_0,20),20)/ts_min(mean(close_0,20),20)-1']<0.02) &
                              (raw_data['where(close_0==ts_max(high_0,5),1,0)']>0) &
                              (raw_data['where(amount_0==ts_max(amount_0,5),1,0)']>0) &
                              (raw_data['where(turn_0>0.05,1,0)']>0) &
                              (raw_data['close_0']>raw_data['mean(close_0,5)']) &
                              (raw_data['close_0']>raw_data['mean(close_0,10)']) &
                              (raw_data['close_0']>raw_data['mean(close_0,20)']) &
                              (raw_data['close_0']>raw_data['mean(close_0,30)']) & 
                              (raw_data['price_limit_status_0']==3)
                             ]
           
        # 生成每日卖出股票 后复权数据除以除权因子是真实价格
        daily_sell_stock=raw_data[raw_data['close_0']/raw_data['adjust_factor_0']>0]   
        
        # 每日买入股票的数据框
        context.daily_stock_to_buy= daily_buy_stock.groupby('date').apply(lambda x:list(x.instrument))
        # 每日卖出股票的数据框.set_index('date')
        context.daily_stock_to_sell=daily_sell_stock.groupby('date').apply(lambda x:list(x.instrument))
        
        
    
    # 回测引擎:初始化函数,只执行一次
    def m6_initialize_bigquant_run(context):
    
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        context.num_stock = 20 # 最多同时持有20只股票
    
    # 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
    def m6_before_trading_start_bigquant_run(context, data):
        pass
    
    m6 = M.trade.v3(
        instruments=m1.data,
        options_data=m4.data,
        start_date='',
        end_date='',
        handle_data=m6_handle_data_bigquant_run,
        prepare=m6_prepare_bigquant_run,
        initialize=m6_initialize_bigquant_run,
        before_trading_start=m6_before_trading_start_bigquant_run,
        volume_limit=0.025,
        order_price_field_buy='open',
        order_price_field_sell='close',
        capital_base=1000000,
        benchmark='000300.SHA',
        auto_cancel_non_tradable_orders=True,
        data_frequency='daily',
        price_type='后复权',
        plot_charts=True,
        backtest_only=False,
        amount_integer=False
    )
    
    [2018-07-07 11:57:10.526148] INFO: bigquant: instruments.v2 开始运行..
    [2018-07-07 11:57:10.532226] INFO: bigquant: 命中缓存
    [2018-07-07 11:57:10.533423] INFO: bigquant: instruments.v2 运行完成[0.007367s].
    [2018-07-07 11:57:10.536917] INFO: bigquant: input_features.v1 开始运行..
    [2018-07-07 11:57:10.541274] INFO: bigquant: 命中缓存
    [2018-07-07 11:57:10.542944] INFO: bigquant: input_features.v1 运行完成[0.006075s].
    [2018-07-07 11:57:10.605124] INFO: bigquant: general_feature_extractor.v6 开始运行..
    [2018-07-07 11:57:10.611174] INFO: bigquant: 命中缓存
    [2018-07-07 11:57:10.612767] INFO: bigquant: general_feature_extractor.v6 运行完成[0.007636s].
    [2018-07-07 11:57:10.616518] INFO: bigquant: derived_feature_extractor.v2 开始运行..
    [2018-07-07 11:57:10.620224] INFO: bigquant: 命中缓存
    [2018-07-07 11:57:10.621423] INFO: bigquant: derived_feature_extractor.v2 运行完成[0.004903s].
    [2018-07-07 11:57:10.725641] INFO: bigquant: backtest.v7 开始运行..
    [2018-07-07 11:57:10.729149] INFO: bigquant: biglearning backtest:V7.1.0
    [2018-07-07 11:57:38.625154] INFO: algo: TradingAlgorithm V1.2.1
    [2018-07-07 11:58:05.694733] INFO: Performance: Simulated 100 trading days out of 100.
    [2018-07-07 11:58:05.696248] INFO: Performance: first open: 2018-01-02 09:30:00+00:00
    [2018-07-07 11:58:05.697394] INFO: Performance: last close: 2018-06-01 15:00:00+00:00
    
    • 收益率-4.68%
    • 年化收益率-11.38%
    • 基准收益率-6.46%
    • 阿尔法-0.14
    • 贝塔0.03
    • 夏普比率-3.86
    • 胜率0.35
    • 盈亏比0.83
    • 收益波动率3.87%
    • 信息比率0.01
    • 最大回撤5.25%
    [2018-07-07 11:58:07.788133] INFO: bigquant: backtest.v7 运行完成[57.062469s].