
Der Filter auf basis der History
Einführung
Es gibt verschiedene Filter: Werte der Indikatoren, Marktvolatilität, Zeit, Wochentag. Sie können alle für die Sortierung der verlustbringenden Trades verwenden. Und es ist ganz einfach, einen solchen Filter im Expert Advisor hinzuzufügen - fügen Sie einfach eine Bedingung vor der Block-Eröffnung.
Aber was sollte getan werden, wenn Sie die EA-History als Filter verwenden möchten? Wenn Sie Ihr Handelssystem nach mehreren erfolglosen Trades ausschalten, werden Sie keine spätere History haben, und deshalb gibt es dann nichts zu analysieren. Zur Lösung dieses Problems müssen wir den Expert Advisor einstellen, damit er virtuell handelt, das heißt, er muss; eine Eröffnung, eine Modifizierung und Schließung der Trades ohne echte Handelsaktivitäten simulieren.
Der Artikel widmet sich diesem Thema.
Experimentelle Strategie
Um unser System zu realisieren, machen wir einige Änderungen im Advisor CrossMACD_DeLuxe.mq4:
- bei der Eröffnung/ Modifizierung / Schließung jeder Position, werden wir Änderungen im Array von virtuellen Positionen schreiben;
- Fügen wir eine Verfolgung der StopLoss und Takeprofit Auslösung von virtuellen Positionen hinzu;
- Fügen wir Filterkriterium hinzu - eine Bedienung, bei deren Erfüllung reale Trades nicht geöffnet werden.
Ich werde versuchen, jeden Schritt der EA-Bearbeitung möglichst in Details zu beschreiben. Aber wenn Sie sich dafür nicht interessieren, können Sie einfach den fertigen Expert Advisor herunterladen und zum Abschnitt "Die Sache lohnt nicht" überspringen.
Berechnung der virtuellen Positionen
Also, es erschien ein Signal eine Position zu öffnen. Die Parameter Stoploss und Takeprofit wurden bereits berechnet und alles ist bereit, die Funktion OrderSend() aufzurufen. Genau in diesem Moment öffnen wir ein virtuelles Trade - müssen wir einfach nur alle notwendigen Parameter der Position in entsprechenden Variablen speichern:
void OpenBuy() { int _GetLastError = 0; double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel; _OpenPriceLevel = NormalizeDouble(Ask, Digits); if(StopLoss > 0) _StopLossLevel = NormalizeDouble(_OpenPriceLevel - StopLoss*Point, Digits); else _StopLossLevel = 0.0; if(TakeProfit > 0) _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + TakeProfit*Point, Digits); else _TakeProfitLevel = 0.0; //---- Eröffnen die virtuelle Position virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel); if(OrderSend(Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, _StopLossLevel, _TakeProfitLevel, "CrossMACD", _MagicNumber, 0, Green) < 0) { _GetLastError = GetLastError(); Alert("Der Fehler OrderSend № ", _GetLastError); return(-1); } } //---- Speichern wir die Parameter der geöffneten Position in Hauptvariablen void virtualOrderSend(int type, double openprice, double stoploss, double takeprofit) { virtTicket = 1; virtType = type; virtOpenPrice = openprice; virtStopLoss = stoploss; virtTakeProfit = takeprofit; }
Wie Sie sehen können, verwenden wir nur fünf Variable:
int virtTicket = 0; // Es bestimmt, ob es eine geöffnete virtuelle Position gibt int virtType = 0; // Der Typ der Position double virtOpenPrice = 0.0; // der Eröffnungskurs der Position double virtStopLoss = 0.0; // Stoploss der Position double virtTakeProfit = 0.0; // Takeprofit der Position
Wir brauchen keine anderen Parameter für die Lösung unserer Aufgabe. Wenn Sie alle Funktionen in diesem Beispiel erweitern wollen, fügen Sie einfach die notwendige Anzahl der Variablen hinzu.
Um die Schließung und Modifizierung der Position zu kontrollieren, müssen wir noch etwas tun. Kopieren Sie den Kontrollblock der geöffneten Positionen, den im Expert Advisor gibt, und wechseln Sie die Parameter der realen Orders in virtuellen:
int start() { // skipped... //+------------------------------------------------------------------+ //|Der Kontrollblock der "virtuellen" Positionen | //+------------------------------------------------------------------+ if(virtTicket > 0) { //---- wenn die Buy-Position geöffnet ist, if(virtType == OP_BUY) { //---- wenn MACD die 0-Linie runter gekreuzt hat, if(NormalizeDouble(MACD_1 + CloseLuft*Point*0.1, Digits + 1) <= 0.0) { //---- Schließen wir die Position virtOrderClose(Bid); } //---- wenn das Signal sich nicht ändert, begleiten wir die Position // von Trailingstop else { if(TrailingStop > 0) { if(NormalizeDouble(Bid - virtOpenPrice, Digits ) > 0.0) { if(NormalizeDouble( Bid - TrailingStop*Point - virtStopLoss, Digits) > 0.0 || virtStopLoss < Point) { virtStopLoss = Bid - TrailingStop*Point; } } } } } //---- wenn die SELL-Position geöffnet ist, if(virtType == OP_SELL) { //---- wenn MACD die 0-Linie nach oben gekreuzt hat, if(NormalizeDouble(MACD_1 - CloseLuft*Point*0.1, Digits + 1 ) >= 0.0) { //---- Schließen wir die Position virtOrderClose(Ask); } //---- wenn das Signal sich nicht ändert, begleiten wir die Position // von Trailingstop else { if ( TrailingStop > 0 ) { if(NormalizeDouble( virtOpenPrice - Ask, Digits ) > 0.0 ) { if(NormalizeDouble( virtStopLoss - ( Ask + TrailingStop*Point ), Digits ) > 0.0 || virtStopLoss <= Point ) { virtStopLoss = Ask + TrailingStop*Point; } } } } } } // skipped... return(0); } //---- Die Schließfunktion der virtuellen Position void virtOrderClose(double closeprice) { //---- Speichern wir die Parameter der geschlossenen Position im Array ArrayResize(virtClosedOrders, virtClosedOrdersCount + 1); virtClosedOrders[virtClosedOrdersCount][0] = virtType; virtClosedOrders[virtClosedOrdersCount][1] = virtOpenPrice; virtClosedOrders[virtClosedOrdersCount][2] = virtStopLoss; virtClosedOrders[virtClosedOrdersCount][3] = virtTakeProfit; virtClosedOrders[virtClosedOrdersCount][4] = closeprice; virtClosedOrdersCount ++; //---- Löschung der Variable virtTicket = 0; virtType = 0; virtOpenPrice = 0.0; virtStopLoss = 0.0; virtTakeProfit = 0.0; }
Sie sehen, dass die Modifizierung einfach einer neuen Wert-Verleihung der Variable virtStopLoss geworden. Und die Schließung ist ziemlich kompliziert - alle Parameter der geschlossenen Order werden im Array gespeichert. Später wird da die gesamte virtuelle History gespeichert. Daraus werden wir die Informationen über die geschlossenen Trades nehmen, um die Entscheidung bezüglich der Eröffnung einer neuen Position zu treffen.
Jetzt müssen wir Schließung der Positionen unter Stoploss und Takeprofit bearbeiten. Zu diesem Zweck fügen wir einige Zeile im erstellten Kontrollblock der virtuellen Positionen hinzu:
if(virtType == OP_BUY) { //---- Überprüfen, ob SL nicht aktiviert wurde if(virtStopLoss > 0.0 && NormalizeDouble(virtStopLoss - Bid, Digits ) >= 0.0) { virtOrderClose(virtStopLoss); } //---- Überprüfen, ob TPL nicht aktiviert wurde if(virtTakeProfit > 0.0 && NormalizeDouble( Bid - virtTakeProfit, Digits ) >= 0.0) { virtOrderClose(virtTakeProfit); } }
Jetzt ist unsere virtuelle History fertig und wir können Filterkriterium hinzufügen.
Was ist "gut" und was ist "schlecht"?
Wir müssen die Positionsöffnung untersagen, nachdem eine bestimmte Bedingung erfüllt wird. Aber welche Bedingung muss man wählen? Mehrere verlustbringenden Trades nacheinander, die Stoploss-Aktivierung oder die Reduzierung des durchschnittlichen Gewinns von mehreren letzten Trades? Es ist schwer, sicher zu beantworten - jede Variante kann ihre Vor- und Nachteile haben.
Zur Überprüfung der Effizienz bei jeder einzelnen Bedingung, lassen Sie uns versuchen, alle drei über die History zu testen:
extern int TradeFiltrVariant = 0; //---- Die Überprüfungsfunktion, ob das reale Handeln notwendig ist oder nicht bool virtCheckCondition() { int pos, check_pos = 2; double last_profit = 0.0, pre_last_profit = 0.0; //---- Je nach dem Wert des TradeFiltrVariant: switch(TradeFiltrVariant) { //---- 1: Wir verbieten das reale Handeln, wenn zwei letzten Trades verlustbringende waren case 1: { //---- Wenn die virtuelle History genügend Orders enthält, if(virtClosedOrdersCount >= check_pos) { for(pos = 1; pos check_pos; pos ++) { //---- Wenn der Trade profitabel ist, liefern true zurück if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && virtClosedOrders[virtClosedOrdersCount-pos][4] - virtClosedOrders[virtClosedOrdersCount-pos][1] >= 0.0) || (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && virtClosedOrders[virtClosedOrdersCount-pos][1] - virtClosedOrders[virtClosedOrdersCount-pos][4] >= 0.0)) { return(true); } } } return(false); } //---- 2: Wir verbieten das reale Handeln, wenn die letzte Position geschlossen wurde // über Stoploss case 2: { //---- Wenn die virtuelle History genügend Orders enthält, if(virtClosedOrdersCount > 0) { //---- Wenn der Schlusskurs der letzten Order mit Stoploss gleich ist, if(virtClosedOrders[virtClosedOrdersCount-1][2] - virtClosedOrders[virtClosedOrdersCount-1][4] < Point && virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][2] < Point) { return(false); } } return(true); } //---- 3: Wir verbieten das reale Handeln, wenn der Gewinn der letzten Position //---- ist geringer als bei der vorletzten Position (oder Verlust höher ist) case 3: { if(virtClosedOrdersCount >= 2) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0) { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - virtClosedOrders[virtClosedOrdersCount-2][1]; } else { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - virtClosedOrders[virtClosedOrdersCount-2][4]; } if(pre_last_profit - last_profit > 0.0) { return(false); } } return(true); } //---- Standardmäßig ist der Filter ausgeschaltet, das heißt, die Position wird immer in der Realität geöffnet default: return(true); } return(true); } void OpenBuy() { int _GetLastError = 0; double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel; _OpenPriceLevel = NormalizeDouble(Ask, Digits); if(StopLoss > 0) { _StopLossLevel = NormalizeDouble(_OpenPriceLevel - StopLoss*Point, Digits); } else { _StopLossLevel = 0.0; } if(TakeProfit > 0) { _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + TakeProfit*Point, Digits); } else { _TakeProfitLevel = 0.0; } //---- Eröffnen die virtuelle Position virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel); //---- Wenn der Filter der virtuellen Positionen das Handeln verbietet, verlassen wir es if(virtCheckCondition() == false) { return(0); } if(OrderSend( Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, _StopLossLevel, _TakeProfitLevel, "CrossMACD", _MagicNumber, 0, Green) < 0 ) { _GetLastError = GetLastError(); Alert("Der Fehler OrderSend № ", _GetLastError); return(-1); } }
Wie Sie sehen können, haben wir jetzt eine externe Variable TradeFiltrVariant. Sie ist verantwortlich dafür, welches Filterkriterium ausgewählt wird:
extern int TradeFiltrVariant = 0; //---- 0: der Filter ist ausgeschaltet, das heißt, die Position wird immer in der Realität geöffnet //---- 1: Wir verbieten das reale Handeln, wenn zwei letzten Trades verlustbringende waren //---- 2: Wir verbieten das reale Handeln, wenn die letzte Position über Stopploss geschlossen wurde //---- 3: Wir verbieten das reale Handeln, wenn der Gewinn der letzten Position, //---- ist geringer als bei der vorletzten Position (oder Verlust höher ist)
Testen Sie nun den Expert Advisor mit verschiedenen Filtern und vergleichen Sie die Ergebnisse.
Die Sache lohnt nicht?
Zum Testen habe ich die folgenden Parameter ausgewählt:
- Symbol: GBPUSD
- Die Periode: Н4, 01.01.2005 - 01.01.2006
- Modellierung: Alle Ticks (Modellierungsqualität 90%, Notierungen HistoryCenter)
- EA-Parameter:
- StopLoss: 50
- TakeProfit: 0 (deaktiviert)
- TrailingStop: 0 (deaktiviert)
- FastEMAPeriod: 12
- SlowEMAPeriod: 26
- OpenLuft: 10
- CloseLuft: 0
Die folgende Tabelle zeigt die Abhängigkeit der Ergebnisse vor dem ausgewählten Filter:
TradeFiltrVariant | Der gesamte Gewinn/Verlust | Trades insgesamt | Gewinn-Trades | Verlust-Trades |
---|---|---|---|---|
0 |
1678.75 | 41 | 9 (22%) | 32 (78%) |
1 |
105.65 | 20 | 2 (10%) | 18 (90%) |
2 |
-550.20 | 11 | 0 (0%) | 11 (100%) |
3 |
1225.13 | 28 | 7 (25%) | 21 (75%) |
Wie Sie sehen können, die Theorie über die Nützlichkeit des Filters noch nicht bestätigt wurde. Darüber hinaus sind die Ergebnisse, die mit dem Filter bekommen wurden, sind schlechter als ohne Filter. Die einzige Ausnahme ist die dritte Variante - die hat den höheren Gewinn-Trades (25% gegen 22%), aber der Gesamtgewinn ist in allen drei Varianten niedriger.
Was haben wir denn falsch gemacht? Wahrscheinlich haben wir falsche Filterkriteriums ausgewählt. Lassen Sie uns versuchen, alle drei Filter in Gegenteil zu ändern, das heißt, das reale Handeln deaktivieren, wenn:
- zwei letzten Trades profitabel waren;
- die letzte Position profitabel ist (wir haben kein Analog mit Stoploss, weil Takeprofit deaktiviert ist);
- oder der Gewinn aus der letzten Position höher ist, als bei der vorletzten Position.
Um den Expert Advisor nicht zu reduzieren, fügen Sie einfach noch drei weitere Werte von TradeFiltrVariant - 4, 5 und 6:
//---- 4: Wir verbieten das reale Handeln, wenn zwei letzten Trades profitabel waren //---- 5: Wir verbieten das reale Handeln, wenn der letzte Trade profitabel war //---- 6: das reale Handeln verbieten, wenn der Gewinn der letzten Position, //---- höher ist als bei der vorletzten Position (oder Verlust geringer ist) //---- 4: Wir verbieten das reale Handeln, wenn zwei letzten Trades profitabel waren case 4: { if(virtClosedOrdersCount >= check_pos) { for(pos = 1; pos check_pos; pos ++) { //---- Wenn der Trade verlustbringende ist, liefern true zurück if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && virtClosedOrders[virtClosedOrdersCount-pos][1] - virtClosedOrders[virtClosedOrdersCount-pos][4] > 0.0) || (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && virtClosedOrders[virtClosedOrdersCount-pos][4] - virtClosedOrders[virtClosedOrdersCount-pos][1] > 0.0)) { return(true); } } } return(false); } //---- 5: Wir verbieten das reale Handeln, wenn der letzte Trade profitabel war case 5: { if(virtClosedOrdersCount >= 1) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(last_profit > 0.0) { return(false); } } return(true); } //---- 6: das reale Handeln verbieten, wenn der Gewinn der letzten Position, //---- höher ist als bei der vorletzten Position (oder Verlust geringer ist) case 6: { if(virtClosedOrdersCount >= 2) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0) { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - virtClosedOrders[virtClosedOrdersCount-2][1]; } else { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - virtClosedOrders[virtClosedOrdersCount-2][4]; } if(last_profit - pre_last_profit > 0.0) { return(false); } } return(true); }
Nun wollen wir drei neue Varianten testen und Sie fügen die in unsere Tabelle hinzu:
AdaptVariant | Der gesamte Gewinn/Verlust | Trades insgesamt | Gewinn-Trades | Verlust-Trades |
---|---|---|---|---|
0 | 1678.75 |
41 | 9 (22%) |
32 (78%) |
1 | 105.65 | 20 | 2 (10%) |
18 (90%) |
2 | -550.20 | 11 | 0 (0%) |
11 (100%) |
3 | 1225.13 | 28 | 7 (25%) |
21 (75%) |
4 |
1779.24 |
39 | 9 (23%) | 30 (77%) |
5 |
2178.95 |
31 |
9 (29%) |
22 (71%) |
6 |
602.32 |
24 |
5 (21%) |
19 (79%) |
Die sechste Variante hat die Hälfte der Trades sortiert - sowohl rentablen als auch verlustbringenden. Die vierte Variante hat zwei verlustbringenden Trades entfernt, der Gesamtgewinn wurde dadurch um 100,49 $ erhöht.
Und die beste war die Variante, die mit dem Verbot des Handelns nach jedem profitablen Trade ist - der Filter hat 10 verlustbringenden Trades entfernt und keinen profitable Trade.
Also, es gibt eine Hoffnung - dass man sogar eine solche einfache und beliebte Strategie verbessern kann!
Schlussfolgerungen
Ich denke, um das System echt zu verbessern, sind solche Filter nicht genug - man muss noch eine viel tiefer Forschung durchführen und neue Schlüsse ziehen.
Die berechneten Filter können daraufhin noch komplizierter sein und auch absolut anders für jede Strategie. Ihre Wirksamkeit hängt direkt von der Abwechslung von profitablen und verlustbringenden Positionen ab.
In diesem Artikel habe ich nur etwas das Thema über Filter betrachtet und hoffe, dass es ein Impuls für die weitere Entwicklung dieses Themas sein wird.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1441





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.