Trailing Stop

 

Hallo,


ich habe da so ein Thema, da verstehe ich nicht, warums nicht immer funktioniert

ich verwende den Hedge modus, soweit so gut, das funktioniert, ich kann beliebig viele Positionen eröffnen.

Jetzt will ich einen Trailingstop testen, und der funktioniert nur Zeitweise, was ich dabei schon gar nicht verstehe, der funktioniert auch im Tester nur Zeitweise


hier mal der Code zum Positionen selektieren


   int PositonsTotal=0; ulong Position_ID=0,ticket=0; double Initial_SL=0;
   if(use_Trailing_Stop==true)
     {
      if(PositionsTotal()>0)
        {
         for(int i=PositionsTotal()-1; i>=0; i--)
           {
            PositionSelect(_Symbol);
            ticket=PositionGetTicket(i);

            if(PositionID_Order(_Symbol,MN,ticket)==ticket)
              {
               if(PositionGetString(POSITION_SYMBOL)== _Symbol &&
                  PositionGetInteger(POSITION_MAGIC)== MN
                  )
                 {
                  Position_ID=PositionGetInteger(POSITION_IDENTIFIER);
                  Initial_SL=NormalizeDouble(MathAbs(Open_Price_Order(_Symbol,MN,Position_ID)-SL_Price_Order(_Symbol,MN,Position_ID))*MathPow(10,_Digits),0);
                  //Print(Open_Price_Order(_Symbol,MN,Position_ID));
                  TrailingStopPosition(_Symbol,Initial_SL,Position_ID);
                  //Print(Initial_SL);
                 }
               else if(PositionID_Order(_Symbol,MN,ticket)==0){TrailingStopPosition(_Symbol,TrailingStop,ticket);}
              }
           }
        }
     }

Die Position ID ist quasi die die ID, aus der ich mir aus der Pending Order die Position ID hole und dann anhand des originalen Stops den SL nachziehe, 

ist wie man bei uns sagt, burgenländisch, geht, geht nicht, geht, ohne eine klare Antwort warums mal geht und mal nicht


jetzt der Code zum Trailing Stop nachziehen


void TrailingStopPosition(const string symbol,const double trailingstop,const ulong Pos_id) //ist eigentlich eine Position Modify funktion, nur eben für den Hedge mode
  {
   MqlTradeRequest request;
   MqlTradeResult  result;

   MqlTick tick;
   if(!SymbolInfoTick(Symbol(),tick)) GetLastError();

   int total=PositionsTotal(); // Anzahl offener Positionen   

   if(PositionSelectByTicket(Pos_id)==true)
     {
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL && 
         NormalizeDouble((tick.bid+trailingstop*_Point),_Digits)<PositionGetDouble(POSITION_SL) &&
         tick.bid <= PositionGetDouble(POSITION_PRICE_OPEN)-TrailingStopOffset*_Point
         )
        {
         // Print(PositionGetDouble(POSITION_SL));
         ZeroMemory(request);
         ZeroMemory(result);
         //--- Parameter der Transaktion setzen
         request.action=TRADE_ACTION_SLTP; // Typ der Transaktion
         request.position = Pos_id;   // das Ticket der Position
         request.symbol = symbol;     // Symbol 
         request.sl=(tick.bid+trailingstop*_Point);                // Stop Loss der Position
         request.tp=PositionGetDouble(POSITION_TP);                // Take Profit der Position

         //Print(PositionGetDouble(POSITION_SL));
         //Print(tick.bid+trailingstop*_Point," ",PositionGetDouble(POSITION_SL));
         // Print("OOP: ", PositionGetDouble(POSITION_PRICE_OPEN)," SL: ", PositionGetDouble(POSITION_SL));
         if(!OrderSend(request,result))
            PrintFormat("OrderSend error %d",GetLastError());  // wenn die Anfrage konnte nicht gesendet werden, den Fehlercode anzeigen
         //--- Details zur Transaktion   
         // PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }

      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY && 
         NormalizeDouble((tick.ask-trailingstop*_Point),_Digits) >PositionGetDouble(POSITION_SL) &&
         tick.ask >= PositionGetDouble(POSITION_PRICE_OPEN)+TrailingStopOffset*_Point 
         )
        {
         // Print(PositionGetDouble(POSITION_SL));
         ZeroMemory(request);
         ZeroMemory(result);
         //--- Parameter der Transaktion setzen
         request.action=TRADE_ACTION_SLTP; // Typ der Transaktion
         request.position = Pos_id;   // das Ticket der Position
         request.symbol = symbol;     // Symbol 
         request.sl=tick.ask-trailingstop*_Point;                // Stop Loss der Position
         request.tp=PositionGetDouble(POSITION_TP);                // Take Profit der Position

         //Print(PositionGetDouble(POSITION_SL));
         // Print(tick.bid-trailingstop*_Point," ",PositionGetDouble(POSITION_SL));
         //  Print("Trailing Done Long");
         if(!OrderSend(request,result))
            PrintFormat("OrderSend error %d",GetLastError());  // wenn die Anfrage konnte nicht gesendet werden, den Fehlercode anzeigen
         //--- Details zur Transaktion   
         // PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }
      //Print("Trailing Done");
     }
  }


