商品期貨跨品種套利策略

1、內容概括

目前國內商品期貨套利模式主要包括產業(yè)鏈套利、跨期套利、內外盤套利和期現套利。下面的內容將講述商品期貨產業(yè)鏈套利模型,參考于東方證券《衍生品系列研究之五-商品期貨套利策略實證》,根據其產業(yè)鏈價值構造邏輯,撰寫策略,并進行實測。這篇研報的理論基礎是產業(yè)鏈價值穩(wěn)定,且利潤回復性強,可以進行反向操作期貨合約,獲取產業(yè)鏈利潤均值回復的交易性機會。

2、鋼廠利潤產業(yè)鏈關系

目前國內商品期貨套利模式主要包括產業(yè)鏈套利、跨期套利、內外盤套利和期現套利。這里我們針對黑色產業(yè)鏈期貨品種進行研究,利用產業(yè)鏈關系進行鋼廠利潤套利,涉及螺紋鋼、鐵礦、焦炭品種。煉鋼工藝中影響總成本的主要因素是原料成本,即鐵礦石、焦炭成本。根據研報內容,我們獲知制造鋼材時鐵礦石與焦炭的消耗可以通過如下方式進行計算:

螺紋鋼期貨價格 = 1.6×鐵礦石期貨價格 + 0.5×焦炭期貨價格 + 其他成本

上述等式是無套利的情形,而市場上的期貨價格是波動的,上述等式在實際的市場中是不等的。如果從價差的變動來看,上述等式左右兩邊的價差可以理解為鋼廠煉鋼的利潤,那么價差的波動就是鋼廠利潤的波動,因此追隨鋼廠利潤波動的模式就是鋼廠利潤套利的模式,在實際操作中,我們用指數合約代替實際價格

鋼廠利潤=1×螺紋鋼指數合約價格-1.6×鐵礦石指數合約價格-0.5×焦炭指數合約價格-其他成本

關于鋼廠煉鋼利潤波動的邏輯,參考研報內容:如果煉鋼利潤過高,鐵礦和焦炭價格會跟漲,擠壓煉鋼利潤;煉鋼利潤過低,鋼材價格回升。我們可以看到鋼廠利潤波動的邏輯性較強,基于此,當鋼廠利潤達到高位時,可以做空利潤,即做空螺紋鋼做多鐵礦石焦炭,當鋼廠利潤處于底位時,可以做多利潤,即做多螺紋鋼做空鐵礦石焦炭。

3、策略模型構建

一般的套利做法是設置固定的價差值進行套利,在價格偏離價差平均水平時進行多空操作,下面是通過期貨指數繪制的鋼廠利潤曲線

從上面的圖中我們發(fā)現價格并沒有一個穩(wěn)定的回復價格,即價差的分布并不對稱,這樣的序列顯然不適合用傳統(tǒng)的回復套利方法,在本報告中我們采用類似布林通道的策略思路,比如當價差超越長期或者短期均值一定標準差之時,可以認為此時的價差水平偏高,因此我們做空價格相對高的期貨,做多價格相對低的期貨,而當二者的價差回歸到一個長期或短期均值的時候同時對二者進行平倉。這樣策略獲得價差回復的收益。

我們對鋼廠利潤波動設計策略進行套利,考慮到不同的期貨品種上市時間不一樣,加上初始統(tǒng)計需要一定的初始數據長度,三個品種中,鐵礦石期貨是最晚,于 2013 年 10 月 18 日上市交易,考慮到計算均值需要一定的數據,我們統(tǒng)一將策略設置為2014 年 1 月 1 日開始回測。

價差序列下穿上軌,利潤沖高回落進行回復,策略空螺紋鋼、多焦煤焦炭;價差序列上穿下軌,利潤過低回復上升,策略多螺紋鋼、空焦煤焦炭。

研報中模型具體設置為

開倉條件:價差在10日均值加1倍標準差和1.2倍標準差之間,有回歸趨勢開倉。

平倉條件:回歸到10日均值進行平倉。

止損:設置的止損為5%,止損后10天內不開倉。

在該示例中,在回測過程中我們設置不同的開倉標準以及止損等條件,發(fā)現以下設置更為合適

開倉條件:價差在15日均值加1.8倍標準差之間,有回歸趨勢開倉。

止損:設置的止損位3%,止損后10天內不開倉

手續(xù)費:萬分之1雙邊


策略代碼

# 導入函數庫
from jqdata import *
import numpy as np

