Geschichten von Handelsrobotern: Ist weniger mehr?
Bevor ich ein Problem lösen kann, muss ich mir erst einmal selbst eingestehen, dass es eins ist. Wenn ich glaube, die Lösung gefunden zu haben, muss ich beweisen, dass ich recht habe.
Ich kenne nur einen Weg, diesen Beweis anzutreten - mit meinem eigenen Geld.
Jesse Livermore
Vorbemerkung
Im Artikel Der letzt Kreuzzug haben wir eine ziemlich interessante, doch derzeit nicht oft eingesetzte Methode zur Anzeige von Marktinformationen untersucht - die Point-&Figure-Charts. Das angebotene Script konnte ein Chart zeichnen. Doch es hat noch keinen automatischen Handel vorgeschlagen. Jetzt können wir versuchen, den Handelsvorgang mit Hilfe des Point-&Figure-Charts zur Analyse und zur Entscheidung über die Richtung und des Handelsvolumens zu automatisieren.
Ich beschreibe hier nicht die grundlegenden Zeichnungsprinzipien, sehen Sie sich einfach ein typisches Chart an:
Copyright (c) 2012-2014 Roman Rich Euro vs US Dollar, Box-20, Reverse-3 1.4588 | \.....\.................................................................... | 1.4588 1.4521 | X\....X\................................................................... | 1.4521 1.4454 | XO\.\.XO\.................................................................. | 1.4454 1.4388 | XOX\X\XO.\................................................................. | 1.4388 1.4322 | XOXOXOXO..\................................................................ | 1.4322 1.4256 | XOXOXOXO...\....\.......................................................... | 1.4256 1.4191 | XOXO/OXO....\...X\......................................................... | 1.4191 1.4125 | XOX/.O/O.....\..XO\........................................................ | 1.4125 1.4060 | XO/../.O......\.XO.\....................................................... | 1.4060 1.3996 | ./.....O.......\XO..\...................................................... | 1.3996 1.3932 | .......OX.......XO...\....................................................X | 1.3932 1.3868 | .......OXO..X.X.XOX...\.................................................X.X | 1.3868 1.3804 | .......OXO..XOXOXOXOX..\..............................................X.XOX | 1.3804 1.3740 | .......OXO..XOXOXOXOXO..\.................................\...........XOXOX | 1.3740 1.3677 | .......OXOX.XO.O.OXOXO...\................................X\..........XOXOX | 1.3677 1.3614 | .......OXOXOX....O.OXO....\...............................XO\.........XOXOX | 1.3614 1.3552 | .......O.OXOX...../OXO.....\..............................XO.\........XOXOX | 1.3552 1.3490 | .........OXOX..../.O.OX.....\.............................XO..\.......XOXO. | 1.3490 1.3428 | .........OXOX.../....OXO.....\X.\.........................XO...\\...X.XOX.. | 1.3428 1.3366 | .........O.OX../.....OXO......XOX\........................XO....X\..XOXOX.. | 1.3366 1.3305 | ...........OX./......OXO....X.XOXO\.....................X.XO....XO\.XOXO... | 1.3305 1.3243 | ...........OX/.......O.O....XOXOXOX\....................XOXO....XO.\XOX.../ | 1.3243 1.3183 | ...........O/..........OX...XOXOXOXO\...................XOXOX.X.XOX.XOX../. | 1.3183 1.3122 | .........../...........OXO..XOXOXOXO.\..........X...X.X.XOXOXOXOXOXOXO../.. | 1.3122 1.3062 | .......................OXOX.XOXO.OXO..\.........XOX.XOXOXOXOXOXOXOXOX../... | 1.3062 1.3002 | .......................O.OXOXO...O/O...\........XOXOXOXOXO.OXO.OXOXO../.... | 1.3002 1.2942 | .........................OXOX..../.O....\.......XOXOXOXOX..OX..OXOX../..... | 1.2942 1.2882 | .........................O.OX.../..O.....\......XOXO.OXO...OX..OXOX./...... | 1.2882 1.2823 | ...........................OX../...OX.....\.....XO...OX.../OX..O/OX/....... | 1.2823 1.2764 | ...........................OX./....OXO.....\....X....OX../.O.../.O/........ | 1.2764 1.2706 | ...........................OX/.....OXO..X...\...X....O../......../......... | 1.2706 1.2647 | ...........................O/......O.OX.XOX..\..X....../................... | 1.2647 1.2589 | .........................../.........OXOXOXO..\.X...../.................... | 1.2589 1.2531 | .....................................OXOXOXO...\X..../..................... | 1.2531 1.2474 | .....................................OXO.OXO....X.../...................... | 1.2474 1.2417 | .....................................OX..O.O..X.X../....................... | 1.2417 1.2359 | .....................................OX....OX.XOX./........................ | 1.2359 1.2303 | .....................................O.....OXOXOX/......................... | 1.2303 1.2246 | ...........................................OXOXO/.......................... | 1.2246 1.2190 | ...........................................OXO./........................... | 1.2190 1.2134 | ...........................................OX.............................. | 1.2134 1.2078 | ...........................................O............................... | 1.2078 1.2023 | ........................................................................... | 1.2023 222222222222222222222222222222222222222222222222222222222222222222222222222 000000000000000000000000000000000000000000000000000000000000000000000000000 111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111112222222222222222222222222222222333333333333333344 ........................................................................... 000000000001111111111111110000000000000000000000011111111000000000000011100 788888899990000001111112221122233445566666677888900001222123444567778901213 ........................................................................... 200011211220111220011231220101212121201112222001100010001002123110112020231 658801925683489071404504193396436668111288937260415979579417630739120547713 000100001012111111110111111100112010210001111101101101011111111101011101110 910501876933613095500253237788652909250001557626626824655375907538165785367 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 550433251023230204310404232105354323532031240033315125241340044324523153453 000000000000000000000000000000000000000000000000000000000000000000000000000
Ich werde nicht anzweifeln, dass in diesem Chart ganz klar Handelsmöglichkeiten sichtbar sind - ich schlage nur vor, dass Sie zwei Handelshypothesen nachprüfen:
Handel mit dem Haupttrend — im Haussenmarkt kaufen und im Baissenmarkt verkaufen.
Stop Losses verwenden, die vor Ihrem Eintritt in den Markt festgelegt werden.
- Kaufen oberhalb der Stützebene mittels Verwendung einer Stop-Order oberhalb des Hochs der vorausgegangenen X-Spalte. Verkaufen unterhalb der Widerstandslinie mittels Verwendung einer Sell-Stop-Order unterhalb des Tiefs der vorausgegangenen O-Spalte und Einsatz eines Trailing Stop an der Pivot-Ebene;
Lassen Sie Ihre Gewinne wachsen.
Schließen Sie Abschlüsse, die Verluste machen (gute Abschlüsse zeigen meist sofortigen Gewinn).
- Kaufen Sie, wenn die Widerstandslinie durchbrochen wird; verkaufen Sie wenn die Stützlinie durchbrochen wird; setzen Sie einen Stop-Loss an der Pivot-Ebene und einen Trailing Stop an der Trendlinie.
Wie wählt man das Volumen?
Achten Sie auf die o.g. Notierungen eines Meisters der Aktienspekulation: arbeiten Sie mit Stop-Orders. Ich steige am liebsten mit einem gewissen Volumen in den Markt ein, sodass der Verlust im Saldo, wenn die Stop Loss-Order ausgelöst wird, nur max. 1 % des Saldos beträgt, den ich akzeptieren kann (Ralph Vince nennt das in Die Mathematik der Geldverwaltung das optimale F). Das Verlustrisiko pro Abschluss ist ein Wert, der gut zu optimieren ist (opt_f im unten stehenden Code).
Daher besitzen wir eine Funktion, die eine Kauf/Verkauf-Order mit dem Volumenberechnungsmechanismus platziert, der vom annehmbaren Risiko pro Abschluss abhängt:
//+------------------------------------------------------------------+ //| The function places an order with a precalculated volume | //+------------------------------------------------------------------+ void PlaceOrder() { //--- Variables for calculating the lot uint digits_2_lot=(uint)SymbolInfoInteger(symbol,SYMBOL_DIGITS); double trade_risk=AccountInfoDouble(ACCOUNT_EQUITY)*opt_f; double one_tick_loss_min_lot=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE_LOSS)*SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP); //--- Fill out the main fields of the request trade_request.magic=magic; trade_request.symbol=symbol; trade_request.action=TRADE_ACTION_PENDING; trade_request.tp=NULL; trade_request.comment=NULL; trade_request.type_filling=NULL; trade_request.stoplimit=NULL; trade_request.type_time=NULL; trade_request.expiration=NULL; if(is_const_lot==true) { order_vol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); } else { order_vol=trade_risk/(MathAbs(trade_request.price-trade_request.sl)*MathPow(10,digits_2_lot)*one_tick_loss_min_lot)*SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP); order_vol=MathMax(order_vol,SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN)); if(SymbolInfoDouble(symbol,SYMBOL_VOLUME_LIMIT)!=0) order_vol=MathMin(order_vol,SymbolInfoDouble(symbol,SYMBOL_VOLUME_LIMIT)); order_vol=NormalizeDouble(order_vol,(int)MathAbs(MathLog10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP)))); } //--- Place an order while(order_vol>0) { trade_request.volume=MathMin(order_vol,SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX)); if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); order_vol=order_vol-SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); }; ticket=trade_result.order; };
Welches Optimierungskriterium soll man verwenden?
Tatsächlich gibt es nur zwei Optimierungskriterien: Minimierung der Inanspruchnahme auf einer gegebenen Renditeebene, oder Maximierung des Saldos für eine gegebene Ebene der Inanspruchnahme. Ich optimiere lieber das zweite Kriterium:
//+------------------------------------------------------------------+ //| Result of strategy run in the testing mode | //+------------------------------------------------------------------+ double OnTester() { if(TesterStatistics(STAT_EQUITY_DDREL_PERCENT)>(risk*100)) return(0); else return(NormalizeDouble(TesterStatistics(STAT_PROFIT),(uint)SymbolInfoInteger(symbol,SYMBOL_DIGITS))); };
wo das Risiko die Stufe der Inanspruchnahme ist, oberhalb derer die Strategie für nicht mehr akzeptabel ist. Dies ist auch eine der Variablen, die optimiert werden muss.
Wann sollte man re-optimieren?
Jemand re-optimiert Strategien in Zeitintervallen (z.B. einmal pro Woche, pro Monat, jemand anderer in Abschlussintervallen (nach 50, 100 Abschlüssen) und wieder ein anderer dann, wenn sich der Markt verändert. Die Notwendigkeit einer Re-Optimierung hängt einzig und allein von dem im vorausgegangenen Abschnitt gewählten Optimierungskriterium ab. Wenn die Inanspruchnahme unter den maximal zugelassenen Risikoparameter fällt, re-optimieren wir die Strategie. Ist alles gut, dann machen wir da gar nichts. Für mich ist eine Inanspruchnahme von mehr als 10% nicht mehr akzeptabel. Daher re-optimiere ich die Arbeitsweise des Systems, sobald es in seinen Abläufen eine größere Inanspruchnahme aufweist.
Kann man alles auf einmal optimieren?
Leider kann man im Strategietester keine externen Variablen für den Modus "Alle in der Marktbeobachtung gewählten Kürzel" optimieren. Daher wählen wir besser die Marktinstrumente zusammen mit anderen externen Variablen aus, die optimiert werden sollen. Das geht folgendermaßen:
//+------------------------------------------------------------------+ //| Enumeration of symbols | //+------------------------------------------------------------------+ enum SYMBOLS { AA=1, AIG, AXP, BA, C, CAT, DD, DIS, GE, HD, HON, HPQ, IBM, IP, INTC, JNJ, JPM, KO, MCD, MMM, MO, MRK, MSFT, PFE, PG, QQQ, T, SPY, UTX, VZ, WMT, XOM }; //+------------------------------------------------------------------+ //| Symbol selection function | //+------------------------------------------------------------------+ void SelectSymbol() { switch(selected_symbol) { case 1: symbol="#AA"; break; case 2: symbol="#AIG"; break; case 3: symbol="#AXP"; break; case 4: symbol="#BA"; break; case 5: symbol="#C"; break; case 6: symbol="#CAT"; break; case 7: symbol="#DD"; break; case 8: symbol="#DIS"; break; case 9: symbol="#GE"; break; case 10: symbol="#HD"; break; case 11: symbol="#HON"; break; case 12: symbol="#HPQ"; break; case 13: symbol="#IBM"; break; case 14: symbol="#IP"; break; case 15: symbol="#INTC"; break; case 16: symbol="#JNJ"; break; case 17: symbol="#JPM"; break; case 18: symbol="#KO"; break; case 19: symbol="#MCD"; break; case 20: symbol="#MMM"; break; case 21: symbol="#MO"; break; case 22: symbol="#MRK"; break; case 23: symbol="#MSFT"; break; case 24: symbol="#PFE"; break; case 25: symbol="#PG"; break; case 26: symbol="#QQQ"; break; case 27: symbol="#T"; break; case 28: symbol="#SPY"; break; case 29: symbol="#UTX"; break; case 30: symbol="#VZ"; break; case 31: symbol="#WMT"; break; case 32: symbol="#XOM"; break; default: symbol="#SPY"; break; }; };
Ggf. können Sie die benötigten Instrumente in die Kürzelauswahlfunktion und die Aufzählung einfügen (die Funktion wird in OnInit() aufgerufen).
Welchen Roboter haben wir jetzt erzeugt?
Kursschwankungs-Handler:
//+------------------------------------------------------------------+ //| A typical ticks handler OnTick() | //| Draw the chart only based on complete bars but first | //| check if it is a new bar. | //| If the bar is new and there is a position, check | //| whether we need to move the stop loss, | //| if the bar is new and no position, check | //| if we have conditions for opening a deal. | //+------------------------------------------------------------------+ void OnTick() { //--- If the bar is new if(IsNewBar()==true) { RecalcIndicators(); //--- Tester/optimizer mode? if((MQLInfoInteger(MQL_TESTER)==true) || (MQLInfoInteger(MQL_OPTIMIZATION)==true)) { //--- Is it the testing period? if(cur_bar_time_dig[0]>begin_of_test) { //--- If there is an open position on the symbol if(PositionSelect(symbol)==true) //--- check if we need to move SL; if need, move it TrailCondition(); //--- If there are no positions else //--- check if we need to open a position; if we need, open it TradeCondition(); } } else { //--- if there is an oprn position on the symbol if(PositionSelect(symbol)==true) //--- check if we need to move SL; if need, move it TrailCondition(); //--- If there are no positions else //--- check if we need to open a position; if we need, open it TradeCondition(); } }; };
Für Strategie 1: "Kaufen oberhalb der Stützebene mittels Verwendung einer Stop-Order oberhalb des Hochs der vorausgegangenen X-Spalte. Verkaufen unterhalb der Widerstandslinie mittels Verwendung einer Sell-Stop-Order unterhalb des Tiefs der vorausgegangenen O-Spalte und Einsatz eines Trailing Stop an der Pivot-Ebene|":
//+------------------------------------------------------------------+ //| Function checks trade conditions for opening a deal | //+------------------------------------------------------------------+ void TradeCondition() { if(order_col_number!=column_count) //--- Are there any orders on the symbol? { if(OrdersTotal()>0) { //--- Delete them! for(int loc_count_1=0;loc_count_1<OrdersTotal();loc_count_1++) { ticket=OrderGetTicket(loc_count_1); if(!OrderSelect(ticket)) Print("Failed to select order #",ticket); if(OrderGetString(ORDER_SYMBOL)==symbol) { trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); }; }; order_col_number=column_count; return; } else { order_col_number=column_count; return; } } else if((MathPow(10,pnf[column_count-1].resist_price)<SymbolInfoDouble(symbol,SYMBOL_ASK)) && (pnf[column_count-1].column_type=='X') && (pnf[column_count-1].max_column_price<=pnf[column_count-3].max_column_price)) { //--- Conditions for BUY met; let's see if there are any pending Buy orders for the symbol with the price we need? trade_request.price=NormalizeDouble(MathPow(10,pnf[column_count-3].max_column_price+double_box),digit_2_orders); trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-3].max_column_price-(reverse-1)*double_box),digit_2_orders); trade_request.type=ORDER_TYPE_BUY_STOP; if(OrderSelect(ticket)==false) //--- No pending orders - place an order { PlaceOrder(); order_col_number=column_count; } else //--- If there is a pending order { //--- what is the type and price of the pending order? if((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP) || ((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP) && (OrderGetDouble(ORDER_PRICE_OPEN)!=trade_request.price))) { //--- The wrong type or the price differs - close the order trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); //--- open with the desired price PlaceOrder(); order_col_number=column_count; }; }; return; } else if((MathPow(10,pnf[column_count-1].resist_price)>SymbolInfoDouble(symbol,SYMBOL_ASK)) && (pnf[column_count-1].column_type=='O') && (pnf[column_count-1].min_column_price>=pnf[column_count-3].min_column_price)) { //--- Conditions for SELL met; let's see if there are any pending Sell orders for the symbol with the price we need? trade_request.price=NormalizeDouble(MathPow(10,pnf[column_count-3].min_column_price-double_box),digit_2_orders); trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-3].min_column_price+(reverse-1)*double_box),digit_2_orders); trade_request.type=ORDER_TYPE_SELL_STOP; if(OrderSelect(ticket)==false) //--- No pending orders, place an order { PlaceOrder(); order_col_number=column_count; } else //--- or there is a pending order { //--- what is the type and price of the pending order? if((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP) || ((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP) && (OrderGetDouble(ORDER_PRICE_OPEN)!=trade_request.price))) { //--- The wrong type or the price differs - close the order trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); //--- and open with the desired price PlaceOrder(); order_col_number=column_count; }; }; return; } else return; }; //+------------------------------------------------------------------+ //| The function checks conditions for moving Stop Loss | //+------------------------------------------------------------------+ void TrailCondition() { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-1].max_column_price-reverse*double_box),digit_2_orders); else trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-1].min_column_price+reverse*double_box),digit_2_orders); if(PositionGetDouble(POSITION_SL)!=trade_request.sl) PlaceTrailOrder(); };
Für Strategie 2: "Kaufen am Durchbruchspunkt der Widerstandslinie; verkaufen am Durchbruchspunkt der Stützlinie; einen Stop-Loss an der Pivot-Ebene und einen Trailing Stop an der Trendlinie setzen":
//+------------------------------------------------------------------+ //| The function checks trade conditions for opening a deal | //+------------------------------------------------------------------+ void TradeCondition() { if(order_col_number!=column_count) //--- Are there any orders for the symbol? { if(OrdersTotal()>0) { //--- Delete them! for(int loc_count_1=0;loc_count_1<OrdersTotal();loc_count_1++) { ticket=OrderGetTicket(loc_count_1); if(!OrderSelect(ticket)) Print("Failed to select order #",ticket); if(OrderGetString(ORDER_SYMBOL)==symbol) { trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); }; }; order_col_number=column_count; return; } else { order_col_number=column_count; return; } } else if(MathPow(10,pnf[column_count-1].resist_price)>SymbolInfoDouble(symbol,SYMBOL_ASK)) { //--- Conditions for BUY met; let's see if there are any pending Buy orders for the symbol with the price we need? trade_request.price=NormalizeDouble(MathPow(10,pnf[column_count-1].resist_price),digit_2_orders); trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-1].resist_price-(reverse-1)*double_box),digit_2_orders); trade_request.type=ORDER_TYPE_BUY_STOP; if(OrderSelect(ticket)==false) //--- No pending orders - place an order { PlaceOrder(); order_col_number=column_count; } else //--- or there is a pending order { //--- what is the type and price of the pending order? if((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP) || ((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP) && (OrderGetDouble(ORDER_PRICE_OPEN)!=trade_request.price))) { //--- The wrong type or the price differs - close the order trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); //--- open with the desired price PlaceOrder(); order_col_number=column_count; }; }; return; } else if(MathPow(10,pnf[column_count-1].resist_price)<SymbolInfoDouble(symbol,SYMBOL_ASK)) { //--- Conditions for SELL met; let's see if there are any pending Sell orders for the symbol with the price we need? trade_request.price=NormalizeDouble(MathPow(10,pnf[column_count-1].supp_price),digit_2_orders); trade_request.sl=NormalizeDouble(MathPow(10,pnf[column_count-1].supp_price+(reverse-1)*double_box),digit_2_orders); trade_request.type=ORDER_TYPE_SELL_STOP; if(OrderSelect(ticket)==false) //--- No pending orders - place an order { PlaceOrder(); order_col_number=column_count; } else //--- If there is a pending order { //--- what is the type and price of the pending order? if((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP) || ((OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP) && (OrderGetDouble(ORDER_PRICE_OPEN)!=trade_request.price))) { //--- The wrong type or the price differs - close the order trade_request.order=ticket; trade_request.action=TRADE_ACTION_REMOVE; if(!OrderSend(trade_request,trade_result)) Print("Failed to send order #",trade_request.order); //--- open with the desired price PlaceOrder(); order_col_number=column_count; }; }; return; } else return; }; //+------------------------------------------------------------------+ //| The function checks conditions for moving Stop Loss | //+------------------------------------------------------------------+ void TrailCondition() { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) trade_request.sl=NormalizeDouble(MathMax(SymbolInfoDouble(symbol,SYMBOL_ASK),MathPow(10,pnf[column_count-1].max_column_price-reverse*double_box)),digit_2_orders); else trade_request.sl=NormalizeDouble(MathMin(SymbolInfoDouble(symbol,SYMBOL_BID),MathPow(10,pnf[column_count-1].min_column_price+reverse*double_box)),digit_2_orders); if(PositionGetDouble(POSITION_SL)!=trade_request.sl) PlaceTrailOrder(); };
Lieber Leser, hier muss ich Sie auf einige Punkte hinweisen.
- Die Kurse von Marktinstrumenten variieren in einer ziemlich großen Bandbreite - von Cents zu Zehntausenden (Beispiele: Aktien und CFDs auf japanischen Börsenplätzen). Daher arbeite ich mit dem Kurslogarithmus für das Point-&Figure-Chart, um für die Boxgröße nicht die Werte von einer bis zu zehntausenden Preisänderungen einstellen zu müssen.
- Die Indizierung des Arrays des Point-&Figure-Charts fängt bei "0" an. Daher ist der Index der letzten Spalte gleich der Anzahl aller Spalten minus einer.
- Der Wert der Stützlinie, falls sie verwendet wird, ist größer als -10,0, doch geringer als der Kurslogarithmus des Kurses. Wird keine Stütz- oder Widerstandslinie verwendet, beträgt ihr Wert im Chart-Array -10,0. Daher werden die Bedingungen für den Durchbruch der Stütz-/Widerstandslinien in ser gleichen Form geschrieben, wie im Code der Strategie Nr. 2 oben.
Der Code für die Hilfsfunktionen findet sich in den Anhängen weiter unten. Der Code für das Chart ist zu umfangreich, daher spare ich ihn mir hier. Ich habe ihn stattdessen samt Kommentaren ebenfalls unten angehängt
Ergebnisse des EA-Handels
In den Dateien symbol_list_1.mhq und smybol_list_2.mhq habe ich zwei Sets Marktkürzel zur Optimierung vorbereitet. Sie umfassen Währungspaare und Aktien-CFDs des Dow Index.
Einrichtungsfenster:
Im ersten Fall sieht das Einrichtungsfenster im Strategietester folgendermaßen aus:
Achten Sie auf die Startzeile des Tests. Der Roboter verlangt mind. ein paar Chartspalten für eine Analyse und Entscheidungsfindung. Und wenn Sie die Boxgröße auf = 50 Preisänderungen oder mehr einstellen, ist oft eine History von 1 Jahr selbst für eine Spalte nicht ausreichend. Daher sollten Sie für Charts mit Boxgröße von 50 Preisänderungen oder mehr aus dem Start des Roboterbetriebs den Zeitraum von ca. 3 Jahren oder mehr verwenden und den Start des Roboterbetriebs in den Teststart-Parametern im Einrichtungsfenster einstellen. In unserem Beispiel müssen Sie für einen Test mit der Boxgröße 100 Preisänderungen seit 01.01.2012 in der Registerkarte "Einstellungen" den Zeitraum seit 01.01.2009 und in der Registerkarte "Parameter" den Zeitraum seit 01.01.2012 einstellen.
Der falsche Wert des Parameters "Minimumposten handeln?" gibt an, das die Postengröße vom Saldo und der Variablen "Risiko pro Handel in %" abhängt (im vorliegenden Fall 1% pro Handel, doch kann dies auch noch optimiert werden). "Max Inanspruchnahme in %" ist das Optimierungskriterium in der OnTester()-Funktion. In diesem Beitrag verwende ich nur zwei Variablen für Optimierung: Kürzel und Boxgröße in Preisänderungen.
Optimierungsperiode: 2012-2013. Der EA läuft am besten auf dem EURUSD-Chart, das dieses Kürzel die beste Kursschwankungsabdeckung liefert. Die unten stehende Tabelle enthält einen kompletten Bericht zum Testen auf verschiedenen Währungspaaren mit Boxgröße 10, auf Basis der ersten Strategie:
Bestanden | Ergebnis | Gewinn | Erwartete Auszahlung | Gewinn-Faktor | Rückfluss-Faktor | Sharpe-Ratio | Angepasst | Eigenkapital, Max % | Handel | ausgewähltes_Kürzel | Feld; |
---|---|---|---|---|---|---|---|---|---|---|---|
0,00 | 0,00 | -1/002,12 | -18,91 | 0,54 | -0,79 | -0,24 | 0,00 | 12,67 | 53,00 | AUDCAD | 10,00 |
1,00 | 886,56 | 886,56 | 14,53 | 1,40 | 1,52 | 0,13 | 886,56 | 5,76 | 61,00 | AUDCHF | 10,00 |
2,00 | 0,00 | -1/451,63 | -10,60 | 0,77 | -0,70 | -0,09 | 0,00 | 19,92 | 137,00 | AUDJPY | 10,00 |
3,00 | -647,66 | -647,66 | -17,50 | 0,57 | -0,68 | -0,24 | -647,66 | 9,46 | 37,00 | AUDNZD | 10,00 |
4,00 | -269,22 | -269,22 | -3,17 | 0,92 | -0,26 | -0,03 | -269,22 | 9,78 | 85,00 | AUDUSD | 10,00 |
5,00 | 0,00 | -811,44 | -13,52 | 0,72 | -0,64 | -0,14 | 0,00 | 12,20 | 60,00 | CADCHF | 10,00 |
6,00 | 0,00 | 1/686,34 | 16,53 | 1,36 | 1,17 | 0,12 | 0,00 | 11,78 | 102,00 | CHFJPY | 10,00 |
7,00 | 356,68 | 356,68 | 5,66 | 1,13 | 0,40 | 0,06 | 356,68 | 8,04 | 63,00 | EURAUD | 10,00 |
8,00 | 0,00 | -1/437,91 | -25,68 | 0,53 | -0,92 | -0,25 | 0,00 | 15,47 | 56,00 | EURCAD | 10,00 |
9,00 | 0,00 | -886,66 | -46,67 | 0,34 | -0,74 | -0,46 | 0,00 | 11,56 | 19,00 | EURCHF | 10,00 |
10,00 | 0,00 | -789,59 | -21,93 | 0,54 | -0,75 | -0,26 | 0,00 | 10,34 | 36,00 | EURGBP | 10,00 |
11,00 | 0,00 | 3/074,86 | 28,47 | 1,62 | 1,72 | 0,20 | 0,00 | 12,67 | 108,00 | EURJPY | 10,00 |
12,00 | 0,00 | -1/621,85 | -19,78 | 0,55 | -0,97 | -0,25 | 0,00 | 16,75 | 82,00 | EURNZD | 10,00 |
13,00 | 152,73 | 152,73 | 2,88 | 1,07 | 0,21 | 0,03 | 152,73 | 6,90 | 53,00 | EURUSD | 10,00 |
14,00 | 0,00 | -1/058,85 | -14,50 | 0,65 | -0,66 | -0,16 | 0,00 | 15,87 | 73,00 | GBPAUD | 10,00 |
15,00 | 0,00 | -1/343,47 | -25,35 | 0,43 | -0,64 | -0,34 | 0,00 | 20,90 | 53,00 | GBPCAD | 10,00 |
16,00 | 0,00 | -2/607,22 | -44,19 | 0,27 | -0,95 | -0,59 | 0,00 | 27,15 | 59,00 | GBPCHF | 10,00 |
17,00 | 0,00 | 1/160,54 | 11,72 | 1,27 | 0,81 | 0,10 | 0,00 | 12,30 | 99,00 | GBPJPY | 10,00 |
18,00 | 0,00 | -1/249,91 | -14,70 | 0,69 | -0,85 | -0,15 | 0,00 | 14,41 | 85,00 | GBPNZD | 10,00 |
19,00 | 208,94 | 208,94 | 5,36 | 1,12 | 0,25 | 0,05 | 208,94 | 7,81 | 39,00 | GBPUSD | 10,00 |
20,00 | 0,00 | -2/137,68 | -21,17 | 0,53 | -0,79 | -0,24 | 0,00 | 25,62 | 101,00 | NZDUSD | 10,00 |
21,00 | 0,00 | -1/766,80 | -38,41 | 0,30 | -0,97 | -0,53 | 0,00 | 18,10 | 46,00 | USDCAD | 10,00 |
22,00 | -824,69 | -824,69 | -11,95 | 0,73 | -0,90 | -0,13 | -824,69 | 9,11 | 69,00 | USDCHF | 10,00 |
23,00 | 2/166,53 | 2/166,53 | 26,10 | 1,58 | 2,40 | 0,18 | 2/166,53 | 7,13 | 83,00 | USDJPY | 10,00 |
2/029,87 | -10/213,52 | 13,40 | 1/659,00 |
Hier ist die tabellarische Zusammenfassung für verschiedene Kürzel und Boxgrößenwerte:
Strategie | Kürzel | Boxgröße | Handel | Eigenkapital, Max % | Gewinn | Ergebnis | Erwarteter Saldo |
---|---|---|---|---|---|---|---|
1 | Währungen | 10 | 1/659 | September | -10/214 | 2/030 | 2/030 |
1 | Währungen | 20 | 400 | 5 | 1/638 | 2/484 | 2/484 |
1 | Aktien | 50 | 350 | 60 | 7/599 | 7/599 | 15/199 |
1 | Aktien | 100 | 81 | 2 | 4/415 | 4/415 | 17/659 |
2 | Währungen | 10 | 338 | 20 | -4/055 | 138 | 138 |
2 | Währungen | 20 | 116 | 8 | 4/687 | 3/986 | 3/986 |
2 | Aktien | 50 | 65 | 6 | 6/770 | 9/244 | 9/244 |
2 | Aktien | 100 | 12 | 1 | -332 | -332 | -5/315 |
Was sehen wir?
Es gibt Narren, die es immer falsch machen.
Und es gibt Narren in der Wall Street, die glauben, man sollte immer handeln.
Es gibt niemanden auf der ganzen Welt, der immer alle notwendigen Informationen besitzt, um Aktien zu kaufen oder zu verkaufen und dies auch noch vernünftig machen zu können.
Die Folgerung daraus mag Sie verwundern: je weniger Sie handeln, umso größer ist die Wahrscheinlichkeit, dass Ihr Depot ansteigt. Hätten wir vor zwei Jahren unseren EA Aktien mit Boxgröße 100 und einem Risiko pro Handel von 1% handeln lassen, hätte der EA bislang nur 81 Abschlüsse gemacht (~ 1,25 Abschlüsse pro Kürzel pro Jahr) und wäre unser Depot um 44% angestiegen, mit einer durchschnittlichen Kapitalinanspruchnahme von etwas mehr als 2%. Da wir eine mögliche Inanspruchnahme von 10% hätten akzeptieren können, hätten wir pro Abschluss 4% riskieren können und unser Depot wäre allein in diesen zwei Jahren um 177% angestiegen - also 90% pro Jahr in US Dollar!!
Nachwort
Der Kurs ist niemals zu hoch, um zu kaufen und niemals zu niedrig, um zu verkaufen.
Nicht Denken führt zum großen Geld. Sondern sitzen.
Die oben beschriebenen Strategien können verändert werden und zeigen bei einer Inanspruchnahme von max. 10% eine noch größere Rendite. Halten Sie sich beim Handel zurück, versuchen Sie lieber einen Makler zu finden, der nicht nur ein "Standard-Set" an Kürzeln von zwei Dutzend Währungspaaren und drei Dutzend Aktien anbietet, sondern mind. drei- bis vierhundert dieser Kürzel (Aktien, Termingeschäfte). Die Wahrscheinlichkeit, dass diese Kürzel miteinander korrelieren ist größer und Ihr Depot ist sicherer. Noch eine letzte Bemerkung - Aktien liefern bessere Ergebnisse als Währungspaare.
PS (Werbung in eigener Sache)
Mein PnF Chartist Script steht im Market zur Verfügung. Es zeichnet mit Hilfe von Notierungen von MT4, MT5 oder Yahoo Finance, Point- & Figure-Charts in Textdateien. Verwenden Sie es für eine visuelle Suche nach Kursmustern, denn nichts ist ein besserer Tester/Optimierer als Ihr eigenes Gehirn. Sobald Sie auf Muster stoßen, verwenden Sie EA-Templates aus diesem Beitrag, die Ihre Ideen beweisen werden.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/910
- 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.