有没有比较简单又容易上手的量化交易策略呢?

接触量化交易之前要先了解量化交易策略,请问大家有没有比较简单又容易上手的量化交易策略呢?

通道策略
所谓通道策略是指利用收盘价或者最高/最低价构造出交易上轨道和下轨道,

很多,可以从经典策略开始:
传统量化策略:小市值策略、海龟策略、金叉死叉策略、行业轮动策略、多因子选股策略等
AI量化策略:Stockranker策略、随机森林策略、CNN策略、DNN策略、Transformer策略、DQN策略等

以上都有策略源码,举个小市值策略的代码案例,其余BigQuant来克隆源码。

小市值策略源码

# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m2_run_bigquant_run(input_1, input_2, input_3):
    # 示例代码如下。在这里编写您的代码
    # 计算行业行业收益
    industry_df = DataSource("basic_info_index_CN_STOCK_A").read()

    SW_industry_list = industry_df[industry_df.instrument.str.startswith('SW')].instrument.tolist()

    SW_industry_df = DataSource("bar1d_index_CN_STOCK_A").read(SW_industry_list)
    
    SW_industry_ret = SW_industry_df.groupby('instrument').apply(calcu_ret)
    
    SW_industry_ret.reset_index(inplace=True, drop=True)
    SW_industry_ret['date'] = SW_industry_ret['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
    
    daily_buy_industry_dict = {dt:seek_head_industry(SW_industry_ret.set_index('date').loc[dt]) for dt in list(set(SW_industry_ret.date))}
    
    
    daily_stock = input_1.read()
    daily_stock['industry_sw_level1_0'] = daily_stock['industry_sw_level1_0'].apply(lambda x:'SW'+str(x)+'.HIX')
    
    daily_stock = daily_stock.groupby(['date', 'industry_sw_level1_0']).apply(seek_head_stock).reset_index()
    
    buy_df = pd.DataFrame()
    for k,v in daily_buy_industry_dict.items():
        buy_df = buy_df.append(daily_stock[(daily_stock.date==k)&(daily_stock.industry_sw_level1_0.apply(lambda x: x in v))])
    
    buy_df = buy_df.groupby('date').apply(lambda x:x[0].values.tolist()).reset_index()
    buy_df[0] = buy_df[0].apply(lambda x:x[0]+x[1]+x[2])
    
    
    data_1 = DataSource.write_df(buy_df)
    
    
    return Outputs(data_1=data_1, data_2=None, data_3=None)

# 计算不同周期的动量
def calcu_ret(df):
    df = df.sort_values('date')
    for i in [42, 84, 126]: # 分别代表2月、4月、半年的动量
        df['ret_%s'%i] = df['close']/df['close'].shift(i)-1 
    return df

# 计算出得分
def seek_head_industry(df):
    for j in ['ret_42','ret_84','ret_126']:
        df['%s'%j] = df['%s'%j].rank(ascending=True) 
    df['score'] = 0.4*df['ret_42']+0.3*df['ret_84']+0.3*df['ret_126']  # 得分的权重分别为0.4、0.3、0.3
    result = df.sort_values('score', ascending=False)
    return list(result.instrument)[:3]  # 前3个行业

# 选出特定行业优质股票
def seek_head_stock(df):
    result = df.sort_values(['myrank'], ascending=False)
    return list(result.instrument[:10]) # 每个行业选10只股票
# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
def m2_post_run_bigquant_run(outputs):
    return outputs

# 回测引擎:初始化函数,只执行一次
def m4_initialize_bigquant_run(context):
    # 手续费设置
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5)) 
    context.mydata = context.options["data"].read()
# 回测引擎:每日数据处理函数,每天执行一次
def m4_handle_data_bigquant_run(context, data):
    # 按月调仓
    if context.trading_day_index % 20 != 0:
        return 
    
    date = data.current_dt.strftime('%Y-%m-%d') # 日期
    # 整理出当天要买入的股票
    stock_to_buy = context.mydata[context.mydata.date==date][0].tolist()[0]
    
    # 通过positions对象,使用列表生成式的方法获取目前持仓的股票列表
    stock_hold_now = [equity.symbol for equity in context.portfolio.positions]
    # 继续持有的股票:调仓时,如果买入的股票已经存在于目前的持仓里,那么应继续持有
    no_need_to_sell = [i for i in stock_hold_now if i in stock_to_buy]
    # 需要卖出的股票
    stock_to_sell = [i for i in stock_hold_now if i not in no_need_to_sell]
  
    # 卖出
    for stock in stock_to_sell:
        # 如果该股票停牌,则没法成交。因此需要用can_trade方法检查下该股票的状态
        # 如果返回真值,则可以正常下单,否则会出错
        # 因为stock是字符串格式,我们用symbol方法将其转化成平台可以接受的形式:Equity格式
        if data.can_trade(context.symbol(stock)):
            # order_target_percent是平台的一个下单接口,表明下单使得该股票的权重为0,
            #   即卖出全部股票,可参考回测文档
            context.order_target_percent(context.symbol(stock), 0)
    
    # 如果当天没有买入的股票,就返回
    if len(stock_to_buy) == 0:
        return

    # 等权重买入 
    weight =  1 / len(stock_to_buy)
    
    # 买入
    for stock in stock_to_buy:
        if data.can_trade(context.symbol(stock)):
            # 下单使得某只股票的持仓权重达到weight,因为weight大于0,因此是等权重买入
            context.order_target_percent(context.symbol(stock), weight)
# 回测引擎:准备数据,只执行一次
def m4_prepare_bigquant_run(context):
    pass
# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
def m4_before_trading_start_bigquant_run(context, data):
    pass


m7 = M.input_features.v1(
    features="""industry_sw_level1_0
myrank=rank_fs_roe_ttm_0+rank_fs_net_profit_qoq_0-rank_pb_lf_0"""
)

m5 = M.instruments.v2(
    start_date='2020-01-01',
    end_date='2021-11-26',
    market='CN_STOCK_A',
    instrument_list='',
    max_count=0
)

m6 = M.general_feature_extractor.v7(
    instruments=m5.data,
    features=m7.data,
    start_date='',
    end_date='',
    before_start_days=90
)

m8 = M.derived_feature_extractor.v3(
    input_data=m6.data,
    features=m7.data,
    date_col='date',
    instrument_col='instrument',
    drop_na=False,
    remove_extra_columns=False,
    user_functions={}
)

m9 = M.dropnan.v2(
    input_data=m8.data
)

m2 = M.cached.v3(
    input_1=m9.data,
    run=m2_run_bigquant_run,
    post_run=m2_post_run_bigquant_run,
    input_ports='',
    params='{}',
    output_ports='data_1'
)

m4 = M.trade.v4(
    instruments=m5.data,
    options_data=m2.data_1,
    start_date='',
    end_date='',
    initialize=m4_initialize_bigquant_run,
    handle_data=m4_handle_data_bigquant_run,
    prepare=m4_prepare_bigquant_run,
    before_trading_start=m4_before_trading_start_bigquant_run,
    volume_limit=0.025,
    order_price_field_buy='open',
    order_price_field_sell='close',
    capital_base=10000000,
    auto_cancel_non_tradable_orders=True,
    data_frequency='daily',
    price_type='真实价格',
    product_type='股票',
    plot_charts=True,
    backtest_only=False,
    benchmark=''
)