Pour la volatilité implicite et l'équation des Black Shoals, Black–Scholes model - Wikipedia
À propos de la lecture des données que vous utilisez De la lecture de Pandas d'informations telles que le prix théorique moyen de l'option Nikkei à la mise en forme \ -vol de nuit
vérification
--Calcul de la volatilité implicite à partir du prix de l'option --Comparaison de la vitesse de calcul (plus précisément, comparaison du temps d'exécution)
[Volatilité \ -Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%83%A9%E3%83%86%E3%82%A3%E3%83%AA% E3% 83% 86% E3% 82% A3 # .E3.82.A4.E3.83.B3.E3.83.97.E3.83.A9.E3.82.A4.E3.83.89.E3.83.BB .E3.83.9C.E3.83.A9.E3.83.86.E3.82.A3.E3.83.AA.E3.83.86.E3.82.A3)
Equations pour $ \ sigma $ (notez que $ C (K, T) $ est une fonction de $ \ sigma $) Prix de marché $ = C (K, T) $ Le $ \ sigma $ obtenu en résolvant> est appelé volatilité implicite.
Comme vous pouvez le voir, C (K, T) est calculé pour trouver σ, qui est le prix du marché, mais comme C (K, T) ne peut pas être résolu simplement, [Algorithme d'enracinement](https: //ja.wikipedia) .org / wiki /% E6% B1% 82% E6% A0% B9% E3% 82% A2% E3% 83% AB% E3% 82% B4% E3% 83% AA% E3% 82% BA% E3% Utilisez 83% A0) etc. pour trouver la volatilité implicite.
L'une d'elles est la Méthode Bisection \ -Wikipedia.
Celui implémenté en C ++ était extrêmement plus rapide que les diverses ingéniosités de Python, et je pense que c'était l'effort de Cython. De plus, C ++ a encore une certaine capacité de réserve comme la parallélisation des threads, cette fois ...!
Dans le cas de Windwos, le multi-processus de Python va lire la bibliothèque Keras à chaque fois, ce qui est mauvais, mais même la version exécutée individuellement sans cela a pris environ 35 secondes.
La fonction inverse utilisant ANN est rapide mais imprécise. Je pense qu'il y a des limites à la conception de NN. (Peut-être que c'est impossible à moins de faire quelque chose comme WGAN / StackGAN)
article | Data Handling | Optimize | BS_Vectorized | Proc | Time[sec] |
---|---|---|---|---|---|
Calcul d'optimisation avec Scipy(Solution numérique) / pandas.apply - Single Process | Pd.apply | minimize_scalar(Scipy) | No | Single | 2.8061 |
Calcul d'optimisation avec Scipy(Solution numérique) /optimisation de la fonction scalaire ndarray boucle x:Vectorisation des fonctions- Single Process | Pd->np | minimize_scalar(Scipy) | Yes | Single | 3.2068 |
Calcul d'optimisation avec Scipy(Solution numérique) /optimisation de la fonction vectorielle ndarray:Vectorisation des fonctions- Single Process | Pd->np | root(Scipy) | Yes | Single | 0.6706 |
optimisation ndarray Cython/optimisation de la fonction vectorielle ndarray- Single Process | Pd->np(CyPy) | root(Scipy) | Yes | Single | 0.6860 |
optimisation ndarray Cython/vecteur d'optimisation de la fonction scalaire ndarray- Single Process | Pd->np(CyPy) | VectBisection(Cython) | Yes | Single | 0.4848 |
Calcul d'optimisation avec Scipy(Solution numérique) / pandas.apply + Multi Process | Pd->Split(Pdx8)->np(CyPy) | VectBisection(Cython) | Yes | MultiProc | 128.3856 |
Apprentissage de la fonction inverse à l'aide de ANN ⇒ Utilisation comme moteur de conférence(Keras) | Pd->np->ANN | N/A | Yes | Single | 0.1526 |
Utiliser Swig(C++la mise en oeuvre)/Boucle simple- Single Process | Pd->np->C++(Swig) | Bisection(C++) | No | Single | 0.0010 |
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
from keras.models import load_model
from datetime import datetime
import dateutil
import scipy.optimize
from scipy.stats import norm
#Version Cython
from BS_Cy import *
#Version Swig
from _BS import *
import multiprocessing as mp
import time
import matplotlib.pyplot as plt
maturity = 19.75/245.
def strip(text):
try:
return text.strip()
except AttributeError:
return text
def BS_norm(F225, Strike, maturity, vol, call):
volSQM = vol * (maturity ** .5)
d1 = np.log(F225/Strike) / volSQM + volSQM/2
d2 = d1 - volSQM
return (F225 * norm.cdf(d1) - Strike*norm.cdf(d2)) if call else \
(Strike * norm.cdf(-d2) - F225*norm.cdf(-d1))
def BS_norm_vect(F225, Strike, maturity, vol, call):
volSQM = vol * (maturity ** .5)
d1 = np.log(F225/Strike) / volSQM + volSQM/2
d2 = d1 - volSQM
Call = F225 * norm.cdf(d1) - Strike*norm.cdf(d2)
Put = Strike * norm.cdf(-d2) - F225*norm.cdf(-d1)
premium = Call * call + Put * np.logical_not(call)
return premium
def myapply(x):
res = scipy.optimize.minimize_scalar(
lambda vol:
(
BS_norm(x['F225_PRICE'], x['STRIKE'], maturity, vol, x['CALL'])
- x['OP_PRICE']
)**2,
method='Bounded', bounds =(0.01, 0.5),
options={'maxiter': 50, 'xatol': 1e-04})
x['vol1'] = res.x
return x
def myapply_vect(F225, Strike, price, call):
x = []
for i in range(len(F225)):
res = scipy.optimize.minimize_scalar(
lambda vol:
( BS_norm_vect(F225[i], Strike[i], maturity, vol,call[i]) - price[i] )**2,
method='Bounded', bounds =(0.01, 0.5),
options={'maxiter': 50, 'xatol': 1e-04})
x.append(res.x)
return x
def myapply_vect2(F225, Strike, price, call):
res = scipy.optimize.root(
lambda vol:( BS_norm_vect(F225, Strike, maturity, vol,call) - price),
np.ones_like(F225)*.3)
return res.x
def pworker(df):
df['vol6'] = cy_apply2(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values)
return df
if __name__ == '__main__':
# #Préparation des données
# [Informations telles que le prix théorique de l'option\|Japan Exchange Group](http://www.jpx.co.jp/markets/derivatives/option-price/01.html)Données de clôture du 10 février 2017 obtenues à partir de.
#Il existe différents éléments, mais l'actif sous-jacent pour le contrat de mars 2017: Seules les données de transaction d'options du Nikkei 225 sont utilisées.
#
# ##Lire des données dans Pandas
# 1.Élevez et nommez vous-même l'en-tête en fonction des informations d'en-tête distribuées séparément du corps de données
# 2.Couper les blancs dans les données de texte lors du chargement
#Nom de l'en-tête(Par nom de variable)
#Code produit,Type de produit,Mois du contrat,Prix de l'exercice,réserve
#Option de vente:Code de stock,le dernier prix,réserve,Prix théorique,Volatilité
#Options d'appel:Code de stock,le dernier prix,réserve,Prix théorique,Volatilité
#Cours de clôture de l'actif sous-jacent,Critères de volatilité
colName = ("CODE","TYPE","MATURITY","STRIKE", "RSV",
"PUT_CODE", "PUT_PRICE", "PUT_RSV", "PUT_TPRICE", "PUT_VOLATILITY",
"CALL_CODE","CALL_PRICE","CALL_RSV","CALL_TPRICE","CALL_VOLATILITY",
"F225_PRICE", "Base_VOL")
df = pd.read_csv('./ose20170210tp.csv',names=colName,
converters = {'CODE' : strip,
'TYPE' : strip})
#Seule l'option Nikkei 225 du contrat de mars 2017 est extraite. Au fait, j'ai supprimé les colonnes inutiles et c'était rafraîchissant.
df = df.query("MATURITY == 201703 & CODE==\"NK225E\"") .drop(['RSV','PUT_RSV','CALL_RSV','PUT_CODE','CALL_CODE','CODE','TYPE','MATURITY'], 1)
# *Puisque PUT et CALL sont séparés, normalisez les données.
# *Lorsque la colonne CALL est TRUE, il s'agit de données CALL et lorsqu'elle est FALSE, il s'agit de données PUT.
# *Le prix d'exercice est également réduit à 14000 yens ou plus et moins de 22000 yens
df_p = df[["STRIKE","PUT_PRICE","PUT_TPRICE", "PUT_VOLATILITY","F225_PRICE", "Base_VOL"]] .rename(columns={'PUT_PRICE': 'OP_PRICE', 'PUT_TPRICE':'OP_TPRICE', 'PUT_VOLATILITY':'OP_VOL'})
df_p['CALL'] = False
df_c = df[["STRIKE","CALL_PRICE","CALL_TPRICE", "CALL_VOLATILITY","F225_PRICE", "Base_VOL"]] .rename(columns={'CALL_PRICE': 'OP_PRICE', 'CALL_TPRICE':'OP_TPRICE', 'CALL_VOLATILITY':'OP_VOL'})
df_c['CALL'] = True
df = df_p.append(df_c).query("OP_PRICE > 1.0 & STRIKE < 22000 & STRIKE >= 14000")
del (df_p,df_c)
tmp_df = df
loop_num = 10
text = 'Time elapsed: %.2f seconds'
result_time = []
result_Col = np.array([["Data Handling","Optimize","BS_Vectorized","Proc","Time[sec]"]])
result_con = np.array([["Pd.apply",
"Pd->np",
"Pd->np",
"Pd->np(CyPy)",
"Pd->np(CyPy)",
"Pd->Split(Pd x 8)->np(CyPy)",
"Pd->np->ANN",
"Pd->np->C++(Swig)"
]])
result_opt = np.array([["minimize_scalar(Scipy)",
"minimize_scalar(Scipy)",
"root(Scipy)",
"root(Scipy)",
"Vect Bisection(Cython)",
"Vect Bisection(Cython)",
"N/A",
"Bisection(C++)"
]])
result_Vect = np.array([["No",
"Yes",
"Yes",
"Yes",
"Yes",
"Yes",
"Yes",
"No"
]])
result_Proc = np.array([["Single",
"Single",
"Single",
"Single",
"Single",
"Multi Proc",
"Single",
"Single"
]])
# 1.Calcul d'optimisation avec Scipy(Solution numérique) / pandas.apply - Single Process
time_start = time.time()
for i in range(loop_num):
tmp_df = df.apply(myapply, axis=1)
result_time.append((time.time() - time_start))
# 2.Calcul d'optimisation avec Scipy(Solution numérique) /boucle ndarray:Vectorisation des fonctions- Single Process
time_start = time.time()
for i in range(loop_num):
tmp_df['vol2'] = myapply_vect(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values)
result_time.append((time.time() - time_start))
# 3.Calcul d'optimisation avec Scipy(Solution numérique) /vecteur ndarray:Vectorisation des fonctions- Single Process
time_start = time.time()
for i in range(loop_num):
tmp_df['vol3'] = myapply_vect2(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values)
result_time.append((time.time() - time_start))
# 4. Cython - Root
time_start = time.time()
for i in range(loop_num):
tmp_df['vol4'] = cy_apply1(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values)
result_time.append((time.time() - time_start))
# 5. Cython - My Bisection
time_start = time.time()
for i in range(loop_num):
tmp_df['vol5'] = cy_apply2(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values)
result_time.append((time.time() - time_start))
# 6. Multi Process
time_start = time.time()
for i in range(loop_num):
p = mp.Pool(processes=8)
split_dfs = np.array_split(df,8)
pool_results = p.map(pworker, split_dfs)
p.close()
p.join()
tmp_df = pd.concat(pool_results, axis=0)
result_time.append((time.time() - time_start))
# 7. ANN
model = load_model('./model.h5')
a = np.array([df['STRIKE'].values/df['F225_PRICE'].values])
b = np.array([np.ones_like(df['F225_PRICE'].values)*maturity/(40./245.)])
c = np.array([(df['OP_PRICE'].values/df['F225_PRICE'].values/0.25)**0.25])
X = np.vstack((a,b,c)).transpose()
time_start = time.time()
for i in range(loop_num):
tmp_df['vol7'] = 0.4*model.predict(X)+0.1
result_time.append((time.time() - time_start))
# 8. Swig C++
tmpmpmp=np.ones_like(df['F225_PRICE'].values).astype(np.float32)
time_start = time.time()
for i in range(loop_num):
tmpmpmp = Swig_Apply_PY(df['F225_PRICE'].values, df['STRIKE'].values,
df['OP_PRICE'].values, df['CALL'].values.astype(dtype=np.int32),tmpmpmp.shape[0])
tmp_df['vol8'] = tmpmpmp
result_time.append((time.time() - time_start))
result_time = np.array([result_time])
print(np.vstack((result_con, result_opt, result_Vect, result_Proc,result_time)).transpose())
Recommended Posts