Optimierung der FX-Systolenparameter in Python

Backtesting von FX Systre mit Python Nachdem wir den Backtesting-Code geschrieben haben, versuchen wir, die Parameter der Systole zu optimieren. Die Optimierung des Handelssystems bedeutet nicht, heutzutage populäres Deep Learning durchzuführen, sondern einfach die Werte der Parameter der technischen Indikatoren zu ändern, um den mit dem höchsten Bewertungswert zu finden. Dies dient zum Üben der Python-Programmierung.

Vorbereitung

Backtesting von FX Systre mit Python Bereiten Sie wie bei die historischen Daten von FX vor. Nach wie vor werde ich die Daten für das Stunden-Chart 2015 von EUR / USD erstellen.

import numpy as np
import pandas as pd
import indicators as ind #indicators.Import von py

dataM1 = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
                     names=('Time','Open','High','Low','Close', ''),
                     index_col='Time', parse_dates=True)
dataM1.index += pd.offsets.Hour(7) #7 Stunden Offset
ohlc = ind.TF_ohlc(dataM1, 'H') #Erstellung von Stundendaten

Verwenden Sie für Indikatoren.py die auf GitHub aufgeführte.

Backtest und seine Bewertung

Verwenden Sie dieselbe Backtest-Funktion wie beim letzten Mal. Berechnen Sie Handelsergebnisse und Gewinn / Verlust unter Einbeziehung historischer Daten und Handelssignale.

def Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit, lots=0.1, spread=2):
    Open = ohlc['Open'].values #Offener Preis
    Point = 0.0001 #Wert von 1pip
    if(Open[0] > 50): Point = 0.01 #1 Pip-Wert des Kreuzkreises
    Spread = spread*Point #Ausbreitung
    Lots = lots*100000 #Tatsächliches Handelsvolumen
    N = len(ohlc) #FX-Datengröße
    BuyExit[N-2] = SellExit[N-2] = True #Endlich Zwangsausgang
    BuyPrice = SellPrice = 0.0 #Verkaufspreis
    
    LongTrade = np.zeros(N) #Handelsinformationen kaufen
    ShortTrade = np.zeros(N) #Handelsinformationen verkaufen
    
    LongPL = np.zeros(N) #Gewinn / Verlust der Kaufposition
    ShortPL = np.zeros(N) #Gewinn / Verlust der Verkaufsposition

    for i in range(1,N):
        if BuyEntry[i-1] and BuyPrice == 0: #Einstiegssignal kaufen
            BuyPrice = Open[i]+Spread
            LongTrade[i] = BuyPrice #Kaufposition offen
        elif BuyExit[i-1] and BuyPrice != 0: #Ausgangssignal kaufen
            ClosePrice = Open[i]
            LongTrade[i] = -ClosePrice #Kaufposition geschlossen
            LongPL[i] = (ClosePrice-BuyPrice)*Lots #Gewinn- und Verlustrechnung
            BuyPrice = 0

        if SellEntry[i-1] and SellPrice == 0: #Eingangssignal verkaufen
            SellPrice = Open[i]
            ShortTrade[i] = SellPrice #Verkaufsposition offen
        elif SellExit[i-1] and SellPrice != 0: #Ausgangssignal verkaufen
            ClosePrice = Open[i]+Spread
            ShortTrade[i] = -ClosePrice #Verkaufsposition geschlossen
            ShortPL[i] = (SellPrice-ClosePrice)*Lots #Gewinn- und Verlustrechnung
            SellPrice = 0

    return pd.DataFrame({'Long':LongTrade, 'Short':ShortTrade}, index=ohlc.index),\
            pd.DataFrame({'Long':LongPL, 'Short':ShortPL}, index=ohlc.index)

Verwenden Sie zur Bewertung des Systems die folgenden Funktionen, um den Gesamtgewinn / -verlust, die Anzahl der Transaktionen, den durchschnittlichen Gewinn / Verlust, den Gewinnfaktor, den maximalen Drawdown und den Wiederherstellungsfaktor zu berechnen. Dies entspricht fast der Ausgabe der MetaTrader-Optimierung.

def BacktestReport(Trade, PL):
    LongPL = PL['Long']
    ShortPL = PL['Short']
    LongTrades = np.count_nonzero(Trade['Long'])//2
    ShortTrades = np.count_nonzero(Trade['Short'])//2
    GrossProfit = LongPL.clip_lower(0).sum()+ShortPL.clip_lower(0).sum()
    GrossLoss = LongPL.clip_upper(0).sum()+ShortPL.clip_upper(0).sum()
    #Gesamtgewinn und -verlust
    Profit = GrossProfit+GrossLoss
    #Anzahl der Transaktionen
    Trades = LongTrades+ShortTrades
    #Durchschnittlicher Gewinn / Verlust
    if Trades==0: Average = 0
    else: Average = Profit/Trades
    #Gewinnfaktor
    if GrossLoss==0: PF=100
    else: PF = -GrossProfit/GrossLoss
    #Maximaler Drawdown
    Equity = (LongPL+ShortPL).cumsum()
    MDD = (Equity.cummax()-Equity).max()
    #Wiederherstellungsfaktor
    if MDD==0: RF=100
    else: RF = Profit/MDD
    return np.array([Profit, Trades, Average, PF, MDD, RF])

