SerialMA_EA

Author: Copyright 2018, MetaQuotes Software Corp.
Price Data Components
Series array that contains open time of each barSeries array that contains close prices for each bar
Orders Execution
Checks for the total of open orders
0 Views
0 Downloads
0 Favorites
SerialMA_EA
ÿþ//+------------------------------------------------------------------+

//|                                                  SerialMA_EA.mq5 |

//|                        Copyright 2018, MetaQuotes Software Corp. |

//|                                                 https://mql5.com |

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

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

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

#property version   "1.00"

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

//| E>4=>9 ?0@0<5B@ "0/5B"                                        |

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

enum ENUM_INPUT_YES_NO

  {

   INPUT_YES   =  1,                      // Yes

   INPUT_NO    =  0                       // No

  };

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

//| 5@5G8A;5=85 @07@5HQ==KE B8?>2 ?>78F89                           |

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

enum ENUM_OPENED_MODE

  {

   OPENED_MODE_ALL_SWING,                 // Position on each signal in one direction (swing)

   OPENED_MODE_ONE_SWING,                 // Always one position (swing)

  };

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

//| E>4=K5 ?0@0<5B@K                                                |

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

sinput   long              InpMagic       =  1234567;                // Experts magic number

input    ENUM_OPENED_MODE  InpModeOpen    =  OPENED_MODE_ALL_SWING;  // Mode of opening positions

input    ENUM_INPUT_YES_NO InpEnableBuy   =  INPUT_YES;              // Long positions is enabled

input    ENUM_INPUT_YES_NO InpEnableSell  =  INPUT_YES;              // Short positions is enabled

input    ENUM_INPUT_YES_NO InpReverse     =  INPUT_NO;               // Reverse trade

input    double            InpVolume      =  0.1;                    // Lots

input    uint              InpStopLoss    =  0;                      // Stop loss in points

input    uint              InpTakeProfit  =  0;                      // Take profit in points

sinput   ulong             InpDeviation   =  10;                     // Slippage of price

sinput   uint              InpSizeSpread  =  2;                      // Multiplier spread for stops

sinput   uint              InpSleep       =  1;                      // Waiting for environment update (in seconds)

sinput   uint              InpNumAttempt  =  3;                      // Number of attempts to get the state of the environment

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

//| :;NG5=8O                                                        |

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

#include <Arrays\ArrayObj.mqh>

#include <Arrays\ArrayLong.mqh>

#include <Trade\TerminalInfo.mqh>

#include <Trade\AccountInfo.mqh>

#include <Trade\Trade.mqh>

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

//| 1J5:BK :;0AA>2                                                  |

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

CSymbolInfo    symbol_info;         // 1J5:B-CSymbolInfo

CAccountInfo   account_info;        // 1J5:B-CAccountInfo

CTerminalInfo  terminal_info;       // 1J5:B-CTerminalInfo

CTrade         trade;               // 1J5:B-CTrade

CArrayObj      list_lines;          // !?8A>: >1J5:B>2-;8=89

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

//| !B@C:BC@0 ?>78F89                                                |

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

struct SDatas

  {

   CArrayLong  list_tickets;        // A?8A>: B8:5B>0

   double      total_volume;        // 1I89 >1JQ<

  };

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

//| !B@C:BC@0 40==KE ?>78F89 ?> B8?0<                                |

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

struct SDataPositions

  {

   SDatas      Buy;                 // 0==K5 ?>78F89 Buy

   SDatas      Sell;                // 0==K5 ?>78F89 Sell

  }

Data;

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

//| !B@C:BC@0 40==KE 8=48:0B>@0                                      |

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

struct SDataInd

  {

   double      line[];              // CD5@ ;8=88

   double      point[];             // CD5@ B>G5:

   double      Line0(void)    const { return line[0];  }

   double      Line1(void)    const { return line[1];  }

   double      Point0(void)   const { return point[0]; }

   double      Point1(void)   const { return point[1]; }

  }

DataInd;

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

//| ;>10;L=K5 ?5@5<5==K5                                            |

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

double         lot;                 // 1JQ< ?>78F88

string         symb;                // !8<2>;

int            prev_total;          // >;8G5AB2> ?>78F89 =0 ?@>H;>9 ?@>25@:5

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

uint           num_attempts;        // >;8G5AB2> ?>?KB>: ?>;CG5=8O B>G=>3> >:@C65=8O

int            sleep;               // 6840=85 >1=>2;5=8O 2 A5:C=40E

int            handle_ind;          // %M=4; Serial_MA

datetime       last_time;           // @5<O >B:@KB8O 10@0 =0 ?@>H;>9 ?@>25@:5

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

//| Expert initialization function                                   |

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

int OnInit()

  {

//--- #AB0=>2:0 B>@3>2KE ?0@0<5B@>2

   if(!SetTradeParameters())

      return INIT_FAILED;

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

   symb=symbol_info.Name();

   prev_total=0;

   last_time=0;

//--- %M=4; Serial_MA

   ResetLastError();

   handle_ind=iCustom(symb,PERIOD_CURRENT,"SerialMA");

   if(handle_ind==INVALID_HANDLE)

     {

      Print("The 'Serial_MA' object was not created: Error ",GetLastError());

      return INIT_FAILED;

     }

//--- =8F80;870F8O <0AA82>2 1CD5@>2

   ResetLastError();

   if(ArrayResize(DataInd.line,2,2)==WRONG_VALUE)

     {

      Print("Error setting the first buffer size ",GetLastError());

      return INIT_FAILED;

     }

   ResetLastError();

   if(ArrayResize(DataInd.point,2,2)==WRONG_VALUE)

     {

      Print("Error setting the second buffer size ",GetLastError());

      return INIT_FAILED;

     }

   ArraySetAsSeries(DataInd.line,true);

   ArraySetAsSeries(DataInd.point,true);

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

   return(INIT_SUCCEEDED);

  }

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

//| Expert deinitialization function                                 |

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

void OnDeinit(const int reason)

  {

//---



  }

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

//| Expert tick function                                             |

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

void OnTick()

  {

//--- @>25@:0 =C;52KE F5=

   if(!RefreshRates() || Point()==0) return;

//--- 0?>;=5=85 A?8A:>2 B8:5B>2 ?>78F89

   int positions_total=PositionsTotal();

   if(prev_total!=positions_total)

     {

      if(FillingListTickets(num_attempts))

         prev_total=positions_total;

      else return;

     }

//--- @>25@:0 =>2>3> 10@0

   if(Time(0)!=last_time)

     {

   //--- 0?>;=5=85 40==KE 8=48:0B>@0 8 ?@>25@:0 ?>;CG5=8O F5=K Close

      if(!FillingDataInd(1) || Close(1)==0)

         return;

   //--- >;CG5=85 A83=0;>2 >B 8=48:0B>@0

      bool open_long=false;

      bool open_short=false;

      if(fabs(MALine(1)-MAPoint(1))<Point())

        {

         if(Close(1)>MALine(0))

           {

            if(!InpReverse)

               open_long=(InpEnableBuy ? true : false);

            else

               open_short=(InpEnableSell ? true : false);

           }

         if(Close(1)<MALine(0))

           {

            if(!InpReverse)

               open_short=(InpEnableSell ? true : false);

            else

               open_long=(InpEnableBuy ? true : false);

           }

        }

   //--- "5:CI55 :>;8G5AB2> ?>78F89

      int num_b=NumberBuy();

      int num_s=NumberSell();

   //--- B:@KB85 ?>78F89 ?> A83=0;0<

      if(open_long && (InpModeOpen==OPENED_MODE_ALL_SWING || (InpModeOpen==OPENED_MODE_ONE_SWING && num_b==0)))

        {

         if(num_s>0)

           {

            bool res=CloseSell();

            if(!FillingListTickets(num_attempts) || !res)

               return;

           }

         if(OpenPosition(POSITION_TYPE_BUY,CorrectLots(lot),""))

           {

            if(!FillingListTickets(num_attempts))

               return;

           }

         else return;

        }

      if(open_short && (InpModeOpen==OPENED_MODE_ALL_SWING || (InpModeOpen==OPENED_MODE_ONE_SWING && num_s==0)))

        {

         if(num_b>0)

           {

            bool res=CloseBuy();

            if(!FillingListTickets(num_attempts) || !res)

               return;

           }

         if(OpenPosition(POSITION_TYPE_SELL,CorrectLots(lot),""))

           {

            if(!FillingListTickets(num_attempts))

               return;

           }

         else return;

        }

   //--- A5 459AB28O =0 =>2>< 10@5 2K?>;=5=K CA?5H=>

      last_time=Time(0);

     }

//---

  }

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