das ganze sieht dann im Tester so aus, dazu muss ich sagen, ich steige immer mit OrderAsync in Trades ein, also im Tester jetzt mal zum testen immer eine direkt Order




warum zieht er bei der Order 36 den Stop nach und bei der Order 38 nicht?


der Tester bemüht sich ja nichtmal, sonst würde ich einen Retcode bekommen


 

Ganz ab vom Thema , OrderAsync erfordert die Auswertung der OnTransActions .

Sonst weißt du garnicht ob der Trade geöffnet wurde.

Und sowieso macht diese Methode nur sind bei z.b. triangular arbitrage Sinn.

Über den Rest guck ich später vielleicht mal , falls nicht ein anderder schneller war

 
Christian:

Ganz ab vom Thema , OrderAsync erfordert die Auswertung der OnTransActions .

Sonst weißt du garnicht ob der Trade geöffnet wurde.

Und sowieso macht diese Methode nur sind bei z.b. triangular arbitrage Sinn.

Über den Rest guck ich später vielleicht mal , falls nicht ein anderder schneller war

Hallo Christian,


OrderAsync funktioniert immer, die OnTransActions brauchst Du für das Order setzen nicht, ich mach das schon seit gut 5 Jahren so. mag sein das es nicht ganz sauber ist, aber es funktioniert


anbei noch der EA was erstellt habe, habs hier für die einfachere Auswertung mit den funktionen zusammenkopiert :-)


MT5 Built 1940, die bietet mein Broker gerade an

Dateien:
MQL5.mq5  36 kb
MQL5.ex5  28 kb
 
Hilfe 😂😂😂
 
amando:
Hilfe 😂😂😂

Ich schau es mir an wenn ich wieder an meinen PC rankomme. (Urlaub). Montag.

 

Ich habe mir das von einem EA von mladen kopiert:

...
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\AccountInfo.mqh>

...

double                     m_adjusted_point;                               // point value adjusted for 3 or 5 points
CSymbolInfo                m_symbol;                                       // symbol info object
CAccountInfo               m_account;                                      // account info wrapper
CPositionInfo              m_Pos;                                          // trade position object
CTrade                     m_Trd;                                          // trading object

struct struct €Eavalues { 
...
};
€Eavalues EaValues;


