利用tushare数据计算期货主力合约的活跃度

利用tushare数据计算期货主力合约的活跃度


用了这么久的CSDN,这是第一篇自己写的东西,权且当作自己的记录,当然也希望能够帮助到有需要的人吧。

期货活跃度

量化从业人员应该对活跃度比较关注,因为一个品种的活跃度越高,说明其中的机会就更多,对于高频交易来说就更容易赚到。关于证券与期货合约的活跃度,似乎还没有一些比较普适的量化指标,笔者也是自己根据直觉经验瞎凑几个量来刻画。首先是交易量,交易量越大,说明市场参与者多,而且流动性好,这样高频交易者的风险相对就会小一点,因为不会持仓很久无法平仓。另一个比较相关的指标是交易量与持仓量的比值,这个指标也可以称为投机度。对于比较活跃的主力合约,每日的交易量可能是持仓量的好几倍。当然这里面有很多都是高频交易商提供的。其次是价格的日内波动,如果一个合约的价格几乎没什么波动,那么这个合约对于高频交易来说也没什么吸引力,因为机会太少,资金成本比较高。与日内波动率比较相关的指标是其回报率的标准差,这也可以表征整个品种的活跃度。显然活跃度应该最好是一个无量纲的量,便于我们对同一品种的时序比较,同时也可以做横截面比较。总结起来就是下面的四个指标:

factor expression weight
x1 vol_ma5/vol_ma20 1.0
x2 std(ret, 20) 100.0
x3 vol / position 1.0
x4 (high-low)/settle 100.0

其实这四个指标的组合方式应该是挺多的,我比较希望的是形如
x 1 ∗ x 2 + x 3 ∗ x 4 x_1*x_2 + x_3*x_4 x1x2+x3x4的方式,但是效果还不是很理想。所以就简单的采用的线性加权的组合,权重系数的选取也是使得各因子值大致在一个量级,从而可以让它们的贡献比较均等。从最后的结果看,还是比较符合预期的。

期货数据的获取

下面就进入正题,我们怎么把这个比较朴素的想法变成一个实实在在的结果,首先得有数据吧。那我们就从获取数据开始。一开始我尝试了使用新浪财经给出的期货数据api接口,甚至他们还提供了分钟线的数据,不过我发现这数据质量实在堪忧,也就放弃了。然后发现我很久之前注册的tushare上竟然也提供相应的期货数据,数据的质量和数量都还挺不错,比如给出了持仓量等数据。下面的这段代码主要是简单介绍tushare的期货数据接口,熟悉的人可略过。

import tushare as ts
ts.set_token('***********')
pro = ts.pro_api()
df = pro.fut_basic(exchange='DCE', fut_type='2', fields='ts_code,symbol,name,list_date,delist_date')

这样就可以得到大商所上市的主力合约(和主力连续)列表了。同样可以得到上期所、郑商所和中金所的,不一一赘述。
对于具体的品种日线信息可以通过如下方式读取,

import datetime as dt
endDate = dt.datetime.today()
startDate = endDate - dt.timedelta(days=100)
df = pro.fut_daily(ts_code='CUL.SHF', start_date=str(startDate).replace('-',''), \
	end_date=str(endDate).replace('-',''))
df.tail()

基本数据结构如下图,
CUL.SHF的基本日内数据

不得不说,其实tushare这个数据也挺反人类的,获取不同信息时,交易所的代号竟然不一样。
经过一些简单的数据处理工作之后,我们可以利用mplfinance这个金融画图工具进行一个简单的可视化。

if 'ts_code' in list(df.columns):
    df.drop(columns='ts_code', inplace=True)
if 'oi_chg' in list(df.columns):
    df.drop(columns='oi_chg', inplace=True)   
df['Date'] = pd.to_datetime(df['trade_date'], format="%Y-%m-%d")
if 'trade_date' in list(df.columns):
    df.drop(columns='trade_date', inplace=True)

data = df.set_index(keys='Date',drop=True)[::-1]
data.rename(columns={
   
    'vol':'volume'}, inplace=True)
mpf.plot(data[startDate:endDate],figsize=(15,6), type='candle',style='charles', volume=True)

结果如下图所示(注意这里面没有设置颜色,红绿的涨跌对应跟我们大陆是反的),
CUL_SHF_KLine
计算四个信号的代码其实很简单,用pandas能够傻瓜式操作,

import matplotlib.pyplot as plt
import seaborn as sns
data['x1'] = data['volume'].rolling(5).mean() / data['volume'].rolling(20).mean()
data['x2'] = 100*(data['high'] - data['low'])/data['settle']
data['x3'] = data['volume']/data['oi']
data['ret']  = np.log(data['close']/data['pre_close'])
data['x4'] = 100*data['ret'].rolling(20).std()

sns.set_context('paper')
sns.set_style('whitegrid')
fig, ax=plt.subplots(figsize=(9,6))
data['x1'].plot(ax=ax)
data['x2'].plot(ax=ax)
data['x3'].plot(ax=ax)
data['x4'].plot(ax=ax)
ax.legend(loc=0)

结果如下:
CUL.SHF的信号值
最后我们对各信号进行直接加总并求其10日均值作为当前的活跃度,这样得到的活跃度形式如下:

data['vitality'] = (data['x1']+data['x4'] + data['x2'] + data['x3']).rolling(5).mean()
data['vitality'].plot(title='vitality of CUL.SHF')

CUL.SHF vitality
大家可以尝试比较下不同品种的活跃度曲线有何区别。我在这里就简单的对上期所交易的品种做了一个横截面的比较,比较的时间是2021.01.29,结果如下:

AG0 vitality is:10.57
SN0 vitality is:10.19
SP0 vitality is:8.80
NI0 vitality is:7.87
FU0 vitality is:7.46
PB0 vitality is:7.31
RU0 vitality is:7.02
HC0 vitality is:6.50
BU0 vitality is:6.30
ZN0 vitality is:6.23
RB0 vitality is:6.17
CU0 vitality is:4.84
AL0 vitality is:4.54
AU0 vitality is:4.34
WR0 vitality is:3.32

我个人经验看还是很准确的。白银的活跃度最近被各种刺激炒起来了,美国放水,散户们的投机热情,各种机构的暗中搅合都对白银的热度有着推波助澜的作用。像SP0和SN0这两个品种,最近的越来越活跃,而前阵子大热的黑色系像RB0最近就有点哑火了。所以我个人对这个结果还是比较满意的,毕竟是一个非常简单的组合了,也可以做一些比较fancy的操作,但是又有什么意义呢?我们本就只是做个大致的参考而已嘛。

以上。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章