## 初始化函數,設定基準等等
def initialize(context):
    # 設定銀華日利作為基準
    set_benchmark('511880.XSHG')
    #設置日志輸出級別
    log.set_level('order', 'error')
    set_parameter(context)
    ### 期貨相關設定 ###
    # 設定賬戶為金融賬戶
    set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='futures')])

    # 期貨類每筆交易時的手續(xù)費是:買入時萬分之1,賣出時萬分之1,平今倉為萬分之1
    set_order_cost(OrderCost(open_commission=0.0001, close_commission=0.0001,close_today_commission=0.0001), type='index_futures')
    
    #獲取可操作資金
    g.init_cash = context.portfolio.starting_cash
    
    #主力合約記錄
    g.main_rb = get_dominant_future('RB', date=context.current_dt)
    g.main_i = get_dominant_future('I', date=context.current_dt)
    g.main_j = get_dominant_future('J', date=context.current_dt)
    
    # 設定保證金比例
    set_option('futures_margin_rate', 0.10)

    # 設置滑點(單邊萬5,雙邊千1)
    set_slippage(PriceRelatedSlippage(0.00),type='future')

    # 開盤時運行
    run_daily( market_open, time='open', reference_security='RB8888.XSGE')
    # 收盤后運行
    run_daily( after_market_close, time='after_close', reference_security='RB8888.XSGE')

# 參數設置函數
def set_parameter(context):
    
    #利潤回歸模型
    g.ma = 15 
    g.up_std = 1.8
    g.down_std=1.8
    g.state = 0
    
    #利潤系數
    #參考研報內容 鋼廠利潤公式 鋼廠利潤= 1*螺紋鋼期貨價格- 1.6*鐵礦石期貨價格+0.5*焦炭期貨價格+其他成本
    g.x=1
    g.y=1.6
    g.z=0.5
    
    #風控部分
    g.risk_days = 10 
    g.tot_values  = [context.portfolio.starting_cash]*g.risk_days
    g.maxdown = 0.03 #最大回撤設置
    
## 開盤時運行函數
def market_open(context):
    
    #風控部分
    #觸發(fā)風控規(guī)則10天內保持空倉
    if g.risk_days < 10:
        #清空持倉
        hold_future_s = context.portfolio.short_positions.keys() 
        hold_future_l = context.portfolio.long_positions.keys()
        #對合約標的全部清空
        if len(hold_future_s)>0:
            print '觸發(fā)風控平空倉'
            for future_s in hold_future_s:
                order_target_value(future_s,0,side='short')
        if len(hold_future_l)>0:
            print '觸發(fā)風控平多倉'
            for future_l in hold_future_l:
                order_target_value(future_l,0,side='long')   
    else:
        #運行風控函數
        risk = rolling_risk(context)  #滾動計算策略回撤
        if risk:
            pass  
        #未觸發(fā)風控邏輯執(zhí)行交易邏輯
        else:
            trade(context)
    g.risk_days += 1 #風控天數累加

#交易主體部分
def trade(context):
    #獲取幾個標的的指數價格序列
    price_df = history(50,security_list=['RB8888.XSGE','I8888.XDCE','J8888.XDCE','JM8888.XDCE','RB9999.XSGE','I9999.XDCE','J9999.XDCE','JM9999.XDCE'])
    #獲取鋼廠利潤
    se = g.x*price_df['RB8888.XSGE'] - g.y*price_df['I8888.XDCE'] - g.z*price_df['J8888.XDCE']
    #資金比例
    #由三者的系數推出資金權重比例
    a,b,c = g.y*g.z,g.x*g.z,g.y*g.z
    #初始資金的十分之一
    cash = g.init_cash*0.1
    
    #資金分配
    cash_i = (b/(a+b+c))*cash
    cash_j = (c/(a+b+c))*cash
    cash_rb = (a/(a+b+c))*cash
    

    #獲取交易信號
    trade_signal = get_signal(se.values)

    #根據交易信號進行交易
    #獲取標的的主力合約
    main_rb = get_dominant_future('RB', date=context.current_dt)
    main_i = get_dominant_future('I', date=context.current_dt)
    main_j = get_dominant_future('J', date=context.current_dt)
    
    #獲取當前持倉的合約
    hold_future_s = context.portfolio.short_positions.keys()
    hold_future_l = context.portfolio.long_positions.keys()
                
    #交易部分
    if trade_signal > 1: #下穿上軌
        print '觸發(fā)交易信號:空螺紋鋼、多鐵礦石、焦煤'
        #對非主力合約的空倉標的全部清空
        if len(hold_future_s)>0:
            for future_s in hold_future_s:
                if future_s != main_rb:
                    order_target_value(future_s,0,side='short')
        #做空螺紋鋼主力
        order_target_value(main_rb,cash_rb, side='short')
        
        #對非主力合約的多倉的標的全部清空
        if len(hold_future_l)>0:
            for future_l in hold_future_l:
                if (future_l != main_i) and (future_l != main_j):
                    order_target_value(future_l,0,side='long')
        #做多鐵礦石、焦煤主力
        order_target_value(main_i,cash_i, side='long')
        order_target_value(main_j,cash_j, side='long')
        
    elif trade_signal < -1: #上穿下軌
        print '觸發(fā)交易信號:多螺紋鋼、空鐵礦石、焦煤'
        #對非主力合約的多倉的標的全部清空
        if len(hold_future_l)>0:
            for future_l in hold_future_l:
                if future_l != main_rb:
                    order_target_value(future_l,0,side='long')
        #做多螺紋鋼主力
        order_target_value(main_rb,cash_rb, side='long')

        #對非主力合約的空倉標的全部清空
        if len(hold_future_s)>0:
            for future_s in hold_future_s:
                if (future_s != main_i) and (future_s != main_j):
                    order_target_value(future_s,0,side='short')
        #做空鐵礦石、焦煤主力
        order_target_value(main_i,cash_i, side='short')
        order_target_value(main_j,cash_j, side='short')

    #移倉換月邏輯
    #主力合約變更進行換倉
    if g.main_rb != main_rb:
        print 'rb主力合約由%s變化為%s'%(g.main_rb,main_rb)
        if g.main_rb in hold_future_s:
            order_target_value(g.main_rb,0,side='short')
            order_target_value(main_rb,cash_rb,side='short')
        elif g.main_rb in hold_future_l:
            order_target_value(g.main_rb,0,side='long')
            order_target_value(main_rb,cash_rb,side='long')
            
    if g.main_j != main_j:
        print 'j主力合約由%s變化為%s'%(g.main_j,main_j)
        if g.main_j in hold_future_s:
            order_target_value(g.main_j,0,side='short')
            order_target_value(main_j,cash_j,side='short')
        elif g.main_j in hold_future_l:
            order_target_value(g.main_j,0,side='long')
            order_target_value(main_j,cash_j,side='long')
        
    if g.main_i != main_i:
        print 'i主力合約由%s變化為%s'%(g.main_i,main_i)
        if g.main_i in hold_future_s:
            order_target_value(g.main_i,0,side='short')
            order_target_value(main_i,cash_i,side='short')
        elif g.main_i in hold_future_l:
            order_target_value(g.main_i,0,side='long')
            order_target_value(main_i,cash_i,side='long')
    #更新主力合約記錄
    g.main_rb = main_rb
    g.main_j  = main_j
    g.main_i  = main_i 
    