void Trailing() {
   if (EaValues.TrStop == 0.0) return;
   int p = PositionsTotal();
   while(p-->0) { // returns the number of open positions
      if(  !m_Pos.SelectByIndex(p))            continue;
      if(   m_Pos.Symbol()!=m_symbol.Name() 
         || m_Pos.Magic()!=EaValues.Mag)   continue;
         
      if(   m_Pos.PositionType()==POSITION_TYPE_BUY )  { // Buy
         if(   m_Pos.PriceCurrent()-m_Pos.PriceOpen()>EaValues.TrStopStep          // EaValues.TrStopStep=stop+Step
            && m_Pos.StopLoss()<m_Pos.PriceCurrent()-(EaValues.TrStopStep) )  {
               if(!m_Trd.PositionModify(   m_Pos.Ticket(), 
                                                m_symbol.NormalizePrice(m_Pos.PriceCurrent()-EaValues.TrStop),
                                                m_Pos.TakeProfit())
                 )
                 Print("Modify BUY ",m_Pos.Ticket(),
                       " Position -> false. Result Retcode: ",m_Trd.ResultRetcode(),
                       ", description of result: ",m_Trd.ResultRetcodeDescription());
               continue;
            }
      } // Buy
      if(m_Pos.PositionType()==POSITION_TYPE_SELL)  { // SEll
         if(    m_Pos.PriceOpen()-m_Pos.PriceCurrent()>EaValues.TrStopStep         // EaValues.TrStopStep = stop+step   
            &&((m_Pos.StopLoss()>(m_Pos.PriceCurrent()+EaValues.TrStopStep)) || (m_Pos.StopLoss()==0)) ) {
               if(!m_Trd.PositionModify( m_Pos.Ticket(),
                                         m_symbol.NormalizePrice(m_Pos.PriceCurrent()+EaValues.TrStop),
                                         m_Pos.TakeProfit())
                 )
                 Print("Modify SELL ",m_Pos.Ticket(),
                       " Position -> false. Result Retcode: ",m_Trd.ResultRetcode(),
                       ", description of result: ",m_Trd.ResultRetcodeDescription());
            }
      } // else  { //Sell
   } // while p--  
}
//+------------------------------------------------------------------+

Bisschen geändert und das nicht getestet.


PS: Im StrategieTester führt der Modus 1 Minute OHLC zu merkwürdigen Kursen (erscheinen auf dem Chart aber nicht im EA zB) einfach testen mit "Jeder Tick anhand realer Ticks"!

 

Der Ansatz mit OOP von Carl ist sowieso das bessere Konzept.

Da ist alles ,womit sich so Anfänger rumschlagen, ja schon fertig in Standardbibliotheken zu finden ist.

Anhand der wenigen Zeilen sieht man den Sinn von OOP. 


Was ich in dem Code von dir sehen konnte :

Erstens:  Ticket = Position_ID !

Desweiteren werden manche Position nicht getrailt weil der SL sofort greift (Stops zu eng)

Dein Code Stil ist nicht Debugger tauglich. Und das ist meiner Meinung das erste was man lernen sollte.

Desweiteren stellt eine Funktion eine Funktion dar mehr nicht. Funktionen so knapp wie möglich halten.

Du rufst einmal in der OnTick() das MqlTick auf . Mehr brauchst du nicht. Gib es weiter an die entsprechende Funktion.

Wird später erst notwendig bei größeren Codes den Tick direkt vor der Nutzfunktion zu füllen.



Solche Konstrukte vermeiden, auch wenn es schön aussieht. 

