TrailingStopAndTake

Author: Copyright 2018, MetaQuotes Software Corp.
Price Data Components
Series array that contains open time of each bar
Orders Execution
It automatically opens orders when conditions are reached
0 Views
0 Downloads
0 Favorites
TrailingStopAndTake
ÿþ//+------------------------------------------------------------------+

//|                                          TrailingStopAnfTake.mq5 |

//|                        Copyright 2018, MetaQuotes Software Corp. |

//|                                                 https://mql5.com |

//+------------------------------------------------------------------+

#property copyright "Copyright 2018, MetaQuotes Software Corp."

#property link      "https://mql5.com"

#property version   "1.01"

//--- enums

enum ENUM_INPUT_YES_NO

  {

   INPUT_YES   =  1,                   // Yes

   INPUT_NO    =  0                    // No

  };

//+------------------------------------------------------------------+

//|                                                                  |

//+------------------------------------------------------------------+

enum ENUM_INPUT_TYPE

  {

   TYPE_ALL    =  WRONG_VALUE,         // Any position

   TYPE_BUY    =  POSITION_TYPE_BUY,   // Buy position

   TYPE_SELL   =  POSITION_TYPE_SELL   // Sell position

  };

//--- input parameters

sinput   uint              InpInitStop       =  400;        // Initial StopLoss size in points (0 - no stop)

sinput   uint              InpInitTake       =  400;        // Initial TakeProfit size in points (0 - no take)

sinput   uint              InpStopLoss       =  200;        // TrailingStop size in points (0 - no trail)

sinput   uint              InpTakeProfit     =  200;        // TrailingTake size in points (0 - no trail)

sinput   ENUM_INPUT_TYPE   InpPositionType   =  TYPE_ALL;   // Positions type

sinput   string            InpTrailingSymbol =  "";         // Positions symbol ("" - any symbol)

sinput   long              InpTrailingMagic  =  0;          // Positions magic number (0 - any magic)

sinput   ulong             InpTrailingTicket =  0;          // Position ticket (0 - all tickets)

sinput   uint              InpTrailingStep   =  10;         // Trailing step

sinput   ENUM_INPUT_YES_NO InpTrailingLoss   =  INPUT_NO;   // Trailing in the unprofitable zone

sinput   int               InpBreakevenPT    =  6;          // Breakeven in points

sinput   uint              InpSizeSpread     =  2;          // Spread multiplier

//--- global variables

MqlTradeRequest   g_request;     // !B@C:BC@0 B>@3>2>3> 70?@>A0 (4;O ?@>25@:8 2 B5AB5@5)

MqlTradeResult    g_result;      // !B@C:BC@0 @57C;LB0B0 B>@3>2>3> 70?@>A0 (4;O ?@>25@:8 2 B5AB5@5)

int               size_spread;   // =>68B5;L A?@540

datetime          prev_time;     // @54K4CI55 2@5<O >B:@KB8O 10@0

//--- includes

#include <Trade\Trade.mqh>       // ">@3>2K9 :;0AA (4;O ?@>25@:8 2 B5AB5@5)

//--- objects

CTrade   trade;                  // 1J5:B-CTrade (4;O ?@>25@:8 2 B5AB5@5)

//+------------------------------------------------------------------+

//| Expert initialization function                                   |

//+------------------------------------------------------------------+

int OnInit()

  {

//--- @>25@:0 B8?0 AGQB0

   if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)

     {

      Print("Netting-account. EA should work on a hedge account.");

      return INIT_FAILED;

     }

//--- #AB0=>2:0 7=0G5=89 ?5@5<5==KE

   size_spread=int(InpSizeSpread<1 ? 1 : InpSizeSpread);

   prev_time=0;

//--- #A?5H=0O 8=8F80;870F8O

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+

//| Expert deinitialization function                                 |

//+------------------------------------------------------------------+

void OnDeinit(const int reason)

  {

//---



  }

//+------------------------------------------------------------------+

//| Expert tick function                                             |

//+------------------------------------------------------------------+

void OnTick()

  {

//--- 

   if(MQLInfoInteger(MQL_TESTER))

     {

      static ulong mn=0;

      if(prev_time!=Time(0))

        {

         mn++;

         trade.SetExpertMagicNumber(mn);

         if(InpPositionType==TYPE_ALL || InpPositionType==TYPE_BUY)

            trade.Buy(0.1);

         if(InpPositionType==TYPE_ALL || InpPositionType==TYPE_SELL)

            trade.Sell(0.1);

         prev_time=Time(0);

        }

     }

   Trailing();

  }

