量化择时策略入门与实操-笔记(同花顺金融量化实验室python实现)

博客介绍了指数估值择时、指数轮动择时和基于风险平价模型的仓位管理三种策略。指数估值择时通过市盈率衡量指数估值,在低估时买入、高估时卖出;指数轮动择时基于动量效应,每月选涨幅最大指数交易;风险平价仓位管理策略追求资产风险权重平衡,每月调整持仓权重。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文字与代码来源:2022年第三届“大湾区杯”粤港澳金融数学建模竞赛在线讲座-6_哔哩哔哩_bilibili

目录

指数估值择时策略

指数轮动择时策略

基于风险平价模型的仓位管理策略

现代资产配置理论(MPT)

基于风险平价模型的仓位管理策略解读


指数估值择时策略

采用指数所有成分股的市盈率指标计算得出,用于衡量指数整体的估值水平,在牛市中,指数估值往往能达到80%及以上,而在熊市中指数估值可能低于20%及以下。投资者通过观察指数估值来判定当前市场估值状况,在低估时买入,高估时卖出,完成长周期指数择时。
• 关键词:估值水平,低估,高估


1. 计算方法

当前指数市盈率 = 当前所有指数成份股市盈率的中位数
近五年指数市盈率最大值 = 取近五年中指数市盈率的极大值
近五年指数市盈率最小值 = 取近五年中指数市盈率的极小值
指数估值 = (当前指数市盈率-近五年指数市盈率最小值)/(近五年指数市盈率最大值-近五年指数市盈率最小值)

2. 择时逻辑
看多:当指数估值(5年)从20%下方涨回20%上方时,市场从下跌阶段反转成上涨阶段,市场热度增加,做多指数
看空:当指数估值(5年)从80%上方跌回80%下方时,市场从上涨阶段反转成下跌阶段,市场回归理性,做空指数

3. 代码

import pandas as pd
import numpy as np
# 初始化函数,全局只运行一次
def init(context):
    # 设置要操作的指数
    context.security = '000300.SH'
    # 设置基准收益:沪深300指数
    set_benchmark(context.security)
    # 每周第一个交易日运行
    run_weekly(trade,1)
    # 估值的年限
    context.year = 5
    # 估值序列储存
    context.pelist = []
## 开盘时运行函数
def trade(context, bar_dict):
    # 获取时间
    date =  get_last_datetime().strftime('%Y-%m-%d')
    # 获取估值
    pe_rate = get_index_valuation(context,date,context.security)
    # 加入序列
    context.pelist.append(pe_rate)
    # 判定估值信号
    if len(context.pelist)>1 and context.pelist[-2]<20 and context.pelist[-1]>=20:
        # 全仓
        order_target_percent(context.security,1)
        # 打印
        print('买入指数{}:当前估值百分位{}'.format(context.security,pe_rate))
    elif len(context.pelist)>1 and context.pelist[-2]>80 and context.pelist[-1]<=80:
        # 空仓
        order_target(context.security,0)
        # 打印
        print('卖出指数{}:当前估值百分位{}'.format(context.security,pe_rate))
# 创建函数:获取指数估值水平
def get_index_valuation(context,date,index_code):
    '''
    输出:市盈率
    '''
    # 创建dataframe
    datadf = pd.DataFrame(columns = ['PE'])
    # 创建月初交易日列表
    monthdatelist = []
    # 获取日期
    datelist = get_trade_days(None,date,context.year*250).strftime('%Y%m%d')
    # 循环时间序列
    for t in range(1,len(datelist)):
        # 判断月度
        if datelist[t-1][4:6]!=datelist[t][4:6]:
            # 添加新月度日期
            monthdatelist.append(datelist[t])
    # 循环月度日期
    for date in monthdatelist[-context.year*12:]:
        # 调用指数估值指标计算函数
        datadf.loc[date] = get_index_PB_PE_PB1(date,index_code)
    # 最大值   
    values_max = datadf.max()
    # 最小值
    values_min = datadf.min()
    # 当前值
    values_now = datadf.ix[-1]
    # 百分位
    T = (values_now - values_min)/(values_max - values_min)
    # 输出
    return round(T.PE,4)*100
