????????我為什么要用國信,就是這個原因,可以做期權,期貨,股票,etf,可轉債的回測。滿足了我所有的需要,我要做指數增強。通常的做法是股票和期貨。但實際上,股票和期權做組合,成本更低。
(1)認沽期權和認購期權的隱含波動率大于50etf波動率時,
以標的資產當前的價格作為行權價買入相同數量、相同標的資產和相同行權日的認購和認沽期權開倉
(2)認沽期權和認購期權的隱含波動率小于50etf波動率且有市場時,平倉
獲取數據:
import datetime
from math import (log, pow, sqrt, exp)from scipy import stats
import numpy as np
import talibcdf = stats.norm.cdf
STEP_CHANGE = 0.001
STEP_UP = 1 + STEP_CHANGE
STEP_DOWN = 1 - STEP_CHANGE
STEP_DIFF = STEP_CHANGE * 2
DX_TARGET = 0.00001
'''
變量說明
s:標的物股票價格
k:行權價
r:無風險利率
t:剩余到期時間(年)
v:隱含波動率
cp:期權類型,+1/-1對應call/put
price:期權價格
'''
初始參數:
def init(ContextInfo):ContextInfo.contract_unit = 10000#隨著時間推移該對合約可能不存了,根據需求手動修改更新ContextInfo.optOne="10001713" ContextInfo.optTwo="10001714"#上面合約的到期年月,根據需求手動修改更新ContextInfo.aa= get_week_of_month(2019, 3)ContextInfo.holdings = {ContextInfo.optOne: 0, ContextInfo.optTwo: 0}ContextInfo.accountID = '8861103625'ContextInfo.s_volatility = []
計算隱含波動率:
def calculateImpv(price, s, k, r, t, cp):"""計算隱含波動率"""# 檢查期權價格必須為正數if price <= 0:return 0# 檢查期權價格是否滿足最小價值(即到期行權價值)meet = Falseif cp == 1 and (price > (s - k) * exp(-r * t)):meet = Trueelif cp == -1 and (price > k * exp(-r * t) - s):meet = True# 若不滿足最小價值,則直接返回0if not meet:return 0# 采用Newton Raphson方法計算隱含波動率v = 0.29 # 初始波動率猜測for i in range(50):# 計算當前猜測波動率對應的期權價格和vega值p = calculatePrice(s, k, r, t, v, cp)vega = calculateOriginalVega(s, k, r, t, v, cp)# 如果vega過小接近0,則直接返回if not vega:break# 計算誤差dx = (price - p) / vega# 檢查誤差是否滿足要求,若滿足則跳出循環if abs(dx) < DX_TARGET:break# 計算新一輪猜測的波動率v += dx# 檢查波動率計算結果非負if v <= 0:return 0# 保留4位小數v = round(v, 4)return v
計算vega:
def calculateOriginalVega(s, k, r, t, v, cp):"""計算原始vega值""" price1 = calculatePrice(s, k, r, t, v*STEP_UP, cp)price2 = calculatePrice(s, k, r, t, v*STEP_DOWN, cp)vega = (price1 - price2) / (v * STEP_DIFF)return vega
計算期權價格:
def calculatePrice(s, k, r, t, v, cp):"""計算期權價格"""# 如果波動率為0,則直接返回期權空間價值if v <= 0:return max(0, cp * (s - k))d1 = (log(s / k) + (r + 0.5 * pow(v, 2)) * t) / (v * sqrt(t))d2 = d1 - v * sqrt(t)price = cp * (s * cdf(cp * d1) - k * cdf(cp * d2) * exp(-r * t))return price
獲取日期:
def get_week_of_month(year, month):"""獲取指定的某天是某個月中的第幾周周一作為一周的開始"""begin = datetime.datetime(year, month, 1).weekday()delta = datetime.timedelta(days=21+begin)exercise_date = datetime.datetime(year, month, 1) + deltareturn exercise_date.strftime('%Y-%m-%d')
策略代碼:
#coding:gbk
"""
跨式期權策略
回測模型示例(非實盤交易策略)(1)認沽期權和認購期權的隱含波動率大于50etf波動率時,
以標的資產當前的價格作為行權價買入相同數量、相同標的資產和相同行權日的認購和認沽期權開倉
(2)認沽期權和認購期權的隱含波動率小于50etf波動率且有市場時,平倉
"""
import datetime
from math import (log, pow, sqrt, exp)from scipy import stats
import numpy as np
import talibcdf = stats.norm.cdf
STEP_CHANGE = 0.001
STEP_UP = 1 + STEP_CHANGE
STEP_DOWN = 1 - STEP_CHANGE
STEP_DIFF = STEP_CHANGE * 2
DX_TARGET = 0.00001
'''
變量說明
s:標的物股票價格
k:行權價
r:無風險利率
t:剩余到期時間(年)
v:隱含波動率
cp:期權類型,+1/-1對應call/put
price:期權價格
'''def init(ContextInfo):ContextInfo.contract_unit = 10000#隨著時間推移該對合約可能不存了,根據需求手動修改更新ContextInfo.optOne="10001713" ContextInfo.optTwo="10001714"#上面合約的到期年月,根據需求手動修改更新ContextInfo.aa= get_week_of_month(2019, 3)ContextInfo.holdings = {ContextInfo.optOne: 0, ContextInfo.optTwo: 0}ContextInfo.accountID = '8861103625'ContextInfo.s_volatility = []
def handlebar(ContextInfo):#當前K線的對應的下標從0開始index = ContextInfo.barpos#當前K線對應的時間:毫秒realtime = ContextInfo.get_bar_timetag(index)current_time = timetag_to_datetime(realtime,'%Y-%m-%d')#當前周期period = ContextInfo.period#取當前K線圖對應的合約當前K線的當前主圖復權方式下的收盤價price_call = ContextInfo.get_market_data(['close'],period=period, stock_code = [ContextInfo.optOne+".SHO"]) price_put = ContextInfo.get_market_data(['close'],period=period, stock_code = [ContextInfo.optTwo+".SHO"])s = ContextInfo.get_market_data(["close"],stock_code = ["510050.SH"],period=period)#print price_call,price_putContextInfo.s_volatility.append(s)s_volatility = np.std(np.array(ContextInfo.s_volatility))ContextInfo.paint("s_volatility", s_volatility*10, -1, 0)k = 2.55r = ContextInfo.get_risk_free_rate(index)/100t = ((datetime.datetime.strptime(ContextInfo.aa, "%Y-%m-%d") - datetime.datetime.strptime(current_time, "%Y-%m-%d")).days) / 365.0cp_call = 1cp_put = -1implied_volatility_call = calculateImpv(price_call, s, k, r, t, cp_call)implied_volatility_put = calculateImpv(price_put, s, k, r, t, cp_put)#print "implied_volatility_call", implied_volatility_call#print "implied_volatility_put", implied_volatility_putContextInfo.paint("implied_volatility", (implied_volatility_put + implied_volatility_call), -1, 0)if (implied_volatility_put + implied_volatility_call) > s_volatility*10 :passorder(50,1101,ContextInfo.accountID ,ContextInfo.optOne,5,-1,1,ContextInfo)passorder(50,1101,ContextInfo.accountID ,ContextInfo.optTwo,5,-1,1,ContextInfo)ContextInfo.holdings[ContextInfo.optOne] = 1ContextInfo.holdings[ContextInfo.optTwo] = 1elif ContextInfo.holdings[ContextInfo.optOne] == 1 and ContextInfo.holdings[ContextInfo.optTwo] == 1 and (implied_volatility_put + implied_volatility_call) < s_volatility*10 :passorder(53,1101,ContextInfo.accountID ,ContextInfo.optOne,5,-1,1,ContextInfo)passorder(53,1101,ContextInfo.accountID ,ContextInfo.optTwo,5,-1,1,ContextInfo)ContextInfo.holdings[ContextInfo.optOne] = 0ContextInfo.holdings[ContextInfo.optTwo] = 0def calculateImpv(price, s, k, r, t, cp):"""計算隱含波動率"""# 檢查期權價格必須為正數if price <= 0:return 0# 檢查期權價格是否滿足最小價值(即到期行權價值)meet = Falseif cp == 1 and (price > (s - k) * exp(-r * t)):meet = Trueelif cp == -1 and (price > k * exp(-r * t) - s):meet = True# 若不滿足最小價值,則直接返回0if not meet:return 0# 采用Newton Raphson方法計算隱含波動率v = 0.29 # 初始波動率猜測for i in range(50):# 計算當前猜測波動率對應的期權價格和vega值p = calculatePrice(s, k, r, t, v, cp)vega = calculateOriginalVega(s, k, r, t, v, cp)# 如果vega過小接近0,則直接返回if not vega:break# 計算誤差dx = (price - p) / vega# 檢查誤差是否滿足要求,若滿足則跳出循環if abs(dx) < DX_TARGET:break# 計算新一輪猜測的波動率v += dx# 檢查波動率計算結果非負if v <= 0:return 0# 保留4位小數v = round(v, 4)return vdef calculateOriginalVega(s, k, r, t, v, cp):"""計算原始vega值""" price1 = calculatePrice(s, k, r, t, v*STEP_UP, cp)price2 = calculatePrice(s, k, r, t, v*STEP_DOWN, cp)vega = (price1 - price2) / (v * STEP_DIFF)return vegadef calculatePrice(s, k, r, t, v, cp):"""計算期權價格"""# 如果波動率為0,則直接返回期權空間價值if v <= 0:return max(0, cp * (s - k))d1 = (log(s / k) + (r + 0.5 * pow(v, 2)) * t) / (v * sqrt(t))d2 = d1 - v * sqrt(t)price = cp * (s * cdf(cp * d1) - k * cdf(cp * d2) * exp(-r * t))return pricedef get_week_of_month(year, month):"""獲取指定的某天是某個月中的第幾周周一作為一周的開始"""begin = datetime.datetime(year, month, 1).weekday()delta = datetime.timedelta(days=21+begin)exercise_date = datetime.datetime(year, month, 1) + deltareturn exercise_date.strftime('%Y-%m-%d')