//| Trade function                                                   |

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

void OnTrade()

  {

//---



  }

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

//| TradeTransaction function                                        |

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

void OnTradeTransaction(const MqlTradeTransaction &trans,

                        const MqlTradeRequest &request,

                        const MqlTradeResult &result)

  {

//---



  }

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

//| 0?>;=5=85 40==KE 8=48:0B>@0                                     |

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

bool FillingDataInd(const int shift)

  {

   int count=2,copied=0;

   ZeroMemory(DataInd);

   copied=CopyBuffer(handle_ind,0,shift,count,DataInd.line);

   if(copied!=count) return false;

   copied=CopyBuffer(handle_ind,1,shift,count,DataInd.point);

   if(copied!=count) return false;

   return true;

  }

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

//| >;CG5=85 40==KE 1CD5@0 ;8=88 ?> 8=45:AC 0 8;8 1                 |

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

double MALine(const int index)

  {

   return(index==0 ? DataInd.Line0() : DataInd.Line1());

  }

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

//| >;CG5=85 40==KE 1CD5@0 B>G5: ?> 8=45:AC 0 8;8 1                 |

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

double MAPoint(const int index)

  {

   return(index==0 ? DataInd.Point0() : DataInd.Point1());

  }

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

//| #AB0=>2:0 B>@3>2KE ?0@0<5B@>2                                    |

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

bool SetTradeParameters()

  {

//--- #AB0=>2:0 A8<2>;0

   ResetLastError();

   if(!symbol_info.Name(Symbol()))

     {

      Print("Error setting ",Symbol()," symbol: ",GetLastError());

      return false;

     }

//--- >;CG5=85 F5=

   ResetLastError();

   if(!symbol_info.RefreshRates())

     {

      Print("Error obtaining ",symbol_info.Name()," data: ",GetLastError());

      return false;

     }

   if(account_info.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)

     {

      Print(account_info.MarginModeDescription(),"-account. EA should work on a hedge account.");

      return false;

     }

//--- 2B><0B8G5A:0O CAB0=>2:0 B8?0 70?>;=5=8O

   trade.SetTypeFilling(GetTypeFilling());

//--- #AB0=>2:0 <038:0

   trade.SetExpertMagicNumber(InpMagic);

//--- #AB0=>2:0 ?@>A:0;L7K20=8O

   trade.SetDeviationInPoints(InpDeviation);

//--- #AB0=>2:0 ;>B0 A :>@@5:B8@>2:>9 2254Q==>3> 7=0G5=8O

   lot=CorrectLots(InpVolume);

//--- #AB0=>2:0 <=>68B5;O A?@540 4;O @0AGQB0 AB>?-?@8:07>2

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

//--- #AB0=>2:0 :>;8G5AB20 ?>?KB>: 8 2@5<5=8 >6840=8O ?@8 ?>;CG5=88 >:@C65=8O

   num_attempts=int(InpNumAttempt<1 ? 1 : InpNumAttempt);

   sleep=int(InpSleep<1 ? 1 : InpSleep)*1000;

//---

   return true;

  }

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

//| 1=>2;5=85 F5=                                                   |

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

bool RefreshRates(void)

  {

   if(!symbol_info.RefreshRates()) return false;

   if(symbol_info.Ask()==0 || symbol_info.Bid()==0) return false;

   return true;

  }

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

//| >72@0I05B F5=C 70:@KB8O 7040==>3> 10@0                          |

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

double Close(int shift)

  {

   double array[];

   if(CopyClose(symb,PERIOD_CURRENT,shift,1,array)==1) return array[0];

   return 0;

  }

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

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

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

datetime Time(int shift)

  {

   datetime array[];

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

   return 0;

  }

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

//| >72@0I05B :>@@5:B=K9 ;>B                                        |

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

double CorrectLots(const double lots,const bool to_min_correct=true)

  {

   double min=symbol_info.LotsMin();

   double max=symbol_info.LotsMax();

   double step=symbol_info.LotsStep();

   return(to_min_correct ? VolumeRoundToSmaller(lots,min,max,step) : VolumeRoundToCorrect(lots,min,max,step));

  }

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

//| >72@0I05B 1;8609H89 :>@@5:B=K9 ;>B                              |

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

double VolumeRoundToCorrect(const double volume,const double min,const double max,const double step)

  {

   return(step==0 ? min : fmin(fmax(round(volume/step)*step,min),max));

  }

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

//| >72@0I05B 1;8609H89 2 <5=LHCN AB>@>=C :>@@5:B=K9 ;>B            |

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

double VolumeRoundToSmaller(const double volume,const double min,const double max,const double step)

  {

   return(step==0 ? min : fmin(fmax(floor(volume/step)*step,min),max));

  }

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

//| >72@0I05B D;03 =5 ?@52KH5=8O >1I53> >1JQ<0 =0 AGQB5             |

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

bool CheckLotForLimitAccount(const ENUM_POSITION_TYPE position_type,const double volume)

  {

   if(symbol_info.LotsLimit()==0) return true;

   double total_volume=(position_type==POSITION_TYPE_BUY ? Data.Buy.total_volume : Data.Sell.total_volume);

   return(total_volume+volume<=symbol_info.LotsLimit());

  }

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

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

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

double CorrectStopLoss(const ENUM_POSITION_TYPE position_type,const int stop_loss)

  {

   if(stop_loss==0) return 0;

   double pt=symbol_info.Point();

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

   int lv=StopLevel(),dg=symbol_info.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)

    );

  }

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

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

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

double CorrectTakeProfit(const ENUM_POSITION_TYPE position_type,const int take_profit)

  {

   if(take_profit==0) return 0;

   double pt=symbol_info.Point();

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

   int lv=StopLevel(),dg=symbol_info.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 @0AAG8B0==K9 StopLevel                                |

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

int StopLevel(void)

  {

   int sp=symbol_info.Spread();

   int lv=symbol_info.StopsLevel();

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

  }

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

//| 0:@K205B ?>78F88 Buy                                            |

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

bool CloseBuy(void)

  {

   int total=Data.Buy.list_tickets.Total();

   bool res=true;

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

     {

      ulong ticket=Data.Buy.list_tickets.At(i);

      if(ticket==NULL) continue;

      if(!trade.PositionClose(ticket,InpDeviation))

         res=false;

     }

   return res;

  }

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

//| 0:@K205B ?>78F88 Sell                                           |

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

bool CloseSell(void)

  {

   int total=Data.Sell.list_tickets.Total();

   bool res=true;

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

     {

      ulong ticket=Data.Sell.list_tickets.At(i);

      if(ticket==NULL) continue;

      if(!trade.PositionClose(ticket,InpDeviation))

         res=false;

     }

   return res;

  }

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

//| 0?>;=O5B <0AA82K B8:5B>2 ?>78F89                                |

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

bool FillingListTickets(const uint number_of_attempts)

  {

//--- @>25@:0 A>AB>O=8O >:@C65=8O

   int n=0,attempts=int(number_of_attempts<1 ? 1 : number_of_attempts);

   while(IsUncertainStateEnv(symb,InpMagic) && n<attempts && !IsStopped())

     {

      n++;

      Sleep(sleep);

     }

   if(n>=attempts && IsUncertainStateEnv(symb,InpMagic))

     {

      Print(__FUNCTION__,": Uncertain state of the environment. Please try again.");

      return false;

     }

//---

   Data.Buy.list_tickets.Clear();

   Data.Sell.list_tickets.Clear();

   Data.Buy.total_volume=0;

   Data.Sell.total_volume=0;

//---

   int total=PositionsTotal();

   for(int i=total-1; i>WRONG_VALUE; i--)

     {

      ulong ticket=PositionGetTicket(i);

      if(ticket==0) continue;

      if(PositionGetInteger(POSITION_MAGIC)!=InpMagic)   continue;

      if(PositionGetString(POSITION_SYMBOL)!=symb)       continue;

      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

      double volume=PositionGetDouble(POSITION_VOLUME);

      if(type==POSITION_TYPE_BUY)

        {

         Data.Buy.list_tickets.Add(ticket);

         Data.Buy.total_volume+=volume;

        }

      else

        {

         Data.Sell.list_tickets.Add(ticket);

         Data.Sell.total_volume+=volume;

        }

     }

   return true;

  }

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

//| >72@0I05B "=5>?@545;Q==>5" A>AB>O=85 B>@3>2>3> >:@C65=8O        |

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

bool IsUncertainStateEnv(const string symbol_name,const ulong magic_number)

  {

   if(MQLInfoInteger(MQL_TESTER)) return false;

   int total=OrdersTotal();

   for(int i=total-1; i>WRONG_VALUE; i--)

     {

      if(OrderGetTicket(i)==0) continue;

      if(OrderGetInteger(ORDER_TYPE)>ORDER_TYPE_SELL) continue;

      if(OrderGetInteger(ORDER_MAGIC)!=magic_number) continue;

      if(!OrderGetInteger(ORDER_POSITION_ID) && OrderGetString(ORDER_SYMBOL)==symbol_name)

         return true;

     }

   return false;

  }

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

//| >72@0I05B :>;8G5AB2> ?>78F89 Buy                                |

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

int NumberBuy(void)

  {

   return Data.Buy.list_tickets.Total();

  }

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

//| >72@0I05B :>;8G5AB2> ?>78F89 Sell                               |

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

int NumberSell(void)

  {

   return Data.Sell.list_tickets.Total();

  }

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

//| >72@0I05B B8? 8A?>;=5=8O >@45@0, @02=K9 type,                   |

//| 5A;8 >= 4>ABC?5= =0 A8<2>;5, 8=0G5 - :>@@5:B=K9 20@80=B          |

//| https://www.mql5.com/ru/forum/170952/page4#comment_4128864       |

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

ENUM_ORDER_TYPE_FILLING GetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_RETURN)

  {

   const ENUM_SYMBOL_TRADE_EXECUTION exe_mode=symbol_info.TradeExecution();

   const int filling_mode=symbol_info.TradeFillFlags();



   return(

          (filling_mode==0 || (type>=ORDER_FILLING_RETURN) || ((filling_mode &(type+1))!=type+1)) ?

          (((exe_mode==SYMBOL_TRADE_EXECUTION_EXCHANGE) || (exe_mode==SYMBOL_TRADE_EXECUTION_INSTANT)) ?

          ORDER_FILLING_RETURN :((filling_mode==SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) : type

          );

  }

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

//| B:@KB85 ?>78F88                                                 |

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

bool OpenPosition(const ENUM_POSITION_TYPE type,const double volume,const string comment)

  {

   double sl=(InpStopLoss==0   ? 0 : CorrectStopLoss(type,InpStopLoss));

   double tp=(InpTakeProfit==0 ? 0 : CorrectTakeProfit(type,InpTakeProfit));

   double ll=trade.CheckVolume(symb,volume,(type==POSITION_TYPE_BUY ? SymbolInfoDouble(symb,SYMBOL_ASK) : SymbolInfoDouble(symb,SYMBOL_BID)),(ENUM_ORDER_TYPE)type);

   if(ll>0 && CheckLotForLimitAccount(type,ll))

     {

      if(RefreshRates())

        {

         if(type==POSITION_TYPE_BUY)

           {

            if(trade.Buy(ll,symb,symbol_info.Ask(),sl,tp,comment))

               return true;

           }

         else

           {

            if(trade.Sell(ll,symb,symbol_info.Bid(),sl,tp,comment))

               return true;

           }

        }

     }

   return false;

  }

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

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 ---