#策略滾動回撤
def rolling_risk(context):
    #記錄21天內最大回撤數值
    value = context.portfolio.total_value 
    g.tot_values.append(value)
    #更新賬戶總價值
    g.tot_values = g.tot_values[1:]
    max_down = 1 - value*1.0/max(g.tot_values)
    #設置最大回撤閾值觸發(fā)止損信號
    if max_down >= g.maxdown:
        print('觸發(fā)滾動最大回撤,進行清倉')
        g.risk_days = 0
        g.tot_values = [value]*10  #賬戶價值序列重置
        return 1  
    else:
        return 0
        
#獲取交易信號   
def get_signal(se):
    #最新價格
    price_now = se[-1]
    se_temp = se[-g.ma:]
    mid = np.mean(se_temp)
    up  = mid + g.up_std*np.std(se_temp)
    down= mid - g.down_std*np.std(se_temp)
    signal = 0
    
    #進行狀態(tài)記錄
    #當前價格所在軌道區(qū)間
    if price_now>up:
        state_new = 2
    elif price_now < down:
        state_new = -2
    elif price_now > mid:
        state_new = 1  
    elif price_now < mid:
        state_new = -1
    else:
        state_new = 0
        
    #進行信號判斷
    #記錄上下穿越軌道的信號
    #下穿上軌
    if g.state==2 and state_new <2:
        signal=2
    #上穿下軌
    elif g.state==-2 and state_new >-2:
        signal=-2
    elif g.state<0 and state_new > 0:
        signal=1  
    elif g.state>0 and state_new <0:
        signal= -1
    else:
        signal= 0
    #更新軌道區(qū)間狀態(tài)
    g.state = state_new
    
    return signal  
    
## 收盤后運行函數
def after_market_close(context):
    
    cash_ratio = 1 - context.portfolio.available_cash*1.0/context.portfolio.total_value
    print '當日策略資金占用比例為:%s'%cash_ratio
    
    l_hold_future = context.portfolio.long_positions.keys()
    s_hold_future = context.portfolio.short_positions.keys()
    
    for future in l_hold_future:
        print '%s有多頭持倉:%s'% (future,context.portfolio.long_positions[future].total_amount)
    for future in s_hold_future:
        print '%s有空頭持倉:%s'% (future,context.portfolio.short_positions[future].total_amount)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 商品期貨套利策略 套利策略一般包括期現套利、跨期套利、跨市場套利、跨品種套利等。 對于商品期貨而言,期現套利必須交...
    鴻鵠Max閱讀 2,833評論 0 1
  • 話說期貨的暴漲暴跌給交易者們結結實實地上了一堂風險教育課,不少人一夜暴虧血本無歸。于是,很多畏懼風險、追求穩(wěn)健的交...
    風暴之王閱讀 949評論 1 2
  • 跨品種價差套利簡介 套利原理 ? 通俗地講,就是兩個合約相關性很好,突然市場出了一個bug,破壞了兩個合約之間的平...
    鴻鵠Max閱讀 1,285評論 0 0
  • 教你炒期貨:基于概率思維與邏輯思維的交易系統(tǒng) Jerry Ma◆ 序言 期貨市場注定是一個充滿話題的市場,有人在這...
    binzeng閱讀 2,173評論 0 2
  • 字符串 1.什么是字符串 使用單引號或者雙引號括起來的字符集就是字符串。 引號中單獨的符號、數字、字母等叫字符。 ...
    mango_2e17閱讀 7,533評論 1 7