时变反转因子择时策略

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

(Rossyfu) #1
克隆策略
In [ ]:
import pandas as pd
import numpy as np
import datetime 
import statsmodels.api as sm
import scipy.stats as st
In [ ]:
# 时变权重反转择时
# 初始数据准备
# 多空组合回测
def get_stock(index, date):
    df = D.history_data(D.instruments(date, date),date,date,fields=[index,'market_cap'])
    sse300 = df[df[index]==1].sort_values('market_cap', ascending=False)
    target_sse = sse300['instrument']
    stocklist=target_sse.tolist()
    return stocklist
def gen_rank(dataframe, stocklist):
    target_df = pd.DataFrame()
    df = dataframe.copy()
    df = df.drop_duplicates('instrument' ,keep='last')
    df.date = df.date.apply(lambda x:x.strftime('%Y-%m'))
    for stock in stocklist:
        a = df[df['instrument'] == stock]
        a = a.drop_duplicates('date',keep='last')
        target_df = target_df.append(a)
    target_df.return_30 = target_df.return_30.apply(lambda x:-x)
    a = target_df.drop(['instrument', 'date'], axis=1)
    b = target_df['instrument']
    a = a.rank(ascending=False)
    df = pd.concat([a, b], axis=1)
    return df
def get_target_stock(context, data):
    target_dict = dict()
    context.stocklist = get_stock('in_csi300', context.today)
    df = D.features(context.stocklist, start_date=context.yestoday, end_date=context.today, fields='return_30', groupped_by_instrument=False, frequency='daily')
    target = gen_rank(df, context.stocklist)
    target = target.set_index('instrument')
    target = target.sort_values(by = 'return_30', ascending=False)
    a = target.head(10)
    b = target.tail(10)
    c = a.append(b)
    context.target_stock = c
    context.buy = a
    context.sell = b
def initialize(context):
    context.today = None
    context.yestoday = None
    context.stocklist = None
    context.i = 1
    context.target_stock = None
    context.buy = None
    context.sell = None
def before_trading_start(context,data):
    today = pd.to_datetime(data.current_dt.strftime('%Y-%m-%d'))
    yestoday = today - datetime.timedelta(120)
    context.yestoday = yestoday
    context.today = today
    context.i = context.i + 1
    if context.i == 2:
        get_target_stock(context, data)
    elif context.i%30 == 0:
        get_target_stock(context, data)
def handle_data(context,data):
    stock_hold_now = {e.symbol: p.amount * p.last_sale_price
                  for e, p in context.perf_tracker.position_tracker.positions.items()} 
    for equity in stock_hold_now:
        if equity not in context.target_stock.index.tolist():
            order_target_percent(context.symbol(equity), 0)
    for equity in context.sell.index.tolist():
        order_target_value(context.symbol(equity), -100000)
    for equity in context.buy.index.tolist():
        order_target_value(context.symbol(equity), 100000)
m9 = M.instruments.v2(
    start_date=T.live_run_param('trading_date', '20151231'),
    end_date=T.live_run_param('trading_date', '20171231'),
    market='CN_STOCK_A',
    instrument_list='',
    max_count=0
)
m_midium = M.trade.v4(
    instruments=m9.data,
    start_date='20151231',
    end_date='20171231',
    initialize=initialize,
    before_trading_start=before_trading_start,
    handle_data=handle_data,
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=50000000,
    volume_limit=1,
    product_type='stock')