//+------------------------------------------------------------------+

//| $C=:F8O B@59;8=30                                                |

//+------------------------------------------------------------------+

void Trailing(void)

  {

   int   total=PositionsTotal();

   for(int i=total; i>=0; i--)

     {

      ulong ticket=PositionGetTicket(i);

      if(ticket==0) continue;

      ulong  magic_number=(ulong)PositionGetInteger(POSITION_MAGIC);

      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

      if(InpPositionType>WRONG_VALUE && type!=(ENUM_POSITION_TYPE)InpPositionType) continue;

      string symbol_name=PositionGetString(POSITION_SYMBOL);

      if(!Condition(symbol_name,magic_number,ticket)) continue;

      double point=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

      if(point==0) continue;

      int    digits=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

      double op_position=PositionGetDouble(POSITION_PRICE_OPEN);

      double tp_position=PositionGetDouble(POSITION_TP);

      double sl_position=PositionGetDouble(POSITION_SL);

      double take_profit=0;

      double stop_loss=0;

      double step=InpTrailingStep*point;

      double price=0,breakeven=0;

      

   //--- >:C?:8

      if(type==POSITION_TYPE_BUY)

        {

      //--- "@0; StopLoss Buy

         if(sl_position==0)

           {

            int sl=int(InpInitStop>0 ? InpInitStop : InpStopLoss>0 ? InpStopLoss : 0);

            if(sl>0)

              {

               stop_loss=CorrectStopLoss(symbol_name,POSITION_TYPE_BUY,op_position-sl*point,op_position);

               if(!PositionModifyByTicket(symbol_name,ticket,stop_loss,tp_position))

                  Print("Position Buy #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

              }

           }

         else

           {

            if(InpStopLoss>0)

              {

               breakeven=NormalizeDouble(op_position+InpBreakevenPT*point,digits);

               price=SymbolInfoDouble(symbol_name,SYMBOL_ASK);

               stop_loss=NormalizeDouble(price-InpStopLoss*point,digits);

               if(!InpTrailingLoss && NormalizeDouble(stop_loss-breakeven,digits)<0) continue;

               if(stop_loss>sl_position+step && CheckCorrectStopLoss(symbol_name,POSITION_TYPE_BUY,stop_loss))

                 {

                  if(!PositionModifyByTicket(symbol_name,ticket,stop_loss,tp_position))

                     Print("Position Buy #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

                 }

              }

           }

      //--- "@0; TakeProfit Buy

         if(tp_position==0)

           {

            int tp=int(InpInitTake>0 ? InpInitTake : InpTakeProfit>0 ? InpTakeProfit : 0);

            if(tp>0)

              {

               take_profit=CorrectTakeProfit(symbol_name,POSITION_TYPE_BUY,op_position+tp*point,op_position);

               if(!PositionModifyByTicket(symbol_name,ticket,sl_position,take_profit))

                  Print("Position Buy #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

              }

           }

         else

           {

            if(InpTakeProfit>0)

              {

               breakeven=NormalizeDouble(op_position+InpBreakevenPT*point,digits);

               price=SymbolInfoDouble(symbol_name,SYMBOL_ASK);

               take_profit=NormalizeDouble(price+InpTakeProfit*point,digits);

               if(!InpTrailingLoss && NormalizeDouble(take_profit-breakeven,digits)<0) take_profit=breakeven;

               if(take_profit<tp_position-step && CheckCorrectTakeProfit(symbol_name,POSITION_TYPE_BUY,take_profit))

                 {

                  if(!PositionModifyByTicket(symbol_name,ticket,sl_position,take_profit))

                     Print("Position Buy #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

                 }

              }

           }

        }

      //--- @>4068

      else

        {

      //--- "@0; StopLoss Sell

         if(sl_position==0)

           {

            int sl=int(InpInitStop>0 ? InpInitStop : InpStopLoss>0 ? InpStopLoss : 0);

            if(sl>0)

              {

               stop_loss=CorrectStopLoss(symbol_name,POSITION_TYPE_SELL,op_position+sl*point,op_position);

               if(!PositionModifyByTicket(symbol_name,ticket,stop_loss,tp_position))

                  Print("Position Sell #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

              }

           }

         else

           {

            if(InpStopLoss>0)

              {

               breakeven=NormalizeDouble(op_position-InpBreakevenPT*point,digits);

               price=SymbolInfoDouble(symbol_name,SYMBOL_BID);

               stop_loss=NormalizeDouble(price+InpStopLoss*point,digits);

               if(!InpTrailingLoss && NormalizeDouble(breakeven-stop_loss,digits)<0) continue;

               if(stop_loss<sl_position-step && CheckCorrectStopLoss(symbol_name,POSITION_TYPE_SELL,stop_loss))

                 {

                  if(!PositionModifyByTicket(symbol_name,ticket,stop_loss,tp_position))

                     Print("Position Sell #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

                 }

              }

           }

      //--- "@0; TakeProfit Sell

         if(tp_position==0)

           {

            int tp=int(InpInitTake>0 ? InpInitTake : InpTakeProfit>0 ? InpTakeProfit : 0);

            if(tp>0)

              {

               take_profit=CorrectTakeProfit(symbol_name,POSITION_TYPE_SELL,op_position-tp*point,op_position);

               if(!PositionModifyByTicket(symbol_name,ticket,sl_position,take_profit))

                  Print("Position Sell #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

              }

           }

         else

           {

            if(InpTakeProfit>0)

              {

               breakeven=NormalizeDouble(op_position-InpBreakevenPT*point,digits);

               price=SymbolInfoDouble(symbol_name,SYMBOL_BID);

               take_profit=NormalizeDouble(price-InpTakeProfit*point,digits);

               if(!InpTrailingLoss && NormalizeDouble(breakeven-take_profit,digits)<0) take_profit=breakeven;

               if(take_profit>tp_position+step && CheckCorrectTakeProfit(symbol_name,POSITION_TYPE_SELL,take_profit))

                 {

                  if(!PositionModifyByTicket(symbol_name,ticket,sl_position,take_profit))

                     Print("Position Sell #",(string)ticket," modification error: ",(string)g_result.retcode," -> ",g_result.comment);

                 }

              }

           }

        }

     }

  }

//+------------------------------------------------------------------+

//| @>25@:0 8AB8==>AB8 CA;>289 ?> A8<2>;C, <038:C 8 B8:5BC          |

//+------------------------------------------------------------------+

bool Condition(const string symbol_name,const ulong magic_number,const long ticket)

  {

   return

   (

    (symbol_name==InpTrailingSymbol || InpTrailingSymbol=="") && 

    (magic_number==InpTrailingMagic || InpTrailingMagic==0) && 

    (ticket==InpTrailingTicket || InpTrailingTicket==0)

    );

  }

//+------------------------------------------------------------------+

//| @>25@O5B 2>7<>6=>ABL <>48D8:0F88 ?> C@>2=N 70<>@>7:8            |

//+------------------------------------------------------------------+

bool CheckFreezeLevel(const string symbol_name,const ENUM_ORDER_TYPE order_type,const double price_modified)

  {

   int lv=(int)SymbolInfoInteger(symbol_name,SYMBOL_TRADE_FREEZE_LEVEL);

   if(lv==0) return true;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return false;

   int dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   double price=(order_type==ORDER_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : 

                 order_type==ORDER_TYPE_SELL ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price_modified);

   return(NormalizeDouble(fabs(price-price_modified)-lv*pt,dg)>0);

  }

//+------------------------------------------------------------------+

//| >72@0I05B :>@@5:B=K9 StopLoss >B=>A8B5;L=> StopLevel            |

//+------------------------------------------------------------------+

double CorrectStopLoss(const string symbol_name,const ENUM_POSITION_TYPE position_type,const double stop_loss,const double open_price=0) {

   if(stop_loss==0) return 0;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return 0;

   double price=(open_price>0 ? open_price : position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : SymbolInfoDouble(symbol_name,SYMBOL_ASK));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (position_type==POSITION_TYPE_BUY ? 

      NormalizeDouble(::fmin(price-lv*pt,stop_loss),dg) :

      NormalizeDouble(::fmax(price+lv*pt,stop_loss),dg)

     );

}

//+------------------------------------------------------------------+

//| >72@0I05B :>@@5:B=K9 StopLoss >B=>A8B5;L=> StopLevel            |

//+------------------------------------------------------------------+

double CorrectStopLoss(const string symbol_name,const ENUM_POSITION_TYPE position_type,const int stop_loss) {

   if(stop_loss==0) return 0;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return 0;

   double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : SymbolInfoDouble(symbol_name,SYMBOL_ASK));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (position_type==POSITION_TYPE_BUY ?

      NormalizeDouble(::fmin(price-lv*pt,price-stop_loss*pt),dg) :

      NormalizeDouble(::fmax(price+lv*pt,price+stop_loss*pt),dg)

     );

}

//+------------------------------------------------------------------+

//| @25@O5B StopLoss =0 :>@@5:B=>ABL >B=>A8B5;L=> StopLevel         |

//+------------------------------------------------------------------+

bool CheckCorrectStopLoss(const string symbol_name,const ENUM_POSITION_TYPE position_type,const double stop_loss)

  {

   if(stop_loss==0) return true;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return false;

   double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : SymbolInfoDouble(symbol_name,SYMBOL_BID));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (

      position_type==POSITION_TYPE_BUY ? 

      NormalizeDouble(stop_loss-price+lv*pt,dg)<0 :

      NormalizeDouble(stop_loss-price-lv*pt,dg)>0

     );

  }

//+------------------------------------------------------------------+

//| >72@0I05B :>@@5:B=K9 TakeProfit >B=>A8B5;L=> StopLevel          |

//+------------------------------------------------------------------+

double CorrectTakeProfit(const string symbol_name,const ENUM_POSITION_TYPE position_type,const int take_profit)

  {

   if(take_profit==0) return 0;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return 0;

   double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : SymbolInfoDouble(symbol_name,SYMBOL_ASK));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (position_type==POSITION_TYPE_BUY ?

      NormalizeDouble(fmax(price+lv*pt,price+take_profit*pt),dg) :

      NormalizeDouble(fmin(price-lv*pt,price-take_profit*pt),dg)

     );

  }

//+------------------------------------------------------------------+

//| >72@0I05B :>@@5:B=K9 TakeProfit >B=>A8B5;L=> StopLevel          |

//+------------------------------------------------------------------+

double CorrectTakeProfit(const string symbol_name,const ENUM_POSITION_TYPE position_type,const double take_profit,const double open_price=0)

  {

   if(take_profit==0) return 0;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return 0;

   double price=(open_price>0 ? open_price : position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : SymbolInfoDouble(symbol_name,SYMBOL_ASK));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (position_type==POSITION_TYPE_BUY ?

      NormalizeDouble(::fmax(price+lv*pt,take_profit),dg) :

      NormalizeDouble(::fmin(price-lv*pt,take_profit),dg)

     );

  }

//+------------------------------------------------------------------+

//| @25@O5B TakeProfit =0 :>@@5:B=>ABL >B=>A8B5;L=> StopLevel       |

//+------------------------------------------------------------------+

bool CheckCorrectTakeProfit(const string symbol_name,const ENUM_POSITION_TYPE position_type,const double take_profit)

  {

   if(take_profit==0) return true;

   double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT);

   if(pt==0) return false;

   double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : SymbolInfoDouble(symbol_name,SYMBOL_BID));

   int lv=StopLevel(symbol_name),dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);

   return

     (

      position_type==POSITION_TYPE_BUY ?

      NormalizeDouble(take_profit-price-lv*pt,dg)>0 :

      NormalizeDouble(take_profit-price+lv*pt,dg)<0

     );

  }

//+------------------------------------------------------------------+

//| >72@0I05B @0AAG8B0==K9 StopLevel                                |

//+------------------------------------------------------------------+

int StopLevel(const string symbol_name)

  {

   int sp=(int)SymbolInfoInteger(symbol_name,SYMBOL_SPREAD);

   int lv=(int)SymbolInfoInteger(symbol_name,SYMBOL_TRADE_STOPS_LEVEL);

   return(lv==0 ? sp*size_spread : lv);

  }

//+------------------------------------------------------------------+

//| >48D8F8@C5B 2K1@0==CN ?> B8:5BC ?>78F8N                         |

//+------------------------------------------------------------------+

bool PositionModifyByTicket(const string symbol_name,const ulong ticket,const double sl,const double tp)

  {

//--- check stopped

   if(IsStopped())

      return(false);

//--- clean

   ZeroMemory(g_request);

   ZeroMemory(g_result);

//--- setting request

   g_request.action  =TRADE_ACTION_SLTP;

   g_request.position=ticket;

   g_request.symbol  =symbol_name;

   g_request.sl      =sl;

   g_request.tp      =tp;

//--- action and return the result

   return(OrderSend(g_request,g_result));

  }

//+------------------------------------------------------------------+

//| >72@0I05B 2@5<O >B:@KB8O 7040==>3> 10@0                         |

//+------------------------------------------------------------------+

datetime Time(int shift)

  {

   datetime array[];

   if(CopyTime(Symbol(),PERIOD_CURRENT,shift,1,array)==1) return array[0];

   return 0;

  }

//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---