gbpusd M5 571 17.09.20

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
gbpusd M5 571 17.09.20
//+--------------------------------------------------------------------+
//| 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    = 20; // Amount for a new position [%]
static input double Maximum_Amount  = 20; // Maximum position amount [lot]
static input double Adding_Amount   = 5; // Amount to add on addition [%]
static input double Reducing_Amount = 10; // Amount to close on reduction [%]
input int Stop_Loss   = 0; // Stop Loss [point]
input int Take_Profit = 0; // Take Profit [point]
input int Break_Even  = 0; // Break Even [point]
static input double Martingale_Multiplier = 0; // Martingale Multiplier

static input string IndicatorName0 = "Vidya Moving Average"; // ------ Indicator parameters ------
input int Slot0IndParam0 = 21; // Period
input int Slot0IndParam1 = 6; // Smooth
static input string IndicatorName1 = "MA Oscillator"; // ------ Indicator parameters ------
input int Slot1IndParam0 = 13; // Fast MA period
input int Slot1IndParam1 = 19; // Slow MA period
input double Slot1IndParam2 = 0; // Level
static input string IndicatorName2 = "Oscillator of Momentum"; // ------ Indicator parameters ------
input int Slot2IndParam0 = 10; // Momentum1 period
input int Slot2IndParam1 = 14; // Momentum2 period
static input string IndicatorName3 = "Oscillator of ATR"; // ------ Indicator parameters ------
input int Slot3IndParam0 = 10; // First ATR period
input int Slot3IndParam1 = 13; // Second ATR period
static input string IndicatorName4 = "Oscillator of RSI"; // ------ Indicator parameters ------
input int Slot4IndParam0 = 10; // First RSI period
input int Slot4IndParam1 = 14; // Second RSI period
static input string IndicatorName5 = "Oscillator of OBOS"; // ------ Indicator parameters ------
input int Slot5IndParam0 = 8; // First OBOS period
input int Slot5IndParam1 = 15; // Second OBOS period
static input string IndicatorName7 = "Bears Power"; // ------ Indicator parameters ------
input int Slot7IndParam0 = 13; // Smoothing period
input double Slot7IndParam1 = 0; // Level
static input string IndicatorName8 = "Donchian Channel"; // ------ Indicator parameters ------
input int Slot8IndParam0 = 34; // Period
input int Slot8IndParam1 = 0; // Shift
static input string IndicatorName9 = "Donchian Channel"; // ------ Indicator parameters ------
input int Slot9IndParam0 = 10; // Period
input int Slot9IndParam1 = 0; // Shift
static input string IndicatorName10 = "CCI MA Oscillator"; // ------ Indicator parameters ------
input int Slot10IndParam0 = 14; // CCI period
input int Slot10IndParam1 = 13; // Signal line period
static input string IndicatorName11 = "Relative Vigor Index"; // ------ Indicator parameters ------
input int Slot11IndParam0 = 10; // RVI period
static input string IndicatorName12 = "Bears Power"; // ------ Indicator parameters ------
input int Slot12IndParam0 = 1; // Smoothing period
input double Slot12IndParam1 = 0; // Level


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

// A unique number of the expert's orders.
static input int Expert_Magic = 17212441; // 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 CommodityChannelIndex : public Indicator
  {
public:
                     CommodityChannelIndex(SlotTypes slotType);
   virtual void      Calculate(DataSet &dataSet);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CommodityChannelIndex::CommodityChannelIndex(SlotTypes slotType)
  {
   SlotType          = slotType;
   IndicatorName     = "Commodity Channel Index";
   WarningMessage    = "";
   IsAllowLTF        = true;
   ExecTime          = ExecutionTime_DuringTheBar;
   IsSeparateChart   = true;
   IsDiscreteValues  = false;
   IsDefaultGroupAll = false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CommodityChannelIndex::Calculate(DataSet &dataSet)
  {
   Data=GetPointer(dataSet);

   MAMethod  maMethod   = (MAMethod) ListParam[1].Index;
   BasePrice basePrice  = (BasePrice) ListParam[2].Index;
   int       period     = (int) NumParam[0].Value;
   double    level      = NumParam[1].Value;
   double    multiplier = NumParam[2].Value;
   int       previous   = CheckParam[0].Checked ? 1 : 0;

   int firstBar=period+previous+2;
   double price[]; Price(basePrice,price);
   double smaBasePrice[]; MovingAverage(period,0,maMethod,price,smaBasePrice);

   double meanDev[]; ArrayResize(meanDev,Data.Bars); ArrayInitialize(meanDev,0);
   for(int bar=period; bar<Data.Bars; bar++)
     {
      double sum= 0;
      for(int i = 0; i<period; i++)
        {
         sum+=MathAbs(price[bar-i]-smaBasePrice[bar]);
        }
      meanDev[bar]=multiplier*sum/period;
     }

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

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      if(MathAbs(meanDev[bar]-0)>Epsilon())
         cci[bar]=(price[bar]-smaBasePrice[bar])/meanDev[bar];
     }

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,cci,level,-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

   MAMethod maMethod=(MAMethod) ListParam[1].Index;
   int period=(int) NumParam[0].Value;
   double level=Data.Point*NumParam[1].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=period+previous+2;

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

   for(int bar=1; bar<Data.Bars; bar++)
     {
      atr1[bar]=MathMax(Data.High[bar],Data.Close[bar-1])-MathMin(Data.Low[bar],Data.Close[bar-1]);
     }

   double atr[]; MovingAverage(period,0,maMethod,atr1,atr);

   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "Average True Range";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,atr);

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   NoDirectionOscillatorLogic(firstBar,previous,atr,level,Component[1],indLogic);
   ArrayCopy(Component[2].Value,Component[1].Value);
  }
//+------------------------------------------------------------------+

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

   MAMethod maMethod=(MAMethod) ListParam[1].Index;
   BasePrice basePrice=(BasePrice) ListParam[2].Index;
   int period=(int) NumParam[0].Value;
   int smoothing=(int) NumParam[1].Value;
   double level=NumParam[2].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=previous+period+smoothing+2;
   double price[];  Price(basePrice,price);
   double deltaPrice[]; ArrayResize(deltaPrice,Data.Bars); ArrayInitialize(deltaPrice,0);

   for(int bar=period; bar<Data.Bars; bar++)
     {
      deltaPrice[bar]=price[bar]-price[bar-period];
     }

   double momentum[]; MovingAverage(smoothing,0,maMethod,deltaPrice,momentum);

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,momentum,level,-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Overbought Oversold Index";

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

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

// Reading the parameters
   int period=(int) NumParam[0].Value;
   int level =(int) NumParam[1].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

// Calculation
   int firstBar=period + previous + 2;

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

   for(int bar=period; bar<Data.Bars; bar++)
     {
      double min = DBL_MAX;
      double max = DBL_MIN;
      for(int i=0; i<period; i++)
        {
         if(Data.High[bar - i]> max) max = Data.High[bar - i];
         if(Data.Low[bar - i] < min) min = Data.Low[bar - i];
        }
      if (MathAbs(min - max) < 0.00001)
         obos[bar] = 0;
      else
         obos[bar] = 100*(Data.Close[bar] - min)/(max - min);
     }

// Saving the components

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

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

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

// Sets the Component's type
   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

// Calculation of the logic
   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,obos,level,100-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="RSI";

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

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

// Reading the parameters
   MAMethod maMethod=(MAMethod) ListParam[1].Index;
   BasePrice basePrice=(BasePrice) ListParam[2].Index;
   int period=(int) NumParam[0].Value;
   double level = NumParam[1].Value;
   int previous = CheckParam[0].Checked ? 1 : 0;

