[PYTHON] Berechnung der impliziten Volatilität mit hoher Geschwindigkeit durchführen (Marktdatenverarbeitung)

Für implizite Volatilität und die Black Shoals-Gleichung Black–Scholes model - Wikipedia

Informationen zum Lesen der von Ihnen verwendeten Daten Vom Lesen von Pandas mit Informationen wie dem theoretischen Preis der Nikkei-Durchschnittsoption bis zur Gestaltung des Nachtfluges

Überprüfung

Was machst du

[Volatility \ -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)

Gleichungen für $ \ sigma $ (beachten Sie, dass $ C (K, T) $ eine Funktion von $ \ sigma $ ist) Marktpreis $ = C (K, T) $ Das durch Lösen erhaltene $ \ sigma $ wird implizite Volatilität genannt.

Wie Sie sehen können, wird C (K, T) berechnet, um σ zu finden, was der Marktpreis ist. Da C (K, T) jedoch nicht einfach gelöst werden kann, [Rooting-Algorithmus](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% Verwenden Sie 83% A0) usw., um die implizite Volatilität zu ermitteln.

Eine davon ist Bisektionsmethode \ -Wikipedia.

Berechnungsbedingung

Aktionselement

Ergebnis der Ausführungszeit

Die in C ++ implementierte war überwältigend schneller als die verschiedenen Einfallsreichtümer in Python, und ich denke, es war Cythons Anstrengung. Darüber hinaus verfügt C ++ noch über Kapazitätsreserven wie Thread-Parallelisierung, diesmal ...!

Im Fall von Windwos liest Pythons Multi-Prozess jedes Mal die Keras-Bibliothek, was schlecht ist, aber selbst die einzeln ausgeführte Version ohne dies dauerte ungefähr 35 Sekunden.

Die Umkehrfunktion mit ANN ist schnell, aber ungenau. Ich denke, dem Design von NN sind Grenzen gesetzt. (Vielleicht ist es unmöglich, wenn Sie nicht so etwas wie WGAN / StackGAN machen)

Artikel Data Handling Optimize BS_Vectorized Proc Time[sec]
Optimierungsberechnung mit Scipy(Numerische Lösung) / pandas.apply - Single Process Pd.apply minimize_scalar(Scipy) No Single 2.8061
Optimierungsberechnung mit Scipy(Numerische Lösung) /ndarray Skalarfunktionsoptimierung x Schleife:Funktionsvektorisierung- Single Process Pd->np minimize_scalar(Scipy) Yes Single 3.2068
Optimierungsberechnung mit Scipy(Numerische Lösung) /Optimierung der ndarray-Vektorfunktion:Funktionsvektorisierung- Single Process Pd->np root(Scipy) Yes Single 0.6706
ndarray Optimierung Cython/Optimierung der ndarray-Vektorfunktion- Single Process Pd->np(CyPy) root(Scipy) Yes Single 0.6860
ndarray Optimierung Cython/Optimierungsvektor für die Skalarfunktion von ndarray- Single Process Pd->np(CyPy) VectBisection(Cython) Yes Single 0.4848
Optimierungsberechnung mit Scipy(Numerische Lösung) / pandas.apply + Multi Process Pd->Split(Pdx8)->np(CyPy) VectBisection(Cython) Yes MultiProc 128.3856
Erlernen der Umkehrfunktion mit ANN ⇒ Verwendung als Konferenzmodul(Keras) Pd->np->ANN N/A Yes Single 0.1526
Mit Swig(C++Implementierung)/Einfache Wiederholung- Single Process Pd->np->C++(Swig) Bisection(C++) No Single 0.0010

Quelle

# -*- 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

#Cython-Version
from BS_Cy import *
#Swig Version
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__':
    # #Datenaufbereitung
    # [Informationen wie Option theoretischer Preis\|Japan Exchange Group](http://www.jpx.co.jp/markets/derivatives/option-price/01.html)Schlusskursdaten am 10. Februar 2017 erhalten von.
    #Es gibt verschiedene Posten, aber den Basiswert für den Vertrag vom März 2017: Es werden nur die Optionstransaktionsdaten von Nikkei 225 verwendet.
    # 
    # ##Lesen Sie Daten in Pandas
    # 1.Erhöhen und benennen Sie den Header selbst basierend auf den Headerinformationen, die getrennt vom Datenkörper verteilt werden
    # 2.Schneiden Sie beim Laden Leerzeichen in Textdaten

    #Headername(Nach Variablenname)
    #Produktcode,Produktart,Vertragsmonat,Ausübungspreis,Reservieren
    #Put-Option:Bestandscode,Schlusskurs,Reservieren,Theoretischer Preis,Volatilität
    #Anrufoptionen:Bestandscode,Schlusskurs,Reservieren,Theoretischer Preis,Volatilität
    #Schlusskurs des zugrunde liegenden Vermögenswerts,Kriterien Volatilität
    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})
    #Es wird nur die Option Nikkei 225 für den Vertrag vom März 2017 extrahiert. Übrigens habe ich unnötige Spalten gelöscht und es war erfrischend.
    df = df.query("MATURITY == 201703 & CODE==\"NK225E\"")    .drop(['RSV','PUT_RSV','CALL_RSV','PUT_CODE','CALL_CODE','CODE','TYPE','MATURITY'], 1)

    # *Da PUT und CALL getrennt sind, normalisieren Sie die Daten.
    # *Wenn die CALL-Spalte TRUE ist, handelt es sich um CALL-Daten, und wenn es sich um FALSE handelt, handelt es sich um PUT-Daten.
    # *Der Ausübungspreis wird ebenfalls auf 14000 Yen oder mehr und weniger als 22000 Yen eingegrenzt
    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.Optimierungsberechnung mit Scipy(Numerische Lösung) / 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.Optimierungsberechnung mit Scipy(Numerische Lösung) /ndarray Schleife:Funktionsvektorisierung- 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.Optimierungsberechnung mit Scipy(Numerische Lösung) /ndarray Vektor:Funktionsvektorisierung- 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

Berechnung der impliziten Volatilität mit hoher Geschwindigkeit durchführen (Marktdatenverarbeitung)
Führen Sie mit Python eine Konvertierung in halber und voller Breite mit hoher Geschwindigkeit durch
[Große Abfrage] Laden Sie einen Teil der BQ-Daten mit hoher Geschwindigkeit in Pandas
Kombinieren Sie mehrere Python-Dateien zu einer Python-Datei
[Python & Unix] Kombinieren Sie mehrere PDF-Dateien zu einer.
Kombinieren Sie mehrere mit Pandas geladene Excel-Dateien zu einer
Berechnung der impliziten Volatilität mit hoher Geschwindigkeit durchführen (Marktdatenverarbeitung)
[Große Abfrage] Laden Sie einen Teil der BQ-Daten mit hoher Geschwindigkeit in Pandas
Eine kleine Geschichte, die Tabellendaten im CSV-Format mit hoher Geschwindigkeit ausgibt