strategy.py-20190422

from rqalpha_plus import run_code
from rqalpha_plus import run_func
# from rqalpha_plus.api import *

#方法二、方法三种对于参数设置涉及的模块分为三个部分,分别为’base’、’extra’、’mod’。这三部分能够设置的所有的参数及备注为下
config = {
  "base": {
    "data_bundle_path": "/home/rice/.rqalpha-plus/bundle",# 回测所需 bundle 数据地址
    "start_date": "2012-01-01",
    "end_date": "2013-01-01",
    "frequency": '1d', # 回测频率, 1d, 1m, tick
    "benchmark": "CBA00201.INDX", # 设置基准合约 为中债财富指数
    "accounts": {
            "bond": 10000000, # 股票初始资金一千万
        }
  },
  "extra": {
    "log_level": "info",# 输出日志等级,有 verbose, info, warning, error 等选项,可以通过设置为 verbose 来查看最详细日志
  },
  "mod": {
      # 模拟撮合模块
    "sys_analyser": {
      "enabled": True,
      "plot": True,
    },
       "sys_simulation": {
            "enabled": True, 
            "priority": 100,
            "volume_limit": False, # 设置是否开启成交量限制
            "volume_percent": 0.5, # 成交量限制比例
            "slippage": 0.0,  # 滑点设置,0.1代表成交价恶化10%
        },
        "bond_backtest": {
            "enabled": True,  # 开启当前 mod
            "priority": 101,  # mod 加载优先级设置,注意,这里的优先级设置需要高于 sys_simulation
            "risk_free_rate": 0.02,  # 设置无风险利率
        },
  },
}
    
    
#code = """



from datetime import datetime
import pandas as pd
import numpy as np
from rqdatac import *
from statsmodels.tsa.arima_model import ARIMA
from numpy import linalg as la
import statsmodels.api as sm

# from rqalpha_plus.api import *
# import rqalpha_plus.api


#找上升和下降的bond的id
def get_level_twoside_order_book_id(open_position_date):

# 对日期数据处理,以月来分割
# open_position_datetime = datetime.strptime(open_position_date,'%Y%m%d')
    if open_position_date.month == 12:
        close_position_date= datetime(month=1, year=open_position_date.year, day=open_position_date.day)
    else:
        close_position_date= datetime(month=open_position_date.month+1, year=open_position_date.year, day=open_position_date.day)
    close_position_date=close_position_date.strftime('%Y%m%d')

    #按照日期找到国债的数据
    #获取债券分板块查询列表,获取close_position_date还在流通的,wind分类下为国债(A01)的债券列表
    bond_id_list=bond.sector('A01',close_position_date,'wind')[:500] 
    bond_instruments = bond.instruments(bond_id_list) #获取bond_id_list中债券的合约基础信息
    bond_df = pd.DataFrame()
    bond_df = pd.DataFrame(columns = ['id','listed_date','maturity_year','coupon_rate'])

    order_book_id_list=[] #债券流通场所代码(或指数代码)
    maturity_year_list=[] #债券期限(年)
    listed_date_list=[] #债券上市日期
    coupon_rate_list=[] #发行票面利率

    for i in bond_instruments: #把所有bond_id_list中债券的合约基础信息合并
        order_book_id_list.append(i.order_book_id) #债券流通场所代码(或指数代码),str OR str list
        maturity_year_list.append(i.maturity_year) #债券期限(年),float
        listed_date_list.append(i.listed_date) #债券上市日期,datetime
        coupon_rate_list.append(i.coupon_rate) #发行票面利率,float

    bond_df['id']=order_book_id_list
    bond_df['listed_date']=listed_date_list
    bond_df['maturity_year']=maturity_year_list
    bond_df['coupon_rate']=coupon_rate_list

    #10年期国债
    bond_10_df = bond_df[bond_df.maturity_year==10].sort_index(by='coupon_rate',ascending=False) 
    #2年期
    bond_2_df = bond_df[bond_df.maturity_year==2].sort_index(by='coupon_rate',ascending=False) 

    id_rate_rise = list(bond_2_df.iloc[-10:]['id'])#上升的id,选十个是为了之后一定能选出五个
    id_rate_down = list(bond_10_df.iloc[:10]['id'])#下降的id

    return id_rate_rise,id_rate_down


def tsfunction(data,begin_date,end_date):
    
    xtrain=np.array(data)
    #看哪些列包含nan
    np.where(np.isnan(xtrain))[1]
    #去除包含nan的列
    xtrain=np.delete(xtrain,np.where(np.isnan(xtrain))[1],1)

    #-------------PCA降维到3个主成分--------
    (n,p)=np.shape(xtrain)
    Xsta=(xtrain-np.tile(np.mean(xtrain,axis=0),(n,1)))/np.tile(np.std(xtrain,axis=0),(n,1));#标准化样本数据 X
    U,D,V=la.svd(Xsta)#SVD分解
    D=np.asmatrix(D).T
    #lam=np.multiply(D,D)/(n-1) #特征根
    W=V.T/np.tile(np.sum(abs(V.T),axis=0),(p,1)) #标准化的特征向量
    #f=lam/sum(lam)#方差贡献率=特征值/所有特征值总和 
    #检验是否可以主成分降维
    #F=np.cumsum(lam)/sum(lam)#累计方差贡献率=前i个特征值总和/所有特征值总和
    #Index=np.where(F[0,:]>0.95)#取累计方差贡献达到95%的q个主成分
    #q=np.array(Index)[1,0]+1 #主成分个数
    Xpc=np.dot(xtrain,W) #降维后的xpc矩阵=标准化后的特征向量*原x矩阵
    pc=Xpc[:,0:3]#主成分矩阵=降维后x矩阵的前3列

    #-------------时间序列-----------------
    df=pd.DataFrame(pc)
    df.columns=['level','slope','curvation']
    df.index = data.index
    #生成pd.Series对象
    ts_level=pd.Series(df['level'].values, index=df.index)  

    #------------level,arima(1,1,3)
    #一阶差分
    ts_level_d = ts_level.diff().dropna()
    ts_level_d.columns = ['diff']

    #建模计算拟合值

    #model = ARIMA(ts_level, order=(1,1,3)).fit(disp=-1)  #ARIMA(p,d,q)

    model = sm.tsa.statespace.SARIMAX(ts_level_d,order=(1,0,3),seasonal_order=(0,0,0,0),
            enforce_stationarity=False, enforce_invertibility=False).fit()
    #We can use SARIMAX model as ARIMAX when seasonal_order is (0,0,0,0) .
    #注意这里用的是ts_d算,因为SARIMAX包的fittedvalues直接给出原始拟合值而不是差分拟合值
    
    #差分拟合值
    diff=model.fittedvalues

    #只取diff中一年的数据
    diff_level=diff[(diff.index>=pd.to_datetime(begin_date))&(diff.index<pd.to_datetime(end_date))]
    
    #每日上升、下降数据
    diff_level_rise=diff_level[diff_level>0]
    diff_level_down=diff_level[diff_level<=0]
    
    #计算月平均
    month_mean=diff_level.resample('1M').mean()
    
    #计算月正值和负值的分别平均
    def custom_resampler1(array):
        rise=array[array>0]
        mean_rise=sum(rise)/len(rise)
        return mean_rise
    
    def custom_resampler2(array):
        down=array[array<=0]
        mean_down=sum(down)/len(down)
        return mean_down
    
    #每月上升、下降阈值
    mean_rise=diff_level.resample('1M').apply(custom_resampler1)#2年
    mean_down=diff_level.resample('1M').apply(custom_resampler2)#10年
    
    #月初数据
    month_begin=diff_level.resample('1MS',how='first')
    #月末数据
    month_end=diff_level.resample('1M',how='last')
    #diff_level.resample('1M').pad() #pad填充nan方法是返回最近的值
    #月初-月末的差值
    month_gap=np.array(month_end)-np.array(month_begin)

    pre_key=np.ones((12),dtype=int)
    for i in range(12):
        if month_gap[i]>mean_rise[i] and mean_rise[i]>0:
            pre_key[i]=1
        elif month_gap[i]<mean_down[i] and mean_rise[i]<0:
            pre_key[i]=-1

    return pre_key



#level_key是封装函数的预测结果,-1或0或1,-1代表上升,1代表下降,0代表不是用的level;
#此函数根据level_key把id_level_rise,id_level_down合并成id_level
def get_level_order_book_id(id_level_rise,id_level_down,level_key): 
    if level_key == 1:   #预测利率水平向上
        id_level = id_level_rise
    else:   #预测利率水平向下
        id_level = id_level_down
    return id_level

#输出买bond的id,对应研报的图16交易框架图
def get_to_buy_bond_ids(level_key,slope_key,curvation_key,open_position_date):
    #如果level_key不为0,则level占主导,采用
    if level_key != 0:
        #id_level_rise是level中上升债券的id,id_level_down是level中下降债券的id
        id_level_rise,id_level_down = get_level_twoside_order_book_id(open_position_date)
        id_level = get_level_order_book_id(id_level_rise,id_level_down,level_key)
        print('预测当前市场满足level交易指令')
        return id_level
    #如果level_key为0,则slope或curvation占主导,这里不采用,因为plato无法实现slope和curvation对应的策略
    elif level_key == 0:
        #缺slope和cutvation的函数,这里没写因为plato做不了slope和curvation的策略
        id_slope_rise,id_slope_down = get_slope_twoside_order_book_id(open_position_date)
        id_slope = get_slope_order_book_id(id_slope_rise,id_slope_down,slope_key)

        id_curvation_rise,id_curvation_down = get_curvation_twoside_order_book_id(open_position_date)
        id_curvation = get_curvation_order_book_id(id_curvation_rise,id_curvation_down,curvation_key)

        if  abs(slope_key) >= abs(curvation_key):
            print('预测当前市场满足slope交易指令')
            return id_slope
        else:
            print('预测当前市场满足curvation交易指令')
            return id_curvation


#输入context是主函数的全局变量,策略交易过程
def update_portfolio(context, bar_dict): 
    #当前时间,返回数据类型是datetime
    open_position_date=context.now #now - 当前时间

    #这里key的结果调用时序函数
    id_level_rise,id_level_down = get_level_twoside_order_book_id(open_position_date)
    data=get_yield_curve(start_date='20120104', end_date='20190226')
    pre_key = tsfunction(data,'20120101','20130101')  
    level_key=pre_key[context.count]# 作为level的标识符,1 :level向上,-1:level向下,0:level变化很小

    slope_key = 1    # 作为slope的标识符,1 :shope变陡,-1:slope变缓,0:为了保证一定会做下单操作不设0
    curvation_key = 1    # 作为curvation的标识符,1 :curvation变凹,-1:curvation变凸,0:为了保证一定会做下单操作不设0

    bond_ids = get_to_buy_bond_ids(level_key,slope_key,curvation_key,open_position_date)
    #print(bond_ids)

    #下单次数加一
    context.count=context.count+1

    #第一次下单的时候只有买入没有卖出
    if context.count == 1:
        #债券流通场所代码(或指数代码)
        for order_book_id in bond_ids:
            print(order_book_id)
            order_percent(order_book_id , 0.2) #order_percent:一定比例下单(股票专用)

    #第二次下单的时候既有买入又有卖出
    else: 
        current_holdings = [order_book_id for order_book_id, position in context.portfolio.positions.items()]
        #portfolio - 投资组合信息  #context.portfolio.positions.items()计算现在portfolio中股票的仓位
        print(context.portfolio.positions.items()) 
       # print(context.portfolio.positions.quantity)

       # if position.quantity != 0]

        print(current_holdings )

        #目前持有集合与这个月算出来需要持有的集合相减取交集
        to_sell = set(current_holdings) - set(bond_ids)
        print(to_sell)
        #卖出
        for order_book_id in to_sell:
            print(order_book_id)
            order_percent(order_book_id, 0)
        #买入
        for order_book_id in bond_ids:
            order_percent(order_book_id , 0.2)

    print('context.portfolio.positions')
    print(context.portfolio.positions)


#主函数
def init(context):
    #全局变量,纪录第几个月
    context.count = 0
    # 设定每月第一个交易日进行调仓,取-1就是最后一天
    scheduler.run_monthly(update_portfolio, tradingday=1)



"""


results = run_code(code, config)

# results = run_func(init=init, config=config, handle_bar=handle_bar)
# from rqdatac import *

# 通过 results['sys_analyser']['bond_positions'] 获取债券仓位
# 通过 results['sys_analyser']['portfolio'] 获取投资组合资金情况
# 通过 results['sys_analyser']['trades']获取历史调仓记录

# 通过 results['sys_analyser']['stock_positions'] 获取股票仓位
# 通过 results['sys_analyser']['bond_positions'] 获取债券仓位
# 通过 results['sys_analyser']['stock_account'] 获取股票账户信息
# 通过 results['sys_analyser']['bond_account'] 获取债券账户信息
# 通过 results['sys_analyser']['portfolio'] 获取总的投资组合资金情况
# 通过 results['sys_analyser']['trades'] 获取历史调仓记录
results['sys_analyser']['portfolio'] #总的投资组合资金情况
#results['sys_analyser']['trades']  #获取历史调仓记录
results['sys_analyser']['bond_positions'] #获取债券仓位

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值