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'] #获取债券仓位