// Calculation
   int firstBar=period + previous + 2;
   double price[]; Price(basePrice,price);
   double pos[];   ArrayResize(pos,Data.Bars); ArrayInitialize(pos,0);
   double neg[];   ArrayResize(neg,Data.Bars); ArrayInitialize(neg,0);
   double rsi[];   ArrayResize(rsi,Data.Bars); ArrayInitialize(rsi,0);

   for(int bar=1; bar<Data.Bars; bar++)
     {
      if(price[bar]>price[bar-1]+Epsilon())
         pos[bar]=price[bar]-price[bar-1];
      if(price[bar]<price[bar-1]-Epsilon())
         neg[bar]=price[bar-1]-price[bar];
     }

   double posMa[]; MovingAverage(period,0,maMethod,pos,posMa);
   double negMa[]; MovingAverage(period,0,maMethod,neg,negMa);

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      if(MathAbs(negMa[bar])>Epsilon())
         rsi[bar]=100 -(100/(1+posMa[bar]/negMa[bar]));
      else
        {
         if(MathAbs(posMa[bar])>Epsilon())
            rsi[bar]=100;
         else
            rsi[bar]=50;
        }
     }

// Saving the components
   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "RSI";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,rsi);

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

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

// Sets the Component's type
   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

// Calculation of the logic
   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,rsi,level,100-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+


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

   MAMethod maMethod=(MAMethod) ListParam[1].Index;
   int period=(int) NumParam[0].Value;
   double level=NumParam[1].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=period+previous+2;
   double price[]; Price(BasePrice_Close,price);
   double ma[];    MovingAverage(period,0,maMethod,price,ma);
   double bearsPower[]; ArrayResize(bearsPower,Data.Bars); ArrayInitialize(bearsPower,0);

   for(int bar=period; bar<Data.Bars; bar++)
     {
      bearsPower[bar]=Data.Low[bar]-ma[bar];
     }

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,bearsPower,level,-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

   MAMethod maSignalMAMethod=(MAMethod) ListParam[2].Index;
   int period1 = (int) NumParam[0].Value;
   int period2 = (int) NumParam[1].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=MathMax(period1,period2)+previous+2;
   double oscillator[]; ArrayResize(oscillator,Data.Bars); ArrayInitialize(oscillator,0);

// ----------------------------------------------------
   CommodityChannelIndex *cci=new CommodityChannelIndex(SlotType);
   cci.ListParam[1].Index = ListParam[1].Index;
   cci.ListParam[2].Index = ListParam[3].Index;
   cci.NumParam[0].Value=NumParam[0].Value;
   cci.NumParam[1].Value=100;
   cci.NumParam[2].Value=0.015;
   cci.CheckParam[0].Checked=CheckParam[0].Checked;
   cci.Calculate(dataSet);

   double indicator1[];
   ArrayResize(indicator1,Data.Bars);
   ArrayCopy(indicator1,cci.Component[0].Value);
   delete cci;

   double indicator2[];
   MovingAverage(period2,0,maSignalMAMethod,indicator1,indicator2);
// -----------------------------------------------------

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      oscillator[bar]=indicator1[bar]-indicator2[bar];
     }

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,oscillator,0,0,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

   if(m_fridayCloseHour==-1)
      m_fridayCloseHour=GetFridayCloseHour();

   double closePrice[]; ArrayResize(closePrice,Data.Bars); ArrayInitialize(closePrice,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(time1.day!=time0.day)
         closePrice[bar-1]=Data.Close[bar-1];
     }

   datetime time        = Data.Time[Data.Bars-1];
   datetime dayOpenTime = (time/86400)*86400;
   MqlDateTime mqlTime; TimeToStruct(time,mqlTime);
   bool isTimeToClose=false;

   if(mqlTime.day_of_week==5)
     {
      datetime fridayCloseTime=(m_fridayCloseHour==-1)
                               ?(dayOpenTime+86400)
                               :(dayOpenTime+m_fridayCloseHour*3600);
      datetime barCloseTime = time+Data.Period*60;
      datetime closeTime    = fridayCloseTime-60;

      isTimeToClose=barCloseTime==fridayCloseTime && Data.ServerTime>closeTime;
     }
   else
     {
      datetime closeTime=dayOpenTime+23*3600+59*60;
      isTimeToClose=Data.ServerTime>closeTime;
     }

   if(isTimeToClose)
      closePrice[Data.Bars-1]=Data.Close[Data.Bars-1];

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

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

   string logicRule=ListParam[0].Text;

   int period   = (int) NumParam[0].Value;
   int shift    = (int) NumParam[1].Value;
   int previous = CheckParam[0].Checked ? 1 : 0;

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

   int firstBar=period+shift+previous+2;

   for(int bar=period+previous+2; bar<Data.Bars-shift; bar++)
     {
      double max = DBL_MIN;
      double min = DBL_MAX;
      for(int i=0; i<period; i++)
        {
         if(Data.High[bar-i]>max)
            max=Data.High[bar-i];
         if(Data.Low[bar-i]<min)
            min=Data.Low[bar-i];
        }
      upperBand[bar + shift] = max;
      lowerBand[bar + shift] = min;
     }

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

   ArrayResize(Component[1].Value,Data.Bars);
   Component[1].CompName = "Lower Band";
   Component[1].DataType = IndComponentType_IndicatorValue;
   Component[1].FirstBar = firstBar;
   ArrayCopy(Component[1].Value,lowerBand);

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

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

   if(SlotType==SlotTypes_Open)
     {
      Component[2].DataType = IndComponentType_OpenLongPrice;
      Component[2].CompName = "Long position entry price";
      Component[3].DataType = IndComponentType_OpenShortPrice;
      Component[3].CompName = "Short position entry price";
     }
   else if(SlotType==SlotTypes_OpenFilter)
     {
      Component[2].DataType = IndComponentType_AllowOpenLong;
      Component[2].CompName = "Is long entry allowed";
      Component[3].DataType = IndComponentType_AllowOpenShort;
      Component[3].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_Close)
     {
      Component[2].DataType = IndComponentType_CloseLongPrice;
      Component[2].CompName = "Long position closing price";
      Component[3].DataType = IndComponentType_CloseShortPrice;
      Component[3].CompName = "Short position closing price";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[2].DataType = IndComponentType_ForceCloseLong;
      Component[2].CompName = "Close out long position";
      Component[3].DataType = IndComponentType_ForceCloseShort;
      Component[3].CompName = "Close out short position";
     }

   if(SlotType==SlotTypes_Open || SlotType==SlotTypes_Close)
     {
      if(period>1)
        {
         for(int bar=firstBar; bar<Data.Bars; bar++)
           {
            // Covers the cases when the price can pass through the band without a signal.
            double open=Data.Open[bar]; // Current open price

            // Upper band
            double valueUp=upperBand[bar-previous]; // Current value
            double valueUp1=upperBand[bar-previous-1]; // Previous value
            double tempValUp=valueUp;

            if((valueUp1>Data.High[bar-1] && valueUp<open) || // The Data.Open price jumps above the indicator
               (valueUp1 < Data.Low[bar-1]  && valueUp > open) || // The Data.Open price jumps below the indicator
               (Data.Close[bar-1] < valueUp && valueUp < open) || // The Data.Open price is in a positive gap
               (Data.Close[bar-1] > valueUp && valueUp > open))   // The Data.Open price is in a negative gap
               tempValUp=open; // The entry/exit level is moved to Data.Open price

            // Lower band
            double valueDown=lowerBand[bar-previous]; // Current value
            double valueDown1=lowerBand[bar-previous-1]; // Previous value
            double tempValDown=valueDown;

            if((valueDown1>Data.High[bar-1] && valueDown<open) || // The Data.Open price jumps above the indicator
               (valueDown1 < Data.Low[bar-1] && valueDown > open)  || // The Data.Open price jumps below the indicator
               (Data.Close[bar-1] < valueDown && valueDown < open) || // The Data.Open price is in a positive gap
               (Data.Close[bar-1]>valueDown && valueDown>open)) // The Data.Open price is in a negative gap
               tempValDown=open; // The entry/exit level is moved to Data.Open price

            if(logicRule=="Enter long at Upper Band" ||
               logicRule=="Exit long at Upper Band")
              {
               Component[2].Value[bar] = tempValUp;
               Component[3].Value[bar] = tempValDown;
              }
            else
              {
               Component[2].Value[bar] = tempValDown;
               Component[3].Value[bar] = tempValUp;
              }
           }
        }
      else
        {
         for(int bar=2; bar<Data.Bars; bar++)
           {
            if(logicRule=="Enter long at Upper Band" || logicRule=="Exit long at Upper Band")
              {
               Component[2].Value[bar] = upperBand[bar - previous];
               Component[3].Value[bar] = lowerBand[bar - previous];
              }
            else
              {
               Component[2].Value[bar] = lowerBand[bar - previous];
               Component[3].Value[bar] = upperBand[bar - previous];
              }
           }
        }
     }
   else
     {
      if(logicRule=="The bar opens below Upper Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_below_the_Upper_Band);
      else if(logicRule=="The bar opens above Upper Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_above_the_Upper_Band);
      else if(logicRule=="The bar opens below Lower Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_below_the_Lower_Band);
      else if(logicRule=="The bar opens above Lower Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_above_the_Lower_Band);
      else if(logicRule=="The bar opens below Upper Band after opening above it")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_below_Upper_Band_after_above);
      else if(logicRule=="The bar opens above Upper Band after opening below it")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_above_Upper_Band_after_below);
      else if(logicRule=="The bar opens below Lower Band after opening above it")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_below_Lower_Band_after_above);
      else if(logicRule=="The bar opens above Lower Band after opening below it")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_opens_above_Lower_Band_after_below);
      else if(logicRule=="The position opens above Upper Band")
        {
         Component[0].PosPriceDependence = PositionPriceDependence_PriceBuyHigher;
         Component[1].PosPriceDependence = PositionPriceDependence_PriceSellLower;
         Component[2].DataType = IndComponentType_Other;
         Component[3].DataType = IndComponentType_Other;
         Component[2].ShowInDynInfo = false;
         Component[3].ShowInDynInfo = false;
        }
      else if(logicRule=="The position opens below Upper Band")
        {
         Component[0].PosPriceDependence = PositionPriceDependence_PriceBuyLower;
         Component[1].PosPriceDependence = PositionPriceDependence_PriceSellHigher;
         Component[2].DataType = IndComponentType_Other;
         Component[3].DataType = IndComponentType_Other;
         Component[2].ShowInDynInfo = false;
         Component[3].ShowInDynInfo = false;
        }
      else if(logicRule=="The position opens above Lower Band")
        {
         Component[0].PosPriceDependence = PositionPriceDependence_PriceSellLower;
         Component[1].PosPriceDependence = PositionPriceDependence_PriceBuyHigher;
         Component[2].DataType = IndComponentType_Other;
         Component[3].DataType = IndComponentType_Other;
         Component[2].ShowInDynInfo = false;
         Component[3].ShowInDynInfo = false;
        }
      else if(logicRule=="The position opens below Lower Band")
        {
         Component[0].PosPriceDependence = PositionPriceDependence_PriceSellHigher;
         Component[1].PosPriceDependence = PositionPriceDependence_PriceBuyLower;
         Component[2].DataType = IndComponentType_Other;
         Component[3].DataType = IndComponentType_Other;
         Component[2].ShowInDynInfo = false;
         Component[3].ShowInDynInfo = false;
        }
      else if(logicRule=="The bar closes below Upper Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_closes_below_the_Upper_Band);
      else if(logicRule=="The bar closes above Upper Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_closes_above_the_Upper_Band);
      else if(logicRule=="The bar closes below Lower Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_closes_below_the_Lower_Band);
      else if(logicRule=="The bar closes above Lower Band")
         BandIndicatorLogic(firstBar,previous,upperBand,lowerBand,Component[2],Component[3],BandIndLogic_The_bar_closes_above_the_Lower_Band);
     }
  }
//+------------------------------------------------------------------+

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

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

   int firstBar=MathMax(fastPeriod,slowPeriod)+previous+2;
   double price[];  Price(basePrice,price);
   double maFast[]; MovingAverage(fastPeriod,0,maMethod,price,maFast);
   double maSlow[]; MovingAverage(slowPeriod,0,maMethod,price,maSlow);
   double oscillator[]; ArrayResize(oscillator,Data.Bars); ArrayInitialize(oscillator,0);

   for(int bar=firstBar; bar<Data.Bars; bar++)
     {
      oscillator[bar]=maFast[bar]-maSlow[bar];
     }

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,oscillator,level,-level,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Oscillator of ATR";

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

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

   int previous=CheckParam[0].Checked ? 1 : 0;

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

// ----------------------------------------------------
   AverageTrueRange *atr1=new AverageTrueRange(SlotType);
   atr1.ListParam[1].Index= ListParam[1].Index;
   atr1.NumParam[0].Value = NumParam[0].Value;
   atr1.CheckParam[0].Checked=CheckParam[0].Checked;
   atr1.Calculate(dataSet);

   AverageTrueRange *atr2=new AverageTrueRange(SlotType);
   atr2.ListParam[1].Index= ListParam[1].Index;
   atr2.NumParam[0].Value = NumParam[1].Value;
   atr2.CheckParam[0].Checked=CheckParam[0].Checked;
   atr2.Calculate(dataSet);

   double indicator1[]; 
   ArrayResize(indicator1,Data.Bars);
   ArrayCopy(indicator1,atr1.Component[0].Value);
   double indicator2[];
   ArrayResize(indicator2,Data.Bars);
   ArrayCopy(indicator2,atr2.Component[0].Value);
// -----------------------------------------------------

   int firstBar=0;
   for(int c=0; c<atr1.Components(); c++)
   {
       if (firstBar<atr1.Component[c].FirstBar)
           firstBar=atr1.Component[c].FirstBar;
       if (firstBar<atr2.Component[c].FirstBar)
           firstBar=atr2.Component[c].FirstBar;
   }
   firstBar+=3;

   for(int bar=firstBar; bar<Data.Bars; bar++)
   {
      oscillator[bar]=indicator1[bar]-indicator2[bar];
   }

   delete atr1;
   delete atr2;

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

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

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

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

   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   NoDirectionOscillatorLogic(firstBar,previous,oscillator,0,Component[1],indLogic);
   ArrayCopy(Component[2].Value,Component[1].Value);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Oscillator of Momentum";

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

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

// Reading the parameters
   int previous=CheckParam[0].Checked ? 1 : 0;

// Calculation
   double oscillator[];
   ArrayResize(oscillator,Data.Bars);
   ArrayInitialize(oscillator,0);

// ----------------------------------------------------
   Momentum *momentum1=new Momentum(SlotType);
   momentum1.ListParam[1].Index = ListParam[1].Index;
   momentum1.ListParam[2].Index = ListParam[2].Index;
   momentum1.NumParam[0].Value=NumParam[0].Value;
   momentum1.CheckParam[0].Checked=CheckParam[0].Checked;
   momentum1.Calculate(dataSet);

   Momentum *momentum2=new Momentum(SlotType);
   momentum2.ListParam[1].Index = ListParam[1].Index;
   momentum2.ListParam[2].Index = ListParam[2].Index;
   momentum2.NumParam[0].Value=NumParam[1].Value;
   momentum2.CheckParam[0].Checked=CheckParam[0].Checked;
   momentum2.Calculate(dataSet);

   double indicator1[];
   ArrayResize(indicator1,Data.Bars);
   ArrayCopy(indicator1,momentum1.Component[0].Value);
   double indicator2[];
   ArrayResize(indicator2,Data.Bars);
   ArrayCopy(indicator2,momentum2.Component[0].Value);
// -----------------------------------------------------

   int firstBar=0;
   for(int c=0; c<momentum1.Components(); c++)
   {
       if (firstBar<momentum1.Component[c].FirstBar)
           firstBar=momentum1.Component[c].FirstBar;
       if (firstBar<momentum2.Component[c].FirstBar)
           firstBar=momentum2.Component[c].FirstBar;
   }
   firstBar+=3;

   for(int bar=firstBar; bar<Data.Bars; bar++)
   {
	  oscillator[bar]=indicator1[bar]-indicator2[bar];
   }

   delete momentum1;
   delete momentum2;

// Saving the components
   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "Histogram";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,oscillator);

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

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

// Sets the Component's type
   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

// Calculation of the logic
   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,oscillator,0,0,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Oscillator of OBOS";

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

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

// Reading the parameters
   int previous=CheckParam[0].Checked ? 1 : 0;

// Calculation
   double oscillator[];
   ArrayResize(oscillator,Data.Bars);
   ArrayInitialize(oscillator,0);

// ----------------------------------------------------
   OverboughtOversoldIndex *obos1=new OverboughtOversoldIndex(SlotType);
   obos1.NumParam[0].Value=NumParam[0].Value;
   obos1.CheckParam[0].Checked=CheckParam[0].Checked;
   obos1.Calculate(dataSet);

   OverboughtOversoldIndex *obos2=new OverboughtOversoldIndex(SlotType);
   obos2.NumParam[0].Value=NumParam[1].Value;
   obos2.CheckParam[0].Checked=CheckParam[0].Checked;
   obos2.Calculate(dataSet);

   double indicator1[];
   ArrayResize(indicator1,Data.Bars);
   ArrayCopy(indicator1, obos1.Component[0].Value);
   double indicator2[];
   ArrayResize(indicator2,Data.Bars);
   ArrayCopy(indicator2, obos2.Component[0].Value);
// -----------------------------------------------------

   int firstBar=0;
   for(int c=0; c<obos1.Components(); c++)
   {
       if (firstBar<obos1.Component[c].FirstBar)
           firstBar=obos1.Component[c].FirstBar;
       if (firstBar<obos2.Component[c].FirstBar)
           firstBar=obos2.Component[c].FirstBar;
   }
   firstBar+=3;

   for(int bar=firstBar; bar<Data.Bars; bar++)
   {
      oscillator[bar]=indicator1[bar]-indicator2[bar];
   }

   delete obos1;
   delete obos2;

// Saving the components
   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "Histogram";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,oscillator);

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

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

// Sets the Component's type
   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

// Calculation of the logic
   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,oscillator,0,0,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Oscillator of RSI";

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

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

// Reading the parameters
   int previous=CheckParam[0].Checked ? 1 : 0;

// Calculation
   double oscillator[];
   ArrayResize(oscillator,Data.Bars);
   ArrayInitialize(oscillator,0);

// ----------------------------------------------------
   RSI *rsi1=new RSI(SlotType);
   rsi1.ListParam[1].Index = ListParam[1].Index;
   rsi1.ListParam[2].Index = ListParam[2].Index;
   rsi1.NumParam[0].Value=NumParam[0].Value;
   rsi1.CheckParam[0].Checked=CheckParam[0].Checked;
   rsi1.Calculate(dataSet);

   RSI *rsi2=new RSI(SlotType);
   rsi2.ListParam[1].Index = ListParam[1].Index;
   rsi2.ListParam[2].Index = ListParam[2].Index;
   rsi2.NumParam[0].Value=NumParam[1].Value;
   rsi2.CheckParam[0].Checked=CheckParam[0].Checked;
   rsi2.Calculate(dataSet);

   double indicator1[];
   ArrayResize(indicator1,Data.Bars);
   ArrayCopy(indicator1,rsi1.Component[0].Value);
   double indicator2[];
   ArrayResize(indicator2,Data.Bars);
   ArrayCopy(indicator2,rsi2.Component[0].Value);
// -----------------------------------------------------

   int firstBar=0;
   for(int c=0; c<rsi1.Components(); c++)
   {
       if (firstBar<rsi1.Component[c].FirstBar)
           firstBar=rsi1.Component[c].FirstBar;
       if (firstBar<rsi2.Component[c].FirstBar)
           firstBar=rsi2.Component[c].FirstBar;
   }
   firstBar+=3;

   for(int bar=firstBar; bar<Data.Bars; bar++)
      oscillator[bar]=indicator1[bar]-indicator2[bar];

   delete rsi1;
   delete rsi2;

// Saving the components
   ArrayResize(Component[0].Value,Data.Bars);
   Component[0].CompName = "Oscillator";
   Component[0].DataType = IndComponentType_IndicatorValue;
   Component[0].FirstBar = firstBar;
   ArrayCopy(Component[0].Value,oscillator);

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

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

// Sets the Component's type
   if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

// Calculation of the logic
   IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter;

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

   OscillatorLogic(firstBar,previous,oscillator,0,0,Component[1],Component[2],indLogic);
  }
//+------------------------------------------------------------------+

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

      IndicatorName="Relative Vigor Index";

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

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

   int period=(int) NumParam[0].Value;
   int previous=CheckParam[0].Checked ? 1 : 0;

   int firstBar=period+4;

   double adRvi[]; ArrayResize(adRvi,Data.Bars); ArrayInitialize(adRvi,0);
   for(int bar=period+3; bar<Data.Bars; bar++)
     {
      double dNum=0;
      double dDeNum=0;
      for(int j=bar; j>bar-period; j--)
        {
         double dValueUp=((Data.Close[j]-Data.Open[j])+2*(Data.Close[j-1]-Data.Open[j-1])+
                          2*(Data.Close[j-2]-Data.Open[j-2])+(Data.Close[j-3]-Data.Open[j-3]))/6;
         double dValueDown=((Data.High[j]-Data.Low[j])+2*(Data.High[j-1]-Data.Low[j-1])+
                            2*(Data.High[j-2]-Data.Low[j-2])+(Data.High[j-3]-Data.Low[j-3]))/6;
         dNum+=dValueUp;
         dDeNum+=dValueDown;
        }
      if(MathAbs(dDeNum-0)>Epsilon())
         adRvi[bar]=dNum/dDeNum;
      else
         adRvi[bar]=dNum;
     }

   double adMASignal[];ArrayResize(adMASignal,Data.Bars); ArrayInitialize(adMASignal,0);
   for(int bar=4; bar<Data.Bars; bar++)
      adMASignal[bar]=(adRvi[bar]+2*adRvi[bar-1]+2*adRvi[bar-2]+adRvi[bar-3])/6;

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

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

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

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

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

   if(ListParam[0].Text=="RVI line rises") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_rises);
   else if(ListParam[0].Text=="RVI line falls") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_falls);
   else if(ListParam[0].Text=="RVI line is higher than zero") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_is_higher_than_the_level_line);
   else if(ListParam[0].Text=="RVI line is lower than zero") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_is_lower_than_the_level_line);
   else if(ListParam[0].Text=="RVI line crosses the zero line upward") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_crosses_the_level_line_upward);
   else if(ListParam[0].Text=="RVI line crosses the zero line downward") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_crosses_the_level_line_downward);
   else if(ListParam[0].Text=="RVI line changes its direction upward") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_changes_its_direction_upward);
   else if(ListParam[0].Text=="RVI line changes its direction downward") 
      OscillatorLogic(firstBar,previous,adRvi,0,0,Component[2],Component[3], IndicatorLogic_The_indicator_changes_its_direction_downward);
   else if(ListParam[0].Text=="RVI line crosses the Signal line upward") 
      IndicatorCrossesAnotherIndicatorUpwardLogic(firstBar,previous,adRvi,adMASignal,Component[2], Component[3]);
   else if(ListParam[0].Text=="RVI line crosses the Signal line downward") 
      IndicatorCrossesAnotherIndicatorDownwardLogic(firstBar,previous,adRvi,adMASignal,Component[2], Component[3]);
   else if(ListParam[0].Text=="RVI line is higher than the Signal line") 
      IndicatorIsHigherThanAnotherIndicatorLogic(firstBar,previous,adRvi,adMASignal,Component[2], Component[3]);
   else if(ListParam[0].Text=="RVI line is lower than the Signal line") 
      IndicatorIsLowerThanAnotherIndicatorLogic(firstBar,previous,adRvi,adMASignal,Component[2], Component[3]);
  }
//+------------------------------------------------------------------+


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

   BasePrice basePrice=(BasePrice)ListParam[2].Index;
   int period    = (int)NumParam[0].Value;
   int smoothing = (int)NumParam[1].Value;
   int previous  = CheckParam[0].Checked ? 1 : 0;

   int firstBar=period+smoothing+previous+2;

   double adBasePrice[];
   Price(basePrice,adBasePrice);

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

   for(int bar=1; bar<Data.Bars; bar++)
     {
      adCMO1[bar] = 0;
      adCMO1[bar] = 0;
      if(adBasePrice[bar]>adBasePrice[bar-1])
         adCMO1[bar]=adBasePrice[bar]-adBasePrice[bar-1];
      if(adBasePrice[bar]<adBasePrice[bar-1])
         adCMO2[bar]=adBasePrice[bar-1]-adBasePrice[bar];
     }

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

   for(int bar=0; bar<period; bar++)
     {
      adCMO1Sum[period - 1] += adCMO1[bar];
      adCMO2Sum[period - 1] += adCMO2[bar];
     }

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

   for(int bar=period; bar<Data.Bars; bar++)
     {
      adCMO1Sum[bar] = adCMO1Sum[bar - 1] + adCMO1[bar] - adCMO1[bar - period];
      adCMO2Sum[bar] = adCMO2Sum[bar - 1] + adCMO2[bar] - adCMO2[bar - period];

      if(adCMO1Sum[bar]+adCMO2Sum[bar]==0)
         adCMO[bar]=100;
      else
         adCMO[bar]=100 *(adCMO1Sum[bar]-adCMO2Sum[bar])/(adCMO1Sum[bar]+adCMO2Sum[bar]);
     }

   double adMA[]; ArrayResize(adMA,Data.Bars); ArrayInitialize(adMA,0);
   double SC=2.0/(smoothing+1);

   for(int bar=0; bar<period; bar++)
      adMA[bar]=adBasePrice[bar];

   for(int bar=period; bar<Data.Bars; bar++)
     {
      double dAbsCMO=MathAbs(adCMO[bar])/100;
      adMA[bar]=SC*dAbsCMO*adBasePrice[bar]+(1-SC*dAbsCMO)*adMA[bar-1];
     }

   if(SlotType==SlotTypes_Open || SlotType==SlotTypes_Close)
     {
      ArrayResize(Component[1].Value,Data.Bars);

      for(int bar=2; bar<Data.Bars; bar++)
        {   // Covers the cases when the price can pass through the MA without a signal
         double dValue   = adMA[bar - previous];     // Current value
         double dValue1  = adMA[bar - previous - 1]; // Previous value
         double dTempVal = dValue;
         if((dValue1>Data.High[bar-1] && dValue<Data.Open[bar]) || // It jumps below the current bar
            (dValue1<Data.Low[bar-1] && dValue>Data.Open[bar]) || // It jumps above the current bar
            (Data.Close[bar - 1] < dValue && dValue < Data.Open[bar]) || // Positive gap
            (Data.Close[bar - 1] > dValue && dValue > Data.Open[bar]))   // Negative gap
            dTempVal=Data.Open[bar];
         Component[1].Value[bar]=dTempVal;
        }
     }
   else
     {
      ArrayResize(Component[1].Value,Data.Bars);
      Component[1].FirstBar=firstBar;

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

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

   if(SlotType==SlotTypes_Open)
     {
      Component[1].CompName = "Position opening price";
      Component[1].DataType = IndComponentType_OpenPrice;
     }
   else if(SlotType==SlotTypes_OpenFilter)
     {
      Component[1].DataType = IndComponentType_AllowOpenLong;
      Component[1].CompName = "Is long entry allowed";
      Component[2].DataType = IndComponentType_AllowOpenShort;
      Component[2].CompName = "Is short entry allowed";
     }
   else if(SlotType==SlotTypes_Close)
     {
      Component[1].CompName = "Position closing price";
      Component[1].DataType = IndComponentType_ClosePrice;
     }
   else if(SlotType==SlotTypes_CloseFilter)
     {
      Component[1].DataType = IndComponentType_ForceCloseLong;
      Component[1].CompName = "Close out long position";
      Component[2].DataType = IndComponentType_ForceCloseShort;
      Component[2].CompName = "Close out short position";
     }

   if(SlotType==SlotTypes_OpenFilter || SlotType==SlotTypes_CloseFilter)
     {
      if(ListParam[0].Text=="The Vidya Moving Average rises")
         IndicatorRisesLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The Vidya Moving Average falls")
         IndicatorFallsLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The bar opens above the Vidya Moving Average")
         BarOpensAboveIndicatorLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The bar opens below the Vidya Moving Average")
         BarOpensBelowIndicatorLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The bar opens above the Vidya Moving Average after opening below it")
         BarOpensAboveIndicatorAfterOpeningBelowLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The bar opens below the Vidya Moving Average after opening above it")
         BarOpensBelowIndicatorAfterOpeningAboveLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The position opens above the Vidya Moving Average")
        {
         Component[0].PosPriceDependence=PositionPriceDependence_BuyHigherSellLower;
         Component[0].UsePreviousBar=previous;
         Component[1].DataType=IndComponentType_Other;
         Component[1].ShowInDynInfo=false;
         Component[2].DataType=IndComponentType_Other;
         Component[2].ShowInDynInfo=false;
        }
      else if(ListParam[0].Text=="The position opens below the Vidya Moving Average")
        {
         Component[0].PosPriceDependence=PositionPriceDependence_BuyLowerSelHigher;
         Component[0].UsePreviousBar=previous;
         Component[1].DataType=IndComponentType_Other;
         Component[1].ShowInDynInfo=false;
         Component[2].DataType=IndComponentType_Other;
         Component[2].ShowInDynInfo=false;
        }
      else if(ListParam[0].Text=="The bar closes below the Vidya Moving Average")
         BarClosesBelowIndicatorLogic(firstBar,previous,adMA,Component[1],Component[2]);
      else if(ListParam[0].Text=="The bar closes above the Vidya Moving Average")
         BarClosesAboveIndicatorLogic(firstBar,previous,adMA,Component[1],Component[2]);
     }
  }
//+------------------------------------------------------------------+