Darunter: hier mal eine "Debugger like" Version von der Trailstop. Kurz getestet 

   if(PositionSelectByTicket(Pos_id)==true)
     {
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL && 
         NormalizeDouble((tick.bid+trailingstop*_Point),_Digits)<PositionGetDouble(POSITION_SL) &&
         tick.bid <= PositionGetDouble(POSITION_PRICE_OPEN)-TrailingStopOffset*_Point
         )
 		       {
int TrailPositionStop(const double trailingstop,const ulong ticket,MqlTick &tick)
{
   MqlTradeRequest request;
   MqlTradeResult  result;
    
   ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
   
   switch (posType)  
    {      
      case POSITION_TYPE_SELL:
           {
             double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
             double tp    =  PositionGetDouble(POSITION_TP);    
             double oldSL =  PositionGetDouble(POSITION_SL);
             double newSL =  (tick.bid+trailingstop*_Point);   
                 
             if(NormalizeDouble(newSL,_Digits) < oldSL && tick.bid <= openPrice-TrailingStopOffset*_Point)
                {
                 ZeroMemory(request);
                 ZeroMemory(result);
   
                 request.action=TRADE_ACTION_SLTP;                         // Typ der Transaktion
                 request.position = ticket;                                // das Ticket der Position
                 request.symbol = _Symbol;                                 // Symbol 
                 request.sl = newSL;                                       // Stop Loss der Position
                 request.tp= tp;                // Take Profit der Position
   
                if(!OrderSend(request,result))
                   {
                     PrintFormat("OrderSend error %d",GetLastError());  // wenn die Anfrage konnte nicht gesendet werden, den Fehlercode anzeigen 
                     return -1;    
                   }
                                 
                PrintFormat("*** Posistion Stop Modifyfied *** retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
                }   
                
             return 1;
           }
           
           
           
      case POSITION_TYPE_BUY:
           {
            
             if(NormalizeDouble((tick.ask-trailingstop*_Point),_Digits) > PositionGetDouble(POSITION_SL) && tick.ask <= PositionGetDouble(POSITION_PRICE_OPEN)+TrailingStopOffset*_Point)
                {
                 ZeroMemory(request);
                 ZeroMemory(result);
   
                 request.action=TRADE_ACTION_SLTP;                         // Typ der Transaktion
                 request.position = ticket;                                // das Ticket der Position
                 request.symbol = _Symbol;                                 // Symbol 
                 request.sl=(tick.ask-trailingstop*_Point);                // Stop Loss der Position
                 request.tp=PositionGetDouble(POSITION_TP);                // Take Profit der Position
   
                if(!OrderSend(request,result))
                   {
                     PrintFormat("OrderSend error %d",GetLastError());  // wenn die Anfrage konnte nicht gesendet werden, den Fehlercode anzeigen 
                     return -1;    
                   }
                                 
                PrintFormat("*** Posistion Stop Modifyfied ***  retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
                }              
             return 1;
           }


           
      default:
           {
             PrintFormat(__FUNCSIG__,": Wrong POSITION_TYPE ");
             return -1;
           }
     

     }

 } 

Ich werde keine Fehlersuche machen aber dir Tipps geben sie selber zu finden. 

Ich denke das ist der bessere Ansatz .

Du kannst natürlich gleich auf OOP umschwenken und das Beispiel von Carl nutzen. 

Um deinen Code anzupassen. 

 
amando:


OrderAsync funktioniert immer, die OnTransActions brauchst Du für das Order setzen nicht, ich mach das schon seit gut 5 Jahren so. mag sein das es nicht ganz sauber ist, aber es funktioniert


Sicher funktioniert das aber solche aussagen tätigst du nicht mehr wenn du mal richtig dicken Batzen Geld verlierst :-)

 
Christian:

Sicher funktioniert das aber solche aussagen tätigst du nicht mehr wenn du mal richtig dicken Batzen Geld verlierst :-)

bei meiner Kontogröße ist das noch überschauber ;-)

 

jetzt muss ich mal nachfragen, was meint Ihr 2 mit OOP?


das mit dem Debugger verstehe ich @Christian, das macht wirklich sinn.

Das mit dem Tick auch, wusste nicht, das man den Tick so in der Kopfzeile der Funktion schreiben kann, gefällt mir allerdings, das hab ich schon lange gesucht
 
amando:

jetzt muss ich mal nachfragen, was meint Ihr 2 mit OOP?

OOP heiß Objekt Orientierte Programmierung. Stell Dir vor

  1. Array: alle "Varaiblen" (a[0], a[1],..) haben den gleichem Typ, dann kam
  2. Struct: Variablen mit verschiedenen Typen und als Krönung die
  3. Klassen: Ein "Struct" das auch über Funktionen (hier genannt Methoden) verfügt, dazu ausgefeilte Möglichkeiten die Daten und die Methoden (Zugriff, Änderung, Sichtbarkeit, ..) zu schützen.
  4. So kann man ein reales Objekt inkl. seinem Verhalten als (digitale) Klasse abbilden, daher der Name.
Google mal nach "Einführung in OOP". Viel Spaß damit am Sonntag :)
Grund der Beschwerde: