2 1000 1 0.7% 0.5 500lev st

Author: Copyright (C) 2020 Forex Software Ltd.
Price Data Components
Orders Execution
Checks for the total of open ordersIt automatically opens orders when conditions are reachedIt Closes Orders by itself It can change open orders parameters, due to possible stepping strategy
Miscellaneous
Uses files from the file systemIt reads information from a fileIt reads information from a fileIt writes information to fileIt writes information to file
0 Views
0 Downloads
0 Favorites
2 1000 1 0.7% 0.5 500lev st
//+--------------------------------------------------------------------+
//| Copyright:  (C) 2020 Forex Software Ltd.                           |
//| Website:    https://forexsb.com/                                   |
//| Support:    https://forexsb.com/forum/                             |
//| License:    Proprietary under the following circumstances:         |
//|                                                                    |
//| This code is a part of Forex Strategy Builder. It is free for      |
//| use as an integral part of Forex Strategy Builder.                 |
//| One can modify it in order to improve the code or to fit it for    |
//| personal use. This code or any part of it cannot be used in        |
//| other applications without a permission.                           |
//| The contact information cannot be changed.                         |
//|                                                                    |
//| NO LIABILITY FOR CONSEQUENTIAL DAMAGES                             |
//|                                                                    |
//| In no event shall the author be liable for any damages whatsoever  |
//| (including, without limitation, incidental, direct, indirect and   |
//| consequential damages, damages for loss of business profits,       |
//| business interruption, loss of business information, or other      |
//| pecuniary loss) arising out of the use or inability to use this    |
//| product, even if advised of the possibility of such damages.       |
//+--------------------------------------------------------------------+

#property copyright "Copyright (C) 2020 Forex Software Ltd."
#property link      "https://forexsb.com"
#property version   "50.0"
#property strict



// -----------------------    External variables   ----------------------- //

static input string StrategyProperties__ = "------------"; // ------ Strategy Properties ------

static input double Entry_Amount    = 1; // Amount for a new position [%]
static input double Maximum_Amount  = 0.5; // Maximum position amount [lot]
static input double Adding_Amount   = 1; // Amount to add on addition [%]
static input double Reducing_Amount = 1; // Amount to close on reduction [%]
input int Stop_Loss   = 875; // Stop Loss [point]
input int Take_Profit = 510; // Take Profit [point]
input int Break_Even  = 0; // Break Even [point]
static input double Martingale_Multiplier = 0; // Martingale Multiplier

static input string IndicatorName1 = "MACD Histogram"; // ------ Indicator parameters ------
input int Slot1IndParam0 = 195; // Slow MA period
input int Slot1IndParam1 = 58; // Fast MA period
input int Slot1IndParam2 = 183; // Signal line period
input double Slot1IndParam3 = 0; // Level
static input string IndicatorName2 = "Trailing Stop"; // ------ Indicator parameters ------
input int Slot2IndParam0 = 2172; // Trailing Stop


static input string ExpertSettings__ = "------------"; // ------ Expert Settings ------

// A unique number of the expert's orders.
static input int Expert_Magic = 7120134; // Expert Magic Number

// If account equity drops below this value, the expert will close out all positions and stop automatic trade.
// The value must be set in account currency. Example:
// Protection_Min_Account = 700 will close positions if the equity drops below 700 USD (EUR if you account is in EUR).
static input int Protection_Min_Account = 0; // Stop trading at min account

// The expert checks the open positions at every tick and if found no SL or SL lower (higher for short) than selected,
// It sets SL to the defined value. The value is in points. Example:
// Protection_Max_StopLoss = 200 means 200 pips for 4 digit broker and 20 pips for 5 digit broker.
static input int Protection_Max_StopLoss = 0; // Ensure maximum Stop Loss [point]

// How many seconds before the expected bar closing to rise a Bar Closing event.
static input int Bar_Close_Advance = 15; // Bar closing advance [sec]

// Expert writes a log file when Write_Log_File = true.
static input bool Write_Log_File = false; // Write a log file

// Custom comment. It can be used for setting a binnary option epxiration perod
static input string Order_Comment = ""; // Custom order comment

// ----------------------------    Options   ---------------------------- //

// Data bars for calculating the indicator values with the necessary precission.
// If set to 0, the expert calculates them automatically.
int Min_Data_Bars=0;

// Separate SL and TP orders
// It has to be set to true for STP brokers that cannot set SL and TP together with the position (with OrderSend()).
// When Separate_SL_TP = true, the expert first opens the position and after that sets StopLoss and TakeProfit.
bool Separate_SL_TP = false; // Separate SL and TP orders 

// TrailingStop_Moving_Step determines the step of changing the Trailing Stop.
// 0 <= TrailingStop_Moving_Step <= 2000
// If TrailingStop_Moving_Step = 0, the Trailing Stop trails at every new extreme price in the position's direction.
// If TrailingStop_Moving_Step > 0, the Trailing Stop moves at steps equal to the number of pips chosen.
// This prevents sending multiple order modifications.
int TrailingStop_Moving_Step = 10;

// FIFO (First In First Out) forces the expert to close positions starting from
// the oldest one. This rule complies with the new NFA regulations.
// If you want to close the positions from the newest one (FILO), change the variable to "false".
// This doesn't change the normal work of Forex Strategy Builder.
bool FIFO_order = true;

// When the log file reaches the preset number of lines,
// the expert starts a new log file.
int Max_Log_Lines_in_File = 2000;

// Used to detect a chart change
string __symbol = "";
int    __period = -1;

enum DataPeriod
  {
   DataPeriod_M1  = 1,
   DataPeriod_M5  = 5,
   DataPeriod_M15 = 15,
   DataPeriod_M30 = 30,
   DataPeriod_H1  = 60,
   DataPeriod_H4  = 240,
   DataPeriod_D1  = 1440,
   DataPeriod_W1  = 10080,
   DataPeriod_MN1 = 43200
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum PosDirection
  {
   PosDirection_None,
   PosDirection_Long,
   PosDirection_Short,
   PosDirection_Closed
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum OrderDirection
  {
   OrderDirection_None,
   OrderDirection_Buy,
   OrderDirection_Sell
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum StrategyPriceType
  {
   StrategyPriceType_Open,
   StrategyPriceType_Close,
   StrategyPriceType_Indicator,
   StrategyPriceType_CloseAndReverse,
   StrategyPriceType_Unknown
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ExecutionTime
  {
   ExecutionTime_DuringTheBar,
   ExecutionTime_AtBarOpening,
   ExecutionTime_AtBarClosing,
   ExecutionTime_CloseAndReverse
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum TraderOrderType
  {
   TraderOrderType_Buy       = 0,
   TraderOrderType_Sell      = 1,
   TraderOrderType_BuyLimit  = 2,
   TraderOrderType_SellLimit = 3,
   TraderOrderType_BuyStop   = 4,
   TraderOrderType_SellStop  = 5
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum TradeDirection
  {
   TradeDirection_None,
   TradeDirection_Long,
   TradeDirection_Short,
   TradeDirection_Both
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum LongTradeEntryPrice
  {
   LongTradeEntryPrice_Bid,
   LongTradeEntryPrice_Ask,
   LongTradeEntryPrice_Chart
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum OperationType
  {
   OperationType_Buy,
   OperationType_Sell,
   OperationType_Close,
   OperationType_Modify
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum TickType
  {
   TickType_Open       = 0,
   TickType_OpenClose  = 1,
   TickType_Regular    = 2,
   TickType_Close      = 3,
   TickType_AfterClose = 4
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum InstrumentType
  {
   InstrumentType_Forex,
   InstrumentType_CFD,
   InstrumentType_Index
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum SlotTypes
  {
   SlotTypes_NotDefined  = 0,
   SlotTypes_Open        = 1,
   SlotTypes_OpenFilter  = 2,
   SlotTypes_Close       = 4,
   SlotTypes_CloseFilter = 8
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum IndComponentType
  {
   IndComponentType_NotDefined,
   IndComponentType_OpenLongPrice,
   IndComponentType_OpenShortPrice,
   IndComponentType_OpenPrice,
   IndComponentType_CloseLongPrice,
   IndComponentType_CloseShortPrice,
   IndComponentType_ClosePrice,
   IndComponentType_OpenClosePrice,
   IndComponentType_IndicatorValue,
   IndComponentType_AllowOpenLong,
   IndComponentType_AllowOpenShort,
   IndComponentType_ForceCloseLong,
   IndComponentType_ForceCloseShort,
   IndComponentType_ForceClose,
   IndComponentType_Other
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum PositionPriceDependence
  {
   PositionPriceDependence_None,
   PositionPriceDependence_PriceBuyHigher,
   PositionPriceDependence_PriceBuyLower,
   PositionPriceDependence_PriceSellHigher,
   PositionPriceDependence_PriceSellLower,
   PositionPriceDependence_BuyHigherSellLower,
   PositionPriceDependence_BuyLowerSelHigher,// Deprecated
   PositionPriceDependence_BuyLowerSellHigher
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum BasePrice
  {
   BasePrice_Open     = 0,
   BasePrice_High     = 1,
   BasePrice_Low      = 2,
   BasePrice_Close    = 3,
   BasePrice_Median   = 4, // Price[bar] = (Low[bar] + High[bar]) / 2;
   BasePrice_Typical  = 5, // Price[bar] = (Low[bar] + High[bar] + Close[bar]) / 3;
   BasePrice_Weighted = 6  // Price[bar] = (Low[bar] + High[bar] + 2 * Close[bar]) / 4;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum MAMethod
  {
   MAMethod_Simple      = 0,
   MAMethod_Weighted    = 1,
   MAMethod_Exponential = 2,
   MAMethod_Smoothed    = 3
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum SameDirSignalAction
  {
   SameDirSignalAction_Nothing,
   SameDirSignalAction_Add,
   SameDirSignalAction_Winner,
   SameDirSignalAction_Loser,
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum OppositeDirSignalAction
  {
   OppositeDirSignalAction_Nothing,
   OppositeDirSignalAction_Reduce,
   OppositeDirSignalAction_Close,
   OppositeDirSignalAction_Reverse
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum PermanentProtectionType
  {
   PermanentProtectionType_Relative,
   PermanentProtectionType_Absolute
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum TrailingStopMode
  {
   TrailingStopMode_Bar,
   TrailingStopMode_Tick
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum IndicatorLogic
  {
   IndicatorLogic_The_indicator_rises,
   IndicatorLogic_The_indicator_falls,
   IndicatorLogic_The_indicator_is_higher_than_the_level_line,
   IndicatorLogic_The_indicator_is_lower_than_the_level_line,
   IndicatorLogic_The_indicator_crosses_the_level_line_upward,
   IndicatorLogic_The_indicator_crosses_the_level_line_downward,
   IndicatorLogic_The_indicator_changes_its_direction_upward,
   IndicatorLogic_The_indicator_changes_its_direction_downward,
   IndicatorLogic_The_price_buy_is_higher_than_the_ind_value,
   IndicatorLogic_The_price_buy_is_lower_than_the_ind_value,
   IndicatorLogic_The_price_open_is_higher_than_the_ind_value,
   IndicatorLogic_The_price_open_is_lower_than_the_ind_value,
   IndicatorLogic_It_does_not_act_as_a_filter,
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum BandIndLogic
  {
   BandIndLogic_The_bar_opens_below_the_Upper_Band,
   BandIndLogic_The_bar_opens_above_the_Upper_Band,
   BandIndLogic_The_bar_opens_below_the_Lower_Band,
   BandIndLogic_The_bar_opens_above_the_Lower_Band,
   BandIndLogic_The_position_opens_below_the_Upper_Band,
   BandIndLogic_The_position_opens_above_the_Upper_Band,
   BandIndLogic_The_position_opens_below_the_Lower_Band,
   BandIndLogic_The_position_opens_above_the_Lower_Band,
   BandIndLogic_The_bar_opens_below_Upper_Band_after_above,
   BandIndLogic_The_bar_opens_above_Upper_Band_after_below,
   BandIndLogic_The_bar_opens_below_Lower_Band_after_above,
   BandIndLogic_The_bar_opens_above_Lower_Band_after_below,
   BandIndLogic_The_bar_closes_below_the_Upper_Band,
   BandIndLogic_The_bar_closes_above_the_Upper_Band,
   BandIndLogic_The_bar_closes_below_the_Lower_Band,
   BandIndLogic_The_bar_closes_above_the_Lower_Band,
   BandIndLogic_It_does_not_act_as_a_filter
  };
//+------------------------------------------------------------------+

bool LabelCreate(const long chart_ID = 0,              // chart's ID
                 const string name = "Label",          // label name
                 const int sub_window = 0,             // subwindow index
                 const int x = 0,                      // X coordinate
                 const int y = 0,                      // Y coordinate
                 const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER,// chart corner for anchoring
                 const string text = "Label",          // text
                 const string font = "Arial",          // font
                 const int font_size = 8,              // font size
                 const color clr = clrWhite,           // color
                 const double angle = 0.0,             // text slope
                 const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER,// anchor type
                 const bool back = false,               // in the background
                 const bool selection = false,          // highlight to move
                 const bool hidden = true,              // hidden in the object list
                 const string tooltip = "\n",           // sets the tooltip
                 const long z_order = 0)                // priority for mouse click
  {
   ResetLastError();

   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))
     {
      Print(__FUNCTION__,": failed to create text label! Error code = ",GetLastError());
      return (false);
     }

   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
   ObjectSetString(chart_ID,name,OBJPROP_TOOLTIP,tooltip);
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);

   return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool LabelTextChange(const long chart_ID,const string name,const string text)
  {
   ResetLastError();
   if(!ObjectSetString(chart_ID,name,OBJPROP_TEXT,text))
     {
      Print(__FUNCTION__,": failed to change the text! Error code = ",GetLastError());
      return (false);
     }
   return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool LabelDelete(const long chart_ID=0,const string name="Label")
  {
   if(!ObjectDelete(chart_ID,name))
     {
      Print(__FUNCTION__,": failed to delete a text label! Error code = ",GetLastError());
      return (false);
     }
   return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color GetChartForeColor(const long chartId=0)
  {
   long foreColor=clrWhite;
   ChartGetInteger(chartId,CHART_COLOR_FOREGROUND,0,foreColor);
   return ((color) foreColor);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color GetChartBackColor(const long chartId=0)
  {
   long backColor=clrBlack;
   ChartGetInteger(chartId,CHART_COLOR_BACKGROUND,0,backColor);
   return ((color) backColor);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string LoadStringFromFile(string filename)
  {
   string text;
   int intSize;

   int handle= FileOpen(filename,FILE_TXT|FILE_READ|FILE_ANSI);
   if(handle == INVALID_HANDLE)
      return "";

   while(!FileIsEnding(handle))
     {
      intSize=FileReadInteger(handle,INT_VALUE);
      text+=FileReadString(handle,intSize);
     }

   FileClose(handle);
   return text;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SaveStringToFile(string filename,string text)
  {
   int handle= FileOpen(filename,FILE_TXT|FILE_WRITE|FILE_ANSI);
   if(handle == INVALID_HANDLE)
      return;

   FileWriteString(handle,text);
   FileClose(handle);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ArrayContainsString(const string &array[],string text)
  {
   for(int i=0; i<ArraySize(array); i++)
     {
      if(array[i]==text)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ArrayAppendString(string &array[],string text)
  {
   int size=ArraySize(array);
   ArrayResize(array,size+1);
   array[size]=text;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string DataPeriodToString(DataPeriod period)
  {
   switch(period)
     {
      case DataPeriod_M1:  return ("M1");
      case DataPeriod_M5:  return ("M5");
      case DataPeriod_M15: return ("M15");
      case DataPeriod_M30: return ("M30");
      case DataPeriod_H1:  return ("H1");
      case DataPeriod_H4:  return ("H4");
      case DataPeriod_D1:  return ("D1");
      case DataPeriod_W1:  return ("W1");
      case DataPeriod_MN1: return ("MN1");
     }

   return ("D1");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
DataPeriod StringToDataPeriod(string period)
  {
   if(period == "M1")  return (DataPeriod_M1);
   if(period == "M5")  return (DataPeriod_M5);
   if(period == "M15") return (DataPeriod_M15);
   if(period == "M30") return (DataPeriod_M30);
   if(period == "H1")  return (DataPeriod_H1);
   if(period == "H4")  return (DataPeriod_H4);
   if(period == "D1")  return (DataPeriod_D1);
   if(period == "W1")  return (DataPeriod_W1);
   if(period == "MN1") return (DataPeriod_MN1);
   return (DataPeriod_D1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
DataPeriod EnumTimeFramesToPeriod(int period)
  {
   switch(period)
     {
      case PERIOD_M1:  return (DataPeriod_M1);
      case PERIOD_M5:  return (DataPeriod_M5);
      case PERIOD_M15: return (DataPeriod_M15);
      case PERIOD_M30: return (DataPeriod_M30);
      case PERIOD_H1:  return (DataPeriod_H1);
      case PERIOD_H4:  return (DataPeriod_H4);
      case PERIOD_D1:  return (DataPeriod_D1);
      case PERIOD_W1:  return (DataPeriod_W1);
      case PERIOD_MN1: return (DataPeriod_MN1);
     }
   return (DataPeriod_D1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetMAMethodsText(string &list[])
  {
   ArrayResize(list,4);
   list[0] = "Simple";
   list[1] = "Weighted";
   list[2] = "Exponential";
   list[3] = "Smoothed";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetBasePricesText(string &list[])
  {
   ArrayResize(list,8);
   list[0] = "Open";
   list[1] = "High";
   list[2] = "Low";
   list[3] = "Close";
   list[4] = "Median";
   list[5] = "Typical";
   list[6] = "Low";
   list[7] = "Weighted";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string SameDirSignalActionToString(SameDirSignalAction action)
  {
   switch(action)
     {
      case SameDirSignalAction_Add:
         return ("Add");
      case SameDirSignalAction_Winner:
         return ("Winner");
      case SameDirSignalAction_Loser:
         return ("Loser");
      case SameDirSignalAction_Nothing:
         return ("Nothing");
     }
   return ("");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string OppositeDirSignalActionToString(OppositeDirSignalAction action)
  {
   switch(action)
     {
      case OppositeDirSignalAction_Close:
         return ("Close");
      case OppositeDirSignalAction_Nothing:
         return ("Nothing");
      case OppositeDirSignalAction_Reduce:
         return ("Reduce");
      case OppositeDirSignalAction_Reverse:
         return ("Reverse");
     }
   return ("");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string SlotTypeToString(SlotTypes slotType)
  {
   string stringCaptionText="Not Defined";
   switch(slotType)
     {
      case SlotTypes_Open:
         stringCaptionText="Opening Point of the Position";
         break;
      case SlotTypes_OpenFilter:
         stringCaptionText="Opening Logic Condition";
         break;
      case SlotTypes_Close:
         stringCaptionText="Closing Point of the Position";
         break;
      case SlotTypes_CloseFilter:
         stringCaptionText="Closing Logic Condition";
         break;
     }

   return (stringCaptionText);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
SlotTypes SlotTypeFromShortString(string shortString)
  {
   if(shortString=="Open")
      return (SlotTypes_Open);
   if(shortString=="OpenFilter")
      return (SlotTypes_OpenFilter);
   if(shortString=="Close")
      return (SlotTypes_Close);
   if(shortString=="CloseFilter")
      return (SlotTypes_CloseFilter);

   return (SlotTypes_NotDefined);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool StringBoolToBool(string flag)
  {
   return (flag == "True" || flag == "true");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringRemoveWhite(string instring)
  {
   if(instring=="" || instring==NULL)
      return ("");
   string out=instring;
   string white[4]={" ","\r","\n","\t"};
   for(int i=0; i<ArraySize(white); i++)
     {
      StringReplace(out,white[i],"");
     }
   return (out);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class ListString
  {
   int               m_count;
   string            m_data[];
public:
   void              Add(string element);
   bool              Contains(string element);
   int               Count();
   string            Get(int index);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ListString::Add(string element)
  {
   ArrayResize(m_data,m_count+1);
   m_data[m_count]=element;
   m_count++;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ListString::Contains(string element)
  {
   for(int i=0; i<m_count; i++)
     {
      if(m_data[i]==element)
         return (true);
     }
   return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ListString::Count()
  {
   return(m_count);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string ListString::Get(int index)
  {
   return(m_data[index]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class DictStringBool
  {
   int               m_count;
   string            m_key[];
   bool              m_val[];
public:
   void              Add(string key,bool value);
   int               Count();
   bool              ContainsKey(string key);
   void              Set(string key,bool value);
   string            Key(int index);
   bool              Value(string key);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DictStringBool::Add(string key,bool value)
  {
   ArrayResize(m_key,m_count+1);
   ArrayResize(m_val,m_count+1);
   m_key[m_count] = key;
   m_val[m_count] = value;
   m_count++;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int DictStringBool::Count()
  {
   return (m_count);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool DictStringBool::ContainsKey(string key)
  {
   if(m_count==0)
      return (false);
   for(int i=0; i<m_count; i++)
     {
      if(m_key[i]==key)
         return (true);
     }
   return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DictStringBool::Set(string key,bool value)
  {
   for(int i=0; i<m_count; i++)
     {
      if(m_key[i]==key)
        {
         m_val[i]=value;
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string DictStringBool::Key(int index)
  {
   return(m_key[index]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool DictStringBool::Value(string key)
  {
   for(int i=0; i<m_count; i++)
     {
      if(m_key[i]==key)
         return (m_val[i]);
     }

   Print("ERROR DictStringBool::Value: Geven key does not exist.");
   return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetFridayCloseHour(void)
  {
   datetime time[];
   int bars=CopyTime(_Symbol,PERIOD_H1,0,7*24,time);
   int fridayCloseHour=-1;

   for(int i=0;i<bars-1;i++)
     {
      MqlDateTime time0; TimeToStruct(time[i+0],time0);
      MqlDateTime time1; TimeToStruct(time[i+1],time1);
      if(time0.day_of_week==5 && time1.day_of_week!=5)
        {
         fridayCloseHour=time0.hour+1;
         PrintFormat("Detected Friday closing time: %d:00",fridayCloseHour);
         break;
        }
     }

   return (fridayCloseHour);
  }
//+------------------------------------------------------------------+

string GetErrorDescription(int errorCode)
  {
   string message;

   switch(errorCode)
     {
      //--- codes returned from trade server
      case 0:    message = "No error"; break;
      case 1:    message = "No error, trade conditions not changed"; break;
      case 2:    message = "Common error"; break;
      case 3:    message = "Invalid trade parameters"; break;
      case 4:    message = "Trade server is busy"; break;
      case 5:    message = "Old version of the client terminal"; break;
      case 6:    message = "No connection with trade server"; break;
      case 7:    message = "Not enough rights"; break;
      case 8:    message = "Too frequent requests"; break;
      case 9:    message = "Malfunctional trade operation (never returned error)"; break;
      case 64:   message = "Account disabled"; break;
      case 65:   message = "Invalid account"; break;
      case 128:  message = "Trade timeout"; break;
      case 129:  message = "Invalid price"; break;
      case 130:  message = "Invalid stops"; break;
      case 131:  message = "Invalid trade volume"; break;
      case 132:  message = "Market is closed"; break;
      case 133:  message = "Trade is disabled"; break;
      case 134:  message = "Not enough money"; break;
      case 135:  message = "Price changed"; break;
      case 136:  message = "Off quotes"; break;
      case 137:  message = "Broker is busy (never returned error)"; break;
      case 138:  message = "Requote"; break;
      case 139:  message = "Order is locked"; break;
      case 140:  message = "Long positions only allowed"; break;
      case 141:  message = "Too many requests"; break;
      case 145:  message = "Modification denied because order is too close to market"; break;
      case 146:  message = "Trade context is busy"; break;
      case 147:  message = "Expirations are denied by broker"; break;
      case 148:  message = "Amount of open and pending orders has reached the limit"; break;
      case 149:  message = "Hedging is prohibited"; break;
      case 150:  message = "Prohibited by FIFO rules"; break;
      //--- mql4 errors case 4000: message = "No error (never generated code)";
      case 4001: message = "Wrong function pointer"; break;
      case 4002: message = "Array index is out of range"; break;
      case 4003: message = "No memory for function call stack"; break;
      case 4004: message = "Recursive stack overflow"; break;
      case 4005: message = "Not enough stack for parameter"; break;
      case 4006: message = "No memory for parameter string"; break;
      case 4007: message = "No memory for temp string"; break;
      case 4008: message = "Non-initialized string"; break;
      case 4009: message = "Non-initialized string in array"; break;
      case 4010: message = "No memory for array string"; break;
      case 4011: message = "Too long string"; break;
      case 4012: message = "Remainder from zero divide"; break;
      case 4013: message = "Zero divide"; break;
      case 4014: message = "Unknown command"; break;
      case 4015: message = "Wrong jump (never generated error)"; break;
      case 4016: message = "Non-initialized array"; break;
      case 4017: message = "Dll calls are not allowed"; break;
      case 4018: message = "Cannot load library"; break;
      case 4019: message = "Cannot call function"; break;
      case 4020: message = "Expert function calls are not allowed"; break;
      case 4021: message = "Not enough memory for temp string returned from function"; break;
      case 4022: message = "System is busy (never generated error)"; break;
      case 4023: message = "Dll-function call critical error"; break;
      case 4024: message = "Internal error"; break;
      case 4025: message = "Out of memory"; break;
      case 4026: message = "Invalid pointer"; break;
      case 4027: message = "Too many formatters in the format function"; break;
      case 4028: message = "Parameters count is more than formatters count"; break;
      case 4029: message = "Invalid array"; break;
      case 4030: message = "No reply from chart"; break;
      case 4050: message = "Invalid function parameters count"; break;
      case 4051: message = "Invalid function parameter value"; break;
      case 4052: message = "String function internal error"; break;
      case 4053: message = "Some array error"; break;
      case 4054: message = "Incorrect series array usage"; break;
      case 4055: message = "Custom indicator error"; break;
      case 4056: message = "Arrays are incompatible"; break;
      case 4057: message = "Global variables processing error"; break;
      case 4058: message = "Global variable not found"; break;
      case 4059: message = "Function is not allowed in testing mode"; break;
      case 4060: message = "Function is not confirmed"; break;
      case 4061: message = "Send mail error"; break;
      case 4062: message = "String parameter expected"; break;
      case 4063: message = "Integer parameter expected"; break;
      case 4064: message = "Double parameter expected"; break;
      case 4065: message = "Array as parameter expected"; break;
      case 4066: message = "Requested history data is in update state"; break;
      case 4067: message = "Internal trade error"; break;
      case 4068: message = "Resource not found"; break;
      case 4069: message = "Resource not supported"; break;
      case 4070: message = "Duplicate resource"; break;
      case 4071: message = "Cannot initialize custom indicator"; break;
      case 4072: message = "Cannot load custom indicator"; break;
      case 4073: message = "No history data"; break;
      case 4074: message = "No memory for history data"; break;
      case 4099: message = "End of file"; break;
      case 4100: message = "Some file error"; break;
      case 4101: message = "Wrong file name"; break;
      case 4102: message = "Too many opened files"; break;
      case 4103: message = "Cannot open file"; break;
      case 4104: message = "Incompatible access to a file"; break;
      case 4105: message = "No order selected"; break;
      case 4106: message = "Unknown symbol"; break;
      case 4107: message = "Invalid price parameter for trade function"; break;
      case 4108: message = "Invalid ticket"; break;
      case 4109: message = "Trade is not allowed in the expert properties"; break;
      case 4110: message = "Longs are not allowed in the expert properties"; break;
      case 4111: message = "Shorts are not allowed in the expert properties"; break;
      case 4200: message = "Object already exists"; break;
      case 4201: message = "Unknown object property"; break;
      case 4202: message = "Object does not exist"; break;
      case 4203: message = "Unknown object type"; break;
      case 4204: message = "No object name"; break;
      case 4205: message = "Object coordinates error"; break;
      case 4206: message = "No specified subwindow"; break;
      case 4207: message = "Graphical object error"; break;
      case 4210: message = "Unknown chart property"; break;
      case 4211: message = "Chart not found"; break;
      case 4212: message = "Chart subwindow not found"; break;
      case 4213: message = "Chart indicator not found"; break;
      case 4220: message = "Symbol select error"; break;
      case 4250: message = "Notification error"; break;
      case 4251: message = "Notification parameter error"; break;
      case 4252: message = "Notifications disabled"; break;
      case 4253: message = "Notification send too frequent"; break;
      case 5001: message = "Too many opened files"; break;
      case 5002: message = "Wrong file name"; break;
      case 5003: message = "Too long file name"; break;
      case 5004: message = "Cannot open file"; break;
      case 5005: message = "Text file buffer allocation error"; break;
      case 5006: message = "Cannot delete file"; break;
      case 5007: message = "Invalid file handle (file closed or was not opened)"; break;
      case 5008: message = "Wrong file handle (handle index is out of handle table)"; break;
      case 5009: message = "File must be opened with FILE_WRITE flag"; break;
      case 5010: message = "File must be opened with FILE_READ flag"; break;
      case 5011: message = "File must be opened with FILE_BIN flag"; break;
      case 5012: message = "File must be opened with FILE_TXT flag"; break;
      case 5013: message = "File must be opened with FILE_TXT or FILE_CSV flag"; break;
      case 5014: message = "File must be opened with FILE_CSV flag"; break;
      case 5015: message = "File read error"; break;
      case 5016: message = "File write error"; break;
      case 5017: message = "String size must be specified for binary file"; break;
      case 5018: message = "Incompatible file (for string arrays-TXT, for others-BIN)"; break;
      case 5019: message = "File is directory, not file"; break;
      case 5020: message = "File does not exist"; break;
      case 5021: message = "File cannot be rewritten"; break;
      case 5022: message = "Wrong directory name"; break;
      case 5023: message = "Directory does not exist"; break;
      case 5024: message = "Specified file is not directory"; break;
      case 5025: message = "Cannot delete directory"; break;
      case 5026: message = "Cannot clean directory"; break;
      case 5027: message = "Array resize error"; break;
      case 5028: message = "String resize error"; break;
      case 5029: message = "Structure contains strings or dynamic arrays"; break;
      default:   message = "Unknown error"; break;
     }

   return (message);
  }
//+------------------------------------------------------------------+

class DataSet
  {
public:
   // Constructor
                     DataSet(string chart);

   // Properties
   string            Chart;
   string            Symbol;
   DataPeriod        Period;

   int               LotSize;
   double            Spread;
   int               Digits;
   double            Point;
   double            Pip;
   bool              IsFiveDigits;
   int               StopLevel;
   double            TickValue;
   double            MinLot;
   double            MaxLot;
   double            LotStep;
   double            MarginRequired;

   int               Bars;

   datetime          ServerTime;
   double            Bid;
   double            Ask;

   datetime          Time[];
   double            Open[];
   double            High[];
   double            Low[];
   double            Close[];
   long              Volume[];

   // Methods
   void              SetPrecision(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DataSet::DataSet(string chart)
  {
   Chart=chart;
   string parts[];
   StringSplit(chart,',',parts);
   Symbol = parts[0];
   Period = StringToDataPeriod(parts[1]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DataSet::SetPrecision(void)
  {
   IsFiveDigits=(Digits==3 || Digits==5);
   Point=1/MathPow(10,Digits);
   Pip=IsFiveDigits ? (10*Point) : Point;
  }
//+------------------------------------------------------------------+

class DataMarket
  {
public:
   string            Symbol;
   DataPeriod        Period;

   bool              IsNewBid;

   double            OldBid;
   double            OldAsk;
   double            OldClose;
   double            Bid;
   double            Ask;
   double            Close;
   long              Volume;

   datetime          TickLocalTime;
   datetime          TickServerTime;
   datetime          BarTime;

   double            AccountBalance;
   double            AccountEquity;
   double            AccountFreeMargin;

   double            PositionLots;
   double            PositionOpenPrice;
   datetime          PositionOpenTime;
   double            PositionStopLoss;
   double            PositionTakeProfit;
   double            PositionProfit;
   PosDirection      PositionDirection;

   int               ConsecutiveLosses;
   int               WrongStopLoss;
   int               WrongTakeProf;
   int               WrongStopsRetry;
   bool              IsFailedCloseOrder;
   int               CloseOrderTickCounter;
   bool              IsSentCloseOrder;

   int               LotSize;
   double            Spread;
   double            Point;
   int               StopLevel;
   double            TickValue;
   double            MinLot;
   double            MaxLot;
   double            LotStep;
   double            MarginRequired;
  };
//+------------------------------------------------------------------+

class IndicatorComp
  {
public:
   // Constructors
                     IndicatorComp();

   // Properties
   string            CompName;
   int               FirstBar;
   int               UsePreviousBar; // Deprecated
   IndComponentType  DataType;
   PositionPriceDependence PosPriceDependence;
   bool              ShowInDynInfo;
   double            Value[];

   // Methods
   double            GetLastValue(int indexFromEnd);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void IndicatorComp::IndicatorComp()
  {
   CompName           = "Not defined";
   DataType           = IndComponentType_NotDefined;
   FirstBar           = 0;
   UsePreviousBar     = 0;
   ShowInDynInfo      = true;
   PosPriceDependence = PositionPriceDependence_None;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double IndicatorComp::GetLastValue(int indexFromEnd=0)
  {
   int bars=ArraySize(Value);
   double lastValue=(bars>indexFromEnd) ? Value[bars-indexFromEnd-1]: 0;
   return (lastValue);
  }
//+------------------------------------------------------------------+

class ListParameter
  {
public:
   // Constructors
   ListParameter()
     {
      Caption = "";
      Text    = "";
      Index   = -1;
      Enabled = false;
     }

   // Properties
   string            Caption;
   string            Text;
   int               Index;
   bool              Enabled;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class NumericParameter
  {
public:
   // Constructor
   NumericParameter()
     {
      Caption = "";
      Value   = 0;
      Enabled = false;
     }

   // Properties
   string            Caption;
   double            Value;
   bool              Enabled;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CheckParameter
  {
public:
   // Constructor
   CheckParameter()
     {
      Caption = "";
      Checked = false;
      Enabled = false;
     }

   // Properties
   string            Caption;
   bool              Checked;
   bool              Enabled;
  };
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Indicator
  {
protected:
   double            Sigma(void);

   double            Epsilon(void);

   void              NormalizeComponentValue(const double &componentValue[],const datetime &strategyTime[],
                                             int ltfShift,bool isCloseFilterShift,double &output[]);

   int               NormalizeComponentFirstBar(int componentFirstBar,datetime &strategyTime[]);

   bool              IsSignalComponent(IndComponentType componentType);

   void              Price(BasePrice priceType,double &price[]);

   void              MovingAverage(int period,int shift,MAMethod maMethod,const double &source[],double &movingAverage[]);

   void              OscillatorLogic(int firstBar,int previous,const double &adIndValue[],double levelLong,double levelShort,
                                     IndicatorComp &indCompLong,IndicatorComp &indCompShort,IndicatorLogic indLogic);

   void              NoDirectionOscillatorLogic(int firstBar,int previous,const double &adIndValue[],double dLevel,
                                                IndicatorComp &indComp,IndicatorLogic indLogic);

   void              BandIndicatorLogic(int firstBar,int previous,const double &adUpperBand[],const double &adLowerBand[],
                                        IndicatorComp &indCompLong,IndicatorComp &indCompShort,BandIndLogic indLogic);

   void              IndicatorRisesLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                         IndicatorComp &indCompShort);

   void              IndicatorFallsLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                         IndicatorComp &indCompShort);

   void              IndicatorChangesItsDirectionUpward(int firstBar,int previous,double &adIndValue[],
                                                        IndicatorComp &indCompLong,IndicatorComp &indCompShort);

   void              IndicatorChangesItsDirectionDownward(int firstBar,int previous,double &adIndValue[],
                                                          IndicatorComp &indCompLong,IndicatorComp &indCompShort);

   void              IndicatorIsHigherThanAnotherIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                                double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                                IndicatorComp &indCompShort);

   void              IndicatorIsLowerThanAnotherIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                               double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                               IndicatorComp &indCompShort);

   void              IndicatorCrossesAnotherIndicatorUpwardLogic(int firstBar,int previous,const double &adIndValue[],
                                                                 double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                                 IndicatorComp &indCompShort);

   void              IndicatorCrossesAnotherIndicatorDownwardLogic(int firstBar,int previous,const double &adIndValue[],
                                                                   double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                                   IndicatorComp &indCompShort);

   void              BarOpensAboveIndicatorLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                                 IndicatorComp &indCompShort);

   void              BarOpensBelowIndicatorLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                                 IndicatorComp &indCompShort);

   void              BarOpensAboveIndicatorAfterOpeningBelowLogic(int firstBar,int previous,const double &adIndValue[],
                                                                  IndicatorComp &indCompLong,IndicatorComp &indCompShort);

   void              BarOpensBelowIndicatorAfterOpeningAboveLogic(int firstBar,int previous,const double &adIndValue[],
                                                                  IndicatorComp &indCompLong,IndicatorComp &indCompShort);

   void              BarClosesAboveIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                  IndicatorComp &indCompLong,IndicatorComp &indCompShort);

   void              BarClosesBelowIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                  IndicatorComp &indCompLong,IndicatorComp &indCompShort);

public:
   // Constructors
                     Indicator(void);

                    ~Indicator(void);

   // Properties
   string            IndicatorName;
   string            WarningMessage;
   bool              IsDiscreteValues;
   bool              UsePreviousBarValue; // Important! Otdated Do not use.
   bool              IsSeparateChart;
   bool              IsBacktester;
   bool              IsDeafultGroupAll; // Important! Outdated. Do not use.
   bool              IsDefaultGroupAll;
   bool              IsAllowLTF;

   SlotTypes         SlotType;
   ExecutionTime     ExecTime;

   ListParameter    *ListParam[5];
   NumericParameter *NumParam[6];
   CheckParameter   *CheckParam[2];

   IndicatorComp    *Component[10];
   DataSet          *Data;

   // Methods
   virtual void      Calculate(DataSet &dataSet);
   void              NormalizeComponents(DataSet &strategyDataSet,int ltfShift,bool isCloseFilterShift);
   void              ShiftSignal(int shift);
   void              RepeatSignal(int repeat);
   int               Components(void);
   string            IndicatorParamToString(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Indicator::Indicator(void)
  {
   IndicatorName="";

   IsBacktester      = false;
   IsDiscreteValues  = false;
   IsSeparateChart   = false;
   IsDeafultGroupAll = false;
   IsDefaultGroupAll = false;
   IsAllowLTF        = true;

   SlotType = SlotTypes_NotDefined;
   ExecTime = ExecutionTime_DuringTheBar;

   for(int i=0; i<5; i++)
      ListParam[i]=new ListParameter();

   for(int i=0; i<6; i++)
      NumParam[i]=new NumericParameter();

   for(int i=0; i<2; i++)
      CheckParam[i]=new CheckParameter();

   for(int i=0; i<10; i++)
      Component[i]=new IndicatorComp();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Indicator::~Indicator(void)
  {
   for(int i=0; i<5; i++)
      delete ListParam[i];

   for(int i=0; i<6; i++)
      delete NumParam[i];

   for(int i=0; i<2; i++)
      delete CheckParam[i];

   for(int i=0; i<10; i++)
      delete Component[i];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::Calculate(DataSet &dataSet)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::NormalizeComponents(DataSet &strategyDataSet,int ltfShift,bool isCloseFilterShift)
  {
   for(int i=0; i<Components(); i++)
     {
      if(Component[i].PosPriceDependence!=PositionPriceDependence_None)
         ltfShift=1;

      double value[];
      NormalizeComponentValue(Component[i].Value,strategyDataSet.Time,ltfShift,isCloseFilterShift,value);
      ArrayCopy(Component[i].Value,value);
      Component[i].FirstBar=NormalizeComponentFirstBar(Component[i].FirstBar,strategyDataSet.Time);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::ShiftSignal(int shift)
  {
   for(int i=0; i<Components(); i++)
     {
      if(!IsSignalComponent(Component[i].DataType))
         continue;
      int bars=ArraySize(Component[i].Value);
      double value[];
      ArrayResize(value,bars);
      ArrayInitialize(value,0);
      ArrayCopy(value,Component[i].Value,shift,0,WHOLE_ARRAY);
      for(int bar=0; bar<bars; bar++)
         Component[i].Value[bar]=value[bar];
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::RepeatSignal(int repeat)
  {
   for(int i=0; i<Components(); i++)
     {
      if(!IsSignalComponent(Component[i].DataType))
         continue;
      int bars=ArraySize(Component[i].Value);
      for(int bar=0; bar<bars; bar++)
        {
         if(Component[i].Value[bar]<0.5)
            continue;
         for(int r=1; r<=repeat; r++)
            if(++bar<bars)
               Component[i].Value[bar]=1;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::NormalizeComponentValue(const double &componentValue[],const datetime &strategyTime[],
                                        int ltfShift,bool isCloseFilterShift,double &output[])
  {
   int strategyBars=ArraySize(strategyTime);
   ArrayResize(output,strategyBars); ArrayInitialize(output,0);
   int reachedBar=0;
   datetime strategyPeriodMinutes=strategyTime[1]-strategyTime[0];

   for(int ltfBar=ltfShift; ltfBar<Data.Bars; ltfBar++)
     {
      datetime ltfOpenTime=Data.Time[ltfBar];
      datetime ltfCloseTime=ltfOpenTime+((int) Data.Period)*60;

      for(int bar=reachedBar; bar<strategyBars; bar++)
        {
         reachedBar=bar;
         datetime time=strategyTime[bar];
         datetime barCloseTime=time+strategyPeriodMinutes;

         if(isCloseFilterShift && barCloseTime==ltfCloseTime)
           {
            output[bar]=componentValue[ltfBar];
           }
         else
           {
            if(time>=ltfOpenTime && time<ltfCloseTime)
               output[bar]=componentValue[ltfBar-ltfShift];
            else if(time>=ltfCloseTime)
                          break;
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Indicator::NormalizeComponentFirstBar(int componentFirstBar,datetime &strategyTime[])
  {
   datetime firstBarTime=Data.Time[componentFirstBar];
   for(int bar=0; bar<ArraySize(strategyTime); bar++)
      if(strategyTime[bar]>=firstBarTime)
         return bar;
   return componentFirstBar;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Indicator::IsSignalComponent(IndComponentType componentType)
  {
   return
   componentType == IndComponentType_AllowOpenLong   ||
   componentType == IndComponentType_AllowOpenShort  ||
   componentType == IndComponentType_CloseLongPrice  ||
   componentType == IndComponentType_ClosePrice      ||
   componentType == IndComponentType_CloseShortPrice ||
   componentType == IndComponentType_ForceClose      ||
   componentType == IndComponentType_ForceCloseLong  ||
   componentType == IndComponentType_ForceCloseShort ||
   componentType == IndComponentType_OpenClosePrice  ||
   componentType == IndComponentType_OpenLongPrice   ||
   componentType == IndComponentType_OpenPrice       ||
   componentType == IndComponentType_OpenShortPrice;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Indicator::Components(void)
  {
   for(int i=0; i<10; i++)
      if(Component[i].DataType==IndComponentType_NotDefined)
         return (i);
   return (10);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Indicator::IndicatorParamToString(void)
  {
   string text;

   for(int i=0; i<5; i++)
      if(ListParam[i].Enabled)
         text+=StringFormat("%s: %s\n",ListParam[i].Caption,ListParam[i].Text);

   for(int i=0; i<6; i++)
      if(NumParam[i].Enabled)
         text+=StringFormat("%s: %g\n",NumParam[i].Caption,NumParam[i].Value);

   for(int i=0; i<2; i++)
      if(CheckParam[i].Enabled)
         text+=StringFormat("%s: %s\n",CheckParam[i].Caption,(CheckParam[i].Checked ? "Yes" : "No"));

   return (text);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::Price(BasePrice priceType,double &price[])
  {
   ArrayResize(price,Data.Bars);
   ArrayInitialize(price,0);

   switch(priceType)
     {
      case BasePrice_Open:
         ArrayCopy(price,Data.Open);
         break;
      case BasePrice_High:
         ArrayCopy(price,Data.High);
         break;
      case BasePrice_Low:
         ArrayCopy(price,Data.Low);
         break;
      case BasePrice_Close:
         ArrayCopy(price,Data.Close);
         break;
      case BasePrice_Median:
         for(int bar=0; bar<Data.Bars; bar++)
         price[bar]=(Data.Low[bar]+Data.High[bar])/2;
         break;
      case BasePrice_Typical:
         for(int bar=0; bar<Data.Bars; bar++)
         price[bar]=(Data.Low[bar]+Data.High[bar]+Data.Close[bar])/3;
         break;
      case BasePrice_Weighted:
         for(int bar=0; bar<Data.Bars; bar++)
         price[bar]=(Data.Low[bar]+Data.High[bar]+2*Data.Close[bar])/4;
         break;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::MovingAverage(int period,int shift,MAMethod maMethod,const double &source[],double &movingAverage[])
  {
   int bars=ArraySize(source);
   ArrayResize(movingAverage,bars);
   ArrayInitialize(movingAverage,0);

   if(period<=1 && shift==0)
     {
      // There is no smoothing
      ArrayCopy(movingAverage,source);
      return;
     }

   if(period>bars || period+shift<=0 || period+shift>bars)
     {
      // Error in the parameters
      string message=IndicatorName+" "+Data.Symbol+" "+DataPeriodToString(Data.Period)+
                     "Wrong MovingAverage parameters(Period: "+IntegerToString(period)+
                     ", Shift: "+IntegerToString(shift)+
                     ", Source bars: "+IntegerToString(bars)+")";
      Print(message);
      ArrayCopy(movingAverage,source);
      return;
     }

   for(int bar=0; bar<period+shift-1; bar++)
      movingAverage[bar]=0;

   double sum=0;
   for(int bar=0; bar<period; bar++)
      sum+=source[bar];

   movingAverage[period+shift-1]=sum/period;
   int lastBar=MathMin(bars,bars-shift);

   switch(maMethod)
     {
      case MAMethod_Simple:
        {
         for(int bar=period; bar<lastBar; bar++)
            movingAverage[bar+shift]=movingAverage[bar+shift-1]+source[bar]/period -
                                     source[bar-period]/period;
        }
      break;
      case MAMethod_Exponential:
        {
         double pr=2.0/(period+1);
         for(int bar=period; bar<lastBar; bar++)
            movingAverage[bar+shift]=source[bar] *pr+movingAverage[bar+shift-1]*(1-pr);
        }
      break;
      case MAMethod_Weighted:
        {
         double weight=period *(period+1)/2.0;
         for(int bar=period; bar<lastBar; bar++)
           {
            sum=0;
            for(int i=0; i<period; i++)
               sum+=source[bar-i]*(period-i);
            movingAverage[bar+shift]=sum/weight;
           }
        }
      break;
      case MAMethod_Smoothed:
        {
         for(int bar=period; bar<lastBar; bar++)
            movingAverage[bar+shift]=(movingAverage[bar+shift-1]*(period-1)+
                                      source[bar])/period;
        }
      break;
      default:
         break;
     }

   for(int bar=bars+shift; bar<bars; bar++)
      movingAverage[bar]=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Indicator::Sigma(void)
  {
   return (IsSeparateChart ? 0.000005 : Data.Point * 0.5);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Indicator::Epsilon(void)
  {
   return (0.0000001);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::OscillatorLogic(int firstBar,int previous,const double &adIndValue[],double levelLong,
                                double levelShort,IndicatorComp &indCompLong,IndicatorComp &indCompShort,
                                IndicatorLogic indLogic)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   switch(indLogic)
     {
      case IndicatorLogic_The_indicator_rises:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int currentBar=bar-previous;
            int baseBar=currentBar-1;
            bool isHigher=adIndValue[currentBar]>adIndValue[baseBar];

            if(!IsDiscreteValues) // Aroon oscillator uses IsDiscreteValues = true
              {
               bool isNoChange=true;
               while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && 
                     isNoChange && baseBar>firstBar)
                 {
                  isNoChange=(isHigher==(adIndValue[baseBar+1]>adIndValue[baseBar]));
                  baseBar--;
                 }
              }

            indCompLong.Value[bar]  = adIndValue[baseBar] < adIndValue[currentBar] - sigma ? 1 : 0;
            indCompShort.Value[bar] = adIndValue[baseBar] > adIndValue[currentBar] + sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_falls:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int  currentBar = bar - previous;
            int  baseBar    = currentBar - 1;
            bool isHigher   = adIndValue[currentBar] > adIndValue[baseBar];

            if(!IsDiscreteValues) // Aroon oscillator uses IsDiscreteValues = true
              {
               bool isNoChange=true;
               while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && isNoChange && 
                     baseBar>firstBar)
                 {
                  isNoChange=(isHigher==(adIndValue[baseBar+1]>adIndValue[baseBar]));
                  baseBar--;
                 }
              }

            indCompLong.Value[bar]  = adIndValue[baseBar] > adIndValue[currentBar] + sigma ? 1 : 0;
            indCompShort.Value[bar] = adIndValue[baseBar] < adIndValue[currentBar] - sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_is_higher_than_the_level_line:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = adIndValue[bar - previous] > levelLong + sigma  ? 1 : 0;
            indCompShort.Value[bar] = adIndValue[bar - previous] < levelShort - sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_is_lower_than_the_level_line:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = adIndValue[bar - previous] < levelLong - sigma  ? 1 : 0;
            indCompShort.Value[bar] = adIndValue[bar - previous] > levelShort + sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_crosses_the_level_line_upward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-previous-1;
            while(MathAbs(adIndValue[baseBar]-levelLong)<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=(adIndValue[baseBar]<levelLong-sigma && 
                                    adIndValue[bar-previous]>levelLong+sigma) ? 1 : 0;
            indCompShort.Value[bar]=(adIndValue[baseBar]>levelShort+sigma && 
                                     adIndValue[bar-previous]<levelShort-sigma) ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_crosses_the_level_line_downward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-previous-1;
            while(MathAbs(adIndValue[baseBar]-levelLong)<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=(adIndValue[baseBar]>levelLong+sigma && 
                                    adIndValue[bar-previous]<levelLong-sigma) ? 1 : 0;
            indCompShort.Value[bar]=(adIndValue[baseBar]<levelShort-sigma && 
                                     adIndValue[bar-previous]>levelShort+sigma) ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_changes_its_direction_upward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int bar0 = bar - previous;
            int bar1 = bar0 - 1;
            while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
               bar1--;

            int iBar2=bar1-1>firstBar ? bar1-1 : firstBar;
            while(MathAbs(adIndValue[bar1]-adIndValue[iBar2])<sigma && iBar2>firstBar)
               iBar2--;

            indCompLong.Value[bar]=(adIndValue[iBar2]>adIndValue[bar1] && adIndValue[bar1]<adIndValue[bar0] && 
                                    bar1==bar0-1) ? 1 : 0;
            indCompShort.Value[bar]=(adIndValue[iBar2]<adIndValue[bar1] && 
                                     adIndValue[bar1]>adIndValue[bar0] && bar1==bar0-1) ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_changes_its_direction_downward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int bar0 = bar - previous;
            int bar1 = bar0 - 1;
            while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
               bar1--;

            int iBar2=bar1-1>firstBar ? bar1-1 : firstBar;
            while(MathAbs(adIndValue[bar1]-adIndValue[iBar2])<sigma && iBar2>firstBar)
               iBar2--;

            indCompLong.Value[bar]=(adIndValue[iBar2]<adIndValue[bar1] && adIndValue[bar1]>adIndValue[bar0] && 
                                    bar1==bar0-1) ? 1 : 0;
            indCompShort.Value[bar]=(adIndValue[iBar2]>adIndValue[bar1] && 
                                     adIndValue[bar1]<adIndValue[bar0] && bar1==bar0-1) ? 1 : 0;
           }
         break;

      default:
         return;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::NoDirectionOscillatorLogic(int firstBar,int previous,const double &adIndValue[],double dLevel,
                                           IndicatorComp &indComp,IndicatorLogic indLogic)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
      indComp.Value[bar]=0;

   switch(indLogic)
     {
      case IndicatorLogic_The_indicator_rises:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int  currentBar = bar - previous;
            int  baseBar    = currentBar - 1;
            bool isHigher   = adIndValue[currentBar] > adIndValue[baseBar];
            bool isNoChange = true;

            while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && isNoChange && baseBar>firstBar)
              {
               isNoChange=(isHigher==(adIndValue[baseBar+1]>adIndValue[baseBar]));
               baseBar--;
              }

            indComp.Value[bar]=adIndValue[baseBar]<adIndValue[currentBar]-sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_falls:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int  currentBar = bar - previous;
            int  baseBar    = currentBar - 1;
            bool isHigher   = adIndValue[currentBar] > adIndValue[baseBar];
            bool isNoChange = true;

            while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && isNoChange && baseBar>firstBar)
              {
               isNoChange=(isHigher==(adIndValue[baseBar+1]>adIndValue[baseBar]));
               baseBar--;
              }

            indComp.Value[bar]=adIndValue[baseBar]>adIndValue[currentBar]+sigma ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_is_higher_than_the_level_line:
         for(int bar=firstBar; bar<Data.Bars; bar++)
         indComp.Value[bar]=adIndValue[bar-previous]>dLevel+sigma ? 1 : 0;
         break;

      case IndicatorLogic_The_indicator_is_lower_than_the_level_line:
         for(int bar=firstBar; bar<Data.Bars; bar++)
         indComp.Value[bar]=adIndValue[bar-previous]<dLevel-sigma ? 1 : 0;
         break;

      case IndicatorLogic_The_indicator_crosses_the_level_line_upward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-previous-1;
            while(MathAbs(adIndValue[baseBar]-dLevel)<sigma && baseBar>firstBar)
               baseBar--;

            indComp.Value[bar]=(adIndValue[baseBar]<dLevel-sigma && 
                                adIndValue[bar-previous]>dLevel+sigma)
            ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_crosses_the_level_line_downward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-previous-1;
            while(MathAbs(adIndValue[baseBar]-dLevel)<sigma && baseBar>firstBar)
               baseBar--;

            indComp.Value[bar]=(adIndValue[baseBar]>dLevel+sigma && 
                                adIndValue[bar-previous]<dLevel-sigma) ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_changes_its_direction_upward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int bar0 = bar - previous;
            int bar1 = bar0 - 1;
            while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
               bar1--;

            int bar2=bar1-1>firstBar ? bar1-1 : firstBar;
            while(MathAbs(adIndValue[bar1]-adIndValue[bar2])<sigma && bar2>firstBar)
               bar2--;

            indComp.Value[bar]=(adIndValue[bar2]>adIndValue[bar1] && adIndValue[bar1]<adIndValue[bar0] && 
                                bar1==bar0-1) ? 1 : 0;
           }
         break;

      case IndicatorLogic_The_indicator_changes_its_direction_downward:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int bar0 = bar - previous;
            int bar1 = bar0 - 1;
            while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
               bar1--;

            int bar2=bar1-1>firstBar ? bar1-1 : firstBar;
            while(MathAbs(adIndValue[bar1]-adIndValue[bar2])<sigma && bar2>firstBar)
               bar2--;

            indComp.Value[bar]=(adIndValue[bar2]<adIndValue[bar1] && adIndValue[bar1]>adIndValue[bar0] && 
                                bar1==bar0-1) ? 1 : 0;
           }
         break;

      default:
         return;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BandIndicatorLogic(int firstBar,int previous,const double &adUpperBand[],const double &adLowerBand[],
                                   IndicatorComp &indCompLong,IndicatorComp &indCompShort,BandIndLogic indLogic)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   switch(indLogic)
     {
      case BandIndLogic_The_bar_opens_below_the_Upper_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Open[bar] < adUpperBand[bar - previous] - sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Open[bar] > adLowerBand[bar - previous] + sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_above_the_Upper_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Open[bar] > adUpperBand[bar - previous] + sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Open[bar] < adLowerBand[bar - previous] - sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_below_the_Lower_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Open[bar] < adLowerBand[bar - previous] - sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Open[bar] > adUpperBand[bar - previous] + sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_above_the_Lower_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Open[bar] > adLowerBand[bar - previous] + sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Open[bar] < adUpperBand[bar - previous] - sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_below_Upper_Band_after_above:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adUpperBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=Data.Open[bar]<adUpperBand[bar-previous]-sigma && 
                                   Data.Open[baseBar]>adUpperBand[baseBar-previous]+sigma ? 1 : 0;

            baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adLowerBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompShort.Value[bar]=Data.Open[bar]>adLowerBand[bar-previous]+sigma && 
                                    Data.Open[baseBar]<adLowerBand[baseBar-previous]-sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_above_Upper_Band_after_below:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adUpperBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=Data.Open[bar]>adUpperBand[bar-previous]+sigma && 
                                   Data.Open[baseBar]<adUpperBand[baseBar-previous]-sigma ? 1 : 0;

            baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adLowerBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompShort.Value[bar]=Data.Open[bar]<adLowerBand[bar-previous]-sigma && 
                                    Data.Open[baseBar]>adLowerBand[baseBar-previous]+sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_below_Lower_Band_after_above:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adLowerBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=Data.Open[bar]<adLowerBand[bar-previous]-sigma && 
                                   Data.Open[baseBar]>adLowerBand[baseBar-previous]+sigma ? 1 : 0;

            baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adUpperBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompShort.Value[bar]=Data.Open[bar]>adUpperBand[bar-previous]+sigma && 
                                    Data.Open[baseBar]<adUpperBand[baseBar-previous]-sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_opens_above_Lower_Band_after_below:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            int baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adLowerBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompLong.Value[bar]=Data.Open[bar]>adLowerBand[bar-previous]+sigma && 
                                   Data.Open[baseBar]<adLowerBand[baseBar-previous]-sigma ? 1 : 0;

            baseBar=bar-1;
            while(MathAbs(Data.Open[baseBar]-adUpperBand[baseBar-previous])<sigma && baseBar>firstBar)
               baseBar--;

            indCompShort.Value[bar]=Data.Open[bar]<adUpperBand[bar-previous]-sigma && 
                                    Data.Open[baseBar]>adUpperBand[baseBar-previous]+sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_closes_below_the_Upper_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Close[bar] < adUpperBand[bar - previous] - sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Close[bar] > adLowerBand[bar - previous] + sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_closes_above_the_Upper_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Close[bar] > adUpperBand[bar - previous] + sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Close[bar] < adLowerBand[bar - previous] - sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_closes_below_the_Lower_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Close[bar] < adLowerBand[bar - previous] - sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Close[bar] > adUpperBand[bar - previous] + sigma ? 1 : 0;
           }
         break;

      case BandIndLogic_The_bar_closes_above_the_Lower_Band:
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            indCompLong.Value[bar]  = Data.Close[bar] > adLowerBand[bar - previous] + sigma ? 1 : 0;
            indCompShort.Value[bar] = Data.Close[bar] < adUpperBand[bar - previous] - sigma ? 1 : 0;
           }
         break;

      default:
         return;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorRisesLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                    IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int  currentBar = bar - previous;
      int  baseBar    = currentBar - 1;
      bool isNoChange = true;
      bool isHigher   = adIndValue[currentBar] > adIndValue[baseBar];

      while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && isNoChange && 
            baseBar>firstBar)
        {
         isNoChange=(isHigher==(adIndValue[baseBar+1]>adIndValue[baseBar]));
         baseBar--;
        }

      indCompLong.Value[bar]  = adIndValue[currentBar] > adIndValue[baseBar] + sigma ? 1 : 0;
      indCompShort.Value[bar] = adIndValue[currentBar] < adIndValue[baseBar] - sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorFallsLogic(int firstBar,int previous,const double &adIndValue[],IndicatorComp &indCompLong,
                                    IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int currentBar=bar-previous;
      int baseBar=currentBar-1;
      bool isNoChange=true;
      bool isLower=adIndValue[currentBar]<adIndValue[baseBar];

      while(MathAbs(adIndValue[currentBar]-adIndValue[baseBar])<sigma && isNoChange && 
            baseBar>firstBar)
        {
         isNoChange=(isLower==(adIndValue[baseBar+1]<adIndValue[baseBar]));
         baseBar--;
        }

      indCompLong.Value[bar]  = adIndValue[currentBar] < adIndValue[baseBar] - sigma ? 1 : 0;
      indCompShort.Value[bar] = adIndValue[currentBar] > adIndValue[baseBar] + sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorIsHigherThanAnotherIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                           double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                           IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int currentBar=bar-previous;
      indCompLong.Value[bar]  = adIndValue[currentBar] > adAnotherIndValue[currentBar] + sigma ? 1 : 0;
      indCompShort.Value[bar] = adIndValue[currentBar] < adAnotherIndValue[currentBar] - sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorIsLowerThanAnotherIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                                          double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                          IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int currentBar=bar-previous;
      indCompLong.Value[bar]  = adIndValue[currentBar] < adAnotherIndValue[currentBar] - sigma ? 1 : 0;
      indCompShort.Value[bar] = adIndValue[currentBar] > adAnotherIndValue[currentBar] + sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorChangesItsDirectionUpward(int firstBar,int previous,double &adIndValue[],
                                                   IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma= Sigma();
   for(int bar = firstBar; bar<Data.Bars; bar++)
     {
      int bar0 = bar - previous;
      int bar1 = bar0 - 1;
      while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
         bar1--;

      int bar2=bar1-1>firstBar ? bar1-1 : firstBar;
      while(MathAbs(adIndValue[bar1]-adIndValue[bar2])<sigma && bar2>firstBar)
         bar2--;

      indCompLong.Value[bar]=(adIndValue[bar2]>adIndValue[bar1] && adIndValue[bar1]<adIndValue[bar0] && 
                              bar1==bar0-1) ? 1 : 0;
      indCompShort.Value[bar]=(adIndValue[bar2]<adIndValue[bar1] && adIndValue[bar1]>adIndValue[bar0] && 
                               bar1==bar0-1) ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorChangesItsDirectionDownward(int firstBar,int previous,double &adIndValue[],
                                                     IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma= Sigma();
   for(int bar = firstBar; bar<Data.Bars; bar++)
     {
      int bar0 = bar - previous;
      int bar1 = bar0 - 1;
      while(MathAbs(adIndValue[bar0]-adIndValue[bar1])<sigma && bar1>firstBar)
         bar1--;

      int bar2=bar1-1>firstBar ? bar1-1 : firstBar;
      while(MathAbs(adIndValue[bar1]-adIndValue[bar2])<sigma && bar2>firstBar)
         bar2--;

      indCompLong.Value[bar]=(adIndValue[bar2]<adIndValue[bar1] && adIndValue[bar1]>adIndValue[bar0] && 
                              bar1==bar0-1) ? 1 : 0;
      indCompShort.Value[bar]=(adIndValue[bar2]>adIndValue[bar1] && adIndValue[bar1]<adIndValue[bar0] && 
                               bar1==bar0-1) ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorCrossesAnotherIndicatorUpwardLogic(int firstBar,int previous,const double &adIndValue[],
                                                            double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                            IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int currentBar=bar-previous;
      int baseBar=currentBar-1;
      while(MathAbs(adIndValue[baseBar]-adAnotherIndValue[baseBar])<sigma && baseBar>firstBar)
         baseBar--;

      indCompLong.Value[bar]=adIndValue[currentBar]>adAnotherIndValue[currentBar]+sigma && 
                             adIndValue[baseBar]<adAnotherIndValue[baseBar]-sigma ? 1 : 0;
      indCompShort.Value[bar]=adIndValue[currentBar]<adAnotherIndValue[currentBar]-sigma && 
                              adIndValue[baseBar]>adAnotherIndValue[baseBar]+sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::IndicatorCrossesAnotherIndicatorDownwardLogic(int firstBar,int previous,const double &adIndValue[],
                                                              double &adAnotherIndValue[],IndicatorComp &indCompLong,
                                                              IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int currentBar=bar-previous;
      int baseBar=currentBar-1;
      while(MathAbs(adIndValue[baseBar]-adAnotherIndValue[baseBar])<sigma && baseBar>firstBar)
        {
         baseBar--;
        }

      indCompLong.Value[bar]=adIndValue[currentBar]<adAnotherIndValue[currentBar]-sigma && 
                             adIndValue[baseBar]>adAnotherIndValue[baseBar]+sigma ? 1 : 0;
      indCompShort.Value[bar]=adIndValue[currentBar]>adAnotherIndValue[currentBar]+sigma && 
                              adIndValue[baseBar]<adAnotherIndValue[baseBar]-sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarOpensAboveIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                            IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      indCompLong.Value[bar]  = Data.Open[bar] > adIndValue[bar - previous] + sigma ? 1 : 0;
      indCompShort.Value[bar] = Data.Open[bar] < adIndValue[bar - previous] - sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarOpensBelowIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                            IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      indCompLong.Value[bar]  = Data.Open[bar] < adIndValue[bar - previous] - sigma ? 1 : 0;
      indCompShort.Value[bar] = Data.Open[bar] > adIndValue[bar - previous] + sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarOpensAboveIndicatorAfterOpeningBelowLogic(int firstBar,int previous,const double &adIndValue[],
                                                             IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int baseBar=bar-1;
      while(MathAbs(Data.Open[baseBar]-adIndValue[baseBar-previous])<sigma && baseBar>firstBar)
         baseBar--;

      indCompLong.Value[bar]=Data.Open[bar]>adIndValue[bar-previous]+sigma && 
                             Data.Open[baseBar]<adIndValue[baseBar-previous]-sigma ? 1 : 0;
      indCompShort.Value[bar]=Data.Open[bar]<adIndValue[bar-previous]-sigma && 
                              Data.Open[baseBar]>adIndValue[baseBar-previous]+sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarOpensBelowIndicatorAfterOpeningAboveLogic(int firstBar,int previous,const double &adIndValue[],
                                                             IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]=0;
      indCompShort.Value[bar]=0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      int baseBar=bar-1;
      while(MathAbs(Data.Open[baseBar]-adIndValue[baseBar-previous])<sigma && baseBar>firstBar)
         baseBar--;

      indCompLong.Value[bar]=Data.Open[bar]<adIndValue[bar-previous]-sigma && 
                             Data.Open[baseBar]>adIndValue[baseBar-previous]+sigma ? 1 : 0;
      indCompShort.Value[bar]=Data.Open[bar]>adIndValue[bar-previous]+sigma && 
                              Data.Open[baseBar]<adIndValue[baseBar-previous]-sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarClosesAboveIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                             IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      indCompLong.Value[bar]  = Data.Close[bar] > adIndValue[bar - previous] + sigma ? 1 : 0;
      indCompShort.Value[bar] = Data.Close[bar] < adIndValue[bar - previous] - sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Indicator::BarClosesBelowIndicatorLogic(int firstBar,int previous,const double &adIndValue[],
                                             IndicatorComp &indCompLong,IndicatorComp &indCompShort)
  {
   double sigma=Sigma();
   firstBar=MathMax(firstBar,2);

   for(int bar=0; bar<firstBar; bar++)
     {
      indCompLong.Value[bar]  = 0;
      indCompShort.Value[bar] = 0;
     }

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      indCompLong.Value[bar]  = Data.Close[bar] < adIndValue[bar - previous] - sigma ? 1 : 0;
      indCompShort.Value[bar] = Data.Close[bar] > adIndValue[bar - previous] + sigma ? 1 : 0;
     }
  }
//+------------------------------------------------------------------+


class DayOpening : public Indicator
  {
public:
                     DayOpening(SlotTypes slotType);
   virtual void      Calculate(DataSet &dataSet);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DayOpening::DayOpening(SlotTypes slotType)
  {
   SlotType          = slotType;
   IndicatorName     = "Day Opening";
   WarningMessage    = "";
   IsAllowLTF        = true;
   ExecTime          = ExecutionTime_AtBarOpening;
   IsSeparateChart   = false;
   IsDiscreteValues  = false;
   IsDefaultGroupAll = false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DayOpening::Calculate(DataSet &dataSet)
  {
   Data=GetPointer(dataSet);

   double openPrice[]; ArrayResize(openPrice,Data.Bars); ArrayInitialize(openPrice,0);

   for(int bar=1; bar<Data.Bars; bar++)
     {
      MqlDateTime time0; TimeToStruct(Data.Time[bar-0], time0);
      MqlDateTime time1; TimeToStruct(Data.Time[bar-1], time1);
      if(time0.day!=time1.day)
         openPrice[bar]=Data.Open[bar];
     }

   Component[0].CompName = "Opening price of the day";
   Component[0].DataType = IndComponentType_OpenPrice;
   Component[0].FirstBar = 2;
   ArrayResize(Component[0].Value,Data.Bars);
   ArrayCopy(Component[0].Value,openPrice);
  }
//+------------------------------------------------------------------+

class MACDHistogram : public Indicator
  {
public:
                     MACDHistogram(SlotTypes slotType);
   virtual void      Calculate(DataSet &dataSet);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MACDHistogram::MACDHistogram(SlotTypes slotType)
  {
   SlotType          = slotType;
   IndicatorName     = "MACD Histogram";
   WarningMessage    = "";
   IsAllowLTF        = true;
   ExecTime          = ExecutionTime_DuringTheBar;
   IsSeparateChart   = true;
   IsDiscreteValues  = false;
   IsDefaultGroupAll = false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MACDHistogram::Calculate(DataSet &dataSet)
  {
   Data=GetPointer(dataSet);

   MAMethod maMethod = (MAMethod) ListParam[1].Index;
   MAMethod slMethod = (MAMethod) ListParam[3].Index;
   BasePrice basePrice=(BasePrice) ListParam[2].Index;
   int slowPeriod = (int) NumParam[0].Value;
   int fastPeriod = (int) NumParam[1].Value;
   int signalPeriod=(int) NumParam[2].Value;
   double level=NumParam[3].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=MathMax(MathMax(slowPeriod,fastPeriod),signalPeriod)+previous+2;

   double price[];  Price(basePrice,price);
   double maSlow[]; MovingAverage(slowPeriod,0,maMethod,price,maSlow);
   double maFast[]; MovingAverage(fastPeriod,0,maMethod,price,maFast);
   double macd[];   ArrayResize(macd,Data.Bars); ArrayInitialize(macd,0);

   for(int bar=slowPeriod-1; bar<Data.Bars; bar++)
     {
      macd[bar]=maFast[bar]-maSlow[bar];
     }

   double maSignalLine[];
   MovingAverage(signalPeriod,0,slMethod,macd,maSignalLine);

   double adHistogram[];
   ArrayResize(adHistogram,Data.Bars);
   ArrayInitialize(adHistogram,0);
   for(int bar=slowPeriod+signalPeriod-1; bar<Data.Bars; bar++)
     {
      adHistogram[bar]=macd[bar]-maSignalLine[bar];
     }

   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "Histogram";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,adHistogram);

   ArrayResize(Component[1].Value,Data.Bars);
   Component[1].CompName = "Signal line";
   Component[1].DataType = IndComponentType_IndicatorValue;
   Component[1].FirstBar = firstBar;
   ArrayCopy(Component[1].Value,maSignalLine);

   ArrayResize(Component[2].Value,Data.Bars);
   Component[2].CompName = "MACD line";
   Component[2].DataType = IndComponentType_IndicatorValue;
   Component[2].FirstBar = firstBar;
   ArrayCopy(Component[2].Value,macd);

   ArrayResize(Component[3].Value,Data.Bars);
   Component[3].FirstBar=firstBar;

   ArrayResize(Component[4].Value,Data.Bars);
   Component[4].FirstBar=firstBar;

   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[3].DataType = IndComponentType_AllowOpenLong;
      Component[3].CompName = "Is long entry allowed";
      Component[4].DataType = IndComponentType_AllowOpenShort;
      Component[4].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[3].DataType = IndComponentType_ForceCloseLong;
      Component[3].CompName = "Close out long position";
      Component[4].DataType = IndComponentType_ForceCloseShort;
      Component[4].CompName = "Close out short position";
     }

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

   if(ListParam[0].Text=="MACD histogram rises")
      indLogic=IndicatorLogic_The_indicator_rises;
   else if(ListParam[0].Text=="MACD histogram falls")
      indLogic=IndicatorLogic_The_indicator_falls;
   else if(ListParam[0].Text=="MACD histogram is higher than the Level line")
      indLogic=IndicatorLogic_The_indicator_is_higher_than_the_level_line;
   else if(ListParam[0].Text=="MACD histogram is lower than the Level line")
      indLogic=IndicatorLogic_The_indicator_is_lower_than_the_level_line;
   else if(ListParam[0].Text=="MACD histogram crosses the Level line upward")
      indLogic=IndicatorLogic_The_indicator_crosses_the_level_line_upward;
   else if(ListParam[0].Text=="MACD histogram crosses the Level line downward")
      indLogic=IndicatorLogic_The_indicator_crosses_the_level_line_downward;
   else if(ListParam[0].Text=="MACD histogram changes its direction upward")
      indLogic=IndicatorLogic_The_indicator_changes_its_direction_upward;
   else if(ListParam[0].Text=="MACD histogram changes its direction downward")
      indLogic=IndicatorLogic_The_indicator_changes_its_direction_downward;

   OscillatorLogic(firstBar,previous,adHistogram,level,-level,Component[3],Component[4],indLogic);
  }
//+------------------------------------------------------------------+

class TrailingStop : public Indicator
  {
public:
   TrailingStop(SlotTypes slotType)
     {
      SlotType=slotType;

      IndicatorName="Trailing Stop";

      IsAllowLTF        = true;
      ExecTime          = ExecutionTime_DuringTheBar;
      IsSeparateChart   = false;
      IsDiscreteValues  = false;
      IsDefaultGroupAll = false;
     }

   virtual void Calculate(DataSet &dataSet);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void TrailingStop::Calculate(DataSet &dataSet)
  {
   Data=GetPointer(dataSet);

// Saving the components
   ArrayResize(Component[0].Value,Data.Bars);
   ArrayInitialize(Component[0].Value,0);
   Component[0].CompName = "Trailing Stop for the transferred position";
   Component[0].DataType = IndComponentType_Other;
   Component[0].ShowInDynInfo=false;
   Component[0].FirstBar=2;
  }
//+------------------------------------------------------------------+



class IndicatorManager
  {
public:
   Indicator        *CreateIndicator(string indicatorName,SlotTypes slotType);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Indicator *IndicatorManager::CreateIndicator(string indicatorName,SlotTypes slotType)
  {
   if(indicatorName == "Day Opening")               return new DayOpening(slotType);
   if(indicatorName == "MACD Histogram")            return new MACDHistogram(slotType);
   if(indicatorName == "Trailing Stop")             return new TrailingStop(slotType);
   
   return NULL;
  }
//+------------------------------------------------------------------+


class IndicatorSlot
  {
public:
   // Constructors
                     IndicatorSlot();
                    ~IndicatorSlot();

   // Properties
   int               SlotNumber;
   SlotTypes         SlotType;
   string            IndicatorName;
   string            LogicalGroup;
   int               SignalShift;
   int               SignalRepeat;
   string            IndicatorSymbol;
   DataPeriod        IndicatorPeriod;

   Indicator        *IndicatorPointer;

   // Methods
   bool              GetUsePreviousBarValue(void);
   string            LogicalGroupToString(void);
   string            AdvancedParamsToString(void);
   string            GetIndicatorSymbol(string baseSymbol);
   DataPeriod        GetIndicatorPeriod(DataPeriod basePeriod);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
IndicatorSlot::IndicatorSlot(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
IndicatorSlot::~IndicatorSlot(void)
  {
   if(CheckPointer(IndicatorPointer)==POINTER_DYNAMIC)
      delete IndicatorPointer;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IndicatorSlot::GetUsePreviousBarValue(void)
  {
   for(int i=0; i<ArraySize(IndicatorPointer.CheckParam); i++)
     {
      if(IndicatorPointer.CheckParam[i].Caption=="Use previous bar value")
         return (IndicatorPointer.CheckParam[i].Checked);
     }
   return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string IndicatorSlot::LogicalGroupToString(void)
  {
   return ("Logical group: " + LogicalGroup);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string IndicatorSlot::AdvancedParamsToString(void)
  {
   string text = "Signal shift: " + IntegerToString(SignalShift) + "\n";
   if(SlotType == SlotTypes_OpenFilter || SlotType==SlotTypes_CloseFilter)
      text+="Signal repeat: "+IntegerToString(SignalRepeat)+"\n";

   string symbol=(IndicatorSymbol=="") ? "Default" : IndicatorSymbol;
   string period=(IndicatorPeriod==DataPeriod_M1)
                 ? "Default"
                 : DataPeriodToString(IndicatorPeriod);
   text += "Symbol: " + symbol + "\n";
   text += "Period: " + period + "\n";

   return (text);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string IndicatorSlot::GetIndicatorSymbol(string baseSymbol)
  {
   string symbol=(IndicatorSymbol=="") ? baseSymbol : IndicatorSymbol;
   return (symbol);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
DataPeriod IndicatorSlot::GetIndicatorPeriod(DataPeriod basePeriod)
  {
   DataPeriod period=(IndicatorPeriod<basePeriod) ? basePeriod : IndicatorPeriod;
   return (period);
  }
//+------------------------------------------------------------------+

class Strategy
  {
private:
   // Fields
   string            strategySymbol;
   DataPeriod        strategyPeriod;
   bool              isInTester;
   int               openSlotsCount;
   int               closeSlotsCount;

   // Methods
   string            GetSlotChart(int slotNumber);

public:
   // Constructor, deconstructor
                     Strategy(int openSlots,int closeSlots);
                    ~Strategy(void);

   // Properties
   string            StrategyName;
   string            Description;
   double            AddingLots;
   double            ReducingLots;
   double            EntryLots;
   double            MaxOpenLots;
   bool              UseAccountPercentEntry;
   bool              UsePermanentSL;
   int               PermanentSL;
   bool              UsePermanentTP;
   int               PermanentTP;
   bool              UseBreakEven;
   int               BreakEven;
   bool              UseMartingale;
   double            MartingaleMultiplier;
   int               FirstBar;
   int               MinBarsRequired;
   int               RecommendedBars;

   PermanentProtectionType PermanentTPType;
   PermanentProtectionType PermanentSLType;
   OppositeDirSignalAction OppSignalAction;
   SameDirSignalAction SameSignalAction;

   IndicatorSlot    *Slot[];

   // Methods
   void        SetSymbol(string symbol)    { strategySymbol = symbol; }
   void        SetPeriod(int period)       { strategyPeriod = EnumTimeFramesToPeriod(period); }
   void        SetIsTester(bool isTester)  { isInTester = isTester; }
   string      GetSymbol(void)             { return (strategySymbol); }
   DataPeriod  GetPeriod(void)             { return (strategyPeriod); }
   bool        IsTester(void)              { return (isInTester); }
   int         OpenSlots(void)             { return (openSlotsCount); };
   int         CloseSlots(void)            { return (closeSlotsCount); };
   int         Slots(void)                 { return (openSlotsCount + closeSlotsCount + 2); }
   int         CloseSlotNumber(void)       { return (openSlotsCount + 1); }
   SlotTypes         GetSlotType(int slotNumber);
   void              GetRequiredCharts(string &charts[]);
   bool              IsUsingLogicalGroups(void);
   bool              IsLogicalGroupSpecial(int slotNumber);
   string            GetDefaultGroup(int slotNumber);
   bool              IsLongerTimeFrame(int slotNumber);
   void              CalculateStrategy(DataSet *&dataSet[]);
   string            DynamicInfoText(void);
   void              DynamicInfoInitArrays(string &params[],string &values[]);
   void              DynamicInfoSetValues(string &values[]);
   string            ToString(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Strategy::Strategy(int openSlots,int closeSlots)
  {
   openSlotsCount=openSlots;
   closeSlotsCount=closeSlots;

   ArrayResize(Slot,Slots());

   for(int i=0; i<Slots(); i++)
     {
      Slot[i]=new IndicatorSlot();
      Slot[i].SlotNumber=i;
      Slot[i].SlotType=GetSlotType(i);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Strategy::~Strategy(void)
  {
   for(int slot=0; slot<ArraySize(Slot); slot++)
     {
      delete Slot[slot];
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
SlotTypes Strategy::GetSlotType(int slotNumber)
  {
   if(slotNumber==0)
      return (SlotTypes_Open);
   else if(slotNumber<CloseSlotNumber())
      return (SlotTypes_OpenFilter);
   else if(slotNumber==CloseSlotNumber())
      return (SlotTypes_Close);
   else
      return (SlotTypes_CloseFilter);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Strategy::IsLongerTimeFrame(int slotNumber)
  {
   return !(Slot[slotNumber].IndicatorSymbol == "" &&
            Slot[slotNumber].IndicatorPeriod == DataPeriod_M1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Strategy::GetSlotChart(int slotNumber)
  {
   string symbol=Slot[slotNumber].GetIndicatorSymbol(GetSymbol());
   DataPeriod period=Slot[slotNumber].GetIndicatorPeriod(GetPeriod());
   string chart=symbol+","+DataPeriodToString(period);
   return (chart);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Strategy::GetRequiredCharts(string &charts[])
  {
   ArrayResize(charts,1);
   charts[0]=GetSymbol()+","+DataPeriodToString(GetPeriod());

   for(int i=0; i<Slots(); i++)
     {
      if(!Slot[i].IndicatorPointer.IsAllowLTF)
         continue;
      if(!IsLongerTimeFrame(i))
         continue;
      string chart=GetSlotChart(i);
      if(!ArrayContainsString(charts,chart))
         ArrayAppendString(charts,chart);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Strategy::CalculateStrategy(DataSet *&dataSet[])
  {
   for(int i=0; i<Slots(); i++)
     {
      string chart=GetSlotChart(i);
      for(int j=0; j<ArraySize(dataSet); j++)
        {
         if(dataSet[j].Chart!=chart)
            continue;

         Slot[i].IndicatorPointer.Calculate(dataSet[j]);

         if(IsLongerTimeFrame(i))
           {
            int ltfShift;
            bool isBasePriceOpen=false;
            bool isCloseFilterShift=false;

            for(int p=1; p<5; p++)
              {
               string listParamCaption=Slot[i].IndicatorPointer.ListParam[p].Caption;
               string listParamText=Slot[i].IndicatorPointer.ListParam[p].Text;
               if(listParamCaption=="Base price" && listParamText=="Open")
                 {
                  isBasePriceOpen=true;
                  break;
                 }
              }

            if(isBasePriceOpen)
              {
               ltfShift=0;
              }
            else
              {
               int prevBarCorrection=(!Slot[i].GetUsePreviousBarValue()) ? 1 : 0;
               ltfShift=Slot[i].IndicatorPeriod!=DataPeriod_M1 && prevBarCorrection;
               isCloseFilterShift=Slot[i].SlotType==SlotTypes_CloseFilter;
              }

            Slot[i].IndicatorPointer.NormalizeComponents(dataSet[0],ltfShift,isCloseFilterShift);
           }

         if(Slot[i].SignalShift>0)
            Slot[i].IndicatorPointer.ShiftSignal(Slot[i].SignalShift);

         if(Slot[i].SignalRepeat>0)
            Slot[i].IndicatorPointer.RepeatSignal(Slot[i].SignalRepeat);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Strategy::IsUsingLogicalGroups()
  {
   bool isUsingGroups=false;
   for(int slot=0; slot<ArraySize(Slot); slot++)
     {
      SlotTypes slotType=Slot[slot].SlotType;
      if(slotType==SlotTypes_OpenFilter)
        {
         string defaultGroup = GetDefaultGroup(slot);
         string logicalGroup = Slot[slot].LogicalGroup;
         if(defaultGroup!=logicalGroup && logicalGroup!="All")
           {
            isUsingGroups=true;
            break;
           }
        }
      else if(slotType==SlotTypes_CloseFilter)
        {
         string defaultGroup = GetDefaultGroup(slot);
         string logicalGroup = Slot[slot].LogicalGroup;
         if(defaultGroup!=logicalGroup)
           {
            isUsingGroups=true;
            break;
           }
        }
     }
   return (isUsingGroups);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Strategy::IsLogicalGroupSpecial(int slotNumber)
  {
   SlotTypes slotType=Slot[slotNumber].SlotType;
   string group= Slot[slotNumber].LogicalGroup;
   if(slotType == SlotTypes_Open|| slotType == SlotTypes_Close)
      return (false);
   if(slotType==SlotTypes_OpenFilter && group!=GetDefaultGroup(slotNumber) && group!="[All]")
      return (true);
   if(slotType==SlotTypes_CloseFilter && group!=GetDefaultGroup(slotNumber))
      return (true);
   if(slotType==SlotTypes_CloseFilter)
     {
      int count = 0;
      for(int i = OpenSlots() + 2; i < Slots(); i++)
         if(Slot[i].LogicalGroup==group)
            count++;
      if(count>1)
         return (true);
     }
   return (false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Strategy::GetDefaultGroup(int slotNumber)
  {
   string group="";
   SlotTypes slotType=GetSlotType(slotNumber);
   if(slotType==SlotTypes_OpenFilter)
     {
      bool isDefault=Slot[slotNumber].IndicatorPointer.IsDeafultGroupAll || 
                     Slot[slotNumber].IndicatorPointer.IsDefaultGroupAll;
      group=isDefault ? "All" : "A";
     }
   else if(slotType==SlotTypes_CloseFilter)
     {
      int index=slotNumber-CloseSlotNumber()-1;
      group=IntegerToString('a'+index);
     }
   return (group);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Strategy::DynamicInfoInitArrays(string &params[],string &values[])
  {
   ArrayResize(params,200);
   ArrayResize(values,200);
   for(int i=0; i<200; i++)
     {
      params[i] = "";
      values[i] = "";
     }

   int index=-2;
   for(int slot=0; slot<Slots(); slot++)
     {
      index++;
      index++;
      params[index]=Slot[slot].IndicatorName;
      for(int i=0; i<Slot[slot].IndicatorPointer.Components(); i++)
        {
         IndComponentType type=Slot[slot].IndicatorPointer.Component[i].DataType;
         if(type==IndComponentType_NotDefined)
            continue;
         if(Slot[slot].IndicatorPointer.Component[i].ShowInDynInfo)
           {
            index++;
            params[index]=Slot[slot].IndicatorPointer.Component[i].CompName;
           }
        }
     }
   ArrayResize(params,index+1);
   ArrayResize(values,index+1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Strategy::DynamicInfoSetValues(string &values[])
  {
   int index=-1;
   for(int slot=0; slot<Slots(); slot++)
     {
      index++;
      index++;
      for(int i=0; i<Slot[slot].IndicatorPointer.Components(); i++)
        {
         IndicatorComp *component=Slot[slot].IndicatorPointer.Component[i];
         IndComponentType type=component.DataType;
         if(type==IndComponentType_NotDefined)
           {
            component=NULL;
            continue;
           }
         int bars=ArraySize(component.Value);
         if(bars<3)
           {
            component=NULL;
            continue;
           }

         string name   = component.CompName;
         double value0 = component.Value[bars - 1];
         double value1 = component.Value[bars - 2];
         double dl0    = MathAbs(value0);
         double dl1    = MathAbs(value0);
         string sFr0   = dl0 < 10 ? "%10.5f" : dl0 < 100 ? "%10.5f" : dl0 < 1000 ? "%10.3f" :
                         dl0<10000 ? "%10.3f" : dl0<100000 ? "%10.2f" : "%10.1f";
         string sFr1=dl1<10 ? "%10.5f" : dl1<100 ? "%10.5f" : dl1<1000 ? "%10.3f" :
                     dl1<10000 ? "%10.3f" : dl1<100000 ? "%10.2f" : "%10.1f";
         string format=sFr1+"    "+sFr0;
         if(component.ShowInDynInfo)
           {
            if(type == IndComponentType_AllowOpenLong  || 
               type == IndComponentType_AllowOpenShort ||
               type == IndComponentType_ForceClose     ||
               type == IndComponentType_ForceCloseLong ||
               type == IndComponentType_ForceCloseShort)
               values[index]=StringFormat("%13s    %13s",(value1<1 ? "No" : "Yes"),(value0<1 ? "No" : "Yes"));
            else
               values[index]=StringFormat(format,value1,value0);
            index++;
           }
         component=NULL;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Strategy::DynamicInfoText()
  {
   string info;
   for(int slot=0; slot<Slots(); slot++)
     {
      info+="\n\n"+Slot[slot].IndicatorName;
      for(int i=0; i<Slot[slot].IndicatorPointer.Components(); i++)
        {
         IndicatorComp *component=Slot[slot].IndicatorPointer.Component[i];
         IndComponentType type=component.DataType;
         if(type==IndComponentType_NotDefined) continue;
         int bars=ArraySize(component.Value);
         if(bars<4) continue;

         string name   = component.CompName;
         double value0 = component.Value[bars - 1];
         double value1 = component.Value[bars - 2];
         double value2 = component.Value[bars - 3];
         double dl     = MathAbs(value0);
         string sFr    = dl < 10 ? "%10.6f" : dl < 100 ? "%10.5f" : dl < 1000 ? "%10.4" :
                         dl<10000 ? "%10.3f" : dl<100000 ? "%10.2f" : "%10.1f";
         string format="\n%-40s "+sFr+"    "+sFr+"    "+sFr;
         if(component.ShowInDynInfo)
           {
            if(type == IndComponentType_AllowOpenLong || 
               type == IndComponentType_AllowOpenShort ||
               type == IndComponentType_ForceClose     ||
               type == IndComponentType_ForceCloseLong ||
               type == IndComponentType_ForceCloseShort)
              {
               info+=StringFormat("\n%-42s %-10s    %-10s    %-10s",name,
                                  (value2 < 1 ? "No" : "Yes"),
                                  (value1 < 1 ? "No" : "Yes"),
                                  (value0 < 1 ? "No" : "Yes"));
              }
            else
              {
               info+=StringFormat(format,name,value2,value1,value0);
              }
           }
         component=NULL;
        }
     }
   return (info);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Strategy::ToString()
  {
   string stopLoss   = UsePermanentSL ? IntegerToString(PermanentSL)            : "None";
   string takeProfit = UsePermanentTP ? IntegerToString(PermanentTP)            : "None";
   string breakEven  = UseBreakEven   ? IntegerToString(BreakEven)              : "None";
   string martingale = UseMartingale  ? DoubleToString(MartingaleMultiplier, 2) : "None";

   string text="Name: "            + StrategyName+"\n"+
               "Symbol: "          + GetSymbol()+"\n"+
               "Period: "          + DataPeriodToString(GetPeriod())+"\n\n"+
               "Trade unit: "      + (UseAccountPercentEntry ? "Percent" : "Lot")+"\n"+
               "Entry amount: "    + DoubleToString(EntryLots,2)+"\n"+
               "Max open lots: "   + DoubleToString(MaxOpenLots,2)+"\n\n"+
               "Same signal: "     + SameDirSignalActionToString(SameSignalAction)+"\n"+
               "Adding amount: "   + DoubleToString(AddingLots,2)+"\n"+
               "Opposite signal: " + OppositeDirSignalActionToString(OppSignalAction)+"\n"+
               "Reducing amount: " + DoubleToString(ReducingLots,2)+"\n\n"+
               "Stop Loss: "       + stopLoss+"\n"+
               "Take Profit: "     + takeProfit+"\n"+
               "Break Even: "      + breakEven+"\n\n"+
               "Martingale: "      + martingale+"\n\n"+
               "Description: "     + Description+"\n\n";

   for(int slot=0; slot<ArraySize(Slot); slot++)
     {
      text+=SlotTypeToString(Slot[slot].SlotType)                + "\n" +
            Slot[slot].IndicatorName                             + "\n" +
            Slot[slot].IndicatorPointer.IndicatorParamToString() + "\n";

      if(Slot[slot].SlotType==SlotTypes_OpenFilter || Slot[slot].SlotType==SlotTypes_CloseFilter)
         text+=Slot[slot].LogicalGroupToString();
      if(Slot[slot].IndicatorPointer.IsAllowLTF)
         text+=Slot[slot].AdvancedParamsToString()+"\n";
     }
   return (text);
  }
//+------------------------------------------------------------------+

class StrategyManager
  {
public:
   Strategy         *GetStrategy(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Strategy *StrategyManager::GetStrategy(void)
  {
    IndicatorManager *indicatorManager=new IndicatorManager();

   Strategy *strategy = new Strategy(1, 0);

   strategy.StrategyName           = "2 1000 1 0.7% 0.5 500lev st";
   strategy.SameSignalAction       = SameDirSignalAction_Add;
   strategy.OppSignalAction        = OppositeDirSignalAction_Reduce;
   strategy.MaxOpenLots            = 0.5;
   strategy.UseAccountPercentEntry = true;
   strategy.EntryLots              = 1;
   strategy.AddingLots             = 1;
   strategy.ReducingLots           = 1;
   strategy.MartingaleMultiplier   = Martingale_Multiplier;
   strategy.UseMartingale          = Martingale_Multiplier > 0;
   strategy.Description            = "Exported on 07/04/2021 from Forex Strategy Builder Professional, v3.8.8";
   strategy.RecommendedBars        = 1000;
   strategy.FirstBar               = 198;
   strategy.MinBarsRequired        = 199;
   strategy.PermanentSL            = Stop_Loss;
   strategy.UsePermanentSL         = Stop_Loss > 0;
   strategy.PermanentSLType        = PermanentProtectionType_Relative;
   strategy.PermanentTP            = Take_Profit;
   strategy.UsePermanentTP         = Take_Profit > 0;
   strategy.PermanentTPType        = PermanentProtectionType_Relative;
   strategy.BreakEven              = Break_Even;
   strategy.UseBreakEven           = Break_Even > 0;

   strategy.Slot[0].IndicatorName    = "Day Opening";
   strategy.Slot[0].SlotType         = SlotTypes_Open;
   strategy.Slot[0].SignalShift      = 0;
   strategy.Slot[0].SignalRepeat     = 0;
   strategy.Slot[0].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[0].IndicatorSymbol  = "";
   strategy.Slot[0].LogicalGroup     = "";
   strategy.Slot[0].IndicatorPointer = indicatorManager.CreateIndicator("Day Opening", SlotTypes_Open);

   strategy.Slot[0].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[0].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[0].IndicatorPointer.ListParam[0].Index   = 0;
   strategy.Slot[0].IndicatorPointer.ListParam[0].Text    = "Enter the market at the beginning of the day";
   strategy.Slot[0].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[0].IndicatorPointer.ListParam[1].Caption = "Base price";
   strategy.Slot[0].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[0].IndicatorPointer.ListParam[1].Text    = "Open";

   strategy.Slot[1].IndicatorName    = "MACD Histogram";
   strategy.Slot[1].SlotType         = SlotTypes_OpenFilter;
   strategy.Slot[1].SignalShift      = 0;
   strategy.Slot[1].SignalRepeat     = 0;
   strategy.Slot[1].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[1].IndicatorSymbol  = "";
   strategy.Slot[1].LogicalGroup     = "A";
   strategy.Slot[1].IndicatorPointer = indicatorManager.CreateIndicator("MACD Histogram", SlotTypes_OpenFilter);

   strategy.Slot[1].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[1].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[1].IndicatorPointer.ListParam[0].Index   = 1;
   strategy.Slot[1].IndicatorPointer.ListParam[0].Text    = "MACD histogram falls";
   strategy.Slot[1].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[1].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[1].IndicatorPointer.ListParam[1].Index   = 2;
   strategy.Slot[1].IndicatorPointer.ListParam[1].Text    = "Exponential";
   strategy.Slot[1].IndicatorPointer.ListParam[2].Enabled = true;
   strategy.Slot[1].IndicatorPointer.ListParam[2].Caption = "Base price";
   strategy.Slot[1].IndicatorPointer.ListParam[2].Index   = 3;
   strategy.Slot[1].IndicatorPointer.ListParam[2].Text    = "Close";
   strategy.Slot[1].IndicatorPointer.ListParam[3].Enabled = true;
   strategy.Slot[1].IndicatorPointer.ListParam[3].Caption = "Signal line method";
   strategy.Slot[1].IndicatorPointer.ListParam[3].Index   = 0;
   strategy.Slot[1].IndicatorPointer.ListParam[3].Text    = "Simple";

   strategy.Slot[1].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[1].IndicatorPointer.NumParam[0].Caption = "Slow MA period";
   strategy.Slot[1].IndicatorPointer.NumParam[0].Value   = Slot1IndParam0;
   strategy.Slot[1].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[1].IndicatorPointer.NumParam[1].Caption = "Fast MA period";
   strategy.Slot[1].IndicatorPointer.NumParam[1].Value   = Slot1IndParam1;
   strategy.Slot[1].IndicatorPointer.NumParam[2].Enabled = true;
   strategy.Slot[1].IndicatorPointer.NumParam[2].Caption = "Signal line period";
   strategy.Slot[1].IndicatorPointer.NumParam[2].Value   = Slot1IndParam2;
   strategy.Slot[1].IndicatorPointer.NumParam[3].Enabled = true;
   strategy.Slot[1].IndicatorPointer.NumParam[3].Caption = "Level";
   strategy.Slot[1].IndicatorPointer.NumParam[3].Value   = Slot1IndParam3;

   strategy.Slot[1].IndicatorPointer.CheckParam[0].Enabled = true;
   strategy.Slot[1].IndicatorPointer.CheckParam[0].Caption = "Use previous bar value";
   strategy.Slot[1].IndicatorPointer.CheckParam[0].Checked = true;

   strategy.Slot[2].IndicatorName    = "Trailing Stop";
   strategy.Slot[2].SlotType         = SlotTypes_Close;
   strategy.Slot[2].SignalShift      = 0;
   strategy.Slot[2].SignalRepeat     = 0;
   strategy.Slot[2].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[2].IndicatorSymbol  = "";
   strategy.Slot[2].LogicalGroup     = "";
   strategy.Slot[2].IndicatorPointer = indicatorManager.CreateIndicator("Trailing Stop", SlotTypes_Close);

   strategy.Slot[2].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[2].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[2].IndicatorPointer.ListParam[0].Index   = 0;
   strategy.Slot[2].IndicatorPointer.ListParam[0].Text    = "Exit at the Trailing Stop level";
   strategy.Slot[2].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[2].IndicatorPointer.ListParam[1].Caption = "Trailing mode";
   strategy.Slot[2].IndicatorPointer.ListParam[1].Index   = 1;
   strategy.Slot[2].IndicatorPointer.ListParam[1].Text    = "New tick (trader)";

   strategy.Slot[2].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[2].IndicatorPointer.NumParam[0].Caption = "Trailing Stop";
   strategy.Slot[2].IndicatorPointer.NumParam[0].Value   = Slot2IndParam0;



    delete indicatorManager;

    return strategy;
  }
//+------------------------------------------------------------------+

#define OP_FLAT          -1
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Position
  {
public:
   // Constructors
                     Position(void);

   // Properties
   int               PosType;
   PosDirection      Direction;
   double            Lots;
   datetime          OpenTime;
   double            OpenPrice;
   double            StopLossPrice;
   double            TakeProfitPrice;
   double            Profit;
   double            Commission;
   long              Ticket;
   string            PosComment;

   // Methods
   string            ToString();

   void              SetPositionInfo(string &positionInfo[]);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Position::Position(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Position::ToString()
  {
   if(PosType==OP_FLAT)
      return ("Position: Flat");

   string text =  "Position: "  +
                  "Time="       + TimeToString(OpenTime,TIME_SECONDS)     +", "+
                  "Type="       + (PosType==OP_BUY ? "Long" : "Short")    +", "+
                  "Lots="       + DoubleToString(Lots,2)                  +", "+
                  "Price="      + DoubleToString(OpenPrice,_Digits)       +", "+
                  "StopLoss="   + DoubleToString(StopLossPrice,_Digits)   +", "+
                  "TakeProfit=" + DoubleToString(TakeProfitPrice,_Digits) +", "+
                  "Commission=" + DoubleToString(Commission,2)            +", "+
                  "Profit="     + DoubleToString(Profit,2);

   if(PosComment!="")
      text+=", \""+PosComment+"\"";

   return (text);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Position::SetPositionInfo(string &positionInfo[])
  {
   if(PosType==OP_FLAT)
     {
      positionInfo[0] = "Position: Flat";
      positionInfo[1] = ".";
     }
   else
     {
      positionInfo[0]=StringFormat("Position: %s %.2f at %s, Profit %.2f",
                                   (PosType==OP_BUY) ? "Long" : "Short",
                                   Lots,
                                   DoubleToString(OpenPrice,_Digits),
                                   Profit);
      positionInfo[1]=StringFormat("Stop Loss: %s, Take Profit: %s",
                                   DoubleToString(StopLossPrice,_Digits),
                                   DoubleToString(TakeProfitPrice,_Digits));
     }
  }
//+------------------------------------------------------------------+

class Logger
  {
   int               logLines;
   int               fileHandle;

public:
   string            GetLogFileName(string symbol,int dataPeriod,int expertMagic);
   int               CreateLogFile(string fileName);
   void              WriteLogLine(string text);
   void              WriteNewLogLine(string text);
   void              WriteLogRequest(string text,string request);
   bool              IsLogLinesLimitReached(int maxLines);
   void              FlushLogFile(void);
   void              CloseLogFile(void);
   int               CloseExpert(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Logger::GetLogFileName(string symbol,int dataPeriod,int expertMagic)
  {
   string time=TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS);
   StringReplace(time,":","");
   StringReplace(time," ","_");
   string rnd=IntegerToString(MathRand());
   string fileName=symbol+"_"+IntegerToString(dataPeriod)+"_"+
                   IntegerToString(expertMagic)+"_"+time+"_"+rnd+".log";
   return (fileName);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Logger::CreateLogFile(string fileName)
  {
   logLines=0;
   int handle=FileOpen(fileName,FILE_CSV|FILE_WRITE,",");
   if(handle>0)
      fileHandle=handle;
   else
      Print("CreateFile: Error while creating log file!");
   return (handle);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Logger::WriteLogLine(string text)
  {
   if(fileHandle <= 0) return;
   FileWrite(fileHandle,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS),text);
   logLines++;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Logger::WriteNewLogLine(string text)
  {
   if(fileHandle <= 0) return;
   FileWrite(fileHandle,"");
   FileWrite(fileHandle,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS),text);
   logLines+=2;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Logger::WriteLogRequest(string text,string request)
  {
   if(fileHandle <= 0) return;
   FileWrite(fileHandle,"\n"+text);
   FileWrite(fileHandle,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS),request);
   logLines+=3;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Logger::FlushLogFile()
  {
   if(fileHandle <= 0) return;
   FileFlush(fileHandle);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Logger::CloseLogFile()
  {
   if(fileHandle <= 0) return;
   WriteNewLogLine(StringFormat("%s Closed.",MQLInfoString(MQL_PROGRAM_NAME)));
   FileClose(fileHandle);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Logger::IsLogLinesLimitReached(int maxLines)
  {
   return (logLines > maxLines);
  }
//+------------------------------------------------------------------+

class ActionTrade;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class StrategyTrader
  {
private:
   ActionTrade      *actionTrade;
   Strategy         *strategy;
   DataMarket       *market;

   double            epsilon;
   bool              isEnteredLong;
   bool              isEnteredShort;
   datetime          timeLastEntryBar;
   datetime          barOpenTimeForLastCloseTick;

   StrategyPriceType openStrPriceType;
   StrategyPriceType closeStrPriceType;
   int               nBarExit;

   ExecutionTime     openTimeExec;
   ExecutionTime     closeTimeExec;
   bool              useLogicalGroups;
   DictStringBool   *groupsAllowLong;
   DictStringBool   *groupsAllowShort;
   ListString       *openingLogicGroups;
   ListString       *closingLogicGroups;

   PosDirection      GetNewPositionDirection(OrderDirection ordDir,double ordLots,PosDirection posDir,double posLots);
   TradeDirection    AnalyzeEntryPrice(void);
   TradeDirection    AnalyzeEntryDirection(void);
   void              AnalyzeEntryLogicConditions(string group,double buyPrice,double sellPrice,bool &canOpenLong,bool &canOpenShort);
   double            AnalyzeEntrySize(OrderDirection ordDir,PosDirection &newPosDir);
   TradeDirection    AnalyzeExitPrice(void);
   double            TradingSize(double size);
   int               AccountPercentStopPoint(double percent,double lots);
   TradeDirection    AnalyzeExitDirection(void);
   TradeDirection    ReduceDirectionStatus(TradeDirection baseDirection,TradeDirection direction);
   TradeDirection    IncreaseDirectionStatus(TradeDirection baseDirection,TradeDirection direction);
   TradeDirection    GetClosingDirection(TradeDirection baseDirection,IndComponentType compDataType);
   int               GetStopLossPoints(double lots);
   int               GetTakeProfitPoints(void);
   void              DoEntryTrade(TradeDirection tradeDir);
   bool              DoExitTrade(void);

public:
   // Constructor, deconstructor
                     StrategyTrader(ActionTrade *actTrade);
                    ~StrategyTrader(void);

   // Methods
   void              OnInit(Strategy *strat,DataMarket *dataMarket);
   void              OnDeinit();
   void              InitTrade(void);
   TickType          GetTickType(bool isNewBar,int closeAdvance);
   void              CalculateTrade(TickType ticktype);

   bool              IsWrongStopsExecution(void);
   void              ResendWrongStops(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::StrategyTrader(ActionTrade *actTrade)
  {
   actionTrade=actTrade;
   epsilon=0.000001;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::~StrategyTrader(void)
  {
   actionTrade = NULL;
   strategy    = NULL;
   market      = NULL;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::OnInit(Strategy *strat,DataMarket *dataMarket)
  {
   strategy = strat;
   market   = dataMarket;

   groupsAllowLong    = new DictStringBool();
   groupsAllowShort   = new DictStringBool();
   openingLogicGroups = new ListString();
   closingLogicGroups = new ListString();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::OnDeinit(void)
  {
   delete groupsAllowLong;
   delete groupsAllowShort;
   delete openingLogicGroups;
   delete closingLogicGroups;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
TickType StrategyTrader::GetTickType(bool isNewBar,int closeAdvance)
  {
   TickType tickType     = TickType_Regular;
   datetime barCloseTime = market.BarTime + market.Period*60;

   if(isNewBar)
     {
      barOpenTimeForLastCloseTick=-1;
      tickType=TickType_Open;
     }

   if(market.TickServerTime>barCloseTime-closeAdvance)
     {
      if(barOpenTimeForLastCloseTick==market.BarTime)
        {
         tickType=TickType_AfterClose;
        }
      else
        {
         barOpenTimeForLastCloseTick=market.BarTime;
         tickType=isNewBar ? TickType_OpenClose : TickType_Close;
        }
     }

   return (tickType);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::CalculateTrade(TickType ticktype)
  {
// Exift
   bool closeOk=false;

   if(closeStrPriceType!=StrategyPriceType_CloseAndReverse && 
      (market.PositionDirection==PosDirection_Short || market.PositionDirection==PosDirection_Long))
     {
      if(ticktype==TickType_Open && closeStrPriceType==StrategyPriceType_Close && openStrPriceType!=StrategyPriceType_Close)
        {  // We have missed close at the previous Bar Close
         TradeDirection direction=AnalyzeExitDirection();
         if(direction==TradeDirection_Both || 
            (direction == TradeDirection_Long  && market.PositionDirection == PosDirection_Short) ||
            (direction == TradeDirection_Short && market.PositionDirection == PosDirection_Long))
           {  // we have a missed close Order
            if(DoExitTrade())
               actionTrade.UpdateDataMarket(market);
           }
        }
      else if(((closeStrPriceType==StrategyPriceType_Open)  && (ticktype==TickType_Open  || ticktype==TickType_OpenClose)) || 
              ((closeStrPriceType==StrategyPriceType_Close) && (ticktype==TickType_Close || ticktype==TickType_OpenClose)))
        {  // Exit at Bar Open or Bar Close.
         TradeDirection direction=AnalyzeExitDirection();
         if(direction==TradeDirection_Both || 
            (direction == TradeDirection_Long  && market.PositionDirection == PosDirection_Short) ||
            (direction == TradeDirection_Short && market.PositionDirection == PosDirection_Long))
           { // Close the current position.
            closeOk=DoExitTrade();
            if(closeOk)
               actionTrade.UpdateDataMarket(market);
           }
        }
      else if(closeStrPriceType==StrategyPriceType_Close && openStrPriceType!=StrategyPriceType_Close && ticktype==TickType_AfterClose)
        {  // Exit at after close tick.
         TradeDirection direction=AnalyzeExitDirection();
         if(direction==TradeDirection_Both || 
            (direction == TradeDirection_Long  && market.PositionDirection == PosDirection_Short) ||
            (direction == TradeDirection_Short && market.PositionDirection == PosDirection_Long))
            closeOk=DoExitTrade(); // Close the current position.
        }
      else if(closeStrPriceType==StrategyPriceType_Indicator)
        { // Exit at an indicator value.
         TradeDirection priceReached=AnalyzeExitPrice();
         if(priceReached==TradeDirection_Long)
           {
            TradeDirection direction=AnalyzeExitDirection();
            if(direction==TradeDirection_Long || direction==TradeDirection_Both)
              {
               if(market.PositionDirection==PosDirection_Short)
                  closeOk=DoExitTrade(); // Close a short position.
              }
           }
         else if(priceReached==TradeDirection_Short)
           {
            TradeDirection direction=AnalyzeExitDirection();
            if(direction==TradeDirection_Short || direction==TradeDirection_Both)
              {
               if(market.PositionDirection==PosDirection_Long)
                 closeOk=DoExitTrade(); // Close a long position.
              }   
           }
         else if(priceReached==TradeDirection_Both)
           {
            TradeDirection direction=AnalyzeExitDirection();
            if(direction==TradeDirection_Long || direction==TradeDirection_Short || direction==TradeDirection_Both)
               closeOk=DoExitTrade(); // Close the current position.
           }
        }
     }

// Checks if we closed a position successfully.
   if(closeOk && !(openStrPriceType==StrategyPriceType_Close && ticktype==TickType_Close))
      return;

// This is to prevent new entry after Bar Closing has been executed.
   if(closeStrPriceType==StrategyPriceType_Close && ticktype==TickType_AfterClose)
      return;

   if(((openStrPriceType==StrategyPriceType_Open) && (ticktype==TickType_Open || ticktype==TickType_OpenClose)) ||
      ((openStrPriceType==StrategyPriceType_Close) && (ticktype==TickType_Close || ticktype==TickType_OpenClose)))
     { // Entry at Bar Open or Bar Close.
      TradeDirection direction=AnalyzeEntryDirection();
      if(direction==TradeDirection_Long || direction==TradeDirection_Short)
         DoEntryTrade(direction);
     }
   else if(openStrPriceType==StrategyPriceType_Indicator)
     { // Entry at an indicator value.
      TradeDirection priceReached=AnalyzeEntryPrice();
      if(priceReached==TradeDirection_Long)
        {
         TradeDirection direction=AnalyzeEntryDirection();
         if(direction==TradeDirection_Long || direction==TradeDirection_Both)
            DoEntryTrade(TradeDirection_Long);
        }
      else if(priceReached==TradeDirection_Short)
        {
         TradeDirection direction=AnalyzeEntryDirection();
         if(direction==TradeDirection_Short || direction==TradeDirection_Both)
            DoEntryTrade(TradeDirection_Short);
        }
      else if(priceReached==TradeDirection_Both)
        {
         TradeDirection direction=AnalyzeEntryDirection();
         if(direction==TradeDirection_Long || direction==TradeDirection_Short)
            DoEntryTrade(direction);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
PosDirection StrategyTrader::GetNewPositionDirection(OrderDirection ordDir,double ordLots,
                                                     PosDirection posDir,double posLots)
  {
   if(ordDir!=OrderDirection_Buy && ordDir!=OrderDirection_Sell)
      return (PosDirection_None);

   PosDirection currentDir=posDir;
   double currentLots=posLots;

   switch(currentDir)
     {
      case PosDirection_Long:
         if(ordDir==OrderDirection_Buy)
            return (PosDirection_Long);
         if(currentLots>ordLots+epsilon)
            return (PosDirection_Long);
         return (currentLots < ordLots - epsilon ? PosDirection_Short : PosDirection_None);
      case PosDirection_Short:
         if(ordDir==OrderDirection_Sell)
            return (PosDirection_Short);
         if(currentLots>ordLots+epsilon)
            return (PosDirection_Short);
         return (currentLots < ordLots - epsilon ? PosDirection_Long : PosDirection_None);
     }

   return (ordDir == OrderDirection_Buy ? PosDirection_Long : PosDirection_Short);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::InitTrade()
  {
   openTimeExec=strategy.Slot[0].IndicatorPointer.ExecTime;
   openStrPriceType=StrategyPriceType_Unknown;
   if(openTimeExec==ExecutionTime_AtBarOpening)
      openStrPriceType=StrategyPriceType_Open;
   else if(openTimeExec==ExecutionTime_AtBarClosing)
      openStrPriceType=StrategyPriceType_Close;
   else
      openStrPriceType=StrategyPriceType_Indicator;

   closeTimeExec=strategy.Slot[strategy.CloseSlotNumber()].IndicatorPointer.ExecTime;
   closeStrPriceType=StrategyPriceType_Unknown;
   if(closeTimeExec==ExecutionTime_AtBarOpening)
      closeStrPriceType=StrategyPriceType_Open;
   else if(closeTimeExec==ExecutionTime_AtBarClosing)
      closeStrPriceType=StrategyPriceType_Close;
   else if(closeTimeExec==ExecutionTime_CloseAndReverse)
      closeStrPriceType=StrategyPriceType_CloseAndReverse;
   else
      closeStrPriceType=StrategyPriceType_Indicator;

   useLogicalGroups=strategy.IsUsingLogicalGroups();

   if(useLogicalGroups)
     {
      strategy.Slot[0].LogicalGroup="All";
      strategy.Slot[strategy.CloseSlotNumber()].LogicalGroup="All";

      for(int slot=0; slot<strategy.CloseSlotNumber(); slot++)
        {
         if(!groupsAllowLong.ContainsKey(strategy.Slot[slot].LogicalGroup))
            groupsAllowLong.Add(strategy.Slot[slot].LogicalGroup, false);
         if(!groupsAllowShort.ContainsKey(strategy.Slot[slot].LogicalGroup))
            groupsAllowShort.Add(strategy.Slot[slot].LogicalGroup, false);
        }

      // List of logical groups
      int longCount=groupsAllowLong.Count();
      for(int i=0; i<longCount; i++)
        {
         openingLogicGroups.Add(groupsAllowLong.Key(i));
        }

      // Logical groups of the closing conditions.
      for(int slot=strategy.CloseSlotNumber()+1; slot<strategy.Slots(); slot++)
        {
         string group=strategy.Slot[slot].LogicalGroup;
         if(!closingLogicGroups.Contains(group) && group!="all")
            closingLogicGroups.Add(group); // Adds all groups except "all"
        }

      if(closingLogicGroups.Count()==0)
         closingLogicGroups.Add("all");
     }

// Search if N Bars Exit is present as CloseFilter,
// could be any slot after first closing slot.
   nBarExit=0;
   for(int slot=strategy.CloseSlotNumber(); slot<strategy.Slots(); slot++)
     {
      if(strategy.Slot[slot].IndicatorName!="N Bars Exit")
         continue;
      nBarExit=(int) strategy.Slot[slot].IndicatorPointer.NumParam[0].Value;
      break;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
TradeDirection StrategyTrader::AnalyzeEntryPrice(void)
  {
   double buyPrice  = 0;
   double sellPrice = 0;
   for(int i=0; i<strategy.Slot[0].IndicatorPointer.Components(); i++)
     {
      IndicatorComp *component=strategy.Slot[0].IndicatorPointer.Component[i];
      IndComponentType compType=component.DataType;
      if(compType==IndComponentType_OpenLongPrice)
         buyPrice=component.GetLastValue();
      else if(compType==IndComponentType_OpenShortPrice)
         sellPrice=component.GetLastValue();
      else if(compType==IndComponentType_OpenPrice || compType==IndComponentType_OpenClosePrice)
         buyPrice=sellPrice=component.GetLastValue();
      component=NULL;
     }

   double basePrice = market.Close;
   double oldPrice  = market.OldClose;
   bool canOpenLong  = false;
   bool canOpenShort = false;

   if(oldPrice<epsilon)
     {  // OldClose==0 for the first tick.
      canOpenLong  = MathAbs(buyPrice - basePrice) < epsilon;
      canOpenShort = MathAbs(sellPrice - basePrice) < epsilon;
     }
   else
     {
      canOpenLong=(buyPrice>oldPrice+epsilon && buyPrice<basePrice+epsilon) || 
                  (buyPrice>basePrice-epsilon && buyPrice<oldPrice-epsilon);
      canOpenShort=(sellPrice>oldPrice+epsilon && sellPrice<basePrice+epsilon) || 
                   (sellPrice>basePrice-epsilon && sellPrice<oldPrice-epsilon);
     }

   TradeDirection direction=TradeDirection_None;

   if(canOpenLong && canOpenShort)
      direction=TradeDirection_Both;
   else if(canOpenLong)
      direction=TradeDirection_Long;
   else if(canOpenShort)
      direction=TradeDirection_Short;

   return (direction);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
TradeDirection StrategyTrader::AnalyzeEntryDirection()
  {
// Do not send entry order when we are not on time
   if(openTimeExec==ExecutionTime_AtBarOpening)
      for(int i=0; i<strategy.Slot[0].IndicatorPointer.Components(); i++)
        {
         IndicatorComp *component=strategy.Slot[0].IndicatorPointer.Component[i];
         if(component.DataType != IndComponentType_OpenLongPrice && 
            component.DataType != IndComponentType_OpenShortPrice &&
            component.DataType != IndComponentType_OpenPrice)
            continue;
         if(component.GetLastValue()<epsilon)
            return (TradeDirection_None);
         component=NULL;
        }

   for(int i=0; i<strategy.Slots(); i++)
     {
      if(strategy.Slot[i].IndicatorName=="Enter Once")
        {
         string logicText=strategy.Slot[i].IndicatorPointer.ListParam[0].Text;
         if(logicText=="Enter no more than once a bar")
           {
            if(market.BarTime==timeLastEntryBar)
               return (TradeDirection_None);
           }
         else if(logicText=="Enter no more than once a day")
           {
            if(TimeDayOfYear(market.BarTime)==TimeDayOfYear(timeLastEntryBar))
               return (TradeDirection_None);
           }
         else if(logicText=="Enter no more than once a week")
           {
            if(TimeDayOfWeek(market.BarTime)>=TimeDayOfWeek(timeLastEntryBar) && 
               market.BarTime<timeLastEntryBar+7*24*60*60)
               return (TradeDirection_None);
           }
         else if(logicText=="Enter no more than once a month")
           {
            if(TimeMonth(market.BarTime)==TimeMonth(timeLastEntryBar))
               return (TradeDirection_None);
           }
        }
     }

// Determining of the buy/sell entry prices.
   double buyPrice=0;
   double sellPrice=0;
   for(int i=0; i<strategy.Slot[0].IndicatorPointer.Components(); i++)
     {
      IndicatorComp *component=strategy.Slot[0].IndicatorPointer.Component[i];
      IndComponentType compType=component.DataType;
      if(compType==IndComponentType_OpenLongPrice)
         buyPrice=component.GetLastValue();
      else if(compType==IndComponentType_OpenShortPrice)
         sellPrice=component.GetLastValue();
      else if(compType==IndComponentType_OpenPrice || compType==IndComponentType_OpenClosePrice)
         buyPrice=sellPrice=component.GetLastValue();
      component=NULL;
     }

// Decide whether to open
   bool canOpenLong=buyPrice>epsilon;
   bool canOpenShort=sellPrice>epsilon;

   if(useLogicalGroups)
     {
      for(int i=0; i<openingLogicGroups.Count(); i++)
        {
         string group=openingLogicGroups.Get(i);

         bool groupOpenLong=canOpenLong;
         bool groupOpenShort=canOpenShort;

         AnalyzeEntryLogicConditions(group,buyPrice,sellPrice,groupOpenLong,groupOpenShort);

         groupsAllowLong.Set(group,groupOpenLong);
         groupsAllowShort.Set(group,groupOpenShort);
        }

      bool groupLongEntry=false;
      for(int i=0; i<groupsAllowLong.Count(); i++)
        {
         string key = groupsAllowLong.Key(i);
         bool value = groupsAllowLong.Value(key);
         if((groupsAllowLong.Count()>1 && key!="All") || groupsAllowLong.Count()==1)
            groupLongEntry=groupLongEntry || value;
        }

      bool groupShortEntry=false;
      for(int i=0; i<groupsAllowShort.Count(); i++)
        {
         string key = groupsAllowShort.Key(i);
         bool value = groupsAllowShort.Value(key);
         if((groupsAllowShort.Count()>1 && key!="All") || groupsAllowShort.Count()==1)
            groupShortEntry=groupShortEntry || value;
        }

      canOpenLong=canOpenLong && groupLongEntry && groupsAllowLong.Value("All");
      canOpenShort=canOpenShort && groupShortEntry && groupsAllowShort.Value("All");
     }
   else
     {
      AnalyzeEntryLogicConditions("A",buyPrice,sellPrice,canOpenLong,canOpenShort);
     }

   TradeDirection direction=TradeDirection_None;
   if(canOpenLong && canOpenShort)
      direction=TradeDirection_Both;
   else if(canOpenLong)
      direction=TradeDirection_Long;
   else if(canOpenShort)
      direction=TradeDirection_Short;

   return (direction);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void StrategyTrader::AnalyzeEntryLogicConditions(string group,double buyPrice,double sellPrice,
                                                 bool &canOpenLong,bool &canOpenShort)
  {
   for(int slotIndex=0; slotIndex<=strategy.CloseSlotNumber(); slotIndex++)
     {
      if(useLogicalGroups && 
         strategy.Slot[slotIndex].LogicalGroup != group &&
         strategy.Slot[slotIndex].LogicalGroup != "All")
         continue;

      for(int i=0; i<strategy.Slot[slotIndex].IndicatorPointer.Components(); i++)
        {
         IndicatorComp *component=strategy.Slot[slotIndex].IndicatorPointer.Component[i];
         if(component.PosPriceDependence==PositionPriceDependence_None)
           {
            if(component.DataType==IndComponentType_AllowOpenLong && 
               component.GetLastValue()<0.5)
               canOpenLong=false;

            if(component.DataType==IndComponentType_AllowOpenShort && 
               component.GetLastValue()<0.5)
               canOpenShort=false;
           }
         else
           {
            int previous=strategy.Slot[slotIndex].GetUsePreviousBarValue() ? 1 : 0;
            if(strategy.IsLongerTimeFrame(slotIndex))
               previous=0;

            double indicatorValue=component.GetLastValue(previous);

            if (indicatorValue > epsilon)
              {
                switch(component.PosPriceDependence)
                  {
                   case PositionPriceDependence_PriceBuyHigher:
                      canOpenLong=canOpenLong && buyPrice>indicatorValue+epsilon;
                      break;
                   case PositionPriceDependence_PriceBuyLower:
                      canOpenLong=canOpenLong && buyPrice<indicatorValue-epsilon;
                      break;
                   case PositionPriceDependence_PriceSellHigher:
                      canOpenShort=canOpenShort && sellPrice>indicatorValue+epsilon;
                      break;
                   case PositionPriceDependence_PriceSellLower:
                      canOpenShort=canOpenShort && sellPrice<indicatorValue-epsilon;
                      break;
                   case PositionPriceDependence_BuyHigherSellLower:
                      canOpenLong  = canOpenLong  && buyPrice  > indicatorValue + epsilon;
                      canOpenShort = canOpenShort && sellPrice < indicatorValue - epsilon;
                      break;
                   case PositionPriceDependence_BuyLowerSelHigher: // Deprecated
                   case PositionPriceDependence_BuyLowerSellHigher:
                      canOpenLong  = canOpenLong  && buyPrice  < indicatorValue - epsilon;
                      canOpenShort = canOpenShort && sellPrice > indicatorValue + epsilon;
                      break;
                  }
               }
            else
              {
                canOpenLong  = false;
                canOpenShort = false;
              }
           }
         component=NULL;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double StrategyTrader::AnalyzeEntrySize(OrderDirection ordDir,PosDirection &newPosDir)
  {
   double size=0;
   PosDirection posDir=market.PositionDirection;
// Orders modification on a fly
// Checks whether we are on the market
   if(posDir==PosDirection_Long || posDir==PosDirection_Short)
     {
      // We are on the market and have Same Dir Signal
      if((ordDir==OrderDirection_Buy && posDir==PosDirection_Long) || 
         (ordDir==OrderDirection_Sell && posDir==PosDirection_Short))
        {
         size=0;
         newPosDir=posDir;
         if(market.PositionLots+TradingSize(strategy.AddingLots)<
            strategy.MaxOpenLots+market.LotStep/2)
           {
            switch(strategy.SameSignalAction)
              {
               case SameDirSignalAction_Add:
                  size=TradingSize(strategy.AddingLots);
                  break;
               case SameDirSignalAction_Winner:
                  if(market.PositionProfit>epsilon)
                  size=TradingSize(strategy.AddingLots);
                  break;
               case SameDirSignalAction_Loser:
                  if(market.PositionProfit<-epsilon)
                  size=TradingSize(strategy.AddingLots);
                  break;
              }
           }
        }
      else if((ordDir==OrderDirection_Buy && posDir==PosDirection_Short) || 
         (ordDir==OrderDirection_Sell && posDir==PosDirection_Long))
           {
            // In case of an Opposite Dir Signal
            switch(strategy.OppSignalAction)
              {
               case OppositeDirSignalAction_Reduce:
                  if(market.PositionLots>TradingSize(strategy.ReducingLots))
                    { // Reducing
                     size=TradingSize(strategy.ReducingLots);
                     newPosDir=posDir;
                    }
                  else
                    { // Closing
                     size=market.PositionLots;
                     newPosDir=PosDirection_Closed;
                    }
                  break;
               case OppositeDirSignalAction_Close:
                  size=market.PositionLots;
                  newPosDir=PosDirection_Closed;
                  break;
               case OppositeDirSignalAction_Reverse:
                  size=market.PositionLots+TradingSize(strategy.EntryLots);
                  newPosDir=(posDir==PosDirection_Long) ? PosDirection_Short : PosDirection_Long;
                  break;
               case OppositeDirSignalAction_Nothing:
                  size=0;
                  newPosDir=posDir;
                  break;
              }
           }
        }
      else
        {
         // We are square on the market
         size=TradingSize(strategy.EntryLots);
         if(strategy.UseMartingale && market.ConsecutiveLosses>0)
           {
            double correctedAmount=size*MathPow(strategy.MartingaleMultiplier,market.ConsecutiveLosses);
            double normalizedAmount=actionTrade.NormalizeEntrySize(correctedAmount);
            size=MathMax(normalizedAmount,market.MinLot);
           }
         size=MathMin(size,strategy.MaxOpenLots);

         newPosDir=(ordDir==OrderDirection_Buy) ? PosDirection_Long : PosDirection_Short;
        }
      return (size);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   TradeDirection StrategyTrader::AnalyzeExitPrice()
     {
      IndicatorSlot *slot=strategy.Slot[strategy.CloseSlotNumber()];

      // Searching the exit price in the exit indicator slot.
      double buyPrice=0;
      double sellPrice=0;
      for(int i=0; i<slot.IndicatorPointer.Components(); i++)
        {
         IndicatorComp *comp=slot.IndicatorPointer.Component[i];
         IndComponentType compType=comp.DataType;

         if(compType==IndComponentType_CloseLongPrice)
            sellPrice=comp.GetLastValue();
         else if(compType==IndComponentType_CloseShortPrice)
            buyPrice=comp.GetLastValue();
         else if(compType==IndComponentType_ClosePrice || 
            compType==IndComponentType_OpenClosePrice)
            buyPrice=sellPrice=comp.GetLastValue();

         comp=NULL;
        }

      // We can close if the closing price is higher than zero.
      bool canCloseLong=sellPrice>epsilon;
      bool canCloseShort=buyPrice>epsilon;

      // Check if the closing price was reached.
      if(canCloseLong)
        {
         canCloseLong=(sellPrice>market.OldBid+epsilon && sellPrice<market.Bid+epsilon) || 
                      (sellPrice<market.OldBid-epsilon && sellPrice>market.Bid-epsilon);
        }
      if(canCloseShort)
        {
         canCloseShort=(buyPrice>market.OldBid+epsilon && buyPrice<market.Bid+epsilon) || 
                       (buyPrice<market.OldBid-epsilon && buyPrice>market.Bid-epsilon);
        }                 

      // Determine the trading direction.
      TradeDirection direction=TradeDirection_None;

      if(canCloseLong && canCloseShort)
         direction=TradeDirection_Both;
      else if(canCloseLong)
         direction=TradeDirection_Short;
      else if(canCloseShort)
         direction=TradeDirection_Long;

      slot=NULL;
      return (direction);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   TradeDirection StrategyTrader::AnalyzeExitDirection()
     {
      int closeSlot=strategy.CloseSlotNumber();

      if(closeTimeExec==ExecutionTime_AtBarClosing)
         for(int i=0; i<strategy.Slot[closeSlot].IndicatorPointer.Components(); i++)
           {
            IndComponentType dataType=strategy.Slot[closeSlot].IndicatorPointer.Component[i].DataType;
            double value = strategy.Slot[closeSlot].IndicatorPointer.Component[i].GetLastValue();
            if(dataType != IndComponentType_CloseLongPrice &&
               dataType != IndComponentType_CloseShortPrice &&
               dataType != IndComponentType_ClosePrice)
               continue;
            if(value<epsilon)
               return (TradeDirection_None);
           }

      if(strategy.CloseSlots()==0)
         return (TradeDirection_Both);

      if(nBarExit>0 && 
         (market.PositionOpenTime+(nBarExit *((int) market.Period*60))<market.TickServerTime))
         return (TradeDirection_Both);

      TradeDirection direction=TradeDirection_None;

      if(useLogicalGroups)
        {
         for(int i=0; i<closingLogicGroups.Count(); i++)
           {
            string group=closingLogicGroups.Get(i);
            TradeDirection groupDirection=TradeDirection_Both;

            // Determining of the slot direction
            for(int slot=strategy.CloseSlotNumber()+1; slot<strategy.Slots(); slot++)
              {
               TradeDirection slotDirection=TradeDirection_None;
               if(strategy.Slot[slot].LogicalGroup==group || strategy.Slot[slot].LogicalGroup=="all")
                 {
                  for(int c=0; c<strategy.Slot[slot].IndicatorPointer.Components(); c++)
                    {
                     if(strategy.Slot[slot].IndicatorPointer.Component[c].GetLastValue()>0)
                        slotDirection=GetClosingDirection(slotDirection,strategy.Slot[slot].IndicatorPointer.Component[c].DataType);
                    }      

                  groupDirection=ReduceDirectionStatus(groupDirection,slotDirection);
                 }
              }

            direction=IncreaseDirectionStatus(direction,groupDirection);
           }
        }
      else
        {   // Search close filters for a closing signal.
         for(int slot=strategy.CloseSlotNumber()+1; slot<strategy.Slots(); slot++)
           {
            for(int c=0; c<strategy.Slot[slot].IndicatorPointer.Components(); c++)
              {
               if(strategy.Slot[slot].IndicatorPointer.Component[c].GetLastValue()>epsilon)
                  direction=GetClosingDirection(direction,strategy.Slot[slot].IndicatorPointer.Component[c].DataType);
              }
           }     
        }

      return (direction);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   TradeDirection StrategyTrader::ReduceDirectionStatus(TradeDirection baseDirection,TradeDirection direction)
     {
      if(baseDirection==direction || direction==TradeDirection_Both)
         return (baseDirection);

      if(baseDirection==TradeDirection_Both)
         return (direction);

      return (TradeDirection_None);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   TradeDirection StrategyTrader::IncreaseDirectionStatus(TradeDirection baseDirection,TradeDirection direction)
     {
      if(baseDirection==direction || direction==TradeDirection_None)
         return (baseDirection);

      if(baseDirection==TradeDirection_None)
         return (direction);

      return (TradeDirection_Both);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   TradeDirection StrategyTrader::GetClosingDirection(TradeDirection baseDirection,IndComponentType compDataType)
     {
      TradeDirection newDirection=baseDirection;

      if(compDataType==IndComponentType_ForceClose)
        {
         newDirection=TradeDirection_Both;
        }
      else if(compDataType==IndComponentType_ForceCloseShort)
        {
         if(baseDirection == TradeDirection_None)
            newDirection = TradeDirection_Long;
         else if(baseDirection==TradeDirection_Short)
            newDirection=TradeDirection_Both;
        }
      else if(compDataType==IndComponentType_ForceCloseLong)
        {
         if(baseDirection == TradeDirection_None)
            newDirection = TradeDirection_Short;
         else if(baseDirection==TradeDirection_Long)
            newDirection=TradeDirection_Both;
        }

      return (newDirection);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   int StrategyTrader::GetStopLossPoints(double lots)
     {
      int  indStop   = INT_MAX;
      bool isIndStop = true;
      int  closeSlot = strategy.CloseSlotNumber();
      string name=strategy.Slot[closeSlot].IndicatorName;

      if(name=="Account Percent Stop")
         indStop=AccountPercentStopPoint(strategy.Slot[closeSlot].IndicatorPointer.NumParam[0].Value,lots);
      else if(name== "ATR Stop")
         indStop =(int) MathRound(strategy.Slot[closeSlot].IndicatorPointer.Component[0].GetLastValue()/market.Point);
      else if(name== "Stop Loss"|| name == "Stop Limit")
         indStop =(int) strategy.Slot[closeSlot].IndicatorPointer.NumParam[0].Value;
      else if(name== "Trailing Stop"|| name == "Trailing Stop Limit")
         indStop =(int) strategy.Slot[closeSlot].IndicatorPointer.NumParam[0].Value;
      else
         isIndStop=false;

      int permStop = strategy.UsePermanentSL ? strategy.PermanentSL : INT_MAX;
      int stopLoss = 0;

      if(isIndStop || strategy.UsePermanentSL)
        {
         stopLoss=MathMin(indStop,permStop);
         if(stopLoss<market.StopLevel)
            stopLoss=market.StopLevel;
        }

      return (stopLoss);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   int StrategyTrader::GetTakeProfitPoints()
     {
      int    takeprofit = 0;
      int    permLimit  = strategy.UsePermanentTP ? strategy.PermanentTP : INT_MAX;
      int    indLimit   = INT_MAX;
      bool   isIndLimit = true;
      int    closeSlot  = strategy.CloseSlotNumber();
      string name       = strategy.Slot[closeSlot].IndicatorName;

      if(name=="Take Profit")
         indLimit = (int) strategy.Slot[closeSlot].IndicatorPointer.NumParam[0].Value;
      else if(name == "Stop Limit" || name == "Trailing Stop Limit")
         indLimit = (int) strategy.Slot[closeSlot].IndicatorPointer.NumParam[1].Value;
      else
         isIndLimit=false;

      if(isIndLimit || strategy.UsePermanentTP)
        {
         takeprofit=MathMin(indLimit,permLimit);
         if(takeprofit<market.StopLevel)
            takeprofit=market.StopLevel;
        }

      return (takeprofit);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void StrategyTrader::DoEntryTrade(TradeDirection tradeDir)
     {
      OrderDirection  ordDir;
      OperationType   opType;
      TraderOrderType type;

      if(timeLastEntryBar!=market.BarTime)
         isEnteredLong=isEnteredShort=false;

      switch(tradeDir)
        {
         case TradeDirection_Long: // Buy
            if(isEnteredLong)
               return;
            ordDir = OrderDirection_Buy;
            opType = OperationType_Buy;
            type   = TraderOrderType_Buy;
            break;
         case TradeDirection_Short: // Sell
            if(isEnteredShort)
               return;
            ordDir = OrderDirection_Sell;
            opType = OperationType_Sell;
            type   = TraderOrderType_Sell;
            break;
         default: // Wrong direction of trade.
            return;
        }

      PosDirection newPosDir=PosDirection_None;
      double size=AnalyzeEntrySize(ordDir,newPosDir);

      if(size<market.MinLot-epsilon)
         return;  // The entry trade is cancelled.

      TrailingStopMode trlMode=TrailingStopMode_Bar;
      int    trlStop   = 0;
      int    closeSlot = strategy.CloseSlotNumber();
      string name      = strategy.Slot[closeSlot].IndicatorName;

      if(name=="Trailing Stop" || name=="Trailing Stop Limit")
        {
         trlStop=(int) strategy.Slot[closeSlot].IndicatorPointer.NumParam[0].Value;
         string mode=strategy.Slot[closeSlot].IndicatorPointer.ListParam[1].Text;
         if(mode!="New bar")
            trlMode=TrailingStopMode_Tick;
        }

      int stopLoss   = GetStopLossPoints(size);
      int takeProfit = GetTakeProfitPoints();
      int breakEven  = strategy.UseBreakEven ? strategy.BreakEven : 0;

      bool response=actionTrade.ManageOrderSend(type,size,stopLoss,takeProfit,trlMode,trlStop,breakEven);

      if(response)
        { // The order was executed successfully.
         timeLastEntryBar=market.BarTime;
         if(type==TraderOrderType_Buy)
            isEnteredLong=true;
         else
            isEnteredShort=true;

         market.WrongStopLoss   = 0;
         market.WrongTakeProf   = 0;
         market.WrongStopsRetry = 0;
        }
      else
        {  // Error in operation execution.
         market.WrongStopLoss = stopLoss;
         market.WrongTakeProf = takeProfit;
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool StrategyTrader::DoExitTrade()
     {
      if(!market.IsFailedCloseOrder)
         market.IsSentCloseOrder=true;
      market.CloseOrderTickCounter=0;

      bool orderResponse=actionTrade.CloseCurrentPosition();

      market.WrongStopLoss   = 0;
      market.WrongTakeProf   = 0;
      market.WrongStopsRetry = 0;

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool StrategyTrader::IsWrongStopsExecution()
     {
      const int maxRetry=4;

      if(market.PositionDirection==PosDirection_Closed || 
         market.PositionLots < epsilon ||
         market.WrongStopsRetry>=maxRetry)
        {
         market.WrongStopLoss   = 0;
         market.WrongTakeProf   = 0;
         market.WrongStopsRetry = 0;
         return (false);
        }

      bool isWrongStop=(market.WrongStopLoss>0 && market.PositionStopLoss<epsilon) || 
                       (market.WrongTakeProf>0 && market.PositionTakeProfit<epsilon);

      return (isWrongStop);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void StrategyTrader::ResendWrongStops()
     {
      double stopLossPrice=0;
      int stopLoss=market.WrongStopLoss;
      if(stopLoss>0)
        {
         if(market.PositionDirection==PosDirection_Long)
            stopLossPrice=market.Bid-stopLoss*market.Point;
         else if(market.PositionDirection==PosDirection_Short)
            stopLossPrice=market.Ask+stopLoss*market.Point;
        }

      double takeProfitPrice=0;
      int takeProfit=market.WrongTakeProf;
      if(takeProfit>0)
        {
         if(market.PositionDirection==PosDirection_Long)
            takeProfitPrice=market.Bid+takeProfit*market.Point;
         else if(market.PositionDirection==PosDirection_Short)
            takeProfitPrice=market.Ask-takeProfit*market.Point;
        }

      bool isSucess=actionTrade.ModifyPosition(stopLossPrice,takeProfitPrice);

      if(isSucess)
        {
         market.WrongStopLoss   = 0;
         market.WrongTakeProf   = 0;
         market.WrongStopsRetry = 0;
        }
      else
        {
         market.WrongStopsRetry++;
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double StrategyTrader::TradingSize(double size)
     {
      if(strategy.UseAccountPercentEntry)
         size=(size/100)*market.AccountEquity/market.MarginRequired;
      if(size>strategy.MaxOpenLots)
         size=strategy.MaxOpenLots;
      return (actionTrade.NormalizeEntrySize(size));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   int StrategyTrader::AccountPercentStopPoint(double percent,double lots)
     {
      double balance   = market.AccountBalance;
      double moneyrisk = balance * percent / 100;
      double spread    = market.Spread;
      double tickvalue = market.TickValue;
      double stoploss  = moneyrisk / (lots * tickvalue) - spread;
      return ((int) MathRound(stoploss));
     }
//+------------------------------------------------------------------+

#define TRADE_RETRY_COUNT 4
#define TRADE_RETRY_WAIT  100
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class ActionTrade
{
private:
   double            epsilon;

   // Fields
   Strategy         *strategy;
   DataSet          *dataSet[];
   DataMarket       *dataMarket;
   Position         *position;
   Logger           *logger;
   StrategyTrader   *strategyTrader;

   // Properties
   int               lastError;
   double            pipsValue;
   int               pipsPoint;
   int               stopLevel;
   datetime          barTime;
   datetime          barHighTime;
   datetime          barLowTime;
   double            barHighPrice;
   double            barLowPrice;
   int               trailingStop;
   TrailingStopMode  trailingMode;
   int               breakEven;
   int               consecutiveLosses;

   string            dynamicInfoParams[];
   string            dynamicInfoValues[];

   // Methods
   bool              CheckEnvironment(int minDataBars);
   bool              CheckChartBarsCount(int minDataBars);
   int               FindBarsCountNeeded(int minDataBars);
   int               SetAggregatePosition(Position *pos);
   void              UpdateDataSet(DataSet *data,int maxBars);
   bool              IsTradeContextFree(void);
   void              ActivateProtectionMinAccount(void);
   void              CloseExpert(void);

   // Trading methods
   double            GetTakeProfitPrice(int type,int takeProfit);
   double            GetStopLossPrice(int type,int stopLoss);
   double            CorrectTakeProfitPrice(int type,double takeProfitPrice);
   double            CorrectStopLossPrice(int type,double stopLossPrice);
   double            NormalizeEntryPrice(double price);
   void              SetMaxStopLoss(void);
   void              SetBreakEvenStop(void);
   void              SetTrailingStop(bool isNewBar);
   void              SetTrailingStopBarMode(void);
   void              SetTrailingStopTickMode(void);
   void              DetectPositionClosing(void);

   // Specific MQ4 trading methods
   bool              OpenNewPosition(int type,double lots,int stopLoss,int takeProfit);
   bool              AddToCurrentPosition(int type,double lots,int stopLoss,int takeProfit);
   bool              ReduceCurrentPosition(double lots,int stopLoss,int takeProfit);
   bool              ReverseCurrentPosition(int type,double lots,int stopLoss,int takeProfit);
   bool              CloseOrder(int orderTicket,double lots);
   bool              SelectOrder(int orderTicket);
   int               SendOrder(int type, double lots, int stopLoss, int takeProfit);
   bool              ModifyOrder(int orderTicket,double stopLossPrice,double takeProfitPrice);

public:
   // Constructors
                     ActionTrade(void);
                    ~ActionTrade(void);

   // Properties
   double            EntryAmount;
   double            MaximumAmount;
   double            AddingAmount;
   double            ReducingAmount;
   string            OrderComment;
   int               MinDataBars;
   int               ProtectionMinAccount;
   int               ProtectionMaxStopLoss;
   int               ExpertMagic;
   bool              SeparateSLTP;
   bool              WriteLogFile;
   bool              FIFOorder;
   int               TrailingStopMovingStep;
   int               MaxLogLinesInFile;
   int               BarCloseAdvance;

   // Methods
   int               OnInit(void);
   void              OnTick(void);
   void              OnDeinit(const int reason);
   void              UpdateDataMarket(DataMarket *market);
   double            NormalizeEntrySize(double size);
   bool              ManageOrderSend(int type,double lots,int stopLoss,int takeProfit,
                                     TrailingStopMode trlMode,int trlStop,int brkEven);
   bool              ModifyPosition(double stopLossPrice,double takeProfitPrice);
   bool              CloseCurrentPosition(void);
};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::ActionTrade(void)
{
   epsilon        = 0.000001;
   position       = new Position();
   logger         = new Logger();
   strategyTrader = new StrategyTrader( GetPointer(this) );
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::~ActionTrade(void)
{
    if ( CheckPointer(position) == POINTER_DYNAMIC )
        delete position;
    if ( CheckPointer(logger) == POINTER_DYNAMIC )
        delete logger;
    if ( CheckPointer(strategyTrader) == POINTER_DYNAMIC )
        delete strategyTrader;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ActionTrade::OnInit()
{
    dataMarket   = new DataMarket();
    barHighTime  = 0;
    barLowTime   = 0;
    barHighPrice = 0;
    barLowPrice  = 1000000;

   string message = StringFormat("%s loaded.", MQLInfoString(MQL_PROGRAM_NAME) );
   Comment(message);
   Print(message);

   if (WriteLogFile)
     {
      logger.CreateLogFile(logger.GetLogFileName(_Symbol, _Period, ExpertMagic));
      logger.WriteLogLine(message);
      logger.WriteLogLine("Entry Amount: "    + DoubleToString(EntryAmount, 2)   + ", " +
                          "Maximum Amount: "  + DoubleToString(MaximumAmount, 2) + ", " +
                          "Adding Amount: "   + DoubleToString(AddingAmount, 2)  + ", " +
                          "Reducing Amount: " + DoubleToString(ReducingAmount,2) );
      logger.WriteLogLine("Protection Min Account: "  + IntegerToString(ProtectionMinAccount) + ", " +
                          "Protection Max StopLoss: " + IntegerToString(ProtectionMaxStopLoss) );
      logger.WriteLogLine("Expert Magic: " + IntegerToString(ExpertMagic) + ", " +
                          "Bar Close Advance: " + IntegerToString(BarCloseAdvance) );
      logger.FlushLogFile();
     }

   if(_Digits==2 || _Digits==3)
      pipsValue=0.01;
   else if(_Digits==4 || _Digits==5)
      pipsValue=0.0001;
   else
      pipsValue=_Digits;

   if(_Digits==3 || _Digits==5)
      pipsPoint=10;
   else
      pipsPoint=1;

   stopLevel=(int) MarketInfo(_Symbol,MODE_STOPLEVEL)+pipsPoint;
   if(stopLevel<3*pipsPoint)
      stopLevel=3*pipsPoint;

   if(ProtectionMaxStopLoss>0 && ProtectionMaxStopLoss<stopLevel)
      ProtectionMaxStopLoss=stopLevel;

   if(TrailingStopMovingStep<pipsPoint)
      TrailingStopMovingStep=pipsPoint;

   StrategyManager *strategyManager=new StrategyManager();

// Strategy initialization
   strategy = strategyManager.GetStrategy();
   strategy.SetSymbol(_Symbol);
   strategy.SetPeriod((DataPeriod) _Period);
   strategy.SetIsTester(MQLInfoInteger(MQL_TESTER));
   strategy.EntryLots    = EntryAmount;
   strategy.MaxOpenLots  = MaximumAmount;
   strategy.AddingLots   = AddingAmount;
   strategy.ReducingLots = ReducingAmount;

   delete strategyManager;

// Checks the requirements.
   bool isEnvironmentGood=CheckEnvironment(strategy.MinBarsRequired);
   if(!isEnvironmentGood)
     {   // There is a non fulfilled condition, therefore we must exit.
      Sleep(20*1000);
      ExpertRemove();
      return (INIT_FAILED);
     }

// Market initialization
   string charts[];
   strategy.GetRequiredCharts(charts);

   string chartsNote = "Loading data: ";
   for(int i=0; i<ArraySize(charts); i++)
      chartsNote+=charts[i]+", ";
   chartsNote+="Minimum bars: "+IntegerToString(strategy.MinBarsRequired)+"...";
   Comment(chartsNote);
   Print(chartsNote);

// Initial data loading
   ArrayResize(dataSet,ArraySize(charts));
   for(int i=0; i<ArraySize(charts); i++)
      dataSet[i]=new DataSet(charts[i]);

   SetAggregatePosition(position);

// Checks the necessary bars.
   MinDataBars=FindBarsCountNeeded(MinDataBars);

// Initial strategy calculation
   for(int i=0; i<ArraySize(dataSet); i++)
      UpdateDataSet(dataSet[i],MinDataBars);
   strategy.CalculateStrategy(dataSet);

// Initialize StrategyTrader
   strategyTrader.OnInit(strategy, dataMarket);
   strategyTrader.InitTrade();

// Initialize the chart's info label.
   strategy.DynamicInfoInitArrays(dynamicInfoParams,dynamicInfoValues);
   int paramsX   = 0;
   int valuesX   = 140;
   int locationY = 40;
   color foreColor=GetChartForeColor(0);
   int count = ArraySize(dynamicInfoParams);
   for(int i = 0; i < count; i++)
     {
      string namep = "Lbl_prm_" + IntegerToString(i);
      string namev = "Lbl_val_" + IntegerToString(i);
      string param = dynamicInfoParams[i] == "" ? "." : dynamicInfoParams[i];
      LabelCreate(0,namep,0,paramsX,locationY,CORNER_LEFT_UPPER,param,"Ariel",8,foreColor);
      LabelCreate(0,namev,0,valuesX,locationY,CORNER_LEFT_UPPER,".","Ariel",8,foreColor);
      locationY+=12;
     }

   LabelCreate(0,"Lbl_pos_0",0,350,0,CORNER_LEFT_UPPER,".","Ariel",10,foreColor);
   LabelCreate(0,"Lbl_pos_1",0,350,15,CORNER_LEFT_UPPER,".","Ariel",10,foreColor);
   LabelCreate(0,"Lbl_pos_2",0,350,29,CORNER_LEFT_UPPER,".","Ariel",10,foreColor);

   Comment("");

   return (INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::OnTick()
  {
   RefreshRates();

   for(int i=0; i<ArraySize(dataSet); i++)
      UpdateDataSet(dataSet[i],MinDataBars);
   UpdateDataMarket(dataMarket);

   bool isNewBar=(barTime<dataMarket.BarTime && dataMarket.Volume<5);
   barTime   = dataMarket.BarTime;
   lastError = 0;

// Checks if minimum account was reached.
   if(ProtectionMinAccount>0 && AccountEquity()<ProtectionMinAccount)
      ActivateProtectionMinAccount();

// Checks and sets Max SL protection.
   if(ProtectionMaxStopLoss>0)
      SetMaxStopLoss();

// Checks if position was closed.
   DetectPositionClosing();

   if(breakEven>0)
      SetBreakEvenStop();

   if(trailingStop>0)
      SetTrailingStop(isNewBar);

   SetAggregatePosition(position);

   if(isNewBar && WriteLogFile)
      logger.WriteNewLogLine(position.ToString());

   if(dataSet[0].Bars>=strategy.MinBarsRequired)
     {
      strategy.CalculateStrategy(dataSet);
      TickType tickType=strategyTrader.GetTickType(isNewBar,BarCloseAdvance);
      strategyTrader.CalculateTrade(tickType);
     }

// Sends OrderModify on SL/TP errors
   if(strategyTrader.IsWrongStopsExecution())
      strategyTrader.ResendWrongStops();

   string accountInfo=StringFormat("%s Balance: %.2f, Equity: %.2f",
                                   TimeToString(dataMarket.TickServerTime,TIME_SECONDS),
                                   AccountInfoDouble(ACCOUNT_BALANCE),
                                   AccountInfoDouble(ACCOUNT_EQUITY));
   LabelTextChange(0,"Lbl_pos_0",accountInfo);
   string positionInfo[2];
   position.SetPositionInfo(positionInfo);
   for(int i=0; i<2; i++)
      LabelTextChange(0,"Lbl_pos_"+IntegerToString(i+1),positionInfo[i]);

   strategy.DynamicInfoSetValues(dynamicInfoValues);
   int count = ArraySize(dynamicInfoValues);
   for(int i = 0; i < count; i++)
     {
      string namev="Lbl_val_"+IntegerToString(i);
      string val=dynamicInfoValues[i]=="" ? "." : dynamicInfoValues[i];
      LabelTextChange(0,namev,val);
     }

   if(WriteLogFile)
     {
      if(logger.IsLogLinesLimitReached(MaxLogLinesInFile))
        {
         logger.CloseLogFile();
         logger.CreateLogFile(logger.GetLogFileName(_Symbol, _Period, ExpertMagic));
        }
      logger.FlushLogFile();
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::OnDeinit(const int reason)
  {
   strategyTrader.OnDeinit();

   if(WriteLogFile)
      logger.CloseLogFile();

   if(CheckPointer(strategy)==POINTER_DYNAMIC)
      delete strategy;

   for(int i=0; i<ArraySize(dataSet); i++)
      if(CheckPointer(dataSet[i])==POINTER_DYNAMIC)
         delete dataSet[i];
   ArrayFree(dataSet);

   if(CheckPointer(dataMarket)==POINTER_DYNAMIC)
      delete dataMarket;

   int count = ArraySize(dynamicInfoParams);
   for(int i = 0; i < count; i++)
     {
      LabelDelete(0,"Lbl_val_"+IntegerToString(i));
      LabelDelete(0,"Lbl_prm_"+IntegerToString(i));
     }

   for(int i=0; i<3; i++)
      LabelDelete(0,"Lbl_pos_"+IntegerToString(i));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ActionTrade::CheckEnvironment(int minDataBars)
  {
   if(!CheckChartBarsCount(minDataBars))
      return (false);

   if(MQLInfoInteger(MQL_TESTER))
     {
      SetAggregatePosition(position);
      return (true);
     }

   if(AccountNumber()==0)
     {
      Comment("\n You are not logged in. Please login first.");
      for(int attempt=0; attempt<200; attempt++)
        {
         if(AccountNumber()==0)
            Sleep(300);
         else
            break;
        }
      if(AccountNumber()==0)
         return (false);
     }

   if(SetAggregatePosition(position)==-1)
      return (false);

   return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ActionTrade::FindBarsCountNeeded(int minDataBars)
  {
   int barStep = 50;
   int minBars = MathMax(minDataBars, 50);
   int maxBars = MathMax(minBars, 3000);

// Initial state
   int initialBars=MathMax(strategy.MinBarsRequired,minBars);
   initialBars=MathMax(strategy.FirstBar,initialBars);
   for(int i=0; i<ArraySize(dataSet); i++)
      UpdateDataSet(dataSet[i],initialBars);
   UpdateDataMarket(dataMarket);
   double initialBid=dataMarket.Bid;
   strategy.CalculateStrategy(dataSet);
   string dynamicInfo= strategy.DynamicInfoText();
   int necessaryBars = initialBars;
   int roundedInitialBars=(int)(barStep*MathCeil(((double) initialBars)/barStep));
   int firstTestBars=roundedInitialBars>=initialBars+barStep/2
                     ? roundedInitialBars
                     : roundedInitialBars+barStep;

   for(int bars=firstTestBars; bars<=maxBars; bars+=barStep)
     {
      for(int i=0; i<ArraySize(dataSet); i++)
         UpdateDataSet(dataSet[i],bars);
      UpdateDataMarket(dataMarket);
      strategy.CalculateStrategy(dataSet);
      string currentInfo=strategy.DynamicInfoText();

      if(dynamicInfo==currentInfo)
         break;

      dynamicInfo=currentInfo;
      necessaryBars=bars;

      if(MathAbs(initialBid-dataMarket.Bid)>epsilon)
        {  // Reset the test if new tick has arrived.
         for(int i=0; i<ArraySize(dataSet); i++)
            UpdateDataSet(dataSet[i],initialBars);
         UpdateDataMarket(dataMarket);
         initialBid=dataMarket.Bid;
         strategy.CalculateStrategy(dataSet);
         dynamicInfo=strategy.DynamicInfoText();
         bars=firstTestBars-barStep;
        }
     }

   string barsMessage="The expert uses "+IntegerToString(necessaryBars)+" bars.";
   if(WriteLogFile)
     {
      logger.WriteLogLine(barsMessage);
      string timeLastBar=TimeToString(dataMarket.TickServerTime,TIME_DATE|TIME_MINUTES);
      logger.WriteLogLine("Indicator values: " + dataSet[0].Chart + ", Time last bar: " + timeLastBar);
      logger.WriteLogLine(dynamicInfo);
     }
   Print(barsMessage);

   return (necessaryBars);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::UpdateDataSet(DataSet *data,int maxBars)
  {
   string symbol = data.Symbol;
   int    period = (int) data.Period;
   int    bars   = MathMin(Bars(symbol, period), maxBars);

   data.LotSize        = (int) MarketInfo(symbol, MODE_LOTSIZE);
   data.Digits         = (int) MarketInfo(symbol, MODE_DIGITS);
   data.StopLevel      = (int) MarketInfo(symbol, MODE_STOPLEVEL);
   data.Point          = MarketInfo(symbol, MODE_POINT);
   data.TickValue      = MarketInfo(symbol, MODE_TICKVALUE);
   data.MinLot         = MarketInfo(symbol, MODE_MINLOT);
   data.MaxLot         = MarketInfo(symbol, MODE_MAXLOT);
   data.LotStep        = MarketInfo(symbol, MODE_LOTSTEP);
   data.MarginRequired = MarketInfo(symbol, MODE_MARGINREQUIRED);
   data.Bars           = bars;
   data.ServerTime     = TimeCurrent();
   data.Bid            = MarketInfo(symbol, MODE_BID);
   data.Ask            = MarketInfo(symbol, MODE_ASK);
   data.Spread         = (data.Ask - data.Bid) / data.Point;

   if(data.MarginRequired<epsilon)
      data.MarginRequired=data.Bid*data.LotSize/100;

   data.SetPrecision();

   MqlRates rates[];
   RefreshRates();
   ArraySetAsSeries(rates,false);
   int copied=CopyRates(symbol,period,0,bars,rates);

   ArrayResize(data.Time,   bars);
   ArrayResize(data.Open,   bars);
   ArrayResize(data.High,   bars);
   ArrayResize(data.Low,    bars);
   ArrayResize(data.Close,  bars);
   ArrayResize(data.Volume, bars);

   for(int i=0; i<bars; i++)
     {
      data.Time[i]   = rates[i].time;
      data.Open[i]   = rates[i].open;
      data.High[i]   = rates[i].high;
      data.Low[i]    = rates[i].low;
      data.Close[i]  = rates[i].close;
      data.Volume[i] = (int) rates[i].tick_volume;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::UpdateDataMarket(DataMarket *market)
  {
   market.Symbol = _Symbol;
   market.Period = (DataPeriod) _Period;

   market.TickLocalTime  = TimeLocal();
   market.TickServerTime = TimeCurrent();
   market.BarTime        = Time[0];

   market.PositionLots       = position.Lots;
   market.PositionOpenPrice  = position.OpenPrice;
   market.PositionOpenTime   = position.OpenTime;
   market.PositionStopLoss   = position.StopLossPrice;
   market.PositionTakeProfit = position.TakeProfitPrice;
   market.PositionProfit     = position.Profit;
   market.PositionDirection  = position.Direction;

   market.AccountBalance    = AccountBalance();
   market.AccountEquity     = AccountEquity();
   market.AccountFreeMargin = AccountFreeMargin();
   market.ConsecutiveLosses = consecutiveLosses;

   market.OldAsk    = market.Ask;
   market.OldBid    = market.Bid;
   market.OldClose  = market.Close;
   market.Ask       = MarketInfo(_Symbol, MODE_ASK);
   market.Bid       = MarketInfo(_Symbol, MODE_BID);
   market.Close     = Close[0];
   market.Volume    = Volume[0];
   market.IsNewBid  = MathAbs(market.OldBid - market.Bid) > epsilon;

   market.LotSize        = (int) MarketInfo(_Symbol, MODE_LOTSIZE);
   market.StopLevel      = (int) MarketInfo(_Symbol, MODE_STOPLEVEL);
   market.Point          = MarketInfo(_Symbol, MODE_POINT);
   market.TickValue      = MarketInfo(_Symbol, MODE_TICKVALUE);
   market.MinLot         = MarketInfo(_Symbol, MODE_MINLOT);
   market.MaxLot         = MarketInfo(_Symbol, MODE_MAXLOT);
   market.LotStep        = MarketInfo(_Symbol, MODE_LOTSTEP);
   market.MarginRequired = MarketInfo(_Symbol, MODE_MARGINREQUIRED);
   market.Spread         = (market.Ask - market.Bid) / market.Point;

   if(market.MarginRequired<epsilon)
      market.MarginRequired=market.Bid*market.LotSize/100;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ActionTrade::CheckChartBarsCount(int minDataBars)
  {
   if(MQLInfoInteger(MQL_TESTER))
     {
      if(Bars(_Symbol,_Period)>=minDataBars)
         return (true);

      string message=
                     "\n Cannot load enough bars! The expert needs minimum "+
                     IntegerToString(minDataBars)+" bars."+
                     "\n Please check the \"Use date\" option"+
                     " and set the \"From:\" and \"To:\" dates properly.";
      Comment(message);
      Print(message);
      return (false);
     }

   int bars=0;
   double rates[][6];

   for(int attempt=0; attempt<10; attempt++)
     {
      RefreshRates();
      bars=ArrayCopyRates(rates,_Symbol,_Period);
      if(bars<minDataBars && GetLastError()==4066)
        {
         Comment("Loading...");
         Sleep(500);
        }
      else
         break;

      if(IsStopped())
         break;
     }

   bool isEnoughBars=(bars>=minDataBars);
   if(!isEnoughBars)
     {
      string message="There isn\'t enough bars. The expert needs minimum "+
                     IntegerToString(minDataBars)+" bars. "+
                     "Currently "+IntegerToString(bars)+" bars are loaded."+
                     "\n Press and hold the Home key to force MetaTrader loading more bars.";
      Comment(message);
      Print(message);
     }

   return (isEnoughBars);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ActionTrade::SetAggregatePosition(Position *pos)
  {
   pos.PosType          = OP_FLAT;
   pos.Direction        = PosDirection_None;
   pos.OpenTime         = D'2050.01.01 00:00';
   pos.Lots             = 0;
   pos.OpenPrice        = 0;
   pos.StopLossPrice    = 0;
   pos.TakeProfitPrice  = 0;
   pos.Profit           = 0;
   pos.Commission       = 0;
   pos.PosComment       = "";

   int positions=0;

   for(int i=0; i<OrdersTotal(); i++)
     {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Error with OrderSelect: ",GetErrorDescription(GetLastError()));
         Comment("Cannot check current position!");
         continue;
        }

      if(OrderMagicNumber()!=ExpertMagic || OrderSymbol()!=_Symbol)
         continue; // An order not sent by Forex Strategy Builder.

      if(OrderType()==OP_BUYLIMIT || OrderType()==OP_SELLLIMIT || 
         OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP)
         continue; // A pending order.

      if(pos.PosType>=0 && pos.PosType!=OrderType())
        {
         string message="There are open positions in different directions!";
         Comment(message);
         Print(message);
         return (-1);
        }

      pos.PosType     = OrderType();
      pos.Direction   = position.PosType == OP_FLAT ? PosDirection_None :
                       position.PosType==OP_BUY ? PosDirection_Long : PosDirection_Short;
      pos.OpenTime    = (OrderOpenTime() < pos.OpenTime) ? OrderOpenTime() : pos.OpenTime;
      pos.OpenPrice   = (pos.Lots * pos.OpenPrice + OrderLots() * OrderOpenPrice()) / (pos.Lots + OrderLots());
      pos.Lots       += OrderLots();
      pos.Commission += OrderCommission();
      pos.Profit     += OrderProfit() + pos.Commission;
      pos.StopLossPrice   = OrderStopLoss();
      pos.TakeProfitPrice = OrderTakeProfit();
      pos.PosComment      = OrderComment();

      positions+=1;
     }

   if(pos.OpenPrice>0)
      pos.OpenPrice=NormalizeDouble(pos.OpenPrice,_Digits);

   if(pos.Lots==0)
      pos.OpenTime=D'2050.01.01 00:00';

   return (positions);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ActionTrade::ManageOrderSend(int type, double lots, int stopLoss, int takeProfit,
                                  TrailingStopMode trlMode, int trlStop, int brkEven)
{
    trailingMode = trlMode;
    trailingStop = trlStop;
    breakEven    = brkEven;

    bool orderResponse=false;
    int positions=SetAggregatePosition(position);

    if (positions < 0)
        return (false);

    if(positions==0)
    {   // Open a new position.
      orderResponse=OpenNewPosition(type,lots,stopLoss,takeProfit);
    }
    else if(positions>0)
    {   // There is an open position.
      if((position.PosType==OP_BUY  && type==OP_BUY ) || 
         (position.PosType==OP_SELL && type==OP_SELL) )
      {
         orderResponse = AddToCurrentPosition(type,lots,stopLoss,takeProfit);
      }
      else if((position.PosType==OP_BUY  && type==OP_SELL) || 
              (position.PosType==OP_SELL && type==OP_BUY) )
      {
          if( MathAbs(position.Lots-lots) < epsilon )
             orderResponse = CloseCurrentPosition();
          else if(position.Lots > lots)
             orderResponse = ReduceCurrentPosition(lots, stopLoss, takeProfit);
          else if(position.Lots < lots)
             orderResponse = ReverseCurrentPosition(type, lots, stopLoss, takeProfit);
      }
    }

    return (orderResponse);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ActionTrade::OpenNewPosition(int type,double lots,int stopLoss,int takeProfit)
{
    bool orderResponse=false;

    if (type!=OP_BUY && type!=OP_SELL)
    {   // Error. Wrong order type!
        Print("Wrong 'Open new position' request - Wrong order type!");
        return (false);
    }

    double orderLots=NormalizeEntrySize(lots);

    if ( AccountFreeMarginCheck(_Symbol,type,orderLots) > 0 )
    {
        if (SeparateSLTP)
        {
            if (WriteLogFile)
                logger.WriteLogLine("OpenNewPosition => SendOrder");

            int orderTicket = SendOrder(type,orderLots,0,0);
            orderResponse   = orderTicket > 0;

            if (orderResponse)
            {
               if (WriteLogFile)
                   logger.WriteLogLine("OpenNewPosition => ModifyPosition");

               double stopLossPrice   = GetStopLossPrice(type, stopLoss);
               double takeProfitPrice = GetTakeProfitPrice(type, takeProfit);

               orderResponse = ModifyOrder(orderTicket, stopLossPrice, takeProfitPrice);
            }
        }
        else
        {
            int orderTicket = SendOrder(type,orderLots,stopLoss,takeProfit);
            orderResponse   = orderTicket > 0;

            if (WriteLogFile)
                logger.WriteLogLine("OpenNewPosition: SendOrder Response = " +
                                    (orderResponse ? "Ok" : "Failed") );

            if (!orderResponse && lastError == 130)
            {   // Invalid Stops. We'll check for forbidden direct set of SL and TP
                if (WriteLogFile)
                    logger.WriteLogLine("OpenNewPosition: SendOrder");

                orderResponse = SendOrder(type, lots, 0, 0);

                if (orderResponse)
                {
                    if (WriteLogFile)
                        logger.WriteLogLine("OpenNewPosition: ModifyPosition");

                   double stopLossPrice   = GetStopLossPrice(type,stopLoss);
                   double takeProfitPrice = GetTakeProfitPrice(type,takeProfit);

                   orderResponse = ModifyOrder(orderTicket, stopLossPrice, takeProfitPrice);

                   if (orderResponse)
                   {
                       SeparateSLTP=true;
                       Print(AccountCompany()," marked with separate stops setting.");
                   }
                }
            }
        }
    }

    SetAggregatePosition(position);

    if (WriteLogFile)
        logger.WriteLogLine(position.ToString());

    return (orderResponse);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::CloseCurrentPosition()
     {
      bool orderResponse = false;
      int  totalOrders   = OrdersTotal();
      int  orders        = 0;
      datetime openPos[][2];

      for(int i=0; i<totalOrders; i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            lastError=GetLastError();
            Print("Error in OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         if(OrderMagicNumber()!=ExpertMagic || OrderSymbol()!=_Symbol)
            continue;

         int orderType = OrderType();
         if(orderType != OP_BUY && orderType != OP_SELL)
            continue;

         orders++;
         ArrayResize(openPos,orders);
         openPos[orders - 1][0] = OrderOpenTime();
         openPos[orders - 1][1] = OrderTicket();
        }

      if(FIFOorder)
         ArraySort(openPos,WHOLE_ARRAY,0,MODE_ASCEND);
      else
         ArraySort(openPos,WHOLE_ARRAY,0,MODE_DESCEND);

      for(int i=0; i<orders; i++)
        {
         if(!OrderSelect((int) openPos[i][1],SELECT_BY_TICKET))
           {
            lastError=GetLastError();
            Print("Error in OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         orderResponse=CloseOrder(OrderTicket(),OrderLots());
        }

      consecutiveLosses=(position.Profit<0) ? consecutiveLosses+1 : 0;
      SetAggregatePosition(position);
      Print("ConsecutiveLosses=",consecutiveLosses);

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::AddToCurrentPosition(int type,double lots,int stopLoss,int takeProfit)
     {
      if(AccountFreeMarginCheck(_Symbol,type,lots)<=0)
         return (false);

      if(WriteLogFile)
         logger.WriteLogLine("AddToCurrentPosition: OpenNewPosition");

      bool orderResponse=OpenNewPosition(type,lots,stopLoss,takeProfit);

      if(!orderResponse)
         return (false);

      double stopLossPrice=GetStopLossPrice(type,stopLoss);
      double takeProfitPrice=GetTakeProfitPrice(type,takeProfit);

      orderResponse=ModifyPosition(stopLossPrice,takeProfitPrice);

      SetAggregatePosition(position);

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::ReduceCurrentPosition(double lots,int stopLoss,int takeProfit)
     {
      int totalOrders=OrdersTotal();
      int orders=0;
      datetime openPos[][2];

      for(int i=0; i<totalOrders; i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            lastError=GetLastError();
            Print("Error in OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         if(OrderMagicNumber()!=ExpertMagic || 
            OrderSymbol()!=_Symbol)
            continue;

         int orderType = OrderType();
         if(orderType != OP_BUY && orderType != OP_SELL)
            continue;

         orders++;
         ArrayResize(openPos,orders);
         openPos[orders - 1][0] = OrderOpenTime();
         openPos[orders - 1][1] = OrderTicket();
        }

      if(FIFOorder)
         ArraySort(openPos,WHOLE_ARRAY,0,MODE_ASCEND);
      else
         ArraySort(openPos,WHOLE_ARRAY,0,MODE_DESCEND);

      for(int i=0; i<orders; i++)
        {
         if(!OrderSelect((int) openPos[i][1],SELECT_BY_TICKET))
           {
            lastError=GetLastError();
            Print("Error in OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         double orderLots=(lots>=OrderLots()) ? OrderLots() : lots;
         CloseOrder(OrderTicket(),orderLots);
         lots-=orderLots;

         if(lots<=0)
            break;
        }

      double stopLossPrice=GetStopLossPrice(position.PosType,stopLoss);
      double takeProfitPrice=GetTakeProfitPrice(position.PosType,takeProfit);

      bool orderResponse=ModifyPosition(stopLossPrice,takeProfitPrice);

      SetAggregatePosition(position);
      consecutiveLosses=0;

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::ReverseCurrentPosition(int type,double lots,int stopLoss,int takeProfit)
     {
      lots-=position.Lots;

      bool orderResponse=CloseCurrentPosition();

      if(!orderResponse)
         return (false);

      orderResponse=OpenNewPosition(type,lots,stopLoss,takeProfit);

      SetAggregatePosition(position);
      consecutiveLosses=0;

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ActionTrade::SendOrder(int type, double lots, int stopLoss, int takeProfit)
{
    int orderTicket = -1;

    for (int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
    {
        if ( IsTradeContextFree() )
        {
            double orderLots       = NormalizeEntrySize(lots);
            double orderPrice      = type == OP_BUY
                                        ? MarketInfo(_Symbol,MODE_ASK)
                                        : MarketInfo(_Symbol,MODE_BID);
            double stopLossPrice   = GetStopLossPrice(type, stopLoss);
            double takeProfitPrice = GetTakeProfitPrice(type, takeProfit);
            color  colorDeal       = type == OP_BUY ? Lime : Red;
            string comment         = OrderComment == ""
                                        ? "Magic="+IntegerToString(ExpertMagic)
                                        : OrderComment;

            orderTicket = OrderSend(_Symbol, type, orderLots, orderPrice, 100,
                                    stopLossPrice, takeProfitPrice, comment,
                                    ExpertMagic, 0, colorDeal);

            lastError = GetLastError();

            if (WriteLogFile)
                logger.WriteLogLine(
                   "SendOrder: "   + _Symbol                                 +
                   ", Type="       + (type==OP_BUY ? "Buy" : "Sell")         +
                   ", Lots="       + DoubleToString(orderLots,2)             +
                   ", Price="      + DoubleToString(orderPrice,_Digits)      +
                   ", StopLoss="   + DoubleToString(stopLossPrice,_Digits)   +
                   ", TakeProfit=" + DoubleToString(takeProfitPrice,_Digits) +
                   ", Magic="      + IntegerToString(ExpertMagic)            +
                   ", Ticket="     + IntegerToString(orderTicket)            +
                   ", LastError="  + IntegerToString(lastError) );
        }

        if (orderTicket > 0)
            break;

        if (lastError!=135 && lastError!=136 && 
            lastError!=137 && lastError!=138)
            break;

        Print("Error with SendOrder: ", GetErrorDescription(lastError));

        Sleep(TRADE_RETRY_WAIT);
    }

    return (orderTicket);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::CloseOrder(int orderTicket, double orderLots)
     {
      if(!OrderSelect(orderTicket,SELECT_BY_TICKET))
        {
         lastError=GetLastError();
         Print("Error with OrderSelect: ",GetErrorDescription(lastError));
         return (false);
        }

      int orderType=OrderType();

      for(int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
        {
         bool orderResponse=false;
         if(IsTradeContextFree())
           {
            double orderPrice=(orderType==OP_BUY)
                              ? MarketInfo(_Symbol,MODE_BID)
                              : MarketInfo(_Symbol,MODE_ASK);
            orderPrice=NormalizeDouble(orderPrice,Digits);

            orderResponse=OrderClose(orderTicket,orderLots,orderPrice,100,Gold);

            lastError=GetLastError();
            if(WriteLogFile)
               logger.WriteLogLine("OrderClose: "+_Symbol+
                                   ", Ticket="+IntegerToString(orderTicket)+
                                   ", Lots="+DoubleToString(orderLots,2)+
                                   ", Price="+DoubleToString(orderPrice,_Digits)+
                                   ", Response="+(orderResponse ? "True" : "False")+
                                   ", LastError="+IntegerToString(lastError));
           }

         if(orderResponse)
            return (true);

         if(lastError==4108)
            return(false); // Invalid ticket error.

         Print("Error with CloseOrder: ",GetErrorDescription(lastError),
               ". Attempt No: ",(attempt+1));

         Sleep(TRADE_RETRY_WAIT);
        }

      return (false);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::ModifyPosition(double stopLossPrice,double takeProfitPrice)
     {
      bool orderResponse=true;

      for(int i=0; i<OrdersTotal(); i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            lastError=GetLastError();
            Print("Error with OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         if(OrderMagicNumber()!=ExpertMagic || OrderSymbol()!=_Symbol)
            continue;

         int type = OrderType();
         if(type != OP_BUY && type != OP_SELL)
            continue;

         orderResponse=ModifyOrder(OrderTicket(),stopLossPrice,takeProfitPrice);
        }

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::ModifyOrder(int orderTicket,double stopLossPrice,double takeProfitPrice)
     {
      if(!SelectOrder(orderTicket))
         return (false);

      stopLossPrice=NormalizeEntryPrice(stopLossPrice);
      takeProfitPrice=NormalizeEntryPrice(takeProfitPrice);
      double oldStopLoss=NormalizeEntryPrice(OrderStopLoss());
      double oldTakeProfit=NormalizeEntryPrice(OrderTakeProfit());

      for(int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
        {
         if(attempt>0)
           {
            stopLossPrice=CorrectStopLossPrice(OrderType(),stopLossPrice);
            takeProfitPrice=CorrectTakeProfitPrice(OrderType(),takeProfitPrice);
           }

         if(MathAbs(stopLossPrice-oldStopLoss)<pipsValue && 
            MathAbs(takeProfitPrice-oldTakeProfit)<pipsValue)
            return(true); // There isn't anything to change.

         bool isSuccess = false;
         string logline = "";
         double orderOpenPrice=0;
         if(IsTradeContextFree())
           {
            orderOpenPrice=NormalizeDouble(OrderOpenPrice(),_Digits);

            isSuccess=OrderModify(orderTicket,orderOpenPrice,stopLossPrice,takeProfitPrice,0);

            lastError=GetLastError();
            if(WriteLogFile)
               logline=
                       "ModifyOrder: "+_Symbol+
                       ", Ticket="+IntegerToString(orderTicket)+
                       ", Price="+DoubleToString(orderOpenPrice,_Digits)+
                       ", StopLoss="+DoubleToString(stopLossPrice,_Digits)+
                       ", TakeProfit="+DoubleToString(takeProfitPrice,_Digits)+")"+
                       "  Magic="+IntegerToString(ExpertMagic)+
                       ", Response="+IntegerToString(isSuccess)+
                       ", LastError="+IntegerToString(lastError);
           }

         if(isSuccess)
           {   // Modification was successful.
            if(WriteLogFile)
               logger.WriteLogLine(logline);
            return (true);
           }
         else if(lastError==1)
           {
            if(!SelectOrder(orderTicket))
               return (false);

            if(MathAbs(stopLossPrice-OrderStopLoss())<pipsValue && 
               MathAbs(takeProfitPrice-OrderTakeProfit())<pipsValue)
              {
               if(WriteLogFile)
                  logger.WriteLogLine(logline+", Checked OK");
               lastError=0;
               return(true); // We assume that there is no error.
              }
           }

         Print("Error with ModifyOrder(",
               orderTicket,", ",
               orderOpenPrice,", ",
               stopLossPrice,", ",
               takeProfitPrice,") ",
               GetErrorDescription(lastError),".");
         Sleep(TRADE_RETRY_WAIT);
         RefreshRates();

         if(lastError==4108)
            return(false);  // Invalid ticket error.
        }

      return (false);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   bool ActionTrade::SelectOrder(int orderTicket)
     {
      bool orderResponse=OrderSelect(orderTicket,SELECT_BY_TICKET);

      if(!orderResponse)
        {
         lastError=GetLastError();
         string message="Error with OrderSelect("+
                        IntegerToString(orderTicket)+")"+
                        ", LastError="+IntegerToString(lastError)+", "+
                        GetErrorDescription(lastError);
         Print(message);
         if(WriteLogFile)
            logger.WriteLogLine(message);
        }

      return (orderResponse);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::GetTakeProfitPrice(int type,int takeProfit)
     {
      if(takeProfit<epsilon)
         return (0);

      if(takeProfit<stopLevel)
         takeProfit=stopLevel;

      double takeProfitPrice=(type==OP_BUY)
                             ? MarketInfo(_Symbol,MODE_BID)+takeProfit*_Point
                             : MarketInfo(_Symbol,MODE_ASK)-takeProfit*_Point;

      return (NormalizeEntryPrice(takeProfitPrice));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::GetStopLossPrice(int type,int stopLoss)
     {
      if(stopLoss<epsilon)
         return (0);

      if(stopLoss<stopLevel)
         stopLoss=stopLevel;

      double stopLossPrice=(type==OP_BUY)
                           ? MarketInfo(_Symbol,MODE_BID)-stopLoss*_Point
                           : MarketInfo(_Symbol,MODE_ASK)+stopLoss*_Point;

      return (NormalizeEntryPrice(stopLossPrice));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::CorrectTakeProfitPrice(int type,double takeProfitPrice)
     {
      if(takeProfitPrice<epsilon)
         return (0);

      double bid = MarketInfo(_Symbol, MODE_BID);
      double ask = MarketInfo(_Symbol, MODE_ASK);

      if(type==OP_BUY)
        {
         double minTPPrice=bid+stopLevel*_Point;
         if(takeProfitPrice<minTPPrice)
            takeProfitPrice=minTPPrice;
        }
      else if(type==OP_SELL)
        {
         double maxTPPrice=ask-stopLevel*_Point;
         if(takeProfitPrice>maxTPPrice)
            takeProfitPrice=maxTPPrice;
        }

      return (NormalizeEntryPrice(takeProfitPrice));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::CorrectStopLossPrice(int type,double stopLossPrice)
     {
      if(stopLossPrice==epsilon)
         return (0);

      double bid = MarketInfo(_Symbol, MODE_BID);
      double ask = MarketInfo(_Symbol, MODE_ASK);

      if(type==OP_BUY)
        {
         double minSLPrice=bid-stopLevel*_Point;
         if(stopLossPrice>minSLPrice)
            stopLossPrice=minSLPrice;
        }
      else if(type==OP_SELL)
        {
         double maxSLPrice=ask+stopLevel*_Point;
         if(stopLossPrice<maxSLPrice)
            stopLossPrice=maxSLPrice;
        }

      return (NormalizeEntryPrice(stopLossPrice));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::NormalizeEntryPrice(double price)
     {
      double tickSize=MarketInfo(_Symbol,MODE_TICKSIZE);
      if(tickSize!=0)
         return (NormalizeDouble(MathRound(price / tickSize) * tickSize, _Digits));
      return (NormalizeDouble(price, _Digits));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   double ActionTrade::NormalizeEntrySize(double size)
     {
      double minlot  = MarketInfo(_Symbol, MODE_MINLOT);
      double maxlot  = MarketInfo(_Symbol, MODE_MAXLOT);
      double lotstep = MarketInfo(_Symbol, MODE_LOTSTEP);

      if(size<minlot-epsilon)
         return (0);

      if(MathAbs(size-minlot)<epsilon)
         return (minlot);

      int steps=(int) MathRound((size-minlot)/lotstep);
      size=minlot+steps*lotstep;

      if(size >= maxlot)
         size = maxlot;

      return (size);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void ActionTrade::SetMaxStopLoss()
     {
      double bid = MarketInfo(_Symbol, MODE_BID);
      double ask = MarketInfo(_Symbol, MODE_ASK);
      double spread=(ask-bid)/_Point;

      for(int i=0; i<OrdersTotal(); i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            lastError=GetLastError();
            Print("Error with OrderSelect: ",GetErrorDescription(lastError));
            continue;
           }

         if(OrderMagicNumber()!=ExpertMagic || 
            OrderSymbol()!=_Symbol)
            continue;

         int type = OrderType();
         if(type != OP_BUY && type != OP_SELL)
            continue;

         int orderTicket=OrderTicket();
         double posOpenPrice=OrderOpenPrice();
         double stopLossPrice=OrderStopLoss();
         double takeProfitPrice=OrderTakeProfit();
         int stopLossPoints=(int)
                            MathRound(MathAbs(posOpenPrice-stopLossPrice)/_Point);

         if(stopLossPrice<epsilon || 
            stopLossPoints>ProtectionMaxStopLoss+spread)
           {
            stopLossPrice=(type==OP_BUY)
                          ? posOpenPrice-_Point *(ProtectionMaxStopLoss+spread)
                          : posOpenPrice+_Point *(ProtectionMaxStopLoss+spread);
            stopLossPrice=CorrectStopLossPrice(type,stopLossPrice);

            if(WriteLogFile)
               logger.WriteLogRequest("SetMaxStopLoss","StopLoss="+
                                      DoubleToString(stopLossPrice,_Digits));

            bool isSuccess=ModifyOrder(orderTicket,stopLossPrice,takeProfitPrice);

            if(isSuccess)
               Print("MaxStopLoss(",ProtectionMaxStopLoss,") set StopLoss to ",
                     DoubleToString(stopLossPrice,_Digits));
           }
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void ActionTrade::SetBreakEvenStop()
     {
      if(SetAggregatePosition(position)<=0)
         return;

      double breakeven=stopLevel;
      if(breakeven<breakEven)
         breakeven=breakEven;

      double breakprice = 0; // Break Even price including commission.
      double commission = 0; // Commission in points.
      if(position.Commission!=0)
         commission=MathAbs(position.Commission)/MarketInfo(_Symbol,MODE_TICKVALUE);

      double bid = MarketInfo(_Symbol, MODE_BID);
      double ask = MarketInfo(_Symbol, MODE_ASK);

      if(position.PosType==OP_BUY)
        {
         breakprice=NormalizeEntryPrice(position.OpenPrice+
                                        _Point*commission/position.Lots);
         if(bid-breakprice>=_Point*breakeven)
           {
            if(position.StopLossPrice<breakprice)
              {
               if(WriteLogFile)
                  logger.WriteLogRequest("SetBreakEvenStop",
                                         "BreakPrice="+DoubleToString(breakprice,_Digits));

               ModifyPosition(breakprice,position.TakeProfitPrice);

               Print("SetBreakEvenStop(",breakEven,
                     ") set StopLoss to ",DoubleToString(breakprice,_Digits),
                     ", Bid=",DoubleToString(bid,_Digits));
              }
           }
        }
      else if(position.PosType==OP_SELL)
        {
         breakprice=NormalizeEntryPrice(position.OpenPrice -
                                        _Point*commission/position.Lots);
         if(breakprice-ask>=_Point*breakeven)
           {
            if(position.StopLossPrice==0 || position.StopLossPrice>breakprice)
              {
               if(WriteLogFile)
                  logger.WriteLogRequest("SetBreakEvenStop","BreakPrice="+
                                         DoubleToString(breakprice,_Digits));

               ModifyPosition(breakprice,position.TakeProfitPrice);

               Print("SetBreakEvenStop(",breakEven,") set StopLoss to ",
                     DoubleToString(breakprice,_Digits),
                     ", Ask=",DoubleToString(ask,_Digits));
              }
           }
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void ActionTrade::SetTrailingStop(bool isNewBar)
     {
      bool isCheckTS=true;

      if(isNewBar)
        {
         if(position.PosType==OP_BUY && position.OpenTime>barHighTime)
            isCheckTS=false;

         if(position.PosType==OP_SELL && position.OpenTime>barLowTime)
            isCheckTS=false;

         barHighTime  = Time[0];
         barLowTime   = Time[0];
         barHighPrice = High[0];
         barLowPrice  = Low[0];
        }
      else
        {
         if(High[0]>barHighPrice)
           {
            barHighPrice = High[0];
            barHighTime  = Time[0];
           }
         if(Low[0]<barLowPrice)
           {
            barLowPrice = Low[0];
            barLowTime  = Time[0];
           }
        }

      if(SetAggregatePosition(position)<=0)
         return;

      if(trailingMode==TrailingStopMode_Tick)
         SetTrailingStopTickMode();
      else if(trailingMode==TrailingStopMode_Bar && isNewBar && isCheckTS)
         SetTrailingStopBarMode();
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void ActionTrade::SetTrailingStopBarMode()
     {
      double bid = MarketInfo(_Symbol, MODE_BID);
      double ask = MarketInfo(_Symbol, MODE_ASK);

      if(position.PosType==OP_BUY)
        {   // Long position
         double stopLossPrice=High[1]-_Point*trailingStop;
         if(position.StopLossPrice<stopLossPrice-pipsValue)
           {
            if(stopLossPrice<bid)
              {
               if(stopLossPrice>bid-_Point*stopLevel)
                  stopLossPrice=bid-_Point*stopLevel;

               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopBarMode",
                                         "StopLoss="+
                                         DoubleToString(stopLossPrice,_Digits));

               ModifyPosition(stopLossPrice,position.TakeProfitPrice);

               Print("Trailing Stop (",trailingStop,") moved to: ",
                     DoubleToString(stopLossPrice,_Digits),
                     ", Bid=",DoubleToString(bid,_Digits));
              }
            else
              {
               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopBarMode",
                                         "StopLoss="+
                                         DoubleToString(stopLossPrice,_Digits));

               bool orderResponse=CloseCurrentPosition();

               int lastErrorOrdClose=GetLastError();
               lastErrorOrdClose=(lastErrorOrdClose>0)
                                 ? lastErrorOrdClose
                                 : lastError;
               if(!orderResponse)
                  Print("Error in OrderClose: ",
                        GetErrorDescription(lastErrorOrdClose));
              }
           }
        }
      else if(position.PosType==OP_SELL)
        {   // Short position
         double stopLossPrice=Low[1]+_Point*trailingStop;
         if(position.StopLossPrice>stopLossPrice+pipsValue)
           {
            if(stopLossPrice>ask)
              {
               if(stopLossPrice<ask+_Point*stopLevel)
                  stopLossPrice=ask+_Point*stopLevel;

               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopBarMode",
                                         "StopLoss="+DoubleToString(stopLossPrice,_Digits));

               ModifyPosition(stopLossPrice,position.TakeProfitPrice);

               Print("Trailing Stop (",trailingStop,") moved to: ",
                     DoubleToString(stopLossPrice,_Digits),
                     ", Ask=",DoubleToString(ask,_Digits));
              }
            else
              {
               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopBarMode",
                                         "StopLoss="+DoubleToString(stopLossPrice,_Digits));

               bool orderResponse=CloseCurrentPosition();

               int lastErrorOrdClose=GetLastError();
               lastErrorOrdClose=(lastErrorOrdClose>0) ? lastErrorOrdClose : lastError;
               if(!orderResponse)
                  Print("Error in OrderClose: ",
                        GetErrorDescription(lastErrorOrdClose));
              }
           }
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   void ActionTrade::SetTrailingStopTickMode()
     {
      if(position.PosType==OP_BUY)
        {   // Long position
         double bid=MarketInfo(_Symbol,MODE_BID);
         if(bid>=position.OpenPrice+_Point*trailingStop)
           {
            if(position.StopLossPrice<bid-_Point *(trailingStop+TrailingStopMovingStep))
              {
               double stopLossPrice=bid-_Point*trailingStop;
               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopTickMode",
                                         "StopLoss="+DoubleToString(stopLossPrice,_Digits));

               ModifyPosition(stopLossPrice,position.TakeProfitPrice);

               Print("Trailing Stop (",trailingStop,") moved to: ",
                     DoubleToString(stopLossPrice,_Digits),
                     ", Bid=",DoubleToString(bid,_Digits));
              }
           }
        }
      else if(position.PosType==OP_SELL)
        {   // Short position
         double ask=MarketInfo(_Symbol,MODE_ASK);
         if(position.OpenPrice-ask>=_Point*trailingStop)
           {
            if(position.StopLossPrice>ask+_Point *(trailingStop+TrailingStopMovingStep))
              {
               double stopLossPrice=ask+_Point*trailingStop;
               if(WriteLogFile)
                  logger.WriteLogRequest("SetTrailingStopTickMode",
                                         "StopLoss="+DoubleToString(stopLossPrice,_Digits));

               ModifyPosition(stopLossPrice,position.TakeProfitPrice);

               Print("Trailing Stop (",trailingStop,") moved to: ",
                     DoubleToString(stopLossPrice,_Digits),
                     ", Ask=",DoubleToString(ask,_Digits));
              }
           }
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::DetectPositionClosing()
{
    const double oldStopLoss   = position.StopLossPrice;
    const double oldTakeProfit = position.TakeProfitPrice;
    const double oldProfit     = position.Profit;
    const int    oldType       = position.PosType;
    const double oldLots       = position.Lots;

    SetAggregatePosition(position);

    if (oldType == OP_FLAT || position.PosType != OP_FLAT)
        return;

    const double closePrice     = (oldType == OP_BUY) ? dataMarket.Bid : dataMarket.Ask;
    const string closePriceText = DoubleToString(closePrice, _Digits);

    consecutiveLosses = oldProfit < 0
        ? consecutiveLosses + 1
        : 0;

    string stopMessage = "Position was closed";

    if ( MathAbs(oldStopLoss - closePrice) < 2 * pipsValue )
        stopMessage = "Activated StopLoss=" + closePriceText;
    else if ( MathAbs(oldTakeProfit - closePrice) < 2 * pipsValue )
        stopMessage = "Activated TakeProfit=" + closePriceText;

    string message = stopMessage +
                 ", ClosePrice="        + closePriceText +
                 ", ClosedLots= "       + DoubleToString(oldLots, 2) +
                 ", Profit="            + DoubleToString(oldProfit, 2)+
                 ", ConsecutiveLosses=" + IntegerToString(consecutiveLosses);

    if (WriteLogFile)
        logger.WriteNewLogLine(message);
    Print(message);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ActionTrade::IsTradeContextFree()
{
    if(IsTradeAllowed())
        return (true);

    const uint startWait = GetTickCount();
    Print("Trade context is busy! Waiting...");

    while(true)
    {
        if ( IsStopped() )
            return (false);

        const uint diff = GetTickCount() - startWait;

        if (diff > 30 * 1000)
        {
            Print("The waiting limit exceeded!");
            return (false);
        }

        if ( IsTradeAllowed() )
        {
            RefreshRates();
            return (true);
        }

        Sleep(100);
    }

    return (true);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::ActivateProtectionMinAccount()
{
    CloseCurrentPosition();

    const string account = DoubleToString(AccountEquity(), 2);
    const string message = "\n" +
        "The account equity (" + account +
        ") dropped below the minimum allowed (" +
        IntegerToString(ProtectionMinAccount) + ").";

    Comment(message);
    Print(message);

    if (WriteLogFile)
        logger.WriteLogLine(message);

    Sleep( 20 * 1000 );
    CloseExpert();
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ActionTrade::CloseExpert(void)
{
    ExpertRemove();
    OnDeinit(0);
}
//+------------------------------------------------------------------+


ActionTrade *actionTrade;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   actionTrade=new ActionTrade();

   actionTrade.EntryAmount            = Entry_Amount    > 77700 ? 0.1 : Entry_Amount;
   actionTrade.MaximumAmount          = Maximum_Amount  > 77700 ? 0.1 : Maximum_Amount;
   actionTrade.AddingAmount           = Adding_Amount   > 77700 ? 0.1 : Adding_Amount;
   actionTrade.ReducingAmount         = Reducing_Amount > 77700 ? 0.1 : Reducing_Amount;
   actionTrade.OrderComment           = Order_Comment;
   actionTrade.MinDataBars            = Min_Data_Bars;
   actionTrade.ProtectionMinAccount   = Protection_Min_Account;
   actionTrade.ProtectionMaxStopLoss  = Protection_Max_StopLoss;
   actionTrade.ExpertMagic            = Expert_Magic;
   actionTrade.SeparateSLTP           = Separate_SL_TP;
   actionTrade.WriteLogFile           = Write_Log_File;
   actionTrade.TrailingStopMovingStep = TrailingStop_Moving_Step;
   actionTrade.FIFOorder              = FIFO_order;
   actionTrade.MaxLogLinesInFile      = Max_Log_Lines_in_File;
   actionTrade.BarCloseAdvance        = Bar_Close_Advance;

   int result=actionTrade.OnInit();

   if(result==INIT_SUCCEEDED)
      actionTrade.OnTick();

   return (result);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(__symbol!=_Symbol || __period!=_Period)
     {
      if(__period>0)
        {
         actionTrade.OnDeinit(-1);
         actionTrade.OnInit();
        }
      __symbol = _Symbol;
      __period = _Period;
     }

   actionTrade.OnTick();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   actionTrade.OnDeinit(reason);

   if(CheckPointer(actionTrade)==POINTER_DYNAMIC)
      delete actionTrade;
  }

/*STRATEGY CODE <?xml version=\"1.0\"?><strategy><programName>Forex Strategy Builder Professional</programName><programVersion>v3.8.8</programVersion><strategyName>2 1000 1 0.7% 0.5 500lev st</strategyName><profileName>Default profile</profileName><dataSourceName>Alpari MT4</dataSourceName><instrumentSymbol>GBPCHF</instrumentSymbol><instrumentPeriod>60</instrumentPeriod><sameDirSignalAction>Add</sameDirSignalAction><oppDirSignalAction>Reduce</oppDirSignalAction><maxOpenLots>0.5</maxOpenLots><useAccountPercentEntry>True</useAccountPercentEntry><entryLots>1</entryLots><addingLots>1</addingLots><reducingLots>1</reducingLots><useMartingale>False</useMartingale><martingaleMultiplier>2</martingaleMultiplier><description>Exported on 07/04/2021 from Forex Strategy Builder Professional, v3.8.8</description><recommendedBars>1000</recommendedBars><openFilters>1</openFilters><closeFilters>0</closeFilters><firstBar>198</firstBar><minBarsRequired>199</minBarsRequired><permanentStopLoss usePermanentSL=\"True\" permanentSLType=\"Relative\">875</permanentStopLoss><permanentTakeProfit usePermanentTP=\"True\" permanentTPType=\"Relative\">510</permanentTakeProfit><breakEven useBreakEven=\"False\">1000</breakEven><slot slotNumber=\"0\" slotType=\"Open\"><indicatorName>Day Opening</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>Enter the market at the beginning of the day</value></listParam><listParam paramNumber=\"1\"><caption>Base price</caption><index>0</index><value>Open</value></listParam></slot><slot slotNumber=\"1\" slotType=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>MACD Histogram</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>1</index><value>MACD histogram falls</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>2</index><value>Exponential</value></listParam><listParam paramNumber=\"2\"><caption>Base price</caption><index>3</index><value>Close</value></listParam><listParam paramNumber=\"3\"><caption>Signal line method</caption><index>0</index><value>Simple</value></listParam><numParam paramNumber=\"0\"><caption>Slow MA period</caption><value>195</value></numParam><numParam paramNumber=\"1\"><caption>Fast MA period</caption><value>58</value></numParam><numParam paramNumber=\"2\"><caption>Signal line period</caption><value>183</value></numParam><numParam paramNumber=\"3\"><caption>Level</caption><value>0.0000</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>True</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"2\" slotType=\"Close\"><indicatorName>Trailing Stop</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>Exit at the Trailing Stop level</value></listParam><listParam paramNumber=\"1\"><caption>Trailing mode</caption><index>1</index><value>New tick (trader)</value></listParam><numParam paramNumber=\"0\"><caption>Trailing Stop</caption><value>2172</value></numParam></slot></strategy> */
//+------------------------------------------------------------------+

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