利用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的操作,但是又有什麼意義呢?我們本就只是做個大致的參考而已嘛。

以上。


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