class IndicatorManager
  {
public:
   Indicator        *CreateIndicator(string indicatorName,SlotTypes slotType);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Indicator *IndicatorManager::CreateIndicator(string indicatorName,SlotTypes slotType)
  {
   if(indicatorName == "Bears Power")               return new BearsPower(slotType);
   if(indicatorName == "CCI MA Oscillator")         return new CCIMAOscillator(slotType);
   if(indicatorName == "Day Closing")               return new DayClosing(slotType);
   if(indicatorName == "Donchian Channel")          return new DonchianChannel(slotType);
   if(indicatorName == "MA Oscillator")             return new MAOscillator(slotType);
   if(indicatorName == "Oscillator of ATR")         return new OscillatorofATR(slotType);
   if(indicatorName == "Oscillator of Momentum")    return new OscillatorofMomentum(slotType);
   if(indicatorName == "Oscillator of OBOS")        return new OscillatorofOBOS(slotType);
   if(indicatorName == "Oscillator of RSI")         return new OscillatorofRSI(slotType);
   if(indicatorName == "Relative Vigor Index")      return new RelativeVigorIndex(slotType);
   if (indicatorName == "Vidya Moving Average") return new VidyaMovingAverage(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(5, 6);

   strategy.StrategyName           = "gbpusd M5  571 17.09.20";
   strategy.SameSignalAction       = SameDirSignalAction_Add;
   strategy.OppSignalAction        = OppositeDirSignalAction_Reverse;
   strategy.MaxOpenLots            = 20;
   strategy.UseAccountPercentEntry = true;
   strategy.EntryLots              = 20;
   strategy.AddingLots             = 5;
   strategy.ReducingLots           = 10;
   strategy.MartingaleMultiplier   = Martingale_Multiplier;
   strategy.UseMartingale          = Martingale_Multiplier > 0;
   strategy.Description            = "Exported on 17.09.2020 from Forex Strategy Builder Professional, v3.8.8";
   strategy.RecommendedBars        = 1000;
   strategy.FirstBar               = 36;
   strategy.MinBarsRequired        = 37;
   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    = "Vidya Moving Average";
   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("Vidya Moving Average", 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 Vidya Moving Average";
   strategy.Slot[0].IndicatorPointer.ListParam[2].Enabled = true;
   strategy.Slot[0].IndicatorPointer.ListParam[2].Caption = "Base price";
   strategy.Slot[0].IndicatorPointer.ListParam[2].Index   = 3;
   strategy.Slot[0].IndicatorPointer.ListParam[2].Text    = "Close";

   strategy.Slot[0].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[0].IndicatorPointer.NumParam[0].Caption = "Period";
   strategy.Slot[0].IndicatorPointer.NumParam[0].Value   = Slot0IndParam0;
   strategy.Slot[0].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[0].IndicatorPointer.NumParam[1].Caption = "Smooth";
   strategy.Slot[0].IndicatorPointer.NumParam[1].Value   = Slot0IndParam1;

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

   strategy.Slot[1].IndicatorName    = "MA Oscillator";
   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("MA Oscillator", 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   = 0;
   strategy.Slot[1].IndicatorPointer.ListParam[0].Text    = "MA Oscillator rises";
   strategy.Slot[1].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[1].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[1].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[1].IndicatorPointer.ListParam[1].Text    = "Simple";
   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.NumParam[0].Enabled = true;
   strategy.Slot[1].IndicatorPointer.NumParam[0].Caption = "Fast 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 = "Slow 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 = "Level";
   strategy.Slot[1].IndicatorPointer.NumParam[2].Value   = Slot1IndParam2;

   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    = "Oscillator of Momentum";
   strategy.Slot[2].SlotType         = SlotTypes_OpenFilter;
   strategy.Slot[2].SignalShift      = 0;
   strategy.Slot[2].SignalRepeat     = 0;
   strategy.Slot[2].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[2].IndicatorSymbol  = "";
   strategy.Slot[2].LogicalGroup     = "A";
   strategy.Slot[2].IndicatorPointer = indicatorManager.CreateIndicator("Oscillator of Momentum", SlotTypes_OpenFilter);

   strategy.Slot[2].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[2].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[2].IndicatorPointer.ListParam[0].Index   = 1;
   strategy.Slot[2].IndicatorPointer.ListParam[0].Text    = "Oscillator falls";
   strategy.Slot[2].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[2].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[2].IndicatorPointer.ListParam[1].Index   = 2;
   strategy.Slot[2].IndicatorPointer.ListParam[1].Text    = "Exponential";
   strategy.Slot[2].IndicatorPointer.ListParam[2].Enabled = true;
   strategy.Slot[2].IndicatorPointer.ListParam[2].Caption = "Base price";
   strategy.Slot[2].IndicatorPointer.ListParam[2].Index   = 4;
   strategy.Slot[2].IndicatorPointer.ListParam[2].Text    = "Median";

   strategy.Slot[2].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[2].IndicatorPointer.NumParam[0].Caption = "Momentum1 period";
   strategy.Slot[2].IndicatorPointer.NumParam[0].Value   = Slot2IndParam0;
   strategy.Slot[2].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[2].IndicatorPointer.NumParam[1].Caption = "Momentum2 period";
   strategy.Slot[2].IndicatorPointer.NumParam[1].Value   = Slot2IndParam1;

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

   strategy.Slot[3].IndicatorName    = "Oscillator of ATR";
   strategy.Slot[3].SlotType         = SlotTypes_OpenFilter;
   strategy.Slot[3].SignalShift      = 0;
   strategy.Slot[3].SignalRepeat     = 0;
   strategy.Slot[3].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[3].IndicatorSymbol  = "";
   strategy.Slot[3].LogicalGroup     = "A";
   strategy.Slot[3].IndicatorPointer = indicatorManager.CreateIndicator("Oscillator of ATR", SlotTypes_OpenFilter);

   strategy.Slot[3].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[3].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[3].IndicatorPointer.ListParam[0].Index   = 3;
   strategy.Slot[3].IndicatorPointer.ListParam[0].Text    = "Oscillator is lower than the zero line";
   strategy.Slot[3].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[3].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[3].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[3].IndicatorPointer.ListParam[1].Text    = "Simple";

   strategy.Slot[3].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[3].IndicatorPointer.NumParam[0].Caption = "First ATR period";
   strategy.Slot[3].IndicatorPointer.NumParam[0].Value   = Slot3IndParam0;
   strategy.Slot[3].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[3].IndicatorPointer.NumParam[1].Caption = "Second ATR period";
   strategy.Slot[3].IndicatorPointer.NumParam[1].Value   = Slot3IndParam1;

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

   strategy.Slot[4].IndicatorName    = "Oscillator of RSI";
   strategy.Slot[4].SlotType         = SlotTypes_OpenFilter;
   strategy.Slot[4].SignalShift      = 0;
   strategy.Slot[4].SignalRepeat     = 0;
   strategy.Slot[4].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[4].IndicatorSymbol  = "";
   strategy.Slot[4].LogicalGroup     = "A";
   strategy.Slot[4].IndicatorPointer = indicatorManager.CreateIndicator("Oscillator of RSI", SlotTypes_OpenFilter);

   strategy.Slot[4].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[4].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[4].IndicatorPointer.ListParam[0].Index   = 0;
   strategy.Slot[4].IndicatorPointer.ListParam[0].Text    = "Oscillator rises";
   strategy.Slot[4].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[4].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[4].IndicatorPointer.ListParam[1].Index   = 1;
   strategy.Slot[4].IndicatorPointer.ListParam[1].Text    = "Weighted";
   strategy.Slot[4].IndicatorPointer.ListParam[2].Enabled = true;
   strategy.Slot[4].IndicatorPointer.ListParam[2].Caption = "Base price";
   strategy.Slot[4].IndicatorPointer.ListParam[2].Index   = 0;
   strategy.Slot[4].IndicatorPointer.ListParam[2].Text    = "Open";

   strategy.Slot[4].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[4].IndicatorPointer.NumParam[0].Caption = "First RSI period";
   strategy.Slot[4].IndicatorPointer.NumParam[0].Value   = Slot4IndParam0;
   strategy.Slot[4].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[4].IndicatorPointer.NumParam[1].Caption = "Second RSI period";
   strategy.Slot[4].IndicatorPointer.NumParam[1].Value   = Slot4IndParam1;

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

   strategy.Slot[5].IndicatorName    = "Oscillator of OBOS";
   strategy.Slot[5].SlotType         = SlotTypes_OpenFilter;
   strategy.Slot[5].SignalShift      = 0;
   strategy.Slot[5].SignalRepeat     = 0;
   strategy.Slot[5].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[5].IndicatorSymbol  = "";
   strategy.Slot[5].LogicalGroup     = "A";
   strategy.Slot[5].IndicatorPointer = indicatorManager.CreateIndicator("Oscillator of OBOS", SlotTypes_OpenFilter);

   strategy.Slot[5].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[5].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[5].IndicatorPointer.ListParam[0].Index   = 3;
   strategy.Slot[5].IndicatorPointer.ListParam[0].Text    = "Oscillator is lower than the zero line";

   strategy.Slot[5].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[5].IndicatorPointer.NumParam[0].Caption = "First OBOS period";
   strategy.Slot[5].IndicatorPointer.NumParam[0].Value   = Slot5IndParam0;
   strategy.Slot[5].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[5].IndicatorPointer.NumParam[1].Caption = "Second OBOS period";
   strategy.Slot[5].IndicatorPointer.NumParam[1].Value   = Slot5IndParam1;

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

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

   strategy.Slot[6].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[6].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[6].IndicatorPointer.ListParam[0].Index   = 0;
   strategy.Slot[6].IndicatorPointer.ListParam[0].Text    = "Exit the market at the end of the day";
   strategy.Slot[6].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[6].IndicatorPointer.ListParam[1].Caption = "Base price";
   strategy.Slot[6].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[6].IndicatorPointer.ListParam[1].Text    = "Close";

   strategy.Slot[7].IndicatorName    = "Bears Power";
   strategy.Slot[7].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[7].SignalShift      = 0;
   strategy.Slot[7].SignalRepeat     = 0;
   strategy.Slot[7].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[7].IndicatorSymbol  = "";
   strategy.Slot[7].LogicalGroup     = "a";
   strategy.Slot[7].IndicatorPointer = indicatorManager.CreateIndicator("Bears Power", SlotTypes_CloseFilter);

   strategy.Slot[7].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[7].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[7].IndicatorPointer.ListParam[0].Index   = 5;
   strategy.Slot[7].IndicatorPointer.ListParam[0].Text    = "Bears Power crosses the Level line downward";
   strategy.Slot[7].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[7].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[7].IndicatorPointer.ListParam[1].Index   = 2;
   strategy.Slot[7].IndicatorPointer.ListParam[1].Text    = "Exponential";

   strategy.Slot[7].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[7].IndicatorPointer.NumParam[0].Caption = "Smoothing period";
   strategy.Slot[7].IndicatorPointer.NumParam[0].Value   = Slot7IndParam0;
   strategy.Slot[7].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[7].IndicatorPointer.NumParam[1].Caption = "Level";
   strategy.Slot[7].IndicatorPointer.NumParam[1].Value   = Slot7IndParam1;

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

   strategy.Slot[8].IndicatorName    = "Donchian Channel";
   strategy.Slot[8].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[8].SignalShift      = 0;
   strategy.Slot[8].SignalRepeat     = 0;
   strategy.Slot[8].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[8].IndicatorSymbol  = "";
   strategy.Slot[8].LogicalGroup     = "b";
   strategy.Slot[8].IndicatorPointer = indicatorManager.CreateIndicator("Donchian Channel", SlotTypes_CloseFilter);

   strategy.Slot[8].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[8].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[8].IndicatorPointer.ListParam[0].Index   = 3;
   strategy.Slot[8].IndicatorPointer.ListParam[0].Text    = "The bar closes above Lower Band";
   strategy.Slot[8].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[8].IndicatorPointer.ListParam[1].Caption = "Base price";
   strategy.Slot[8].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[8].IndicatorPointer.ListParam[1].Text    = "High & Low";

   strategy.Slot[8].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[8].IndicatorPointer.NumParam[0].Caption = "Period";
   strategy.Slot[8].IndicatorPointer.NumParam[0].Value   = Slot8IndParam0;
   strategy.Slot[8].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[8].IndicatorPointer.NumParam[1].Caption = "Shift";
   strategy.Slot[8].IndicatorPointer.NumParam[1].Value   = Slot8IndParam1;

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

   strategy.Slot[9].IndicatorName    = "Donchian Channel";
   strategy.Slot[9].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[9].SignalShift      = 0;
   strategy.Slot[9].SignalRepeat     = 0;
   strategy.Slot[9].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[9].IndicatorSymbol  = "";
   strategy.Slot[9].LogicalGroup     = "c";
   strategy.Slot[9].IndicatorPointer = indicatorManager.CreateIndicator("Donchian Channel", SlotTypes_CloseFilter);

   strategy.Slot[9].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[9].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[9].IndicatorPointer.ListParam[0].Index   = 1;
   strategy.Slot[9].IndicatorPointer.ListParam[0].Text    = "The bar closes above Upper Band";
   strategy.Slot[9].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[9].IndicatorPointer.ListParam[1].Caption = "Base price";
   strategy.Slot[9].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[9].IndicatorPointer.ListParam[1].Text    = "High & Low";

   strategy.Slot[9].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[9].IndicatorPointer.NumParam[0].Caption = "Period";
   strategy.Slot[9].IndicatorPointer.NumParam[0].Value   = Slot9IndParam0;
   strategy.Slot[9].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[9].IndicatorPointer.NumParam[1].Caption = "Shift";
   strategy.Slot[9].IndicatorPointer.NumParam[1].Value   = Slot9IndParam1;

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

   strategy.Slot[10].IndicatorName    = "CCI MA Oscillator";
   strategy.Slot[10].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[10].SignalShift      = 0;
   strategy.Slot[10].SignalRepeat     = 0;
   strategy.Slot[10].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[10].IndicatorSymbol  = "";
   strategy.Slot[10].LogicalGroup     = "d";
   strategy.Slot[10].IndicatorPointer = indicatorManager.CreateIndicator("CCI MA Oscillator", SlotTypes_CloseFilter);

   strategy.Slot[10].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[10].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[10].IndicatorPointer.ListParam[0].Index   = 7;
   strategy.Slot[10].IndicatorPointer.ListParam[0].Text    = "CCI MA Oscillator changes its direction downward";
   strategy.Slot[10].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[10].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[10].IndicatorPointer.ListParam[1].Index   = 0;
   strategy.Slot[10].IndicatorPointer.ListParam[1].Text    = "Simple";
   strategy.Slot[10].IndicatorPointer.ListParam[2].Enabled = true;
   strategy.Slot[10].IndicatorPointer.ListParam[2].Caption = "Signal line method";
   strategy.Slot[10].IndicatorPointer.ListParam[2].Index   = 3;
   strategy.Slot[10].IndicatorPointer.ListParam[2].Text    = "Smoothed";
   strategy.Slot[10].IndicatorPointer.ListParam[3].Enabled = true;
   strategy.Slot[10].IndicatorPointer.ListParam[3].Caption = "Base price";
   strategy.Slot[10].IndicatorPointer.ListParam[3].Index   = 6;
   strategy.Slot[10].IndicatorPointer.ListParam[3].Text    = "Weighted";

   strategy.Slot[10].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[10].IndicatorPointer.NumParam[0].Caption = "CCI period";
   strategy.Slot[10].IndicatorPointer.NumParam[0].Value   = Slot10IndParam0;
   strategy.Slot[10].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[10].IndicatorPointer.NumParam[1].Caption = "Signal line period";
   strategy.Slot[10].IndicatorPointer.NumParam[1].Value   = Slot10IndParam1;

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

   strategy.Slot[11].IndicatorName    = "Relative Vigor Index";
   strategy.Slot[11].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[11].SignalShift      = 0;
   strategy.Slot[11].SignalRepeat     = 0;
   strategy.Slot[11].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[11].IndicatorSymbol  = "";
   strategy.Slot[11].LogicalGroup     = "e";
   strategy.Slot[11].IndicatorPointer = indicatorManager.CreateIndicator("Relative Vigor Index", SlotTypes_CloseFilter);

   strategy.Slot[11].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[11].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[11].IndicatorPointer.ListParam[0].Index   = 11;
   strategy.Slot[11].IndicatorPointer.ListParam[0].Text    = "RVI line is lower than the Signal line";

   strategy.Slot[11].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[11].IndicatorPointer.NumParam[0].Caption = "RVI period";
   strategy.Slot[11].IndicatorPointer.NumParam[0].Value   = Slot11IndParam0;

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

   strategy.Slot[12].IndicatorName    = "Bears Power";
   strategy.Slot[12].SlotType         = SlotTypes_CloseFilter;
   strategy.Slot[12].SignalShift      = 0;
   strategy.Slot[12].SignalRepeat     = 0;
   strategy.Slot[12].IndicatorPeriod  = DataPeriod_M1;
   strategy.Slot[12].IndicatorSymbol  = "";
   strategy.Slot[12].LogicalGroup     = "f";
   strategy.Slot[12].IndicatorPointer = indicatorManager.CreateIndicator("Bears Power", SlotTypes_CloseFilter);

   strategy.Slot[12].IndicatorPointer.ListParam[0].Enabled = true;
   strategy.Slot[12].IndicatorPointer.ListParam[0].Caption = "Logic";
   strategy.Slot[12].IndicatorPointer.ListParam[0].Index   = 3;
   strategy.Slot[12].IndicatorPointer.ListParam[0].Text    = "Bears Power is lower than the Level line";
   strategy.Slot[12].IndicatorPointer.ListParam[1].Enabled = true;
   strategy.Slot[12].IndicatorPointer.ListParam[1].Caption = "Smoothing method";
   strategy.Slot[12].IndicatorPointer.ListParam[1].Index   = 3;
   strategy.Slot[12].IndicatorPointer.ListParam[1].Text    = "Smoothed";

   strategy.Slot[12].IndicatorPointer.NumParam[0].Enabled = true;
   strategy.Slot[12].IndicatorPointer.NumParam[0].Caption = "Smoothing period";
   strategy.Slot[12].IndicatorPointer.NumParam[0].Value   = Slot12IndParam0;
   strategy.Slot[12].IndicatorPointer.NumParam[1].Enabled = true;
   strategy.Slot[12].IndicatorPointer.NumParam[1].Caption = "Level";
   strategy.Slot[12].IndicatorPointer.NumParam[1].Value   = Slot12IndParam1;

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



    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>gbpusd M5  571 17.09.20</strategyName><profileName>Default profile</profileName><dataSourceName>FSB Demo data</dataSourceName><instrumentSymbol>GBPUSD</instrumentSymbol><instrumentPeriod>5</instrumentPeriod><sameDirSignalAction>Add</sameDirSignalAction><oppDirSignalAction>Reverse</oppDirSignalAction><maxOpenLots>20</maxOpenLots><useAccountPercentEntry>True</useAccountPercentEntry><entryLots>20</entryLots><addingLots>5</addingLots><reducingLots>10</reducingLots><useMartingale>False</useMartingale><martingaleMultiplier>2</martingaleMultiplier><description>Exported on 17.09.2020 from Forex Strategy Builder Professional, v3.8.8</description><recommendedBars>1000</recommendedBars><openFilters>5</openFilters><closeFilters>6</closeFilters><firstBar>36</firstBar><minBarsRequired>37</minBarsRequired><permanentStopLoss usePermanentSL=\"False\" permanentSLType=\"Relative\">580</permanentStopLoss><permanentTakeProfit usePermanentTP=\"False\" permanentTPType=\"Relative\">430</permanentTakeProfit><breakEven useBreakEven=\"False\">635</breakEven><slot slotNumber=\"0\" slotType=\"Open\"><indicatorName>Vidya Moving Average</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>Enter the market at the Vidya Moving Average</value></listParam><listParam paramNumber=\"2\"><caption>Base price</caption><index>3</index><value>Close</value></listParam><numParam paramNumber=\"0\"><caption>Period</caption><value>21</value></numParam><numParam paramNumber=\"1\"><caption>Smooth</caption><value>6</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=\"1\" slotType=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>MA Oscillator</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>MA Oscillator rises</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>0</index><value>Simple</value></listParam><listParam paramNumber=\"2\"><caption>Base price</caption><index>3</index><value>Close</value></listParam><numParam paramNumber=\"0\"><caption>Fast MA period</caption><value>13</value></numParam><numParam paramNumber=\"1\"><caption>Slow MA period</caption><value>19</value></numParam><numParam paramNumber=\"2\"><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=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>Oscillator of Momentum</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>1</index><value>Oscillator 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>4</index><value>Median</value></listParam><numParam paramNumber=\"0\"><caption>Momentum1 period</caption><value>10</value></numParam><numParam paramNumber=\"1\"><caption>Momentum2 period</caption><value>14</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=\"3\" slotType=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>Oscillator of ATR</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>3</index><value>Oscillator is lower than the zero line</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>0</index><value>Simple</value></listParam><numParam paramNumber=\"0\"><caption>First ATR period</caption><value>10</value></numParam><numParam paramNumber=\"1\"><caption>Second ATR period</caption><value>13</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=\"4\" slotType=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>Oscillator of RSI</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>Oscillator rises</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>1</index><value>Weighted</value></listParam><listParam paramNumber=\"2\"><caption>Base price</caption><index>0</index><value>Open</value></listParam><numParam paramNumber=\"0\"><caption>First RSI period</caption><value>10</value></numParam><numParam paramNumber=\"1\"><caption>Second RSI period</caption><value>14</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"5\" slotType=\"OpenFilter\" logicalGroup=\"A\"><indicatorName>Oscillator of OBOS</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>3</index><value>Oscillator is lower than the zero line</value></listParam><numParam paramNumber=\"0\"><caption>First OBOS period</caption><value>8</value></numParam><numParam paramNumber=\"1\"><caption>Second OBOS period</caption><value>15</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=\"6\" slotType=\"Close\"><indicatorName>Day Closing</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>0</index><value>Exit the market at the end of the day</value></listParam><listParam paramNumber=\"1\"><caption>Base price</caption><index>0</index><value>Close</value></listParam></slot><slot slotNumber=\"7\" slotType=\"CloseFilter\" logicalGroup=\"a\"><indicatorName>Bears Power</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>5</index><value>Bears Power crosses the Level line downward</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>2</index><value>Exponential</value></listParam><numParam paramNumber=\"0\"><caption>Smoothing period</caption><value>13</value></numParam><numParam paramNumber=\"1\"><caption>Level</caption><value>0.0000</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"8\" slotType=\"CloseFilter\" logicalGroup=\"b\"><indicatorName>Donchian Channel</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>3</index><value>The bar closes above Lower Band</value></listParam><listParam paramNumber=\"1\"><caption>Base price</caption><index>0</index><value>High &amp; Low</value></listParam><numParam paramNumber=\"0\"><caption>Period</caption><value>34</value></numParam><numParam paramNumber=\"1\"><caption>Shift</caption><value>0</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"9\" slotType=\"CloseFilter\" logicalGroup=\"c\"><indicatorName>Donchian Channel</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>1</index><value>The bar closes above Upper Band</value></listParam><listParam paramNumber=\"1\"><caption>Base price</caption><index>0</index><value>High &amp; Low</value></listParam><numParam paramNumber=\"0\"><caption>Period</caption><value>10</value></numParam><numParam paramNumber=\"1\"><caption>Shift</caption><value>0</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"10\" slotType=\"CloseFilter\" logicalGroup=\"d\"><indicatorName>CCI MA Oscillator</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>7</index><value>CCI MA Oscillator changes its direction downward</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>0</index><value>Simple</value></listParam><listParam paramNumber=\"2\"><caption>Signal line method</caption><index>3</index><value>Smoothed</value></listParam><listParam paramNumber=\"3\"><caption>Base price</caption><index>6</index><value>Weighted</value></listParam><numParam paramNumber=\"0\"><caption>CCI period</caption><value>14</value></numParam><numParam paramNumber=\"1\"><caption>Signal line period</caption><value>13</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"11\" slotType=\"CloseFilter\" logicalGroup=\"e\"><indicatorName>Relative Vigor Index</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>11</index><value>RVI line is lower than the Signal line</value></listParam><numParam paramNumber=\"0\"><caption>RVI period</caption><value>10</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></slot><slot slotNumber=\"12\" slotType=\"CloseFilter\" logicalGroup=\"f\"><indicatorName>Bears Power</indicatorName><listParam paramNumber=\"0\"><caption>Logic</caption><index>3</index><value>Bears Power is lower than the Level line</value></listParam><listParam paramNumber=\"1\"><caption>Smoothing method</caption><index>3</index><value>Smoothed</value></listParam><numParam paramNumber=\"0\"><caption>Smoothing period</caption><value>1</value></numParam><numParam paramNumber=\"1\"><caption>Level</caption><value>0.0000</value></numParam><checkParam paramNumber=\"0\"><caption>Use previous bar value</caption><value>False</value></checkParam><signalShift>0</signalShift><signalRepeat>0</signalRepeat><indicatorSymbol></indicatorSymbol><indicatorPeriod>M1</indicatorPeriod></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 ---