量化多因子

# 克隆自聚宽文章:https://www.joinquant.com/post/1399
# 原标题:【量化课堂】多因子策略入门
# 原作者:JoinQuant量化课堂

#多因子策略入门新版
#作者:指指点点

'''
================================================================================
总体回测前
================================================================================
'''

#总体回测前要做的事情
def initialize(context):
    set_params()        #1设置策参数
    set_variables() #2设置中间变量
    set_backtest()   #3设置回测条件
    run_daily(handle_data_v2, "every_bar")


#1
#设置策参数
def set_params():
    g.tc=15  # 调仓频率
    g.yb=63  # 样本长度
    g.N=20   # 持仓数目
    g.factors=["market_cap","roe"] # 用户选出来的因子
    # 因子等权重里1表示因子值越小越好,-1表示因子值越大越好
    g.weights=[[1],[-1]]
    
    
#2
#设置中间变量
def set_variables():
    g.t=0              #记录回测运行的天数
    g.if_trade=False   #当天是否交易
    
    
#3
#设置回测条件
def set_backtest():
    set_option('use_real_price', True)#用真实价格交易
    log.set_level('order', 'error')





'''
================================================================================
每天开盘前
================================================================================
'''

#每天开盘前要做的事情
def before_trading_start(context):
    if g.t%g.tc==0:
        #每g.tc天,交易一次行
        g.if_trade=True 
        # 设置手续费与手续费
        set_slip_fee(context) 
        # 设置可行股票池:获得当前开盘的沪深300股票池并剔除当前或者计算样本期间停牌的股票
        g.all_stocks = set_feasible_stocks(get_index_stocks('000300.XSHG'),g.yb,context)
        # 查询所有财务因子
        # g.q = query(valuation,balance,cash_flow,income,indicator).filter(valuation.code.in_(g.all_stocks))
    g.t+=1
    
#4
# 设置可行股票池
# 过滤掉当日停牌的股票,且筛选出前days天未停牌股票
# 输入:stock_list为list类型,样本天数days为int类型,context(见API)
# 输出:list
def set_feasible_stocks(stock_list,days,context):
    # 得到前days天的所有股票,停牌开盘价是np.NAN
    df =get_price(stock_list, count=days,end_date=context.current_dt,frequency='1d', fields=['open'],fill_paused=False,panel=False) 
    # 前days天有开盘价是np.NAN的股票代码
    stopcode = df[df.open.isna()].code.drop_duplicates()
    # 过滤停牌股票得到前days天未停牌股票的代码list:
    feasible_stocks = df[~df.code.isin(stopcode)].code.unique().tolist()
    return feasible_stocks
    
#5
# 根据不同的时间段设置滑点与手续费
def set_slip_fee(context):
    # 将滑点设置为0
    set_slippage(FixedSlippage(0)) 
    # 根据不同的时间段设置手续费
    dt=context.current_dt
    log.info(type(context.current_dt))
    
    if dt>datetime.datetime(2013,1, 1):
        set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5)) 
        
    elif dt>datetime.datetime(2011,1, 1):
        set_commission(PerTrade(buy_cost=0.001, sell_cost=0.002, min_cost=5))
            
    elif dt>datetime.datetime(2009,1, 1):
        set_commission(PerTrade(buy_cost=0.002, sell_cost=0.003, min_cost=5))
                
    else:
        set_commission(PerTrade(buy_cost=0.003, sell_cost=0.004, min_cost=5))




'''
================================================================================
每天交易时
================================================================================
'''

def handle_data_v2(context):
    if g.if_trade==True:
    # 计算现在的总资产,以分配资金,这里是等额权重分配
        g.everyStock=context.portfolio.total_value/g.N
        # 获得今天日期的字符串
        todayStr=str(context.current_dt.date())
        # 新代码,对应老代码,逻辑一致
        toBuy = get_toBuy(todayStr)
        # 对于不需要持仓的股票,全仓卖出
        order_stock_sell(context,toBuy)
        # 对于不需要持仓的股票,按分配到的份额买入
        order_stock_buy(context,toBuy)
    g.if_trade=False    

##21
# 取股票新代码
def get_toBuy(todayStr):
    # 获得因子排序
    df = get_fundamentals(query(valuation,indicator).filter(valuation.code.in_(g.all_stocks)),todayStr)
    df =  df.set_index("code")[g.factors]
    df.loc[df[df.market_cap.isna()].index,"market_cap"] = df.market_cap.mean()
    df.loc[df[df.roe.isna()].index,"roe"] = df.roe.mean()
    rankdf = df.rank(method='min',ascending=False)
    # 计算每个股票的得分
    rankdf['point'] = np.dot(rankdf.to_records(index=False).tolist(),[[1],[-1]])
    # 对股票的得分进行排名,取前N名的股票
    toBuy = rankdf.sort_values("point",ascending=False).head(g.N).index.tolist()
    return toBuy


#6
#获得卖出信号,并执行卖出操作
#输入:context, data,toBuy-list
#输出:none
def order_stock_sell(context,toBuy):
    #如果现有持仓股票不在股票池,清空
    list_position=context.portfolio.positions.keys()
    for stock in list_position:
        if stock not in toBuy:
            order_target(stock, 0)

#7
#获得买入信号,并执行买入操作
#输入:context, data,toBuy-list
#输出:none
def order_stock_buy(context,toBuy):
    # 对于不需要持仓的股票,按分配到的份额买入
    for s in g.all_stocks:
        if s in toBuy:
            order_target_value(s, g.everyStock)

'''
================================================================================
每天收盘后
================================================================================
'''
# 每日收盘后要做的事情(本策略中不需要)
def after_trading_end(context):
    return

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值