# 创建函数:指数估值指标计算
def get_index_PB_PE_PB1(date,indexcode):
    '''
    函数使用注释:
    输入:日期,指数代码
    算法:中位数
    输出:指数市盈率
    '''
    # 获取成份股
    stocks = get_index_stocks(indexcode,date)
    # 获取市盈率数据
    q = query(factor.symbol,
              factor.pe_ttm).filter(
              factor.symbol.in_(stocks),
              factor.date == date)
    # 获取数据
    df = get_factors(q)
    # 计算中位数
    PE_index = df.median().factor_pe_ttm
    return [PE_index]

指数轮动择时策略

1. 基本逻辑(动量效应)

强者越强:涨幅最大的指数,投资者参与热度高,不断吸引新的资金进入,推动指数持续上涨

弱者越弱:出现跌幅的指数,投资者愈发认为市场表现较弱并撤出资金,导致指数进一步下跌

2. 交易逻辑

每个月第一个交易日,计算所有指数ETF近20个交易日的涨幅,并排序得出涨幅最大的指数及涨幅值

做多:如果涨幅最大的指数ETF,涨幅值大于0,则做多指数,买入该ETF

做空:如果涨幅最大的指数ETF,其涨幅值小于等于0,则看空指数,保持空仓

风控:监控持仓ETF,每天计算近20个交易日的涨幅,如果涨幅值小于等于0,则卖出。

3. 代码

import pandas as pd
#初始化函数
def init(context):   
    # 按月交易第一个交易日
    run_monthly(trade,date_rule=1)
    # 输入需要交易的ETF
    context.security = ['159901.OF', # 深证100ETF
                        '510050.OF', # 上证50ETF
                        '159915.OF', # 创业板ETF
                        '510300.OF', # 沪深300ETF
                        '510500.OF', # 中证500ETF
                        '510180.OF', # 上证180ETF
                        '159902.OF', # 中小板100ETF
                        '159905.OF', # 深红利ETF
                        ]
    # 指数强度系数(天)
    context.N = 20
#交易函数
def trade(context,bar_dict):
    # 获取指数行情数据
    price = history(context.security,['close'],context.N,'1d',True,'pre',is_panel=1)
    # 获取收盘价
    df = price['close']
    # 计算强弱
    indexreturn = df.iloc[-1]/df.iloc[0]-1
    # 排序
    indexreturn = indexreturn.sort_values()
    print(indexreturn)
    # 选取最强指数及强弱值
    index_T = indexreturn.iloc[-1]
    index = list(indexreturn.index)[-1]
    # 获取当前持仓
    holdindex = list(context.portfolio.stock_account.positions.keys())
    for stock in holdindex:
        # 清仓
        order_target(stock, 0)
    if index_T>0:
        # 买入
        order_target_percent(index,1)
        # 打印
        print('最强指数{},强弱度{},买入'.format(index,round(index_T,4)))
#设置风控
def handle_bar(context,bar_dict):
    # 获取指数行情数据
    price = history(context.security,['close'],context.N,'1d',True,'pre',is_panel=1)
    # 获取收盘价
    df = price['close']
    # 计算强弱
    indexreturn = df.iloc[-1]/df.iloc[0]-1
    # 排序
    indexreturn = indexreturn.sort_values()
    # 选取最强指数及强弱值
    index_T = indexreturn.iloc[-1]
    index = list(indexreturn.index)[-1]
    # 获取当前持仓
    holdindex = list(context.portfolio.stock_account.positions.keys())
    # 择时判定
    if index_T<=0:
        for index in holdindex:
            # 清仓
            order_target(index, 0)
            # 打印
            print('最强指数强弱度{},清仓'.format(index_T))

基于风险平价模型的仓位管理策略

现代资产配置理论(MPT)

1. 均值-方差模型

现代资产配置理论(MPT)将资金合理分配在多种资产上,在控制风险的前提下最大化预期收益率。

1952年,马科维茨Markowitz提出“均值-方差”模型,用均值刻画资产预期收益率,用方差刻画资产潜在风险;分析各资产的均值-方差,找到有效前沿,所有在有效前沿上的点即为最优投资组合。投资者给定组合预期收益率,可以找到最低风险的组合;投资者给定组合的风险水平,可以找到收益最大的组合。