In [ ]:
# 时变因子择时正式开始
# 回测计算系数部分
def get_params(context,data):
    def gen_target_rank(dataframe, stocklist):
        target_df = pd.DataFrame()
        df = dataframe.copy()
        df = df.drop_duplicates('instrument' ,keep='last')
        df.date = df.date.apply(lambda x:x.strftime('%Y-%m'))
        for stock in stocklist:
            a = df[df['instrument'] == stock]
            a = a.drop_duplicates('date',keep='last')
            target_df = target_df.append(a)
        target_df.return_30 = target_df.return_30.apply(lambda x:-x)
        a = target_df.drop(['instrument', 'date'], axis=1)
        b = target_df['instrument']
        a = a.rank(ascending=False)
        df = pd.concat([a, b], axis=1)
        return df
    def get_target_stock(context, data):
        target_dict = dict()
        context.yestoday = D.trading_days(market='CN',start_date=context.yestoday, end_date=context.today).iloc[0]['date'].strftime('%Y%m%d')
        context.stocklist = get_stock('in_csi300', context.today.strftime('%Y%m%d'))
        df = D.features(context.stocklist, start_date=context.yestoday, end_date=context.today, fields=['return_30'], groupped_by_instrument=False, frequency='daily')
        target = gen_target_rank(df, context.stocklist)
        target = target.set_index('instrument')
        target = target.sort_values(by = 'return_30', ascending=False)
        a = target.head(10)
        b = target.tail(10)
        c = a.append(b)
        context.target_stock_list = c
        context.buy = a
        context.sell = b
    def initialize(context):
        context.stocklist = None
        context.j = 1
        context.target_stock_list = None
        context.buy = None
        context.sell = None
    def before_trading_start(context,data):
        today = pd.to_datetime(data.current_dt.strftime('%Y-%m-%d'))
        yestoday = today - datetime.timedelta(120)
        context.yestoday = yestoday
        context.today = today
        context.j = context.j + 1
        if context.j == 2:
            get_target_stock(context, data)
        elif context.j%30 == 0:
            get_target_stock(context, data)
    def handle_data(context,data):
        stock_hold_now = {e.symbol: p.amount * p.last_sale_price
                      for e, p in context.perf_tracker.position_tracker.positions.items()} 
        for equity in stock_hold_now:
            if equity not in context.target_stock_list.index.tolist():
                order_target_percent(context.symbol(equity), 0)
        for equity in context.sell.index.tolist():
            order_target_value(context.symbol(equity), -100000)
        for equity in context.buy.index.tolist():
            order_target_value(context.symbol(equity), 100000)
    m9 = M.instruments.v2(
        start_date=T.live_run_param('trading_date', '20180101'),
        end_date=T.live_run_param('trading_date', '20190415'),
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    last_two_year = context.today - datetime.timedelta(730)
    m_medium = M.trade.v4(
        instruments=m9.data,
        start_date=last_two_year.strftime('%Y%m%d'),
        end_date=context.today.strftime('%Y%m%d'),
        initialize=initialize,
        before_trading_start=before_trading_start,
        handle_data=handle_data,
        # 买入订单以开盘价成交
        order_price_field_buy='open',
        # 卖出订单以开盘价成交
        order_price_field_sell='open',
        capital_base=50000000,
        volume_limit=1,
        product_type='stock',
        plot_charts=False
    )
    a = m_medium.raw_perf.read_df().algorithm_period_return.reset_index()
    b = m_medium.raw_perf.read_df().benchmark_period_return.reset_index()
    a['index'] = a['index'].apply(lambda x:pd.to_datetime(x).strftime('%Y-%m'))
    a = a.set_index('algorithm_period_return')
    a = a.drop_duplicates(keep='last')
    a =a.reset_index()
    a = a.set_index('index')
    b['index'] = b['index'].apply(lambda x:pd.to_datetime(x).strftime('%Y-%m'))
    b = b.set_index('benchmark_period_return')
    b = b.drop_duplicates(keep='last')
    b = b.reset_index()
    b = b.set_index('index')
    a = (a - a.shift(1))*50
    b = b - b.shift(1)
    c = pd.concat([a, b], axis=1)
    target_df = pd.DataFrame()
    last_two_year = D.trading_days(market='CN',start_date=last_two_year, end_date=context.today).iloc[0]['date'].strftime('%Y%m%d')
    context.stocklist = get_stock('in_csi300', context.today.strftime('%Y%m%d'))
    df = D.features(context.stocklist, start_date=last_two_year, end_date=context.today.strftime('%Y%m%d'), fields=['amount_30', 'return_30', 'market_cap_0', 'volatility_30_0'], groupped_by_instrument=False, frequency='daily')
    for stock in context.stocklist:
        a = df[df['instrument'] == stock]
        a.date = a.date.apply(lambda x:x.strftime('%Y-%m'))
        a = a.drop_duplicates('date',keep='last')
        target_df = target_df.append(a)
    medium = target_df.groupby('date')
    mkt = pd.DataFrame()
    for name, group in medium:
        group.market_cap_0 = group.market_cap_0/group.market_cap_0.sum()
        group.mkt_illiq = group.market_cap_0*abs(group.return_30)/group.amount_30
        group.mkt_volatility = group.market_cap_0*group.volatility_30_0
        mkt_illiq = group.mkt_illiq.sum()
        mkt_volatility = group.mkt_volatility.sum()
        target = {'mkt_illiq':mkt_illiq, 'mkt_volatility':mkt_volatility}
        target = pd.DataFrame(target, index=[name])
        mkt = mkt.append(target)
    terminal = pd.concat([c, mkt], axis=1).dropna()
    z = terminal.iloc[-1, :] 
    a = sm.OLS(terminal.iloc[:,0].astype(float),sm.add_constant(terminal.iloc[:,1:].astype(float))).fit()
    return z.benchmark_period_return, z.mkt_illiq, z.mkt_volatility, a.params.const, a.params.benchmark_period_return, a.params.mkt_illiq, a.params.mkt_volatility
In [ ]:
# 正式开始回测部分
def initialize(context):
    context.today = None
    context.yestoday = None
    context.stocklist = None
    context.i = 1
    context.target_stock = None
    context.benchmark_period_return = None
    context.mkt_illiq = None
    context.mkt_volatility = None
    context.const_param = None
    context.benchmark_period_return_param = None
    context.mkt_illiq_param = None
    context.mkt_volatility_param = None
def filter_stock(context, data):
    target_dict = dict()
    context.stocklist = get_stock('in_csi300', context.today)
    context.yestoday = D.trading_days(market='CN',start_date=context.yestoday, end_date=context.today).iloc[0]['date'].strftime('%Y%m%d')
    df = D.features(context.stocklist, start_date=context.yestoday, end_date=context.today, fields=['pe_ttm_0', 'fs_roe_0', 'fs_net_profit_yoy_0', 'return_30', 'volatility_30_0', 'beta_csi300_30_0'], groupped_by_instrument=False, frequency='daily')
    perdict_return = (context.const_param + context.benchmark_period_return*context.benchmark_period_return_param + 
    context.mkt_illiq*context.mkt_illiq_param + context.mkt_volatility*context.mkt_volatility_param)
    q = st.norm.cdf(perdict_return)
    target = gen_rank(df, context.stocklist)
    for stock in context.stocklist:
        target_stock_info = target[target['instrument'] == stock]
        try:
            score = (target_stock_info.fs_net_profit_yoy_0.values[0]/6 + target_stock_info.pe_ttm_0.values[0]/6 +  
            target_stock_info.fs_roe_0.values[0]/6 + 2*q*target_stock_info.return_30.values[0]/6 + 
            target_stock_info.volatility_30_0.values[0]/6 + target_stock_info.beta_csi300_30_0.values[0]/6)
            target_dict[stock] = score
        except:
            continue
    target_dict = pd.Series(target_dict)
    target_dict = target_dict.sort_values(ascending=False)
    target_dict = target_dict.head(10)
    context.target_stock = target_dict
def before_trading_start(context,data):
    today = pd.to_datetime(data.current_dt.strftime('%Y-%m-%d'))
    yestoday = today - datetime.timedelta(120)
    context.yestoday = yestoday
    context.today = today
    context.i = context.i + 1
    if context.i == 2:
        context.benchmark_period_return, context.mkt_illiq, context.mkt_volatility, context.const_param, context.benchmark_period_return_param, context.mkt_illiq_param, context.mkt_volatility_param = get_params(context, data)
        filter_stock(context, data)
    elif context.i%30 == 0:
        context.benchmark_period_return, context.mkt_illiq, context.mkt_volatility, context.const_param, context.benchmark_period_return_param, context.mkt_illiq_param, context.mkt_volatility_param = get_params(context, data)
        filter_stock(context, data)
def handle_data(context,data):
    if len(context.portfolio.positions) > 0:
        stock_hold_now = {e.symbol: p.amount * p.last_sale_price
                      for e, p in context.perf_tracker.position_tracker.positions.items()} 
        for equity in stock_hold_now:
            if equity not in context.target_stock.index.tolist():
                order_target_percent(context.symbol(equity), 0)
    for equity in context.target_stock.index.tolist():
        order_target_percent(context.symbol(equity), 0.1)
m9 = M.instruments.v2(
    start_date=T.live_run_param('trading_date', '2018-01-01'),
    end_date=T.live_run_param('trading_date', '2019-04-15'),
    market='CN_STOCK_A',
    instrument_list='',
    max_count=0
)

# 启动回测
m = M.trade.v4(
    instruments=m9.data,
    start_date='20180101',
    end_date='20190415',
    initialize=initialize,
    before_trading_start=before_trading_start,
    handle_data=handle_data,
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=10000000,
    volume_limit=1,
    product_type='stock')
In [ ]:
 

(focus666) #2

您好 请问这个有研报么? 只看代码看不太懂


(supertrim258) #3

这篇帖子,现在报错了。
—> 28 df = D.features(context.stocklist, start_date=context.yestoday, end_date=context.today, fields=‘return_30’, groupped_by_instrument=False, frequency=‘daily’)
29 target = gen_rank(df, context.stocklist)
30 target = target.set_index(‘instrument’)

TypeError: features() got an unexpected keyword argument ‘frequency’
平台更新以后,这篇帖子可更新么?大神们……