FX Systre Parameteroptimierung in Python Also habe ich alle Parameterkombinationen des Handelssystems ausprobiert, um die optimale Lösung zu finden.
Wenn die Anzahl der Kombinationen klein ist, gibt es kein Problem mit Round-Robin, aber wenn die Anzahl der Kombinationen groß ist, wird es ziemlich schwierig. Der Optimierungsalgorithmus dafür ist [Metahuristics](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%BF%E3%83%92%E3%83%A5% E3% 83% BC% E3% 83% AA% E3% 82% B9% E3% 83% 86% E3% 82% A3% E3% 82% AF% E3% 82% B9). Ich wollte einen bekannten genetischen Algorithmus implementieren, habe aber vorher eine einfachere Zufallssuche in Python geschrieben.
Setzen Sie die Funktion zum Konvertieren von 1-Minuten-Daten in einen anderen Zeitrahmen und die technische Indexfunktion in Indikatoren.py sowie den vorherigen Backtest und die Funktion zum Auswerten in backtest.py. Die Quelle finden Sie unter GitHub. Der folgende Code erstellt 1-Stunden-Daten in ohlc
.
import numpy as np
import pandas as pd
import indicators as ind #indicators.Import von py
from backtest import Backtest,BacktestReport
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
In der vorherigen Optimierung haben wir optimiert, indem wir zwei Parameter innerhalb eines bestimmten Bereichs wie folgt geändert haben.
SlowMAperiod = np.arange(10, 61) #Bereich der langfristigen gleitenden Durchschnittsperiode
FastMAperiod = np.arange(5, 31) #Bereich des kurzfristigen gleitenden Durchschnittszeitraums
Bei dieser Rate gibt es nur 1066 Möglichkeiten, aber ich werde die Anzahl der Kombinationen später ändern.
Bei einer einfachen Zufallssuche sollten Parameterwerte nacheinander zufällig generiert und derjenige mit der höchsten Backtest-Bewertung übernommen werden, hier jedoch einmal, damit er auf genetische Algorithmen angewendet werden kann. Ich habe ungefähr 20 Parameterkombinationen in jeder Generation ausprobiert und versucht, sie für mehrere Generationen zu wiederholen.
def Optimize(ohlc, SlowMAperiod, FastMAperiod):
def shift(x, n=1): return np.concatenate((np.zeros(n), x[:-n])) #Schaltfunktion
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])
M = 20 #Anzahl der Personen
Eval = np.zeros([M, 6]) #Bewertungsgegenstand
Param = np.zeros([M, 2], dtype=int) #Parameter
RandomSearch(Param, Eval[:,0], SlowMAperiod, FastMAperiod) #Parameterinitialisierung
gens = 0 #Anzahl der Generationen
while gens < 100:
for k in range(M):
i = Param[k,0]
j = Param[k,1]
#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)
#Generationswechsel
Param = RandomSearch(Param, Eval[:,0], SlowMAperiod, FastMAperiod)
gens += 1
Slow = SlowMAperiod[Param[:,0]]
Fast = FastMAperiod[Param[:,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'])
Der Unterschied zum letzten Mal besteht darin, dass wir ein Array "Param" vorbereitet haben, um die Kombination von Parametern für jede Generation zu speichern. Dann wird der Parametersatz mit dem größten Bewertungswert (in diesem Fall Gesamtgewinn / -verlust) für jede Generation gespeichert (Elite-Save), und die verbleibenden Parameter werden wiederholt zufällig generiert.
Eine Funktion, die zufällig Parameter mit Elite-Speicher generiert, kann wie folgt geschrieben werden:
#Zufällige Suche mit Elite Save
def RandomSearch(Param, Eval, SlowMAperiod, FastMAperiod):
Param = Param[np.argsort(Eval)[::-1]] #Sortieren
NewParam = np.vstack((np.random.randint(len(SlowMAperiod), size=len(Eval)),
np.random.randint(len(FastMAperiod), size=len(Eval)))).T
NewParam[0] = Param[0] #Elite speichern
return NewParam
Die Methode besteht darin, die Auswertungswerte zu sortieren und den 0. Parameter erneut einzustellen. Wenn Sie dies tun, erhalten Sie:
result = Optimize(ohlc, SlowMAperiod, FastMAperiod)
result.sort_values('Profit', ascending=False)
Slow | Fast | Profit | Trades | Average | PF | MDD | RF | |
---|---|---|---|---|---|---|---|---|
0 | 27 | 8 | 2507.1 | 264.0 | 9.496591 | 1.423497 | 485.1 | 5.168213 |
15 | 18 | 5 | 944.1 | 428.0 | 2.205841 | 1.110187 | 693.1 | 1.362141 |
19 | 48 | 14 | 825.4 | 238.0 | 3.468067 | 1.131883 | 927.7 | 0.889727 |
16 | 42 | 29 | 720.4 | 308.0 | 2.338961 | 1.094974 | 1011.8 | 0.711998 |
8 | 44 | 25 | 589.3 | 246.0 | 2.395528 | 1.089205 | 1141.1 | 0.516432 |
6 | 60 | 25 | 588.8 | 120.0 | 4.906667 | 1.126946 | 1025.0 | 0.574439 |
4 | 22 | 5 | 493.5 | 124.0 | 3.979839 | 1.105354 | 1106.3 | 0.446082 |
11 | 26 | 7 | 391.2 | 206.0 | 1.899029 | 1.069326 | 1099.8 | 0.355701 |
17 | 13 | 7 | 343.2 | 152.0 | 2.257895 | 1.069697 | 990.9 | 0.346352 |
18 | 45 | 20 | 174.5 | 160.0 | 1.090625 | 1.032210 | 1118.4 | 0.156026 |
12 | 38 | 20 | 169.8 | 170.0 | 0.998824 | 1.029754 | 939.8 | 0.180677 |
3 | 21 | 11 | 148.6 | 460.0 | 0.323043 | 1.016830 | 1203.1 | 0.123514 |
5 | 34 | 13 | -342.0 | 170.0 | -2.011765 | 0.939258 | 1160.8 | -0.294624 |
7 | 42 | 22 | -374.4 | 156.0 | -2.400000 | 0.933744 | 1189.6 | -0.314728 |
1 | 51 | 20 | -441.4 | 160.0 | -2.758750 | 0.922788 | 1089.9 | -0.404991 |
9 | 58 | 27 | -1485.5 | 222.0 | -6.691441 | 0.787506 | 2394.0 | -0.620510 |
10 | 19 | 25 | -1620.0 | 234.0 | -6.923077 | 0.775828 | 1845.7 | -0.877716 |
13 | 33 | 16 | -1625.0 | 400.0 | -4.062500 | 0.827957 | 2307.7 | -0.704164 |
2 | 44 | 24 | -1885.7 | 508.0 | -3.712008 | 0.828287 | 2652.2 | -0.710995 |
14 | 55 | 12 | -2048.3 | 398.0 | -5.146482 | 0.776908 | 2813.6 | -0.728000 |
Auf diese Weise wurde nach der optimalen Lösung gesucht, aber es ist nur natürlich, dass 20 Personen seit 100 Generationen, dh fast 2000 Mal, vor Gericht gestellt wurden.
Da es diesmal nur zwei Parameter gibt, nimmt die Anzahl der Kombinationen nicht so stark zu,
SlowMAperiod = np.arange(10, 161) #Bereich der langfristigen gleitenden Durchschnittsperiode
FastMAperiod = np.arange(5, 131) #Bereich des kurzfristigen gleitenden Durchschnittszeitraums
Erhöhen wir es auf 19.026 Möglichkeiten. Ergebnis ist
Slow | Fast | Profit | Trades | Average | PF | MDD | RF | |
---|---|---|---|---|---|---|---|---|
0 | 52 | 48 | 2003.4 | 190.0 | 10.544211 | 1.426773 | 1106.4 | 1.810738 |
5 | 125 | 26 | 1312.6 | 58.0 | 22.631034 | 1.513939 | 896.4 | 1.464302 |
16 | 49 | 47 | 1203.9 | 62.0 | 19.417742 | 1.448046 | 773.0 | 1.557439 |
11 | 56 | 55 | 989.6 | 116.0 | 8.531034 | 1.245266 | 922.0 | 1.073319 |
14 | 52 | 34 | 704.0 | 62.0 | 11.354839 | 1.261632 | 527.2 | 1.335357 |
13 | 152 | 36 | 545.5 | 75.0 | 7.273333 | 1.133198 | 936.5 | 0.582488 |
2 | 140 | 58 | 457.4 | 196.0 | 2.333673 | 1.085960 | 867.1 | 0.527505 |
18 | 40 | 109 | 308.1 | 88.0 | 3.501136 | 1.073977 | 1435.0 | 0.214704 |
6 | 75 | 107 | 255.1 | 78.0 | 3.270513 | 1.066815 | 1145.1 | 0.222775 |
3 | 158 | 85 | 172.7 | 122.0 | 1.415574 | 1.036899 | 1530.6 | 0.112832 |
12 | 68 | 32 | -622.3 | 90.0 | -6.914444 | 0.836838 | 1629.9 | -0.381803 |
10 | 120 | 111 | -638.0 | 37.0 | -17.243243 | 0.787057 | 1233.4 | -0.517269 |
8 | 153 | 30 | -667.3 | 35.0 | -19.065714 | 0.776284 | 1558.8 | -0.428086 |
7 | 43 | 74 | -749.0 | 39.0 | -19.205128 | 0.770245 | 1766.8 | -0.423930 |
15 | 63 | 104 | -774.3 | 92.0 | -8.416304 | 0.835339 | 1692.6 | -0.457462 |
9 | 154 | 56 | -1296.9 | 58.0 | -22.360345 | 0.675945 | 1733.3 | -0.748226 |
1 | 152 | 24 | -1315.2 | 74.0 | -17.772973 | 0.664627 | 2130.3 | -0.617378 |
19 | 155 | 27 | -1363.8 | 60.0 | -22.730000 | 0.672006 | 1474.4 | -0.924986 |
17 | 109 | 40 | -1478.5 | 62.0 | -23.846774 | 0.651379 | 1784.5 | -0.828523 |
4 | 148 | 122 | -1957.4 | 100.0 | -19.574000 | 0.626400 | 2171.4 | -0.901446 |
Recommended Posts