Zu optimierende Parameter und deren Bereich

Im vorherigen Backtest wurde der Zeitraum für den langfristigen gleitenden Durchschnitt auf 30 und der Zeitraum für den kurzfristigen gleitenden Durchschnitt auf 10 festgelegt. Bei dieser Optimierung werden wir diese beiden Zeiträume jedoch ändern.

Die Änderungsperiode beträgt 10 bis 50 für den langfristigen gleitenden Durchschnitt und 5 bis 30 für den kurzfristigen gleitenden Durchschnitt. Fügen Sie es wie folgt in das Array ein.

SlowMAperiod = np.arange(10, 51) #Bereich der langfristigen gleitenden Durchschnittsperiode
FastMAperiod = np.arange(5, 31)  #Bereich des kurzfristigen gleitenden Durchschnittszeitraums

Es gibt 41 und 26 Möglichkeiten für jede Periode, aber die Kombination der beiden Perioden beträgt $ 41 \ mal 26 = 1066 $.

Optimierung

Optimieren Sie durch Ersetzen des Periodenbereichs dieses Parameters. Mit zunehmender Anzahl von Periodenkombinationen kann die Berechnungszeit nicht ignoriert werden. Daher müssen unnötige Berechnungen so weit wie möglich vermieden werden.

Berechnen Sie vorerst die Zeitreihen von 41 und 26 gleitenden Durchschnitten im Voraus. Dann werden für 1066 Kombinationen Kauf- / Verkaufssignale erzeugt, zurückgetestet und ausgewertet, und Parameterwerte und Bewertungswerte werden ausgegeben. Ein Beispiel für den Code lautet wie folgt.

def Optimize(ohlc, SlowMAperiod, FastMAperiod):
    SlowMA = np.empty([len(SlowMAperiod), len(ohlc)]) #Langfristiger gleitender Durchschnitt
    for i in range(len(SlowMAperiod)):
        SlowMA[i] = ind.iMA(ohlc, SlowMAperiod[i])

    FastMA = np.empty([len(FastMAperiod), len(ohlc)]) #Kurzfristiger gleitender Durchschnitt
    for i in range(len(FastMAperiod)):
        FastMA[i] = ind.iMA(ohlc, FastMAperiod[i])
    
    N = len(SlowMAperiod)*len(FastMAperiod)
    Eval = np.empty([N, 6]) #Bewertungsgegenstand
    Slow = np.empty(N) #Langfristiger gleitender Durchschnittszeitraum
    Fast = np.empty(N) #Kurzfristiger gleitender Durchschnittszeitraum
    def shift(x, n=1): return np.concatenate((np.zeros(n), x[:-n])) #Schaltfunktion
    k = 0
    for i in range(len(SlowMAperiod)):
        for j in range(len(FastMAperiod)):
            #Einstiegssignal kaufen
            BuyEntry = (FastMA[j] > SlowMA[i]) & (shift(FastMA[j]) <= shift(SlowMA[i]))
            #Eingangssignal verkaufen
            SellEntry = (FastMA[j] < SlowMA[i]) & (shift(FastMA[j]) >= shift(SlowMA[i]))
            #Ausgangssignal kaufen
            BuyExit = SellEntry.copy()
            #Ausgangssignal verkaufen
            SellExit = BuyEntry.copy()
            #Backtest
            Trade, PL = Backtest(ohlc, BuyEntry, SellEntry, BuyExit, SellExit) 
            Eval[k] = BacktestReport(Trade, PL)
            Slow[k] = SlowMAperiod[i]
            Fast[k] = FastMAperiod[j]
            k += 1
    return pd.DataFrame({'Slow':Slow, 'Fast':Fast, 'Profit': Eval[:,0], 'Trades':Eval[:,1],
                         'Average':Eval[:,2],'PF':Eval[:,3], 'MDD':Eval[:,4], 'RF':Eval[:,5]},
                         columns=['Slow','Fast','Profit','Trades','Average','PF','MDD','RF'])
            
result = Optimize(ohlc, SlowMAperiod, FastMAperiod)

Ich war besorgt über die Berechnungszeit, aber mit der 1,8-GHz-CPU des Core i5-3337U dauerte es ungefähr 12 Sekunden. Ich habe versucht, die gleichen Bedingungen mit MetaTrader 5 zu optimieren, aber es hat fast 50 Sekunden gedauert, daher denke ich, dass es für Python einigermaßen praktisch war.

Ergebnisse der Optimierung

Sie können den optimalen Parameterwert finden, indem Sie die Optimierungsergebnisse nach Ihren bevorzugten Elementen sortieren. Wenn Sie beispielsweise nach dem Gesamtgewinn / -verlust sortieren, ist dies wie folgt.