2. 风险平价模型

现实生活中,股票和期货市场的风险显著高于债券和货币市场,且资产未来的收益率很难预估,因此均值-方差模型的实际效果远达不到预期效果。

2005年,磐安资产管理公司的钱恩平博士首次提出著名的风险平价策略,不预测资产未来收益率,追求资产本身的风险权重平衡。风险平价策略让每项资产在组合中的风险贡献相等,实现资产风险分散化。

基于风险平价模型的仓位管理策略解读

1. 基本逻辑

当股票市场持续上涨时,股票资产的风险降低,需要提高股票资产仓位,降低国债仓位,以保证资产间风险相同。

当股票市场出现断崖式下跌时,股票资产的风险提升,需要降低股票资产仓位,增加国债仓位,以保证资产间风险相同。

2. 交易逻辑

每月第一个交易日,采用风险平价模型,以每项资产在组合中的风险贡献相等原则,重新计算所有指数ETF的持仓权重:

加仓:新持仓权重大于原持仓权重的ETF,加仓至新持仓权重仓位。

减仓:新持仓权重小于原持仓权重的ETF,减仓至新持仓权重仓位

3. 代码

import pandas as pd 
import numpy as np 
import scipy.optimize as sco
# 初始化函数,全局只运行一次
def init(context):
    # 设置基准收益
    set_benchmark('000001.SH')
    # 配置资产列表
    context.assetlist = ['513100.OF', # 纳斯达克ETF
                        '159919.OF', # 沪深300
                        '510180.OF', # 上证180ETF
                        '159905.OF', # 深红利ETF
                        '159915.OF', # 创业板ETF
                        '518880.OF', # 黄金ETF
                        '159928.OF', # 消费ETF
                        '512010.OF', # 医药ETF
                        '510230.OF', # 金融ETF
                        ]
    # 每月第一个交易日运行
    run_monthly(assetfun,date_rule=1)
## 开盘时运行函数
def assetfun(context, bar_dict):
    # 获取资产收益
    assetdata = history(context.assetlist,['close'],250,'1d',skip_paused=True,fq='pre',is_panel=True)['close']
    # 获取资产收益率
    ret_data = np.log(assetdata/assetdata.shift(1)).dropna()
    # 计算资产权重
    assetweight = portfolio_optimize(ret_data)
    # 输出资产权重
    print(assetweight)
    # 循环调整权重
    for s in context.assetlist:
        # 调制至目标仓位
        order_target_percent(s,assetweight[s])
# 风险评价主函数
def portfolio_optimize(ret_mat,cov_shrink=True,method='risk_parity'):
    #time horizon
    T=len(ret_mat)
    t=int(T/4)
    #expect return
    exp_ret=ret_mat.mean()*252
    #covariance
    if cov_shrink==False:
        cov_mat=ret_mat.cov()*252
    #shrink covariance to 4 time period
    if cov_shrink==True:
        cov_mat=252*(ret_mat.iloc[:t].cov()*(1/10)+ret_mat.iloc[t+1:2*t].cov()*(2/10)
                     +ret_mat.iloc[2*t+1:3*t].cov()*(3/10)+ret_mat.iloc[3*t:].cov()*(4/10))
    #set input data
    k=len(ret_mat.columns)
    weights=np.array(k*[1/k])
    #set function
    def risk_parity(weights):
        risk_vector=np.dot(weights,cov_mat)
        marginal_risk=weights*risk_vector/np.sqrt(np.dot(weights.T,np.dot(cov_mat,weights)))
        TRC=[np.sum((i-marginal_risk)**2) for i in marginal_risk]
        return np.sum(TRC)
    #set constraints
    bnds=tuple((0,1) for x in range(k))
    cons = ({'type':'eq', 'fun': lambda x: sum(x) - 1})
    
    if method=='risk_parity':
        result = sco.minimize(risk_parity,weights,bounds=bnds,constraints=cons,method='SLSQP')
    optimal_weights=pd.Series(index=cov_mat.index,data=result['x'])
    return optimal_weights

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值