result.sort_values('Profit', ascending=False).head(20)
        Slow  Fast  Profit  Trades   Average        PF     MDD        RF
   445  27.0   8.0  2507.1   264.0  9.496591  1.423497   485.1  5.168213
   470  28.0   7.0  2486.0   260.0  9.561538  1.419642   481.2  5.166251
   446  27.0   9.0  2263.3   252.0  8.981349  1.376432   624.7  3.623019
   444  27.0   7.0  2171.4   272.0  7.983088  1.341276   504.7  4.302358
   471  28.0   8.0  2102.3   250.0  8.409200  1.359030   540.3  3.890986
   497  29.0   8.0  2093.3   242.0  8.650000  1.365208   603.8  3.466876
   495  29.0   6.0  2063.5   256.0  8.060547  1.342172   620.6  3.325008
   498  29.0   9.0  2053.5   238.0  8.628151  1.362451   686.5  2.991260
   546  31.0   5.0  1959.4   254.0  7.714173  1.344256   529.7  3.699075
   520  30.0   5.0  1940.3   276.0  7.030072  1.313538   681.7  2.846267
   496  29.0   7.0  1931.5   248.0  7.788306  1.322891   611.3  3.159660
   422  26.0  11.0  1903.4   248.0  7.675000  1.309702   708.7  2.685763
   523  30.0   8.0  1903.0   232.0  8.202586  1.327680   823.9  2.309746
   524  30.0   9.0  1875.8   234.0  8.016239  1.328598   908.6  2.064495
   573  32.0   6.0  1820.8   242.0  7.523967  1.320688   639.8  2.845889
   420  26.0   9.0  1819.1   258.0  7.050775  1.282035   667.0  2.727286
   572  32.0   5.0  1808.2   256.0  7.063281  1.313564   522.9  3.458023
   598  33.0   5.0  1799.6   248.0  7.256452  1.317183   613.2  2.934768
   419  26.0   8.0  1777.4   274.0  6.486861  1.273817   552.7  3.215849
   434  26.0  23.0  1739.6   368.0  4.727174  1.241049  1235.5  1.408013

Daraus ergeben sich für die langfristige gleitende Durchschnittsperiode 27 Werte für die Parameter, die den Gesamtgewinn / -verlust maximieren, und für die kurzfristige gleitende Durchschnittsperiode 8.

Als Test sieht die in diesem Zeitraum erneut getestete Asset-Kurve folgendermaßen aus: chart.png

Hört sich gut an. Es ist jedoch selbstverständlich, dass ein solches Ergebnis durch Optimierung der Parameter erzielt werden kann, und es ist nicht sehr erfreulich. Es ist nur eine Enttäuschung, einen weiteren Zeitraum zu testen.

Dieses Mal ist es in Ordnung, schnellere Ergebnisse als der Backtest von MetaTrader zu erzielen. MetaTrader kann auch in Tick-Einheiten Backtesting durchführen, aber ich denke, es wird viel Zeit in Python dauern. Es ist noch ein langer Weg.

Recommended Posts

Optimierung der FX-Systolenparameter in Python
Backtesting von FX Systre mit Python (1)
Python in der Optimierung
Verwenden Sie den Parameterspeicher in Python
Backtesting von FX Systre mit Python (2)
Lösen Sie Optimierungsprobleme mit Python
Übertragen Sie Parameterwerte in Python
Implementierung der HMM-Parameterschätzung in Python
GPyOpt, ein Paket zur Bayes'schen Optimierung in Python
[FX] Hit oanda-API mit Python mit Docker
Ich habe versucht, die Bayes'sche Optimierung von Python zu verwenden
Quadtree in Python --2
CURL in Python
Geokodierung in Python
SendKeys in Python
Metaanalyse in Python
Unittest in Python
Epoche in Python
Zwietracht in Python
Deutsch in Python
DCI in Python
Quicksort in Python
nCr in Python
N-Gramm in Python
Programmieren mit Python
Plink in Python
Konstante in Python
FizzBuzz in Python
SQLite in Python
Schritt AIC in Python
LINE-Bot [0] in Python
CSV in Python
Reverse Assembler mit Python
Reflexion in Python
Konstante in Python
nCr in Python.
Format in Python
Scons in Python 3
Puyopuyo in Python
Python in Virtualenv
PPAP in Python
Quad-Tree in Python
Reflexion in Python
Chemie mit Python
Hashbar in Python
DirectLiNGAM in Python
LiNGAM in Python
In Python reduzieren
In Python flach drücken
Zeigen Sie FX (Forex) Daten Candle Stick in Python an
Sortierte Liste in Python
Täglicher AtCoder # 36 mit Python
Clustertext in Python
AtCoder # 2 jeden Tag mit Python
Täglicher AtCoder # 32 in Python
Täglicher AtCoder # 6 in Python
Täglicher AtCoder # 18 in Python
Bearbeiten Sie Schriftarten in Python
Singleton-Muster in Python