//#define FOR_TESTER 
//#define FOR_OPT // disble draw channel, news
//+------------------------------------------------------------------+
//|                                                Generic A-TLP.mq4 |
//|                                                 Trade Like A Pro |
//|                                          http://tradelikeapro.ru |
//|                                                      open source |
//|   Version 9.5  - added filters by CCI                                                    |
//|   Version 10.0 - Minor code optimization                                                 |
//|   Version 11.1 - counter trades are allowed, the parameter is entered,                   |
//|               limiting the opening of trades in one direction                            |
//|               within a given number of minutes                                           |
//|   Version 11.2 - all of the above combined into one advisor                              |
//|               and will continue to be an integral part of it;                            |
//|               - the parameter for calculating the period StDev has been moved to external|
//|               variables                                                                  |
//|   Version 11.3 - fixed bug related to CCI                                                |
//|   Version 11.4 - info panel bug fixed;                                                   |
//|               - added the ability to trade on each tick;                                 |
//|               - minimum volatility check now                                             |
//|               is carried out at the entrance to the position opening block               |
//|   Version 11.6 - added trailing stop                                                     |
//|   Version 11.7 - bugs fixed                                                              |
//|   Version 11.7.31 - channel calculation is decoupled from TF15                           |
//|   Version 11.9 - added a pause after a losing trade,                                     |
//|               - filter by max. candle length,                                            |
//|               - auto lot size based on balance, not equity,                              |
//|               - the possibility of banning trawling in rollover,                         |
//|               - print in the log about the presence of a signal at high in front         |
//|   Version 11.9.1 - filters are made to be disabled (pause after                          |
//|               loss and max candle)                                                       |
//|               - two modes of operation of the lastloss function have been implemented (for |
//|               tester and for trading)                                                    |
//|               - custom logging (LogMode variable)                                        |
//|               - small code optimization                                                  |
//|   Version 11.9.2 - corrected informing                                                   |
//|   Version 11.9.3 - bugs fixed                                                            |
//|   Version 11.9.4 - small code additions                                                  |
//|   Version 11.10.6 - changed the type of trade timing for                                 |
//|                    the possibility of optimizing it.                                     |
//|                  - removed unnecessary (duplicate) external parameters.                  |
//|                    Functions are now disabled at a value of 0.                           |
//|                  - sorting external parameters                                           | 
//|   Version 11.10.7 - fixed Auto_Risk calculation                                          |  
//|                  - removing redundant variables                                          |
//|   Version 11.10.8 - minor edits                                                          | 
//|   Version 11.10.9 - redundant variables removed                                          |
//|                  - pause filter message corrected                                        |
//|   Version 12.01.14 -code rework, improvements for optimization                           |
//|                  - additional fixes, improvements                                        |
//|                     every_tick now runs the loop 1 time                                  |
//|                     per minute at the time of opening a new bar on М1                    |
//|   Version 12.01.15 - return MaxDailyRange to settings and                                |
//|                     every_tick now runs the loop 1 time                                  |
//|                     per minute at the time of opening a new bar on М1                    |
//|   Version 12.01.16 - permission to trade in the Second Session without                   |
//|                     trading in First Session                                             |
//|   Version 12.01.17 - session bug fixed                                                   |
//|                   - the upper and lower levels of the CCI are combined into one          |
//|   Version 12.01.18 - fixed parameter normalization error                                 |
//|                     MaxDailyRange                                                        |
//|   Version 12.01.19 - writing to the log when MaxDailyRange is increased and              |
//|                     CCI filter                                                           |
//|                   - BB_Deviation now used                                                |
//|   Version 12.01.20 - channel border is now checked by price                              |
//|                     Ask when opening a deal for purchases, and when                      |
//|                     closing for sales                                                    |
//|   Version 12.01.21 - Introduced parameter OnlyBid, if true cancels                       |
//|                     change introduced on 01/12/20                                        |
//|                   - ShowCandleDots parameter changed to                                  |
//|                     VisualDebug, draws a channel with set                                |
//|                     indented, and displays the operation of filters                      |
//|                   - Added check SetName if currency                                      |
//|                     graphics are in SetName in the info panel next to                    |
//|                     SetName will be printed and [OK] otherwise [WARNING]                 |
//|                   - Optimization for faster performance                                  |
//|   Version 12.01.22 - fixed bug with spread display                                       |
//|                   - with Max_Spread=0, the line is not displayed now                     |
//|                     NORMAL/HIGH for spread                                               |
//|                   - added the OnTester function, which returns                           |  
//|                     ratio of profit to maximum drawdown                                  |
//|   Version 12.01.23 - fixed RollOver Filter                                               |
//|                   - second channel bb added to VisualDebug                               |
//|                     at Exit_Distance, if available                                       |
//|                     open positions, when exiting, the chart will display                 | 
//|                     it is written on what filter left. inscriptions                      |
//|                     made further from the price, overseas channel.                       |
//|                   - all messages in paragraphs are given to                              |
//|                     four-digit                                                           |
//|   Version 12.02.24 - Changed type of trade timing                                        |
//|   Version 12.02.25 - Optimization for faster performance                                 |
//|   Version 12.26    - use_rollover_filter variable changed to                             |
//|                     OpenOrdersInRollover and CloseOrdersInRollover                       |
//|                   - Correct transfer of trading time through midnight                    |
//|   Version 12.27    - Trading hours values ​​greater than 24,                               |
//|                     carried over to the next day                                         |
//|   Version 12.28    - Fixed display of time in the info panel                             |
//|   Version 12.30    - When autotrading is disabled, it displays a warning                 |
//|                   - Added parameter TradeAllDaysInTheSameTime,                           |
//|                     including trading on all days at the same time (Monday time is used) |
//|                   - Added on/off options individual day sessions                         |
//|                   - Added the CheckMDRAfter0 parameter, which includes                   |
//|                     checking MaxDailyRange after midnight                                |
//|                   - Calculation of money management from the minimum equity and balance  |
//|                   - Added parameter MM_Depo as lot calculation                           |
//|                     lot size (Lots) by depot size (MM_Depo)                              |
//|   Version 12.31    - maxcandle parameter now instead of length one                       |
//|                     candles are calculated as a range of motion                          |
//|                     prices for a given number of bars                                    |
//|                   - Fixed output in the info panel                                       |
//|                   - Checking for the minimum / maximum lot                               |
//|                   - embedded VisualDebug with trendlines                                 |
//|                   - added Max_Spread_mode2 as an alternative                             |
//|                     rollover to the filter, if the value is greater than zero            |
//|                     Max_Spread filters only purchases at                                 |
//|                     opening, and Max_Spread_mode2 - selling at closing                   |
//|   Version 12.32    - Fixed logging output                                                |
//|                   - Bugs fixed                                                           |
//|                   - Ability to open multiple orders                                      |
//|   Version 12.33    - Changed the construction of channel border lines                    |
//|                   - Fixed filter by MA                                                   |
//|                   - Fixed non-working CCI exit filter                                    |
//|   Version 12.34    - Fixed a bug in the construction of channel borders                  |
//|                   - Fixed prohibition of trailing stop in rollover                       |
//|                   - Now the number of orders is set to one                               |
//|                     parameter                                                            |
//|   Version 12.35    - Added filter for maximum currency volume                            |
//|                     Recommended value MaxAmountCurrencyMult=2                            |
//|   Version 12.36    - Max_Spread_mode2 parameter changed to                               |
//|                     CheckSpreadOnSellOpen enabling check                                 |
//|                     spread when selling, and Max_Spread_On_Close,                        |
//|                     checking spread at closing sales                                     |
//|                   - Added option to pause between trades when                            |
//|                     opening multiple orders                                              |
//|                   - Added simultaneous close option                                      |
//|                     order groups                                                         |
//|                   - The journal now writes the closing price                             |
//|                     and profit                                                           |
//|                   - Fixed output of messages to the log                                  |
//|                     when autotrading is disabled                                         |
//|                   - Checking for the number of orders on retry                           |
//|                     opening a deal after an unsuccessful attempt                         |
//|                   - Added news filter                                                    |
//|   Version 12.37    - Ability to change VisualDebug colors                                |
//|                   - Checking for errors when receiving data                              |
//|                     from other timeframes                                                |
//|                   - Custom timeframe for CCI                                             |
//|   Version 12.37.1  - Fixed a bug in calculating the distance between open orders                          
//|                   - Fix checking for errors when receiving data from other timeframes                         
//|   Version 12.37.2  - Instead of the total profit of several orders - now considered the average profit         
//|                   - Fixed a bug with non-simultaneous closing multiple orders                           
//|                   - Added parameter MDRFromHiLo, including range check from the high/low of the day
//|                   - Added time shift option             
//|                   - MaxDailyRange is now calculated taking into account time shift                               
//|   Version 12.38    - Fixed disabling filter with Exit_Distance = 0                        
//|                   - Fixed MaxDailyRange calculation after midnight
//|                   - Fixed rollover time calculation           
//|                   - When CheckMDRAfter0 is enabled the range from the previous day is not checked on Monday                                
//|                   - Fixed display of session time, time which accounted for at the close of the market
//|                   - TimeShift parameter changed to GMT_Offset  
//|   Version 12.38.1  - Added K1Band channel as an alternative to BBands
//|                   - Filter by maximum volume for a given currency is replaced by a filter by the maximum  the number of transactions in one direction        
//|   Version 12.38.2  - Added parameter SkipDay as a day skip,   
//|                     1-5 - Monday-Friday, 6 - Friday evening,
//|                     7 - Monday morning                        
//|                   - Fixed bug with MaxAmountCurrency        
//|   Version 12.38.3  - Added editable comment field     
//|                   - Added parameter OpenAfterTradeHours, allowing to open additional orders in multi-order trading after completion trading session                              
//|   Version 12.38.4  - Added parameter MaxAmountCurrencyPair     
//|                     as a filter by the maximum number of transactions for a given pair                           
//|                   - Parameter MaxAmount_SkipManualTrades as skipping trades opened manually            
//|                   - Added parameter MaxSpreadOnClose_Profit as the number of points of profit at which it is allowed to close deals if the spread exceeds Max_Spread_On_Close
//|                   - Removed K1Band                                
//|                   - Added a partial closing filter   
//|                   - Added parameter News_CloseProfit as profit at which it is allowed to close deals before the news              
//|   Version 12.38.5  - Correction of a pause between transactions when multi-order trading                   
//|   Version 12.38.7  - Added parameter MaxConsecutiveOrders as maximum number of consecutive open orders                                      
//|   Version 12.38.8  - Prohibition of trading if the set name is not  contains the name of the traded pair          
//|   Version 12.38.9  - The DoNotCheckAfterFirst parameter, which disables checking filters (MDR, etc.) when opening additional orders                       |
//|                   - Possibility to activate a trailing stop and breakeven on time                         
//|                   - Redesigned partial closure filter       
//|                   - Added Hard Exit filter as forced closing on time              
//|                   - Fixing a bug with simultaneous closing oppositely directed orders          
//|                   - Reschedule time filter fix positions over the weekend                     
//|   Version 12.38.10
//|               - Added prohibition of trading based on global variables.
//|                 Names of global variables - stop on pairs in which the currency "GA_CURRENCY_Stop" is present, stop on all pairs "GA_StopAll".
//|   Version 12.39
//|               - Breakeven activation by time of day
//|   Version 12.39.1
//|               - Added the ExitChannelTP parameter, puts the take on the level where the exit should be when the channel is touched
//|   Version 12.39.2
//|               - Correction of ExitChannelTP, when the price is outside Exit_Profit_Pips, TakeProfit will be set at the level of Exit_Profit_Pips
//|               - Added parameter DisableFilter2, disables EA closing when channel is touched without changing Exit_Distance, for use with ExitChannelTP
//|               - ExitChannelTP calculates TakeProfit for sales with a limit of Max_Spread_On_Close, was Max_Spread
//|   Version 12.39.3
//|               - Adding BB Shift and Max_Volatility parameters
//|               - Conclusion in the dashboard about the prohibition of trade based on global variables
//|   Version 12.39.4
//|               - Added ExitChannelTP visualization, take modification history and Exit_Profit_Pips level
//|   Version 12.39.5
//|               - Replacing _Point with old_point
//|               - Fixed bug with MDRFromHiLo
//|   Version 12.39.6
//|               - Fixed bug with checking MDR after 0 hours
//|               - Fixed error when calculating lot with TickValue = 0
//|   Version 12.39.7
//|               - Added the MDR_Toward parameter, which prohibits opening trades in the direction of price movement if the range of price movement exceeds the specified value
//|               - Added DisableSLAtRollover parameter, which disables Stop Loss in rollover
//|               - added statistics on slippage and delays when opening and closing orders
//|               - the BrokerStatToFile parameter writes these statistics to the file BrokerStat.csv
//|   Version 12.39.7_ATR - Added dynamic stop loss (from version 11.94.18)
//|   Version 12.39.8
//|               - When using a dynamic stop loss, the maximum stop loss size is limited by the Stop_Loss parameter, and the minimum - Min_SL
//|               - After Stop Loss is disabled during a rollover, after the end of the rollover, Stop Loss is restored at the same distance as before the shutdown
//|               - Added DisableStart and DisableEnd parameters to exclude time period from optimization
//|   Version 12.39.9
//|               - Added parameter MinPauseBetweenOrders as the minimum pause between trades without using the MultiOrders function
//|               - CheckBBChannel parameter to check the BB channel when opening subsequent orders
//|               - News filter changed
//|   Version 12.39.10
//|               - Fixed placing stop loss after rollover when using multiple orders
//|               - Fixed trailing stop on ATR when Stop Loss is disabled in rollover
//|   Version 12.39.11
//|               - Added a virtual deposit to calculate the risk relative to the profit / loss received only by this EA (when using several EAs on one account)
//|               - Added the ability to increase the lot after a losing trade
//|               - Fixed bug with CCI
//|               - Displaying information about open deals in the info panel
//|               - Added the ManualTrading parameter to display buttons for manually opening trades
//|   Version 12.39.12
//|               - Added maxcandle2 parameter similar to maxcandle parameter
//|               - Added the ability to specify parameter templates in the comments to the order: %MagicNumber%, %Auto_Risk%, %MM_Depo%, %Lots%, %SetName%, %TimeFrame%
//|               - Displaying GMT and DST information on the info panel
//|               - Added parameters DesiredRecoveryFactor, DesiredProfitFactor, MinTrades as the desired characteristics of the final set during optimization (recovery factor, profit factor, minimum number of trades)
//|   Version 12.39.13
//|               - Added parameter DesiredExpectancy as the desired mathematical expectation in points
//|   Version 12.39.14
//|               - Added filter ATR
//|               - Added tracking module for delays and slippages
//|   Version 12.39.15
//|               - Added daylight saving time for different contracts DST
//|   Version 12.39.16
//|               - Added a global variable to control the lot size of the entire setup
//|                 Multiplier, IncoGlobalRiskScale
//|   Version 12.39.17
//|               - Added MultLot - lot multiplier for the next deal in the grid
//|   Version 12.39.18
//|               - Added LastTradeDayDecember and FirstTradeDayJanuary
//|   Version 12.39.19
//|               - Added option to disable trading on holidays - DisableTradeOnHolidays (Currently USA only https://en.wikipedia.org/wiki/Federal_holidays_in_the_United_States, https://www.opm.gov/policy-data-oversight/pay-leave/federal-holidays/#url=2021)
//|   Version 12.39.20
//|               - Switching to using the news library (instead of the indicator that stopped working)
//|   Версия 12.39.21
//|               - Added filter SP500
//|   Версия 12.39.22
//|               - SP500 filter bug fixes
//|   Версия 12.39.23
//|               - fixed GMT offset for news
//+------------------------------------------------------------------+
//         author of the idea
//            Sergey5  bashni2001@mail.ru  

//         Senior Programmer
//            yur4ello

//         Huge gratitude to for the help in realization of the idea
//            Alexandr69
//            nixxer
//            grabli
//            LeoK

#property copyright "Trade Like A Pro"
#property link      "http://tradelikeapro.ru"
#property version   "12.39.23"
#property strict

#include <stderror.mqh>
#include <..\Libraries\stdlib.mq4>
//uncomment this line if you prefer web requests going via terminal WebRequest
//in this case htts://ec.forexprostools.com will have to be added to the web request permissions
//#define NO_DLL 1
#include <crossplatform/include/UrdalaNewsLoader.mqh>   
#include <crossplatform/include/SP500Checker.mqh>

enum     _EventLogs{
                              ALL                        = 1,                 //1. all
                              MAIN                       = 2,                 //2. major
							         NONE					         = 3			         //3. none
         };
         
enum     _MaxMin{
         MAX = 1,
         MIN = 2
         };
         
enum DstMode{
   DST_OFF        = 0,  //No DST
   DST_EUROPE     = 1,  //Europe (Alpari)
   DST_NEW_YORK   = 2,  //New-York (Tickmill)  
   DST_AUSTRALIA  = 3,  //Australia (Global Prime)
};
string dstStr[] = { "OFF", "Europe", "New-York", "Australia"};
   
struct LastOrder{
   datetime time;
   double profit;
   string sltp;
   int ticket;
   double slip;
};
LastOrder last_buy, last_sell;
int LastHistoryTotal=0; 
  
//--------------------------------------
extern   string S_1          = "audcad. euraud. eurchf. gbpaud. gbpcad. gbpchf. gbpusd. nzdcad. nzdchf. usdchf"; //English. v12.39.23   [ Revised 2022june12 ]
extern   string               SetName                    = "Generic_A-TLP_v.12.39.23 euraud M15  170102 r4";                //SetName
input    bool                 ForbidTradeIfSetNameWarning= false;             //Disable trading if SetName warning (false = ignore)
extern   ENUM_TIMEFRAMES      TimeFrame                  = PERIOD_M15;        //TimeFrame for Bollinger Bands. Use m15
extern   bool                 every_tick                 = 1;                 //Trade every tick
extern   int                  MagicNumber                = 170102;
extern   bool                 AllowLong                  = true;
extern   bool                 AllowShort                 = true;
extern   int                  Slippage                   = 5;
extern   string S_11          = "<==== Money Management ====>"; // >   >   >   >   >   >    >    >    >    > 
extern   double               Lots                       = 0.01;
extern   double               VirtualDepoForAutoRisk     = 0;                 // Virtual Deposit in Account Currency
extern   double               VirtualDepoPercent         = 0;                 // Virtual Deposit in Percent
extern   datetime             VirtualDepoStartDate       = D'2010.01.01';     // VirtualDepoStartDate (yyyy.mm.dd)
extern   double               Auto_Risk                  = 2.0;               // Auto Risk % (0= disabled)
input    int                  MM_Depo                    = 0;                 // Deposit per Lots
extern   double               LotMultAfterProfit         = 0.0;
extern   double               LotMultAfterLoss           = 0.0;
extern   double               LotMult_SizeLoss           = 0.0;               //Size of Loss
extern   double               Max_Lots                   = 0.0;
extern   double               Max_Auto_Risk              = 0.0;
extern   int                  CloseAtDrawdown            = 0;
extern   int                  CloseAtDrawdownPercent     = 0;
extern   int                  MaxAmountCurrency          = 0;                 //MaxAmountCurrency
extern   int                  MaxAmountCurrencyPair      = 0;                 //MaxAmountCurrencyPair
extern   bool                 MaxAmount_SkipManualTrades = true;
extern   string S_12         = "<==== General settings ====>"; // >   >   >   >   >   >    >    >    >    > 
input    bool                 CheckSpreadOnSellOpen      = false;
extern   bool                 CheckSpreadOnBuyClose      = false;
extern   double               Max_Spread                 = 0;                 //Max Spread
extern   double               Max_Spread_On_Close        = 0;
extern   double               MaxSpreadOnClose_Profit    = 0;
extern   double               Stop_Loss                  = 30;                //Stop Loss
extern   double               Take_Profit                = 9999;              //Take Profit
extern   int                  TP_perc                    = 100;               //TP_percentage
extern   int                  min_TP                     = 0;                 //Minimum TP
extern   bool                 VirtualSLTP                = true;
extern   bool                 DisableSLAtRollover        = false;
extern   int                  MaxDailyRange              = 200;
extern   bool                 MDRFromHiLo                = false;
extern   int                  MDR_Toward                 = 1000;
extern   bool                 MDR_Toward_FromHiLo        = false;
extern   bool                 CheckMDRAfter0             = true;
extern   bool                 SkipMDRAfter0OnMondays     = false;
extern   bool                 Hedging                    = true;              //Hedging
extern   int                  MinPauseBetweenOrders      = 10;

extern   string   S_3_1       = "<==== Dynamic SL ====>"; //
input    int                  Min_SL                     = 15; 
input    int                  ATR_P                      = 9;  //ATR_P - period ATR = 0 - off.
input    double               Coof_ATR                   = 6;
input    bool                 Trail_ATR                  = false;

extern   string S_8          = "<==== MULTI ORDERS ====>";                    // >   >   >   >   >   >    >    >    >    > 
extern   int                  TotalOrders                = 1;
extern   double               OrdersDistance             = 22;
extern   int                  MinPause                   = 20;                 //MinPause (seconds)
extern   int                  MaxConsecutiveOrders       = 0;
input    double               MultLot                    = 1.0;               //Next Lot Multiplier
input    bool                 OpenAfterTradeHours        = false;
input    bool                 DoNotCheckAfterFirst       = false;
input    bool                 CheckBBChannel             = false;
input    bool                 CloseSimultaneously        = true;             //CloseSimultaneously

extern   string S_2          = "<==== ENTER SETTINGS ====>";                  // >   >   >   >   >   >    >    >    >    > 
extern   string S_21         = "Bollinger Band Settings";                     //Bollinger Band
         bool                 UseBBChannel               = true;
extern   int                  BB_Period                  = 15;                //BB: Period
extern   double               BB_Deviation               = 2;                 //BB: Deviation
extern   double               Entry_Break                = 2;                 //BB: Entry_Break
extern   int                  Min_Volatility             = 4;                 //BB: Min_Volatility
extern   int                  Max_Volatility             = 1000;
extern   int                  BB_Shift                   = 1;
extern   bool                 OnlyBid                    = true;              //BB: Check channel touch only at Bid price

extern   string S_21_1       = "ATR Filter";
extern   ENUM_TIMEFRAMES      ATR_Timeframe              = PERIOD_H1;         //ATR Filter: ATR Timeframe
extern   int                  ATR_Period                 = 0;                 //ATR Filter: period (0-off)
extern   int                  Max_ATR_Pips               = 20;                //ATR Filter: max ATR, pips

extern   string S_22         = "CCI settings";                               //CCI
input    ENUM_TIMEFRAMES      TimeFrame_CCI              = PERIOD_CURRENT;   //CCI: TimeFrame
extern   int                  cci_Period_open            = 0;                //CCI: Period
extern   int                  cci_level_open             = 100;              //CCI: cci_level_open (upper & lower)

extern   string S_23         = "With max. candle length = 0 = off.";         //Filter by candle size (input)
extern   double               maxcandle                  = 1000; 
extern   int                  barcount                   = 8; 
extern   double               maxcandle2                 = 0; 
extern   int                  barcount2                  = 8; 

extern   string S_24         = "On pause = 0 = off.";                       //Filter by loss of the previous order
extern   int                  pause                      = 0;               //Pause after a losing trade (minutes)
extern   double               sizeloss                   = 0;               //Pause loss (in pips)

extern   string S_4          = "<==== Trailing stop/Breakeven ====>";       // >   >   >   >   >   >    >    >    >    > 
extern   double               Trail_Start                = 100;             //Trailling Start
extern   double               Trail_Size                 = 100;             //Trailling Distance
extern   double               Trail_Step                 = 11;              //Trailling Step
extern   int                  Trail_Minutes              = 0;
input    bool                 Trail_From_BE_Line         = false;
extern   bool                 rollover_trall_end         = false;           //Rollover_trail_end
extern   double               BE_Start                   = 0;               //BE_Start 
extern   double               BE_Dist                    = 1;               //BE_Dist. move SL by Y points to profit
extern   int                  BE_Minutes                 = 0;
extern   int                  BE_After_Hour              = -1;
extern   int                  BE_After_Min               = 0;

extern   string S_3          = "<==== EXIT SETTINGS ====>";                 // >   >   >   >   >   >    >    >    >    > 
extern   string S_31         = "With Exit_Minutes = 0 = off.";              //1. Time Filter. 
extern   int                  Exit_Minutes               = 0;              //Exit_Minutes 200
extern   double               Time_Profit_Pips           = 0;              //Time_Profit_Pips 20
input    bool                 FixMondayTimeBug           = true;
extern   string S_32         = "With Exit_Distance > 100 = off.";             //2. Channel Filter. 
extern   double               Exit_Distance              = -13;
extern   int                  Exit_Profit_Pips           = 2;
input    bool                 ExitChannelTP              = true;
input    bool                 DisableFilter2             = true;             
extern   string S_33         = "When MA_period = 0 = off.";                   //3. MA Filter.
extern   ENUM_TIMEFRAMES      TimeFrameMA                = PERIOD_M1; 
extern   ENUM_MA_METHOD       MA_type                    = MODE_SMA;
         ENUM_APPLIED_PRICE   MA_price                   = PRICE_CLOSE;
extern   int                  MA_period                  = 2;
extern   double               Reverse_Profit             = 20;
extern   string S_35         = "With PartialClose_Percent = 0 = off.";        //4. Partial Close
extern   double               PartialClose_Percent       = 0;
extern   int                  Part_Profit_Pips           = 0;
extern   int                  Part_Distance              = -10;
extern   bool                 Part_AllowCloseFull        = false;
extern   string S_34         = "With CCI: Period = 0 = off.";                 //5. CCI Filter. 
extern   int                  cci_Period_close           = 0;                 //CCI: Period
extern   int                  cci_level_close            = 100;               //CCI: upper and lower level
extern   int                  CCI_Profit_Pips            = 20;
extern   string S_36         = "With HardExit_Minutes = 0 and HardExit_TimeHour = -1 = off.";                //6. Hard Exit Filter. 
extern   int                  HardExit_Minutes           = 0;
extern   int                  HardExit_TimeHour          = -1;
extern   int                  HardExit_TimeMin           = 0;
extern   int                  HardExit_Profit            = -100;

extern   string S_5          = "<==== Trade Time Filter ====>";               // >   >   >   >   >   >    >    >    >    > 
extern   int                  GMT_Offset                 = 2;                 //Winter GMT offset of your broker
extern   DstMode              DSTMode                    = DST_NEW_YORK;      //DST contract of your broker
extern   bool                 TradeAllDaysInTheSameTime  = false;             //TradeAllDaysInTheSameTime (MONDAY & all days)
extern   int                  SkipDay                    = 0;
extern   bool                 DisableTradeOnHolidays     = false;             //Disable trade on holidays
extern   string S_51          = "<== MONDAY / ALL DAYS ==>";                  // MONDAY & all days.
extern   bool                 MONDAY_Enabled             = true;              //MONDAY_Enabled
extern   int                  MONDAY_Start_Trade_Hour    = 23;                //Start Trade Hour
extern   int                  MONDAY_Start_Trade_Minute  = 0;                 //Start Trade Minute
extern   int                  MONDAY_End_Trade_Hour      = 1;                 //End Trade Hour
extern   int                  MONDAY_End_Trade_Minute    = 0;                 //End Trade Minute 
extern   string S_52          = "<== TUESDAY ==>";       // TUESDAY 
extern   bool                 TUESDAY_Enabled             = true;             //TUESDAY_Enabled
extern   int                  TUESDAY_Start_Trade_Hour   = 23;                //Start Trade Hour
extern   int                  TUESDAY_Start_Trade_Minute = 0;                 //Start Trade Minute
extern   int                  TUESDAY_End_Trade_Hour     = 1;                 //End Trade Hour
extern   int                  TUESDAY_End_Trade_Minute   = 15;                //End Trade Minute 
extern   string S_53          = "<== WEDNESDAY ==>";     // WEDNESDAY
extern   bool                 WEDNESDAY_Enabled             = true;           //WEDNESDAY_Enabled
extern   int                  WEDNESDAY_Start_Trade_Hour = 22;                //Start Trade Hour
extern   int                  WEDNESDAY_Start_Trade_Minute=15;                //Start Trade Minute
extern   int                  WEDNESDAY_End_Trade_Hour   = 2;                 //End Trade Hour
extern   int                  WEDNESDAY_End_Trade_Minute = 45;                //End Trade Minute 
extern   string S_54          = "<== THURSDAY ==>";      // THURSDAY 
extern   bool                 THURSDAY_Enabled             = true;            //THURSDAY_Enabled
extern   int                  THURSDAY_Start_Trade_Hour  = 23;                //Start Trade Hour
extern   int                  THURSDAY_Start_Trade_Minute= 0;                 //Start Trade Minute
extern   int                  THURSDAY_End_Trade_Hour    = 1;                 //End Trade Hour
extern   int                  THURSDAY_End_Trade_Minute  = 15;                //End Trade Minute 
extern   string S_55          = "<== FRIDAY ==>";        // FRIDAY 
extern   bool                 FRIDAY_Enabled             = true;              //FRIDAY_Enabled
extern   int                  FRIDAY_Start_Trade_Hour    = 19;                //Start Trade Hour
extern   int                  FRIDAY_Start_Trade_Minute  = 0;                 //Start Trade Minute
extern   int                  FRIDAY_End_Trade_Hour      = 1;                 //End Trade Hour
extern   int                  FRIDAY_End_Trade_Minute    = 0;                 //End Trade Minute 

extern   string S_6          = "<==== Roll Over Filter ====>";                // >   >   >   >   >   >    >    >    >    > 
//input    bool                 use_rollover_filter        = 0;               //Use_rollover_filter
input    bool                 OpenOrdersInRollover       = true;              //OpenOrdersInRollover
input    bool                 CloseOrdersInRollover      = false;             //CloseOrdersInRollover
input    string               rollover_start             = "23:55";           //Rollover_start
input    string               rollover_end               = "00:25";           //Rollover_end
input    int                  LastTradeDayDecember       = 31;                //LastTradeDayDecember
input    int                  FirstTradeDayJanuary       = 1;                 //FirstTradeDayJanuary   
  
extern   string S_89         = "<=== SP500 Filter ====>";                // >   >   >   >   >   >    >    >    >    > 
input string                  SP500Symbol                = "US500";           //SP500 symbol (empty - filter off)
input int                     SP500CrashLimitPips        = 1200;              //Limit for SP500 crash
input bool                    SP500CrashOnly             = true;              //Ignore spikes, only filter crashes

extern   string S_9          = "<==== News Filter ====>";                // >   >   >   >   >   >    >    >    >    > 
extern   bool                UseNewsFilter               = false;             //UseNewsFilter
extern   int                 CloseTimeBeforeNews         = 30;                //Close all open trades before the news, minutes (0=off)
extern   int                 News_CloseProfit            = -100;             
extern   int                 TimeBeforeNews              = 60;                //Do not open deals until the news, minutes
extern   int                 TimeAfterNews               = 120;               //Do not open trades after the news, minutes
//extern   int                 news_offset                 = 3;               //Server timezone
extern   bool                Vhigh                       = true;              //Show important news
extern   bool                Vmedium                     = false;             //Show average news
extern   bool                Vlow                        = false;             //Show weak news 
extern   string              NewsSymb = "USD,EUR,GBP,CHF,CAD,AUD,NZD,JPY";    //Currencies to be shown in the news (empty=only current currencies)
input string                 NewsKeywords                = "";                //Keywords for filtering news, separated by commas (empty=allnews) 
extern   color               highc                       = clrRed;            //Big news color
extern   color               mediumc                     = clrLime;           //Medium news color
extern   color               lowc                        = clrBlue;           //Weak news color

extern   string S_71         = "<==== Optimization ====>";                    // >   >   >   >   >   >    >    >    >    > 
input    double               DesiredRecoveryFactor      = 0;                 //Recovery factor, not less
input    double               DesiredProfitFactor        = 1;                 //Profit, no less
input    double               DesiredExpectancy          = 0;                 //Mathematical expectation, in points
input    double               RecoveryFactor_Power       = 1;          
input    double               ProfitFactor_Power         = 2;
input    double               Expectancy_Power           = 1;          
input    int                  MinTrades                  = 0;                 //Number of transactions, not less
input    string               DisableStart               = "2000.01.01 12:00";//DisableStart trading = yyyy.mm.dd hh:mm
input    string               DisableEnd                 = "2000.02.01 12:00";//DisableEnd trading   = yyyy.mm.dd hh:mm

extern   string S_7          = "<==== Other Settings ====>";                  // >   >   >   >   >   >    >    >    >    > 
extern   bool                 showinfopanel              = true;              //Show dashboard
extern   bool                 ManualTrading              = true;
input    color                Col_info                   = clrDarkBlue;       //Dashboard color
input    color                Col_info2                  = clrGray;           //Dashboard color for disabled trading
extern   bool                 VisualDebug                = true;
extern   bool                 BrokerStatToFile           = true;
input    color                ChannelEnterColor          = clrYellow;         //BB channel color
input    color                ChannelExitColor           = clrCornflowerBlue; //BB channel color when exiting
input    color                WarnEnterColor             = clrLightSkyBlue;   //Login warning color 
input    color                WarnExitColor              = clrPlum;           //Exit alert color 
extern   _EventLogs           LogMode                    = 1;                 //Logging mode
input    bool                 WriteLogFile               = 0;                 //Write logs to a file
extern   string               Comm                       = "Generic A-TLP|%MagicNumber%";                //Comment

//--------------------------------------
         double               old_point                  = 0.0001;
         double               stoplevel                 = 0;
         double               lots                       = 0;
         double               lots_opened_buy            = 0;
         double               lots_opened_sell           = 0;  
         int                  count_sell, count_buy;       
         int                  day_of_trade               = 0;
         string               tp_info                    = "";
         string               be_info                    = "";
         string               f1_info                    = "";
         string               f2_info                    = "";
         string               f3_info                    = "";
         string               f4_info                    = "";
         string               f5_info                    = "";
         string               f6_info                    = "";
         string               filter_info                = "";
         string               risk_info                  = "";
         string               risk_scale                 = "";
         string               info_panel                 = "";
         string               maxspread                  = ""; 
         string               TradeHoursFirst            = "";
         string               TradeHoursSecond           = "";
         datetime             _TimeCurrent, _TimeM1, _TimePeriod, iTimeTF, iTimeM1, iTime_MA, iTime_CCI;
         datetime             need_to_verify_channel     = iTime(NULL,TimeFrame,1);
         datetime             ma_period_check,cci_period_check;
         datetime             time_open_buy              = TimeCurrent();
         datetime             time_open_sell             = TimeCurrent();
   
         double               channel_width              = 0;
         double               channel_upper, channel_lower;
         double               channel_buy, channel_sell, channel_buy_exit, channel_sell_exit;
         double               ma_shift[5];
         int                  cci_signal_open,cci_signal_close;
         double               stoploss, takeprofit;
         double               orig_stoploss;
         double               last_sl[2];
         int                  lastticket, lasthistorytotal, lasthistorytotal2;  
         datetime             lasttimewrite, lastbarwrite, lastbarwrite_allowtrade, last_closetime = 0;                                        
//--- options for writing data to a file
         string               InpFileName;                                    // File name
         string               fileName                   = "EA_Generic";      // File name
         string               InpDirectoryName           = "Generic LOGS";    // Directory name

         bool                 _RealTrade = (!(bool)::MQLInfoInteger(::MQL_TESTER) && !(bool)::MQLInfoInteger(::MQL_OPTIMIZATION) && !(bool)::MQLInfoInteger(::MQL_VISUAL_MODE));
         bool                 SetEqSymbol;
         datetime             StartTime, EndTime, PrevDayStartTime, PrevDayEndTime;
         datetime             rtime1, rtime2;
         int                  rtimestart,rtimeend;
         int                  Start_Trade_Hour[7], End_Trade_Hour[7], Start_Trade_Minute[7], End_Trade_Minute[7];
         bool                 Day_Trade_Enabled[7];
         string               First_StartTimeStr,First_EndTimeStr,Second_StartTimeStr,Second_EndTimeStr;
         string               daystring[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
         int                  day_of_year_trade=0;
         string               set_name_info = "";
//         bool                 _IsFirstSession;
         color                infopanelcolor,previnfopanelcolor;
         int                  _DayOfWeek;
         double               buy_total_profit,sell_total_profit;
         datetime             first_buy_open_time, first_sell_open_time;
         datetime             lastnewsupdate1,lastnewsupdate2;
         bool                 _IsNews,_IsCloseBeforeNews;
         bool                 skip_tick;
         string               _period;
         bool                 timer_active;
         int                  CloseReason_Multi[2];
         datetime             DayStartTimeShift;
         int                  TimeShift;
         int                  _DayOfWeekShift;
         double               range;
         bool                 _IsTime;
         int                  consecutive_orders_buy=0,consecutive_orders_sell=0;
         datetime             _HardExitTime, _BE_Time;
         ulong                OnTickStart;     
         datetime             _DisableTimeStart,_DisableTimeEnd;
         double               virtual_balance=0, virtual_profit=0, opened_profit;
//---- variables for calculating simultaneously open positions

         string Currencies = "AUD,EUR,USD,CHF,JPY,NZD,GBP,CAD,SGD,NOK,SEK,DKK,ZAR,MXN,HKD,HUF,CZK,PLN,RUR,TRY,XAU,XAG";

         int NumOfCurrencies;  // Total number of currencies taken into account
         string Currency[];    // Accounted currencies
         double VolumesArray[];
         datetime LastUpdateTime;
         bool AllowTrade;
         bool trading_allowed_global;
         double ordersl[6],ordertp[6];
         double globalRiskScale = 1;
         NewsLoader* newsLoader;
         SP500Checker *sp500Checker;
         NewsCheckStatus newsCheckStatus;
struct Stats {
datetime startdate;
int trades;
double gross_profit;
double gross_loss;
double pf;
double expectancy;
double expectancy_pips;
double profit_pips;
};
         Stats stats;
 //---- variables for calculating simultaneously open positions

string                        GlobPrefix="GA_", s1str, s2str;
double                        mintpb,mintps,tpb,tps;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   s1str = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
   s2str = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);

   int height=370;
   //if(!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) { Print("Error: Trade Expert is not Allowed"); return(INIT_FAILED); }
   
   if((bool)::MQLInfoInteger(::MQL_OPTIMIZATION)){LogMode=3; showinfopanel=false; VisualDebug=false;}
   
   AllowTrade = true;   
   string _SetName=SetName;
   StringToUpper(_SetName);
   SetEqSymbol = StringFind(_SetName, StringSubstr(_Symbol,0,6))>=0;
   if (_RealTrade && ForbidTradeIfSetNameWarning && !SetEqSymbol) {
      Print("Wrong set name! Trading not allowed.");
      AllowTrade = false;
      }

   #ifndef FOR_TESTER
   if (MaxAmountCurrency>0) height += 37;
   if (MaxAmountCurrencyPair>0) height += 37;
   //if (VirtualDepoForAutoRisk>0 || VirtualDepoPercent>0) height += 37;
   height += 73;
   height += 37;
   if (VirtualDepoForAutoRisk>0 || VirtualDepoPercent>0) height += 12;
   if(showinfopanel) fRectLabelCreate(0,"info_panel",0,0,28,170,height,Col_info);
   if (ManualTrading) {
      fRectLabelCreate(0,"sell_btn",0,7,63,75,25,C'255,0,0',2,0,clrRed,STYLE_SOLID,1,false,false,true,1);
      fRectLabelCreate(0,"buy_btn",0,87,63,75,25,C'0,0,255',2,0,clrBlue,STYLE_SOLID,1,false,false,true,1);
      fLabelCreate(0,"SELL",0,44,75,"SELL",0,"Verdana",12,clrWhite);
      fLabelCreate(0,"BUY",0,124,75,"BUY",0,"Verdana",12,clrWhite);
      }

   #endif
   
   _period = PeriodString(_Period);
    
   if (LogMode < 3) InpFileName = fileName + "_" + Symbol() + "_" + _period + ".txt";
   
   if (Digits <= 3) old_point = 0.01;
   else old_point = 0.0001;
   
   stoplevel = /*(int)*/MarketInfo(Symbol(), MODE_STOPLEVEL)*_Point/old_point;
   maxspread = (Max_Spread > 0 ? DoubleToString(Max_Spread,1) + " pips" : "OFF");
   
   _TimeM1 = StrToTime(TimeToString(TimeCurrent(),TIME_MINUTES));
   
   day_of_year_trade=0; // when the EA is reinitialized, some variables are not reset to zero, but retain their last values
   infopanelcolor=0;
   previnfopanelcolor=0;
   lastnewsupdate1=0;
   lastnewsupdate2=0;
   ma_period_check=0;
   cci_period_check=0;
   need_to_verify_channel=0;
   timer_active=false;
   
   if (!TradeAllDaysInTheSameTime) {
      Start_Trade_Hour[1] = MONDAY_Start_Trade_Hour; 
      Start_Trade_Hour[2] = TUESDAY_Start_Trade_Hour; 
      Start_Trade_Hour[3] = WEDNESDAY_Start_Trade_Hour; 
      Start_Trade_Hour[4] = THURSDAY_Start_Trade_Hour; 
      Start_Trade_Hour[5] = FRIDAY_Start_Trade_Hour; 
      End_Trade_Hour[1] = MONDAY_End_Trade_Hour;
      End_Trade_Hour[2] = TUESDAY_End_Trade_Hour;
      End_Trade_Hour[3] = WEDNESDAY_End_Trade_Hour;
      End_Trade_Hour[4] = THURSDAY_End_Trade_Hour;
      End_Trade_Hour[5] = FRIDAY_End_Trade_Hour;
      Start_Trade_Minute[1] = MONDAY_Start_Trade_Minute;
      Start_Trade_Minute[2] = TUESDAY_Start_Trade_Minute;
      Start_Trade_Minute[3] = WEDNESDAY_Start_Trade_Minute;
      Start_Trade_Minute[4] = THURSDAY_Start_Trade_Minute;
      Start_Trade_Minute[5] = FRIDAY_Start_Trade_Minute;
      End_Trade_Minute[1]= MONDAY_End_Trade_Minute;
      End_Trade_Minute[2]= TUESDAY_End_Trade_Minute;
      End_Trade_Minute[3]= WEDNESDAY_End_Trade_Minute;
      End_Trade_Minute[4]= THURSDAY_End_Trade_Minute;
      End_Trade_Minute[5]= FRIDAY_End_Trade_Minute;
      }
   else {
      for(int i=1; i<=5; i++) {
         Start_Trade_Hour[i]=MONDAY_Start_Trade_Hour;
         Start_Trade_Minute[i]=MONDAY_Start_Trade_Minute;
         End_Trade_Hour[i]=MONDAY_End_Trade_Hour;
         End_Trade_Minute[i]=MONDAY_End_Trade_Minute;
         }
      }

   for(int i=1; i<=5; i++) {
      while (Start_Trade_Hour[i]*60+Start_Trade_Minute[i]>End_Trade_Hour[i]*60+End_Trade_Minute[i]) End_Trade_Hour[i] += 24;
      }

   Day_Trade_Enabled[1]=MONDAY_Enabled;   
   Day_Trade_Enabled[2]=TUESDAY_Enabled;   
   Day_Trade_Enabled[3]=WEDNESDAY_Enabled;   
   Day_Trade_Enabled[4]=THURSDAY_Enabled;   
   Day_Trade_Enabled[5]=FRIDAY_Enabled;   
      
   if (SkipDay >= 1 && SkipDay <= 5) Day_Trade_Enabled[SkipDay]=false;
   if (SkipDay == 6 && Start_Trade_Hour[5] < 24) { Start_Trade_Hour[5] = 24; Start_Trade_Minute[5] = 0; }
   if (SkipDay == 7 && End_Trade_Hour[5] > 24) { End_Trade_Hour[5] = 24; End_Trade_Minute[5] = 0; }

   for(int i=0; i<=6; i++) {
      if (!Day_Trade_Enabled[i]) {
         Start_Trade_Hour[i]=0;
         Start_Trade_Minute[i]=0;
         End_Trade_Hour[i]=0;
         End_Trade_Minute[i]=0;
         }
      }
        
   rtimestart=-1;
   rtimeend=-1;     
   string tt[];
   int i;
   i=StringSplit(rollover_start,StringGetCharacter(":",0),tt);
   if (i==2) {
      rtimestart=StrToInteger(tt[0])*60*60+StrToInteger(tt[1])*60;
      }
   i=StringSplit(rollover_end,StringGetCharacter(":",0),tt);
   if (i==2) {
      rtimeend=StrToInteger(tt[0])*60*60+StrToInteger(tt[1])*60;
      }
   if (rtimestart ==-1 || rtimeend == -1) {
      Print("Rollover time set incorrectly.");
      return(INIT_FAILED);
      }
  
   _DisableTimeStart = StringToTime(DisableStart);
   _DisableTimeEnd = StringToTime(DisableEnd);
   
   if (OrdersDistance < 0.5) OrdersDistance=0.5;
   if (TotalOrders < 1) TotalOrders=1;
   if (TotalOrders > 10) { Print("The number of orders is set to more than 10. The maximum number of orders: 10"); TotalOrders=10; }

   TimeShift = GMT_Offset - 2 - fGetDSTShift();
   
   if (PartialClose_Percent > 1) PartialClose_Percent = 1;
   
   if (MaxConsecutiveOrders == -1) MaxConsecutiveOrders = TotalOrders;

   /*if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) */stats = CountVirtualBalance(virtual_balance,virtual_profit);
   /*if (sizeloss < 0) {
      Print("The amount of loss to pause before opening the next order must be specified in positive numbers!");
      Print("Current value: ",sizeloss/PipsDivided," Reduced to: ", MathAbs(sizeloss/PipsDivided));
      sizeloss = MathAbs(sizeloss);
   }  */
      
   //if (!_RealTrade && MarketInfo(NULL,MODE_SPREAD) > Max_Spread && Max_Spread > 0) { Print("Error: Current Spread (" + DoubleToString(MarketInfo(NULL,MODE_SPREAD)*old_point,1) +  ") > MaxSpread (" + DoubleToString(Max_Spread*old_point,1) + ")"); return(INIT_FAILED); }
    
   Take_Profit = MathMax(Take_Profit,NormalizeDouble(stoplevel,1));
   Stop_Loss = MathMax(Stop_Loss,NormalizeDouble(stoplevel,1));
   orig_stoploss = Stop_Loss;
   
   /*if (Auto_Risk > 0) */lots = AutoMM_Count(0); //trading lot calculation
   //else lots = Lots;
   
   f1_info = "\n  1. Time Filter: OFF";
   f2_info = "\n  2. Channel Filter: OFF";
   f3_info = "\n  3. MA Filter: OFF";
   f4_info = "\n  4. Partial Close: OFF";
   f5_info = "\n  5. CCI Filter: OFF";
   f6_info = "\n  6. Hard Exit Filter: OFF";

   if(Exit_Minutes > 0) f1_info = "\n  1. Time Filter: ON";
   if(Exit_Distance < 100) f2_info = "\n  2. Channel Filter: ON";
   if(MA_period > 0) f3_info = "\n  3. MA Filter: ON";
   if(PartialClose_Percent > 0) f4_info = "\n  4. Partial Close: ON";
   if(cci_Period_close > 0) f5_info = "\n  5. CCI Filter: ON";
   if(HardExit_Minutes > 0 || HardExit_TimeHour > -1) f6_info = "\n  6. Hard Exit Filter: ON";
   filter_info = f1_info + f2_info + f3_info + f4_info + f5_info + f6_info;

   if(Auto_Risk > 0.0) {
      if (MM_Depo == 0) {
         risk_info = "\n  AutoRisk = " + DoubleToString(Auto_Risk, 1) + "%"+(TotalOrders>1?"*"+IntegerToString(TotalOrders)+" = "+DoubleToString(Auto_Risk*TotalOrders, 1)+"%":"");
         }
      else
         {
         risk_info = "\n  AutoRisk = " + DoubleToString(Lots, 2) + " Lot / " + IntegerToString(MM_Depo) + " "+AccountInfoString(ACCOUNT_CURRENCY);
         }   
      }
   else
      risk_info = "\n  AutoRisk - Not activated";
   
   be_info = "\n  Breakeven: ";
   if(BE_Start > 0/* && Y > 0*/) {
      be_info += DoubleToString(BE_Start,1)+" / " + DoubleToString(BE_Dist,1)+" pips"; //breakeven
      if (BE_Minutes > 0) be_info += " / " + IntegerToString(BE_Minutes)+" Min";
      }
   else if (BE_Minutes > 0) {
      be_info += DoubleToString(BE_Dist,1)+" pips / " + IntegerToString(BE_Minutes)+" Min";
      }
   else be_info += "OFF";

   StringReplace(Comm,"%MagicNumber%",IntegerToString(MagicNumber));
   StringReplace(Comm,"%Auto_Risk%",(string)Auto_Risk);
   StringReplace(Comm,"%MM_Depo%",IntegerToString(MM_Depo));
   StringReplace(Comm,"%Lots%",DoubleToString(Lots,2));
   StringReplace(Comm,"%SetName%",SetName);
   StringReplace(Comm,"%TimeFrame%",PeriodString(TimeFrame));
   
   if (StringLen(Comm)>31) Comm = StringSubstr(Comm,0,31);
   
   
   set_name_info=(StringLen(_SetName)>28 ? StringSubstr(_SetName,0,28)+"..." : _SetName);
   
   _IsNews=false;
#ifndef NO_DLL   
   if (_RealTrade) {
      if (UseNewsFilter && !(bool)::TerminalInfoInteger(::TERMINAL_DLLS_ALLOWED)) {
   		string q = "For the news filter to work, it is necessary to enable the use of the DLL in the settings. The news filter is off.";
		   Print(q);
         #ifndef FOR_TESTER   
            fWriteDataToFile(q);
       	#endif
         Alert(q);
         return (INIT_FAILED);
      }      
   }
#endif

   newsLoader = new NewsLoader(GMT_Offset + (IsSummerTime(DSTMode) ? 1 : 0), 
                                 NewsSymb,                     //v12.39.23
                                 NewsKeywords,                 //v12.39.23
                                 Vhigh,                        //v12.39.23
                                 Vmedium,                      //v12.39.23
                                 Vlow,                         //v12.39.23
                                 true,                         //draw lines on chart
                                 false,                        //only draw future news
                                 highc,                        //high news color
                                 mediumc,                      //medium news color
                                 lowc,                         //low news color
                                 60 * 60 * 24,                 //refresh period, seconds (it fetches the whole week)
                                 UseNewsFilter);
   newsCheckStatus.Reset();
   string sp500symbol = SP500Symbol;
   StringTrimRight(sp500symbol);
   StringTrimLeft(sp500symbol);
   sp500Checker = new SP500Checker(sp500symbol, SP500CrashLimitPips, SP500CrashOnly); 

   NumOfCurrencies = StringSplit(Currencies,StringGetCharacter(",",0),Currency);
   if (NumOfCurrencies >= 0) { ArrayResize(VolumesArray,NumOfCurrencies); } else { MaxAmountCurrency = 0; MaxAmountCurrencyPair = 0; }
   
   Comment("");
   
   OnTick();   

   #ifndef FOR_TESTER
   UpdateInfoPanel();
   #else
   if (_RealTrade) {
      Comment("FOR_TESTER Mode Enabled.\nPlease comment line '#define FOR_TESTER' and recompile the EA.\nTrading is disabled.");
      Print("The EA is compiled in tester mode. Comment out the #define FOR_TESTER line and recompile the EA. Trading not allowed.");
      AllowTrade = false;
      }
   #endif
   
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(_RealTrade){
      Comment("");
      if (showinfopanel) fRectLabelDelete(0,"info_panel");
      if (ObjectFind("sell_btn")>=0) fRectLabelDelete(0,"sell_btn");
      if (ObjectFind("buy_btn")>=0) fRectLabelDelete(0,"buy_btn");
      if (ObjectFind("SELL")>=0) fLabelDelete(0,"SELL");
      if (ObjectFind("BUY")>=0) fLabelDelete(0,"BUY");
   }
   if(CheckPointer(newsLoader) == POINTER_DYNAMIC)
      delete (newsLoader);
   if(CheckPointer(sp500Checker) == POINTER_DYNAMIC)
      delete(sp500Checker);
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{

   #ifndef FOR_TESTER 
   OnTickStart=GetMicrosecondCount();
   #endif
   #ifndef FOR_TESTER 
   CheckScale();
   #endif
   
   skip_tick = false;
   _TimeCurrent = TimeCurrent();
   _DayOfWeek = DayOfWeek();   

   iTimeTF = iTime(NULL,TimeFrame,0); 
   #ifndef FOR_TESTER   
      if (_RealTrade) if (IsError("iTime",iTimeTF)) skip_tick=true;
   #endif   
   iTimeM1 = iTime(NULL,PERIOD_M1,0); 
   #ifndef FOR_TESTER      
      if (_RealTrade) if (IsError("iTimeM1",iTimeM1)) skip_tick=true;
   #endif   
   iTime_MA = iTime(NULL,TimeFrameMA,0); 
   #ifndef FOR_TESTER      
      if (_RealTrade) if (IsError("iTime MA",iTime_MA)) skip_tick=true;
   #endif   
   iTime_CCI = iTime(NULL,TimeFrame_CCI,0); 
   #ifndef FOR_TESTER      
      if (_RealTrade) if (IsError("iTime CCI",iTime_CCI)) skip_tick=true;
   #endif   
   
   if ((_DayOfWeek>=0) && (_DayOfWeek<=6)) {
      if (day_of_year_trade != DayOfYear()) {
      
         TimeShift = GMT_Offset - 2 - fGetDSTShift();
         
         int weekends_shift=0;
         if (TimeDayOfWeek(TimeCurrent()) == 0 && TimeShift < 0) { weekends_shift = -24*60*60; }
         if (TimeDayOfWeek(TimeCurrent()) == 6 && TimeShift > 0) { weekends_shift = +24*60*60; }
         _DayOfWeekShift = TimeDayOfWeek(TimeCurrent()+weekends_shift-TimeShift*60*60); 
         if (_DayOfWeekShift > 5) _DayOfWeekShift=1;
         if (_DayOfWeekShift < 1) _DayOfWeekShift=5;
         int _PrevDayOfWeekShift = _DayOfWeekShift-1;   
         if (_PrevDayOfWeekShift < 1) _PrevDayOfWeekShift=5;
         if (_PrevDayOfWeekShift > 5) _PrevDayOfWeekShift=1;

         datetime _CurrentDate = StrToTime(TimeToString(_TimeCurrent,TIME_DATE));
         DayStartTimeShift = _CurrentDate+TimeShift*60*60;

         PrevDayStartTime=_CurrentDate-24*60*60+(Start_Trade_Hour[_PrevDayOfWeekShift])*60*60+Start_Trade_Minute[_PrevDayOfWeekShift]*60+TimeShift*60*60;
         PrevDayEndTime = _CurrentDate-24*60*60+(End_Trade_Hour[_PrevDayOfWeekShift])*60*60+End_Trade_Minute[_PrevDayOfWeekShift]*60+TimeShift*60*60;
         StartTime=_CurrentDate+(Start_Trade_Hour[_DayOfWeekShift])*60*60+Start_Trade_Minute[_DayOfWeekShift]*60+TimeShift*60*60;
         EndTime = _CurrentDate+(End_Trade_Hour[_DayOfWeekShift])*60*60+End_Trade_Minute[_DayOfWeekShift]*60+TimeShift*60*60;
         
         if (_DayOfWeek == 0 && StartTime < DayStartTimeShift+24*60*60) { StartTime=DayStartTimeShift+24*60*60; }
         if (_DayOfWeek == 5 && EndTime > DayStartTimeShift+24*60*60) { EndTime=DayStartTimeShift+24*60*60; }
         
         _HardExitTime = _CurrentDate + HardExit_TimeHour*60*60 + HardExit_TimeMin*60 + TimeShift*60*60;
         _BE_Time = _CurrentDate + BE_After_Hour*60*60 + BE_After_Min*60 + TimeShift*60*60;

         #ifndef FOR_TESTER   
         if (showinfopanel) {
            First_StartTimeStr=TimeToString(PrevDayStartTime,TIME_MINUTES);
            if (TimeDayOfWeek(PrevDayStartTime) != _DayOfWeek) First_StartTimeStr = "00:00";
            First_EndTimeStr=TimeToString(PrevDayEndTime,TIME_MINUTES);
            if (TimeDayOfWeek(PrevDayEndTime) != _DayOfWeek) First_EndTimeStr = "00:00";
            Second_StartTimeStr=TimeToString(StartTime,TIME_MINUTES);
            if (TimeDayOfWeek(StartTime) != _DayOfWeek) Second_StartTimeStr = "00:00";
            Second_EndTimeStr=TimeToString(EndTime,TIME_MINUTES);
            if (TimeDayOfWeek(EndTime) != _DayOfWeek) Second_EndTimeStr = "00:00";
            }
         #endif   
         
         
         rtime1 = _CurrentDate + rtimestart + TimeShift*60*60;
         rtime2 = _CurrentDate + rtimeend + TimeShift*60*60;
         //if (rtime2 < rtime1) rtime2 += 24*60*60;
         //rtime1 = StrToTime(StringConcatenate(TimeToString(_TimeCurrent,TIME_DATE)," ",rollover_start))+TimeShift*60*60;
         //rtime2 = StrToTime(StringConcatenate(TimeToString(_TimeCurrent,TIME_DATE)," ",rollover_end))+TimeShift*60*60;

         day_of_year_trade = DayOfYear();
         }
      }

   int ht=OrdersHistoryTotal();
   if(LastHistoryTotal!=ht){
      LastHistoryTotal=ht;
      #ifndef FOR_TESTER
      GetLastProfit(ht);
      #endif
      //if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) {
         stats = CountVirtualBalance(virtual_balance, virtual_profit);
//         lots = AutoMM_Count();
      //   }
   }
   if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0 || CloseAtDrawdown > 0 || CloseAtDrawdownPercent > 0) {
      double p,l;
      opened_profit = CountOpenedProfit(p,l);
      }
   #ifndef FOR_TESTER          
   trading_allowed_global = false;
   if (!GlobalVariableCheck(GlobPrefix+"StopAll") && !GlobalVariableCheck(GlobPrefix+s1str+"_Stop") && !GlobalVariableCheck(GlobPrefix+s2str+"_Stop")) trading_allowed_global = true;

      UpdateInfoPanel();
   #endif   
   
   if (_TimeM1 == iTimeM1 && !every_tick ) return ;
   _TimeM1 =  iTimeM1;

   _IsTime = IsTime();
   if(!_IsTime && CountOrder(-1)<1) return;

   if(need_to_verify_channel != iTimeTF){ //update the indicator data once a period
      if (UseBBChannel) {
         channel_upper = iBands(NULL,TimeFrame,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_UPPER,BB_Shift);
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iBands",channel_upper)) skip_tick=true;
         #endif
         channel_lower = iBands(NULL,TimeFrame,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_LOWER,BB_Shift);
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iBands 2",channel_upper)) skip_tick=true;
         #endif
         }

      #ifndef FOR_OPT  
      if(!skip_tick && VisualDebug){
         if(_IsTime) {
            if (UseBBChannel) {
               DrawChannel("up_", channel_upper + Entry_Break*old_point, ChannelEnterColor);
               DrawChannel("down_", channel_lower - Entry_Break*old_point, ChannelEnterColor);
               }
            }
         if (UseBBChannel) {
         //if(CountOrder(OP_BUY) > 0) {
            DrawChannel("down_exit_", channel_upper + Exit_Distance*old_point, ChannelExitColor);

         //}
         //if(CountOrder(OP_SELL) > 0) {
            DrawChannel("up_exit_", channel_lower - Exit_Distance*old_point, ChannelExitColor);
         //}
            }

      }
      #endif
      
      if(ExitChannelTP) fSetTPbyExitChannel();
      
      if(Trail_ATR) fATR();
      
      channel_width = channel_upper - channel_lower;
      if (!skip_tick) need_to_verify_channel = iTimeTF;
      
      if(TP_perc > 0) Take_Profit = MathMax(NormalizeDouble(channel_width/old_point /100 * TP_perc,1), min_TP); //check for dynamic TP
 
      IsNews(_IsNews,_IsCloseBeforeNews); // to update the dashboard
 
   }
   
   #ifndef FOR_TESTER   
   if(ma_period_check != iTime_MA && MA_period > 0){
      for (int i=1;i<=4;i++) {
         ma_shift[i] = NormalizeDouble(iMA(NULL, TimeFrameMA, MA_period, 0, MA_type, MA_price, i),Digits);
         if (_RealTrade) if (IsError("iMA "+IntegerToString(i),ma_shift[i])) skip_tick=true;
         }
      if (!skip_tick) ma_period_check = iTime_MA;
      }   
   #endif   
      
   if(cci_period_check != iTime_CCI){
      if (cci_Period_open>0) {
         cci_signal_open=fGetCCISignal(cci_Period_open,PRICE_CLOSE,cci_level_open,1);
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iCCI open",cci_signal_open,false)) skip_tick=true; // iCCI can return 0 without error
         #endif   
         } else cci_signal_open=-1;
      if (cci_Period_close>0) {
         cci_signal_close=fGetCCISignal(cci_Period_close,PRICE_CLOSE,cci_level_close,1);
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iCCI close",cci_signal_close,false)) skip_tick=true;
         #endif
         } else cci_signal_close=-1;
      if (!skip_tick) cci_period_check = iTime_CCI;
      }   

   #ifndef FOR_TESTER   
   if (skip_tick) { 
      //Print("skipping tick");
      SetTimer(1);
      return; 
      }
      
   if (timer_active) { EventKillTimer();timer_active=false; }
   #endif
 

   range = 0;
   count_buy = 0;
   count_sell = 0;
   int _OrdersTotal = OrdersTotal();
   CloseReason_Multi[OP_BUY]=0;CloseReason_Multi[OP_SELL]=0;
   
   if (TotalOrders>1 && CloseSimultaneously) {
      int cnt_buy=CountOrder(OP_BUY);
      int cnt_sell=CountOrder(OP_SELL);
      if (cnt_buy > 0) buy_total_profit=GetOrdersTotalProfit(OP_BUY)/cnt_buy;
      if (cnt_sell > 0) sell_total_profit=GetOrdersTotalProfit(OP_SELL)/cnt_sell;
      first_buy_open_time=GetFirstOpenTime(OP_BUY);
      first_sell_open_time=GetFirstOpenTime(OP_SELL);
      }

   for(int pos = _OrdersTotal - 1; pos >= 0; pos--){
      if(!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {
			if (LogMode < 3) {
				string q = __FUNCTION__ + ": Failed to select order! " + fMyErDesc();
				Print(q);
				#ifndef FOR_TESTER   
				   fWriteDataToFile(q);
				#endif 
			}   
      }
      else if(OrderType() <= OP_SELL && OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {

         if(OrderType() == OP_BUY) {
            count_buy++;
            if(!VirtualSLTP && OrderStopLoss() != 0.0 && OrderTakeProfit() != 0 && fGetRollOver() && DisableSLAtRollover){ 
               last_sl[OP_BUY] = OrderStopLoss();
               fModifyPosition(OrderTicket(), OrderOpenPrice(), 0, OrderTakeProfit(), 0, clrGreen);
               }
            if((!VirtualSLTP && OrderStopLoss() == 0.0) || (VirtualSLTP && ordersl[OP_BUY] == 0.0)){ //order modification
               if (!fGetRollOver() || !DisableSLAtRollover) {
                  stoploss = NormalizeDouble(OrderOpenPrice() - Stop_Loss*old_point, Digits);
                  if (last_sl[OP_BUY] != 0 && TotalOrders == 1) { stoploss = last_sl[OP_BUY]; last_sl[OP_BUY] = 0; }
                  if (Bid <= stoploss) stoploss = NormalizeDouble(Bid - MathMax(stoplevel,0.1)*old_point, Digits);
               } else stoploss = 0; 
               takeprofit = NormalizeDouble(OrderOpenPrice() + Take_Profit*old_point, Digits);
               
               if(!ExitChannelTP) 
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, takeprofit, 0, clrGreen);
               else
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, MathMax(MathMax(tpb, OrderOpenPrice()+Exit_Profit_Pips*old_point), mintpb), 0, clrGreen);

               //if (!VirtualSLTP) continue; // if SL=0, then will not close
            }
            
            if(((BE_Start > 0 && BE_Start > BE_Dist && Bid - OrderOpenPrice() >= BE_Start*old_point) || (((BE_Minutes > 0 && _TimeCurrent - OrderOpenTime() > 60*BE_Minutes) || (BE_After_Hour > -1 && OrderOpenTime() < _BE_Time && _TimeCurrent >= _BE_Time)) && Bid - OrderOpenPrice() >= (BE_Dist+stoplevel)*old_point)) /*&& Y > 0*/ && (!VirtualSLTP?OrderStopLoss():ordersl[OP_BUY]) < OrderOpenPrice()){ //breakeven
               stoploss = NormalizeDouble(OrderOpenPrice() + BE_Dist*old_point, Digits);
               if (stoploss > (!VirtualSLTP?OrderStopLoss():ordersl[OP_BUY]))
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, OrderTakeProfit(), 0, clrGreen);
            }
            
            Modify_and_exit_condition(OrderType(),OrderLots(),OrderOpenPrice(),OrderOpenTime(),OrderTicket(),OrderStopLoss()); //modifying orders and checking exit conditions
         }
         
         else if(OrderType() == OP_SELL){
            count_sell++;
            if(!VirtualSLTP && OrderStopLoss() != 0.0 && OrderTakeProfit() != 0 && fGetRollOver() && DisableSLAtRollover){ 
               last_sl[OP_SELL] = OrderStopLoss();
               fModifyPosition(OrderTicket(), OrderOpenPrice(), 0, OrderTakeProfit(), 0, clrGreen);
               }
            if ((!VirtualSLTP && OrderStopLoss() == 0.0) || (VirtualSLTP && ordersl[OP_SELL] == 0.0)) { //order modification
               if (!fGetRollOver() || !DisableSLAtRollover) {
                  stoploss = NormalizeDouble(OrderOpenPrice() + Stop_Loss*old_point, Digits);
                  if (last_sl[OP_SELL] != 0 && TotalOrders == 1) { stoploss = last_sl[OP_SELL]; last_sl[OP_SELL] = 0; }
                  if (Ask >= stoploss) stoploss = NormalizeDouble(Ask + MathMax(stoplevel,0.1)*old_point, Digits);
               } else stoploss = 0;
               takeprofit = NormalizeDouble(OrderOpenPrice() - Take_Profit*old_point, Digits);
               
               if(!ExitChannelTP) 
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, takeprofit, 0, clrGreen);
               else
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, MathMin(MathMin(tps, OrderOpenPrice()-Exit_Profit_Pips*old_point), mintps), 0, clrGreen);
                  
               //if (!VirtualSLTP) continue;          
            }
            
            if(((BE_Start > 0 && BE_Start > BE_Dist && OrderOpenPrice() - Ask >= BE_Start*old_point) || (((BE_Minutes > 0 && _TimeCurrent - OrderOpenTime() > 60*BE_Minutes) || (BE_After_Hour > -1 && OrderOpenTime() < _BE_Time && _TimeCurrent >= _BE_Time)) && OrderOpenPrice() - Ask > (BE_Dist+stoplevel)*old_point)) /*&& Y > 0*/ && (!VirtualSLTP?OrderStopLoss():ordersl[OP_SELL]) > OrderOpenPrice()){ //БУ
               stoploss = NormalizeDouble(OrderOpenPrice() - BE_Dist*old_point, Digits);
               if (stoploss < (!VirtualSLTP?OrderStopLoss():ordersl[OP_SELL]))
                  fModifyPosition(OrderTicket(), OrderOpenPrice(), stoploss, OrderTakeProfit(), 0, clrGreen);
            }
            
            Modify_and_exit_condition(OrderType(),OrderLots(),OrderOpenPrice(),OrderOpenTime(),OrderTicket(),OrderStopLoss()); //modifying orders and checking exit conditions
         }
      }     
   }       
   
   if (!AllowTrade) return;
   
   //if (!GlobalVariableCheck(GlobPrefix+"StopAll") && !GlobalVariableCheck(GlobPrefix+s1str+"_Stop") && !GlobalVariableCheck(GlobPrefix+s2str+"_Stop")){
      
      if((!_IsTime && !OpenAfterTradeHours) || (!OpenOrdersInRollover && fGetRollOver())) return;
      double h_price;
      bool is_order_dist;
      bool openresult;
      bool channel_condition=false;
      bool bb_condition=false;
      bool con_orders;
      
      h_price=GetMaxMinOpenPrice(OP_BUY,MIN); // minimum price of open orders
      if (h_price != 0) is_order_dist = Ask < h_price-OrdersDistance*old_point; else is_order_dist = true;  // distance from open orders is not less than the specified one
   
      count_buy=CountOrder(OP_BUY);
      count_sell=CountOrder(OP_SELL);
      
      RefreshRates();
      
      channel_condition = (OnlyBid ? Bid : Ask) < channel_lower - Entry_Break*old_point;
      
      con_orders = MaxConsecutiveOrders == 0 || (MaxConsecutiveOrders != 0 && consecutive_orders_buy < MaxConsecutiveOrders);
      
     // Opening trades if all conditions are met
      if (AllowLong) {
         if (count_buy < 1 && _IsTime && _TimeCurrent-time_open_buy>MinPauseBetweenOrders && //if there are no open purchases
            channel_condition) {  //if the BB channel is touched
              openresult=OpenTradeConditions("BUY",OP_BUY,time_open_buy,count_buy,count_sell);
         }
         else if(count_buy >= 1 && count_buy < TotalOrders && is_order_dist && _TimeCurrent-GetLastOpenTime(OP_BUY)>MinPause && con_orders &&
            (channel_condition || !CheckBBChannel)) { 
              openresult=OpenTradeConditions("BUY",OP_BUY,time_open_buy,count_buy,count_sell);
         }
      } 
   
      h_price=GetMaxMinOpenPrice(OP_SELL,MAX); // maximum price of open orders
      if (h_price != 0) is_order_dist = Bid > h_price+OrdersDistance*old_point; else is_order_dist = true; // distance from open orders is not less than the specified one
      
      count_buy=CountOrder(OP_BUY);
      count_sell=CountOrder(OP_SELL);
   
      channel_condition=false;
      bb_condition=false;
      
      RefreshRates();
      
      channel_condition = Bid > channel_upper + Entry_Break*old_point;
      
      con_orders = MaxConsecutiveOrders == 0 || (MaxConsecutiveOrders != 0 && consecutive_orders_sell < MaxConsecutiveOrders);
   
      if (AllowShort) {
         if (count_sell < 1 && _IsTime && _TimeCurrent-time_open_sell>MinPauseBetweenOrders && //if there are no open sales
            channel_condition) {  //if the BB channel is touched
              openresult=OpenTradeConditions("SELL",OP_SELL,time_open_sell,count_sell,count_buy);
         }         
         else if(count_sell >= 1 && count_sell < TotalOrders && is_order_dist && _TimeCurrent-GetLastOpenTime(OP_SELL)>MinPause && con_orders &&
             (channel_condition || !CheckBBChannel)) {  
              openresult=OpenTradeConditions("SELL",OP_SELL,time_open_sell,count_sell,count_buy);
         }   
      }
   //}
   
      int Error = GetLastError(); //looking for errors at the end
   if(Error != 0) Print("OnTick() Error ",Error,": ",ErrorDescription(Error));
}

void SetTimer(int time) {
if (!_RealTrade) return;
if (!timer_active) EventSetTimer(time);
}

void OnTimer()
{
timer_active=true;
OnTick();
}

//+------------------------------------------------------------------+
bool Modify_and_exit_condition(int _OrderType, double _OrderLots, double _OrderOpenPrice, datetime _OrderOpenTime,int _OrderTicket, double _OrderStopLoss) {
               
   if((Trail_Start > 0 || Trail_Minutes > 0) && Trail_Size > 0) { //Trail an open position
      if (!rollover_trall_end || (rollover_trall_end && !fGetRollOver())) fTrailingStopFunc();
   }
   
   if(ATR_P>0 && Trail_ATR){
      bool change_sl_condition = false;
      if (OrderSelect(OrderTicket(), SELECT_BY_TICKET, MODE_TRADES)) { // to update the TP value, if called on the same tick when the order was created - first SL and TP are placed, then Modify_and_exit_condition is called, and it considers that TP=0. probably and _OrderStopLoss would be wrong, but it's not requested anywhere
         if (OrderStopLoss() != 0) { // do not trail if SL=0. DisableSLAtRollover?
            if (_OrderType == OP_BUY) {
               stoploss = NormalizeDouble(_OrderOpenPrice - Stop_Loss * old_point, _Digits);
               change_sl_condition = (!CompareDoubles(stoploss,OrderStopLoss()) && stoploss < _OrderOpenPrice);
               }
            if (_OrderType == OP_SELL) {
               stoploss = NormalizeDouble(_OrderOpenPrice + Stop_Loss * old_point, _Digits);
               change_sl_condition = (!CompareDoubles(stoploss,OrderStopLoss()) && stoploss > _OrderOpenPrice);
               }         
            if (change_sl_condition) {   
               fModifyPosition(_OrderTicket, _OrderOpenPrice, stoploss, OrderTakeProfit(), 0, clrGreen);
               DrawHistorySL(_OrderTicket, stoploss);   
            }
         }
      }
   }

   string logstr="";
   string warnstr="";
   string filterstr="";
   int filterno=0;

   bool condition_for_the_exit = false;
//   bool channel_condition = false;
   bool bb_condition=false;
   bool channel_condition2 = false;
   
   double PriceType = Ask; //if a sell order.
   double OrderDistance = _OrderOpenPrice - PriceType;
   double orderdist;
   string orderstr="";
   string ordertotalstr="";
   
   if (_OrderType == OP_BUY) { //if order buy
      PriceType = Bid;
      OrderDistance = PriceType - _OrderOpenPrice;
   }
  
   if (TotalOrders>1 && CloseSimultaneously) {
      orderdist=OrderDistance;
      orderstr="; order profit - "+DoubleToString(orderdist/old_point,1)+" points";
      ordertotalstr=" average";
      if (_OrderType == OP_BUY) {
         OrderDistance=buy_total_profit;
         _OrderOpenTime=first_buy_open_time;
         }
      if (_OrderType == OP_SELL) {
         OrderDistance=sell_total_profit;
         _OrderOpenTime=first_sell_open_time;
         }
      }
  
   if (UseBBChannel) {
      if (_OrderType == OP_SELL && (OnlyBid ? Bid : Ask) <= channel_lower - Exit_Distance*old_point) bb_condition = true;
      else if (_OrderType == OP_BUY && Bid >= channel_upper + Exit_Distance*old_point) bb_condition = true;
      }
      
   if (_OrderType == OP_SELL && (OnlyBid ? Bid : Ask) <= channel_lower - Part_Distance*old_point) channel_condition2 = true;
   else if (_OrderType == OP_BUY && Bid >= channel_upper + Part_Distance*old_point) channel_condition2 = true;
      
   if (VirtualSLTP) {
      if((!fGetRollOver() || !DisableSLAtRollover) && ((_OrderType == OP_BUY && PriceType <= ordersl[OP_BUY] && ordersl[OP_BUY] != 0) || (_OrderType == OP_SELL && PriceType >= ordersl[OP_SELL] && ordersl[OP_SELL] != 0))) {   
         condition_for_the_exit = true;
         filterno=100;
   	   if (LogMode < 2) {
		     warnstr="SL";
		      filterstr="SL";
   		   logstr = "Stop Loss orders #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits);
         }
      }
   
      if((_OrderType == OP_BUY && PriceType >= ordertp[OP_BUY] && ordertp[OP_BUY] != 0) || (_OrderType == OP_SELL && PriceType <= ordertp[OP_SELL] && ordertp[OP_SELL] != 0)) {   
         condition_for_the_exit = true;
         filterno=101;
   	   if (LogMode < 2) {
		     warnstr="TP";
		      filterstr="TP";
   		   logstr = "Take Profit orders #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits);
         }  
      }   
   }
   
   int exitmin=Exit_Minutes;
   if (FixMondayTimeBug && _DayOfWeekShift == 1 && _TimeCurrent - _OrderOpenTime > 86400) {exitmin = Exit_Minutes + 48*60;}
   if((Exit_Minutes > 0 && _TimeCurrent - _OrderOpenTime > 60 * exitmin && // the order is open for more than Exit_Minutes and
      OrderDistance > Time_Profit_Pips*old_point) || (CloseReason_Multi[_OrderType] == 1)) {                                 // floating profit over Time_Profit_Pips (0)
      condition_for_the_exit = true;
      filterno=1;
	   if (LogMode < 2) {
		   warnstr="1. Time";
		   filterstr="1. Time";
		   logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) + " (filter "+filterstr+")" + ". Time of existence more " + IntegerToString(Exit_Minutes) +
		         " minute and"+ordertotalstr+" floating profit is more than " + DoubleToString(Time_Profit_Pips,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + orderstr + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
	   }
   }
   if((UseBBChannel && Exit_Distance < 100 && bb_condition && !DisableFilter2 &&    // the price went out of the channel and
      OrderDistance > Exit_Profit_Pips*old_point && !condition_for_the_exit) || (CloseReason_Multi[_OrderType] == 2)) {           // floating profit over Exit_Profit_Pips (-12)
      condition_for_the_exit = true;
      filterno=2;
	   if (LogMode < 2) {
		   warnstr="2. BB Channel";
		   filterstr="2. BB Channel";
		   logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" + ". The price crossed the channel border " + DoubleToString((_OrderType==OP_SELL?channel_lower:channel_upper),Digits) + " on " +
			      DoubleToString(Exit_Distance,1) + " points and"+ordertotalstr+" floating profit amounted to more than " + DoubleToString(Exit_Profit_Pips,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + orderstr + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
      }
   }

   if(MA_period > 0 && _OrderOpenTime < iTime(NULL,TimeFrameMA,0) ) { //filter by MA
   
   #ifdef FOR_TESTER   
   if(ma_period_check != iTime_MA && MA_period > 0){
      for (int i=1;i<=4;i++) {
         ma_shift[i] = NormalizeDouble(iMA(NULL, TimeFrameMA, MA_period, 0, MA_type, MA_price, i),Digits);
         //if (_RealTrade) if (IsError("iMA "+IntegerToString(i),ma_shift[i])) skip_tick=true;
         }
      /*if (!skip_tick) */ma_period_check = iTime_MA;
      }   
   #endif   

      int MA_Type_Exit = -1; //zeroing
      if (ma_shift[1] > ma_shift[2] && ma_shift[2] <= ma_shift[3] && ma_shift[3] <= ma_shift[4]) MA_Type_Exit = OP_SELL;
      else if (ma_shift[1] < ma_shift[2] && ma_shift[2] >= ma_shift[3] && ma_shift[3] >= ma_shift[4]) MA_Type_Exit = OP_BUY;
      
      if((((_OrderType == OP_SELL && MA_Type_Exit == OP_SELL) || (_OrderType == OP_BUY && MA_Type_Exit == OP_BUY)) && //moving average rises or falls
         OrderDistance > Reverse_Profit*old_point && !condition_for_the_exit) || (CloseReason_Multi[_OrderType] == 3)) { // and floating profit over Reverse_Profit (20)
         condition_for_the_exit = true;
         filterno=3;
		   if (LogMode < 2) {
			   warnstr="3. MA";
			   filterstr="3. MA";
			   logstr = "Closing an order #" + IntegerToString(OrderTicket()) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" + ". The moving average changes" +
				      " And"+ordertotalstr+" floating profit over " + DoubleToString(Reverse_Profit,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + orderstr + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
		   }
      }
   }

   if((cci_Period_close > 0 && !condition_for_the_exit && OrderDistance > CCI_Profit_Pips*old_point && cci_signal_close != _OrderType &&
      cci_signal_close != -1) || (CloseReason_Multi[_OrderType] == 5)) { //filter by CCI
      condition_for_the_exit = true;
      filterno=5;
	   if (LogMode < 2) {
		   warnstr="5. CCI";
		   filterstr="5. CCI";
		   logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
	   }
   }
   
   if((PartialClose_Percent > 0 && channel_condition2 && ((_OrderType == OP_BUY?_OrderLots == lots_opened_buy:_OrderLots == lots_opened_sell)) && !condition_for_the_exit &&    // partial closure
      OrderDistance > Part_Profit_Pips*old_point) || (CloseReason_Multi[_OrderType] == 4)) {          
      double _lots = MathFloor((_OrderLots*PartialClose_Percent)/MarketInfo(Symbol(), MODE_LOTSTEP))* MarketInfo(Symbol(), MODE_LOTSTEP);
      _lots = MathMax(_lots, MarketInfo(Symbol(), MODE_MINLOT)); //comparison of the received lot with the minimum
      
      if ((_lots < _OrderLots) || (Part_AllowCloseFull && _lots <= _OrderLots)) {
         condition_for_the_exit = true;
         _OrderLots = _lots;
         filterno=4;
   	   if (LogMode < 2) {
		      warnstr="4. Partial Close";
   		   filterstr="4. Partial Close";
		     logstr = "Partial closure "+DoubleToString(_OrderLots,2)+" lots of orders #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" +
		      ". Floating profit amounted to more than " + DoubleToString(Part_Profit_Pips,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + orderstr + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
            }
         }      
   }
   
   int hardexitmin=HardExit_Minutes;
   if (FixMondayTimeBug && _DayOfWeekShift == 1 && _TimeCurrent - _OrderOpenTime > 86400) {hardexitmin = HardExit_Minutes + 48*60;}
   if(HardExit_Minutes > 0 || HardExit_TimeHour > -1) {
      bool IsHardExitTime = false;
      string reason = "";
      if (HardExit_Minutes > 0 && _TimeCurrent - _OrderOpenTime > 60 * hardexitmin) {
         IsHardExitTime = true;
         reason = "Time of existence more " + IntegerToString(HardExit_Minutes) + " minutes";
         }
      if (HardExit_TimeHour > -1 && _OrderOpenTime < _HardExitTime && _TimeCurrent >=_HardExitTime) {
         IsHardExitTime = true;
         reason = "Closing at the start of the day - " + IntegerToString(HardExit_TimeHour) + ":" + IntegerToString(HardExit_TimeMin,2,StringGetCharacter("0",0));
         }
      if ((IsHardExitTime && // the order is open for more than Exit_Minutes and
      (OrderDistance > HardExit_Profit*old_point)) || (CloseReason_Multi[_OrderType] == 6)) {                                 //    floating profit over Time_Profit_Pips (0)
         condition_for_the_exit = true;
         filterno=6;
   	   if (LogMode < 2) {
		      warnstr="6. Hard Exit";
   		   filterstr="6. Hard Exit";
		      logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" + ". "+ reason +
   		         " And"+ordertotalstr+" floating profit is " + "more "+ DoubleToString(HardExit_Profit,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + orderstr + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
	      }
	   }   
   }


   if((!condition_for_the_exit && 
      ((CloseAtDrawdown > 0 && -opened_profit >= CloseAtDrawdown) || (CloseAtDrawdownPercent > 0 && (-opened_profit)*100/(VirtualDepoForAutoRisk==0&&VirtualDepoPercent==0?::AccountInfoDouble(::ACCOUNT_BALANCE):virtual_balance) >= CloseAtDrawdownPercent) || ((VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) && virtual_balance+opened_profit <= 0))) ||
      (CloseReason_Multi[_OrderType] == 9)) { //drawdown filter
      condition_for_the_exit = true;
      filterno=9;
	   if (LogMode < 2) {
		   warnstr="9. Drawdown";
		   filterstr="9. Drawdown";
		   logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) +  " (filter "+filterstr+")" + ". Drawdown over "+DoubleToString(-opened_profit,2)+" "+AccountInfoString(ACCOUNT_CURRENCY)+"; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
	   }
   }
   
   #ifndef FOR_OPT
   if (UseNewsFilter && CloseTimeBeforeNews != 0 && OrderDistance > News_CloseProfit*old_point && !condition_for_the_exit) { //news filter
      if (lastnewsupdate2 != iTimeM1) {
         IsNews(_IsNews,_IsCloseBeforeNews);
         lastnewsupdate2 = iTimeM1;
         }
      if (_IsCloseBeforeNews) {
         condition_for_the_exit = true;
         if (LogMode < 2) {
   		   logstr = "Closing an order #" + IntegerToString(_OrderTicket) + " by price "+ DoubleToString(PriceType,Digits) + ".news filter, and"+ordertotalstr+" floating profit is more than " + DoubleToString(News_CloseProfit,1) + " points: " + DoubleToString(OrderDistance/old_point,1)+" points" + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
   		   warnstr="7. News";
   		   filterstr="7. News";
         }   
      }
   }   
   #endif

   if(CloseReason_Multi[_OrderType] == 0 && condition_for_the_exit && filterno != 100 && filterno != 101) {
      if ((!CloseOrdersInRollover) && fGetRollOver()) {
         if (LogMode < 2 && _TimeCurrent-lasttimewrite > 60) {
            logstr = "Attempt to close an order #" + IntegerToString(OrderTicket()) + " (filter "+filterstr+"): Rollover filter. The order was not closed.";
            warnstr += " + rollover";
            DrawWarn(warnstr, WarnExitColor);
            Print(logstr);
            #ifndef FOR_TESTER   
               fWriteDataToFile(logstr);
            #endif
            lasttimewrite = _TimeCurrent;
            }   
         return(false);
      }
      if(Max_Spread_On_Close>0){
         if ((Ask - Bid) > Max_Spread_On_Close*old_point && (OrderType()==OP_SELL || CheckSpreadOnBuyClose) && OrderDistance < MaxSpreadOnClose_Profit*old_point) { //filter by maximum spread
            if (LogMode < 2 && _TimeCurrent-lasttimewrite > 60) {
               logstr = "Attempt to close an order #" + IntegerToString(OrderTicket()) + " (filter "+filterstr+"): Spread (" + DoubleToString((Ask - Bid) / old_point, 1) + " points) more than the maximum (" + DoubleToString(Max_Spread_On_Close, 1) + ")! The order was not closed.";
               warnstr += " + spread";
               DrawWarn(warnstr, WarnExitColor);
               Print(logstr);
               #ifndef FOR_TESTER   
                  fWriteDataToFile(logstr);               
               #endif   
               lasttimewrite = _TimeCurrent;
            }   
             return(false);
         }
      }
   }
      
   if(condition_for_the_exit) { //if at least one filter worked:
   
      if (TotalOrders>1 && CloseSimultaneously) CloseReason_Multi[_OrderType]=filterno;

      if ((bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED) || lastbarwrite_allowtrade != iTimeTF) {
      if (warnstr != "") DrawWarn(warnstr, WarnExitColor);
      if (logstr != "") {
         Print(logstr);
         #ifndef FOR_TESTER   
            fWriteDataToFile(logstr);
         #endif   
         }
         if (!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) {
            string q = Symbol() + "| Trading not allowed." + " Order "+(_OrderType == OP_BUY?"BUY":"SELL")+" #" + IntegerToString(OrderTicket()) + " was not closed.";
            Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
            lastbarwrite_allowtrade = iTimeTF;
            }
         }
         
       if (!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) return(false);

      #ifndef FOR_TESTER
      bool res=OrderCloseX(_OrderTicket, _OrderLots, _OrderType, Slippage, clrViolet);
      #else
      bool res=OrderClose(_OrderTicket, _OrderLots, NormalizeDouble(PriceType, Digits), Slippage, clrViolet);
      #endif
      if (res && (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0)) CountVirtualBalance(virtual_balance, virtual_profit); // чтобы не открылся на том же тике при балансе меньше нуля
      return res;
      /*if(!OrderClose(_OrderTicket, _OrderLots, NormalizeDouble(PriceType, Digits), Slippage, clrViolet)){ //закрытие ордера
			if (LogMode < 3) {
			   string q = __FUNCTION__ + ": Ордер " + Symbol() + " #" + IntegerToString(OrderTicket()) + " не был закрыт! " + fMyErDesc();
			   Print(q);
			   #ifndef FOR_TESTER   
			      fWriteDataToFile(q);
			   #endif   
			}
			Sleep(3000);
			return(false);
      }
      else{
         //Sleep(1000);
         return(true);
      }*/
      //Sleep(3000);
      return(true);
   }

   return(true);
}

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
bool OpenTradeConditions(string _OrderType, int OP_TYPE, datetime &time_open, int order_cnt, int opposite_order) {     

bool donotcheck = (order_cnt > 0 && DoNotCheckAfterFirst);

   if(/*order_cnt == 0 && */cci_Period_open > 0 && cci_signal_open != OP_TYPE) { //filter by CCI // check only when opening the first order
      if (LogMode < 2 && lastbarwrite != iTimeTF) {
         string q = Symbol() + "| CCI not out of level: ±" + IntegerToString(cci_level_open) + " Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("filter CCI",WarnEnterColor);
	      lastbarwrite = iTimeTF;
      }   
      return(false);
   }
   
   if(cci_Period_close > 0 && cci_signal_close != OP_TYPE && cci_signal_close != -1) { //filter by CCI on closing is enabled
      if (LogMode < 2 && lastbarwrite != iTimeTF) {
         string q = Symbol() + "| Close CCI is below: ±" + IntegerToString(cci_level_close) + " Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("filter CCI close",WarnEnterColor);
	      lastbarwrite = iTimeTF;
      }   
      return(false);
   }

   if (!donotcheck && channel_width != 0 && channel_width < Min_Volatility*old_point) { //channel width filter
      if (LogMode < 2 && lastbarwrite != iTimeTF) {
         string q = Symbol() + "| Current channel width: (" + DoubleToString(channel_width/old_point, 1) + " points) less than the minimum channel width: " + DoubleToString(Min_Volatility, 1) + ". Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("filter channel width",WarnEnterColor);
	      lastbarwrite = iTimeTF;
      }   
      return(false);
   }
   if (!donotcheck && Max_Volatility>0 && channel_width > Max_Volatility*old_point) { //filter by maximum channel width
      if (LogMode < 2 && lastbarwrite != iTimeTF) {
         string q = Symbol() + "| Current channel width: (" + DoubleToString(channel_width/old_point, 1) + " points) greater than the maximum channel width: " + DoubleToString(Max_Volatility, 1) + " Order " + _OrderType + " was not open.";
         Print(q); fWriteDataToFile(q);
         DrawWarn("filter max channel width",WarnEnterColor);
	      lastbarwrite = iTimeTF;
      }   
      return(false);
   }
   if (!donotcheck && maxcandle > 0 && barcount > 0) { 
      double candlehl=0;
      double candlerange=0;
      if (OP_TYPE==OP_BUY) {
         candlehl=iHigh(NULL,TimeFrame,iHighest(NULL,TimeFrame,MODE_HIGH,barcount,0));
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iHigh",candlehl)) { SetTimer(1);return(false); }
         #endif
         candlerange=candlehl-Ask;
         }
      if (OP_TYPE==OP_SELL) {
         candlehl=iLow(NULL,TimeFrame,iLowest(NULL,TimeFrame,MODE_LOW,barcount,0));
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iLow",candlehl)) { SetTimer(1);return(false); }
         #endif   
         candlerange=Bid-candlehl;
         }
      if (candlerange>maxcandle*old_point) {   
//      if (((OP_TYPE==OP_BUY) && (candlehl-Ask>maxcandle*old_point)) ||
//         ((OP_TYPE==OP_SELL) && (Bid-candlehl>maxcandle*old_point))) {
      //if ((candle() > maxcandle*old_point)){ // Filter by size of previous candles
         if (LogMode < 2 && lastbarwrite != iTimeTF) {
            //string q = Symbol() + "| Found candle for previous " + IntegerToString(barcount) + " bars, more " + DoubleToString(maxcandle, 1) + " points. Order " + _OrderType + " was not open.";
            string q = Symbol() + "| Price movement range for the previous " + IntegerToString(barcount) + " bars "+_period+" (" + DoubleToString(candlerange/old_point, 1) + " points) more " + DoubleToString(maxcandle, 1) + " points. Order " + _OrderType + " was not open.";
            Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
            DrawWarn("filter maxcandle",WarnEnterColor);
	         lastbarwrite = iTimeTF;
         }   
         return(false);
      }   
   }
   if (!donotcheck && maxcandle2 > 0 && barcount2 > 0) { 
      double candlehl=0;
      double candlerange=0;
      if (OP_TYPE==OP_BUY) {
         candlehl=iHigh(NULL,TimeFrame,iHighest(NULL,TimeFrame,MODE_HIGH,barcount2,0));
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iHigh",candlehl)) { SetTimer(1);return(false); }
         #endif
         candlerange=candlehl-Ask;
         }
      if (OP_TYPE==OP_SELL) {
         candlehl=iLow(NULL,TimeFrame,iLowest(NULL,TimeFrame,MODE_LOW,barcount2,0));
         #ifndef FOR_TESTER   
            if (_RealTrade) if (IsError("iLow",candlehl)) { SetTimer(1);return(false); }
         #endif   
         candlerange=Bid-candlehl;
         }
      if (candlerange>maxcandle2*old_point) {   
//      if (((OP_TYPE==OP_BUY) && (candlehl-Ask>maxcandle2*old_point)) ||
//         ((OP_TYPE==OP_SELL) && (Bid-candlehl>maxcandle2*old_point))) {
      //if ((candle() > maxcandle2*old_point)){ // Filter by size of previous candles
         if (LogMode < 2 && lastbarwrite != iTimeTF) {
            //string q = Symbol() + "| Found candle for previous " + IntegerToString(barcount2) + " bars, more " + DoubleToString(maxcandle2, 1) + " points. Order " + _OrderType + " was not open.";
            string q = Symbol() + "| Price movement range for the previous " + IntegerToString(barcount2) + " bars "+_period+" (" + DoubleToString(candlerange/old_point, 1) + " points) more " + DoubleToString(maxcandle2, 1) + " points. Order " + _OrderType + " was not open.";
            Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
            DrawWarn("filter maxcandle2",WarnEnterColor);
	         lastbarwrite = iTimeTF;
         }   
         return(false);
      }   
   }   
   if (!Hedging && opposite_order >= 1) { //no hedging filter
      if (LogMode < 2 && _TimeCurrent-lasttimewrite > 120) {
         string q = Symbol() + "| The hedging positions filter is enabled and an opposite trade is found. Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("filter hedge",WarnEnterColor);
	      lasttimewrite = _TimeCurrent;
      }   
      return(false);
   }   
   if(!donotcheck && (MaxDailyRange > 0 || MDR_Toward > 0)) { //MaxDailyRange filter
      int mdr_shift=0;
      double OpenD1;
      datetime timeopend1=DayStartTimeShift;
      if (TimeShift < 0 && _TimeCurrent > DayStartTimeShift+24*60*60 && (!CheckMDRAfter0 || (CheckMDRAfter0 && _DayOfWeekShift == 1 && SkipMDRAfter0OnMondays))) {
         timeopend1 = DayStartTimeShift+24*60*60;
         }
      if (/*TimeShift == 0 && */CheckMDRAfter0 && _TimeCurrent < StartTime && (!SkipMDRAfter0OnMondays || _DayOfWeekShift != 1)) {
         timeopend1 = DayStartTimeShift-24*60*60;
         }
      //if (CheckMDRAfter0 && _IsFirstSession) mdr_shift=1;
      //iOpenD1=iOpen(NULL,PERIOD_D1,mdr_shift);
      int barshift;
      int a=0;
      // there may not be a bar at exactly 0:00, then there will be an error
      do {
         barshift=iBarShift(NULL, _Period, timeopend1, true); 
         if (barshift==-1) timeopend1 -= 24*60*60; // if it falls on the weekend
         //if (barshift==-1) Print("BarShift = -1, timeopend1 = ",TimeToString(timeopend1));
         a++;
         } while (barshift == -1 && a < 5);
      if (barshift == -1) { /* Print("BarShift Error"); */ return(false); }
      OpenD1 = iOpen(NULL, _Period, barshift);
      #ifndef FOR_TESTER   
         if (_RealTrade) if (IsError("iOpen mdr",OpenD1)) { SetTimer(1); return(false); }
      #endif   
      double mdr = 0;
      double mdr_toward = 0;
      if (MDRFromHiLo) {
         if (OP_TYPE==OP_BUY) mdr = iHigh(NULL,0,iHighest(NULL,0,MODE_HIGH,barshift+1,0)) - Bid;
                         else mdr = Bid - iLow(NULL,0,iLowest(NULL,0,MODE_LOW,barshift+1,0));
         }  
      else 
         if (OP_TYPE==OP_BUY) mdr = OpenD1 - Bid;
                         else mdr = Bid - OpenD1;
      if (MDR_Toward_FromHiLo) {
         if (OP_TYPE==OP_BUY) mdr_toward = Bid - iLow(NULL,0,iLowest(NULL,0,MODE_LOW,barshift+1,0));
                         else mdr_toward = iHigh(NULL,0,iHighest(NULL,0,MODE_HIGH,barshift+1,0)) - Bid;
         }  
      else 
         if (OP_TYPE==OP_BUY) mdr_toward = Bid - OpenD1;
                         else mdr_toward = OpenD1 - Bid;
      //double mdr = OP_TYPE==OP_BUY ? OpenD1 - Bid : Bid - OpenD1;
      range=mdr;
      //if (mdr == 0) { Print("mdr = 0"); return(false); }
      if(MaxDailyRange > 0 && mdr > MaxDailyRange*old_point){
         if (LogMode < 2 && lastbarwrite != iTimeTF) {
            string q = Symbol() + "| Daily range of price movement: (" + DoubleToString(mdr/old_point, 1) + " points) , more MaxDailyRange: " + DoubleToString(MaxDailyRange,1) + " Order " + _OrderType + " was not open.";
            Print(q);
            DrawWarn("filter MDR",WarnEnterColor);
	         lastbarwrite = iTimeTF;
         }   
         return(false);
      }
      if(MDR_Toward > 0 && mdr_toward > MDR_Toward*old_point){
         if (LogMode < 2 && lastbarwrite != iTimeTF) {
            string q = Symbol() + "| Daily range of price movement in the direction of the transaction: (" + DoubleToString(mdr_toward/old_point, 1) + " points), more MDR_Toward: " + DoubleToString(MDR_Toward,1) + " Order " + _OrderType + " was not open.";
            Print(q);
            DrawWarn("filter MDR Toward",WarnEnterColor);
	         lastbarwrite = iTimeTF;
         }   
         return(false);
      }
   }
   #ifndef FOR_OPT
   if (UseNewsFilter) { //news filter
      if (lastnewsupdate1 != iTimeM1) {
         IsNews(_IsNews,_IsCloseBeforeNews);
         lastnewsupdate1 = iTimeM1;
         }
      if (_IsNews) {  
         if (LogMode < 2 && lastbarwrite != iTimeTF) {
            string q = Symbol() + "| News filter. Order " + _OrderType + " was not open.";
            Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
            DrawWarn("filter news",WarnEnterColor);
      	   lastbarwrite = iTimeTF;
         }   
         return(false);
      }
   }
   #endif

   if (_RealTrade && MaxAmountCurrency>0) { //filter by maximum allowed volume
      string Str,Str1,Str2;
      double MaxLot;
      MaxLot=MaxAmountCurrency;
      CheckArbitrage();
      Str1 = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
      Str2 = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);
      bool allow_by_max_amount=true;
      if (OP_TYPE==OP_BUY) {
         if (Volumes(Str1) >= MaxLot) { Str=Str1; allow_by_max_amount=false; }
         if (Volumes(Str2) <= -MaxLot) { Str=Str2; allow_by_max_amount=false; }
         }
      if (OP_TYPE==OP_SELL) {
         if (Volumes(Str1) <= -MaxLot) { Str=Str1; allow_by_max_amount=false; }
         if (Volumes(Str2) >= MaxLot) { Str=Str2; allow_by_max_amount=false; }
         }
      if (!allow_by_max_amount) {
         if (LogMode < 2 && lastbarwrite != Time[0]) {
            string q = Symbol() + "| Maximum number of transactions in one direction ("+DoubleToString(MaxLot,0)+") on " + Str + " will be exceeded." + " Order " + _OrderType + " was not open.";
            Print(q);
            DrawWarn("filter MaxAmountCurrency",WarnEnterColor);
   	      lastbarwrite = Time[0];
         }   
         return(false);      
      }
   }
   if (_RealTrade && MaxAmountCurrencyPair>0) { //filter by maximum allowed volume
      if (CountOrder2(OP_TYPE) >= MaxAmountCurrencyPair) {
         if (LogMode < 2 && lastbarwrite != Time[0]) {
            string q = Symbol() + "| Maximum number of transactions in one direction ("+IntegerToString(MaxAmountCurrencyPair)+") по " + _Symbol + " will be exceeded." + " Order " + _OrderType + " was not open.";
            Print(q);
            DrawWarn("filter MaxAmountCurrencyPair",WarnEnterColor);
   	      lastbarwrite = Time[0];
         }   
         return(false);      
      }
   }

   if (Max_Spread > 0 && (Ask - Bid) > Max_Spread*old_point && (CheckSpreadOnSellOpen || OP_TYPE==OP_BUY)) { //filter by maximum spread
      if (LogMode < 2 && _TimeCurrent-lasttimewrite > 60) {
         string q = Symbol() + "| Spread (" + DoubleToString((Ask - Bid) / old_point, 1) + " points) more than the maximum (" + DoubleToString(Max_Spread, 1) + ")! Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("filter spread",WarnEnterColor);
	      lasttimewrite = _TimeCurrent;
      }   
      return(false);
   }   
  
  
  
   if (pause > 0) { //if the last order is not closed in profit (or the loss is greater than the specified one)
      if (lastloss() != 0) { return(false); }
      }
         
   #ifndef FOR_TESTER
   if (!trading_allowed_global) {
      if (LogMode < 3 && lastbarwrite_allowtrade != iTimeTF) {
         string q = Symbol() + "| Trade prohibited based on global variables." + " Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("trade is not allowed",WarnEnterColor);
	      lastbarwrite_allowtrade = iTimeTF;
      }   
      return(false);
      }
   #endif   

   #ifndef FOR_TESTER
   if (!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) {
      if (LogMode < 3 && lastbarwrite_allowtrade != iTimeTF) {
         string q = Symbol() + "| Trading not allowed." + " Order " + _OrderType + " was not open.";
         Print(q); #ifndef FOR_TESTER    fWriteDataToFile(q); #endif
         DrawWarn("trade is not allowed",WarnEnterColor);
	      lastbarwrite_allowtrade = iTimeTF;
      }   
      return(false);
      }
   #endif   

   if(!donotcheck && ATR_Period > 0) {
      double atrValue = iATR(Symbol(), ATR_Timeframe, ATR_Period, 0);
      if(atrValue > Max_ATR_Pips * old_point) {
         string q = Symbol() + "| Current ATR: (" + DoubleToString(atrValue/old_point, 1) + " pips) is greater than the maximum ATR: " + DoubleToString(Max_ATR_Pips, 1) + " Order " + _OrderType + " was not open.";
         Print(q); fWriteDataToFile(q);
         DrawWarn("filter ATR",WarnEnterColor);
	      lastbarwrite = iTimeTF;
         return (false);
      }
   }
   if(!sp500Checker.IsAllowedByCrashFilter()) {
         fWriteDataToFile("SP500 crash detected");
         DrawWarn("SP500 Filter",WarnEnterColor);
	      lastbarwrite = iTimeTF;
         return (false);
   }
   
   if ((VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) && virtual_balance <= 0) { //virtual deposit filter
      if (LogMode < 2 && lastbarwrite != Time[0]) {
         string q = Symbol() + "| Virtual deposit = "+DoubleToString(virtual_balance,2)+" " + AccountInfoString(ACCOUNT_CURRENCY) + "." + " Order " + _OrderType + " was not open.";
         Print(q);
         DrawWarn("filter VirtualBalance",WarnEnterColor);
	      lastbarwrite = Time[0];
      }   
      return(false);      
   }

   bool res=false;
   
      res=OpenTrade(_OrderType, order_cnt);  //open a trade order
      if (res) {
         time_open = _TimeCurrent; 
         if (OP_TYPE == OP_BUY) consecutive_orders_buy++; else consecutive_orders_sell++;
         }
      
   return(res); 
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+      
bool OpenTrade(string type, int _orderCount){ //opening orders
   double price = 0;
   int cmd = -1;
   int err = 0;
   color col_type = clrNONE;
   
   lastbarwrite_allowtrade = 0;
   
   #ifndef FOR_TESTER
   double start_bid = Bid , start_ask = Ask;
   double start_price=0;
   if(type == "BUY") start_price = Ask;
   if(type == "SELL") start_price = Bid;
   Print(__FUNCTION__,": Open ",type," (Bid = ",DoubleToString(Bid,_Digits),", Ask = ",DoubleToString(Ask,_Digits),", Spread = ",DoubleToString((Ask-Bid)/old_point,1)," points), Time: ",TimeCurrent());
   #endif
   
   if(ATR_P>0) fATR(); 

      
   /*if (Auto_Risk > 0) */lots = AutoMM_Count(_orderCount); //trading lot calculation
   //else lots = Lots;
         
   if(type == "BUY"){
      cmd = OP_BUY;
      col_type = clrAqua;
      lots_opened_buy = lots;
   }
   if(type == "SELL"){
      cmd = OP_SELL;
      col_type = clrRed;
      lots_opened_sell = lots;
   }
   #ifndef FOR_TESTER
   string WorkTime=DoubleToString((GetMicrosecondCount()-OnTickStart)/1000.0,2);
   int order_count=CountOrder(cmd);
   for(int count = 0; count < 5; count++){
   #endif
      int ticket=0;
      uint st_time=0;
      #ifndef FOR_TESTER
      if (CountOrder(cmd)<=order_count) { 
      #endif
         RefreshRates();
         if(type == "BUY") price = Ask;
         if(type == "SELL") price = Bid;
         #ifndef FOR_TESTER
            st_time = GetTickCount();
            if (Bid != start_bid || Ask != start_ask) {
               Print(__FUNCTION__,": Open ",type,": Price changed: (Bid = ",DoubleToString(Bid,_Digits),", Ask = ",DoubleToString(Ask,_Digits),", Spread = ",DoubleToString((Ask-Bid)/old_point,1)," points), Time: ",TimeCurrent());
               }
            double diff = (cmd == OP_BUY ? price - start_price : start_price - price);
            if (diff > Slippage*_Point) {
               Print(__FUNCTION__,": ",type," trade could not be opened: Slippage (",DoubleToString(diff/old_point,1)," points) is more than "+DoubleToString(Slippage*_Point/old_point,1)," points.");
               return(false);
               }
         #endif
         ticket = OrderSend(Symbol(), cmd, lots, price, Slippage, 0, 0, Comm, MagicNumber, 0, col_type);   
      #ifndef FOR_TESTER
         //Sleep(3000);
         }
      else { // if an error was returned on the previous attempt, but the order was opened
         ticket=GetLastOrderTicket(cmd); // return the ticket of the last open order
         }   
      #endif
      if(ticket > 0){
         uint time = GetTickCount() - st_time;
         lastticket = ticket;
         if (VirtualSLTP) {
            ordersl[cmd]=0;
            ordertp[cmd]=0;
            }
         last_sl[cmd]=0;
   	   if(!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) {
		     if (LogMode < 3) {
   				string q = __FUNCTION__ + ": failed to allocate order " +
   						 IntegerToString(ticket) + "! " + fMyErDesc();
   				Print(q);
   				#ifndef FOR_TESTER
   				fWriteDataToFile(q);
   				#endif
   				//break;
		      }
         } else {
		     if (LogMode < 2) {
   				string q = __FUNCTION__ + ": order " + type + " open for price " + DoubleToString(OrderOpenPrice(),Digits) + "; Channel Width  = " + DoubleToString(channel_width/old_point,1) + "; DailyRange  = " + DoubleToString(range/old_point,1) + "; Spread = " + DoubleToString((Ask - Bid) / old_point, 1)+ " points.";
			   	Print(q);
   				#ifndef FOR_TESTER
   				double slip = (cmd == OP_BUY ? OrderOpenPrice() - price : price - OrderOpenPrice());
               Print(__FUNCTION__,": ",type," order #",OrderTicket()," opened: price = ",DoubleToString(OrderOpenPrice(),_Digits),", cmd = ",DoubleToString(price,_Digits),", slip = ",DoubleToString(slip/old_point,1)," points, delay = ",time," ms");
               BrokerStatWrite(ticket,"open","ea",NormalizeDouble(slip/old_point,1),time,WorkTime);
   				#endif
   				#ifndef FOR_TESTER
			   	fWriteDataToFile(q);
   				#endif
			   	//break;
   		   }
		   }
         return(true);
      } // ticket>0
      else {
         lastticket = 0;
         err=GetLastError();
         #ifndef FOR_TESTER
         if(err != ERR_INVALID_PRICE && err != ERR_PRICE_CHANGED && err != ERR_REQUOTE && err != ERR_OFF_QUOTES && err != ERR_TRADE_CONTEXT_BUSY) break;
         #endif
		   if (LogMode < 3) {
   		   string q = __FUNCTION__ + ": Order opening error " + type + ": " + fMyErDesc(err);
   		   Print(q);
   		   #ifndef FOR_TESTER
   		   fWriteDataToFile(q);
   		   #endif
		   }
         Sleep(3000);
      }
   #ifndef FOR_TESTER
   }
   #endif
   if (LogMode < 3) {
	   string q = __FUNCTION__ + ": order " + type + " was not open!: " + fMyErDesc(err);
	   Print(q);
	   #ifndef FOR_TESTER
	   fWriteDataToFile(q);
	   #endif
      }
   Sleep(3000);
   return(false);
}
//+------------------------------------------------------------------+          
//+------------------------------------------------------------------+
bool OrderCloseX(int ticket1, double lot, int otype, int slp, color clr=CLR_NONE){
    int err = 0; double price = 0; uint start=GetTickCount();
    bool exit_loop = false;
    bool res = false;

    int retry = 5;
    int cnt1   = 0;
    
   #ifndef FOR_TESTER
   double start_bid = Bid , start_ask = Ask;
   Print(__FUNCTION__,": Close ",(otype==OP_BUY ? "BUY" : "SELL")," #",ticket1,": (Bid = ",DoubleToString(Bid,_Digits),", Ask = ",DoubleToString(Ask,_Digits),", Spread = ",DoubleToString((Ask-Bid)/old_point,1)," points), Time: ",TimeCurrent());
   #endif
   
    string WorkTime=DoubleToString((GetMicrosecondCount()-OnTickStart)/1000.0,2);

   
    while(!exit_loop && cnt1<retry){
        RefreshRates();
        if(otype == OP_BUY)  price=Bid;
        if(otype == OP_SELL) price=Ask;
        #ifndef FOR_TESTER
            if (Bid != start_bid || Ask != start_ask) {
               Print(__FUNCTION__,": Close ",(otype==OP_BUY ? "BUY" : "SELL")," #",ticket1,": Price changed: (Bid = ",DoubleToString(Bid,_Digits),", Ask = ",DoubleToString(Ask,_Digits),", Spread = ",DoubleToString((Ask-Bid)/old_point,1)," points), Time: ",TimeCurrent());
               }
        #endif
        start=GetTickCount();
        if(!OrderClose(ticket1, lot, price, slp, clr)){
           err = GetLastError();
           switch(err){
             case ERR_INVALID_PRICE:
                  RefreshRates();
                  break;
             case ERR_REQUOTE:
                  RefreshRates();
                  break;
             case ERR_OFF_QUOTES:
                  RefreshRates();
                  break;
             case ERR_BROKER_BUSY:
                  break;
             default:
                  exit_loop = true;
                  break;
           }
           Sleep(1000);
           cnt1++;
        }else{
           err = 0;
           exit_loop = true;
        }
   }
   
   if(exit_loop && err == 0){ 
      uint time=GetTickCount()-start;
      retry = 10;     
      cnt1=0;
      exit_loop = false;
      
      while(!exit_loop && cnt1<retry){
         exit_loop = OrderSelect(ticket1, SELECT_BY_TICKET, MODE_HISTORY);
         if(exit_loop){
            double Slp = NormalizeDouble((OrderType()==OP_BUY ? price - OrderClosePrice() : OrderClosePrice() - price)/old_point,1); 
            Print(__FUNCTION__,": ",(OrderType()==OP_BUY ? "BUY" : "SELL")," order #",OrderTicket()," closed:"," price / cmd / slip / delay = ",DoubleToString(OrderClosePrice(),_Digits)," / ",DoubleToString(price,_Digits)," / ",DoubleToString(Slp,1)+" points / ",time," ms",", WorkTime = ",WorkTime," ms");
            BrokerStatWrite(ticket1,"close","ea",Slp,time,WorkTime);
            res = true;
         }else
            Sleep(1000);
         cnt1++;
      }
      if(!exit_loop) Print(Hour(),":",Minute()," | ",__FUNCTION__," ",fMyErDesc());
   }else      
      if(err != ERR_NO_ERROR && err != ERR_NO_RESULT) Print(__FUNCTION__," #",ticket1,": ",ErrorDescription(err));
      
  return res;    
}
//+------------------------------------------------------------------+          
//+------------------------------------------------------------------+
void CheckScale() {
   double checkScale = 1.0;
   if(GlobalVariableCheck("IncoGlobalRiskScale")) {
      checkScale = GlobalVariableGet("IncoGlobalRiskScale");
   } else {
      risk_scale = "";
   }
   if(MathAbs(checkScale - globalRiskScale) > DBL_EPSILON) {
      globalRiskScale = checkScale;
      risk_scale = "\n  Global Risk Scale: " + DoubleToString(globalRiskScale, 2);
      UpdateInfoPanel();
   }
}
double AutoMM_Count(int _orderCount) { //Lot calculation when specifying the risk percentage in the settings.
   double lot=Lots;
   double maxautorisklot = 0;
   if (Auto_Risk > 0.0) {
      if (MM_Depo == 0) { 
         double TickValue;
         int a=0;
         do {
            TickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
            a++;
            if (TickValue == 0) Sleep(500);
            } while (TickValue == 0 && a < 10);
         if (TickValue == 0) { Print("TickValue Error"); lot = MarketInfo(Symbol(), MODE_MINLOT); return(lot); }   
         double Balance = (::AccountInfoDouble(::ACCOUNT_EQUITY) > ::AccountInfoDouble(::ACCOUNT_BALANCE) ? ::AccountInfoDouble(::ACCOUNT_BALANCE) - ::AccountInfoDouble(::ACCOUNT_CREDIT) : ::AccountInfoDouble(::ACCOUNT_EQUITY) - ::AccountInfoDouble(::ACCOUNT_CREDIT));
         if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) Balance = virtual_balance;
         lot = (Balance * (Auto_Risk / 100)) / (Stop_Loss*old_point/_Point) / TickValue; 
         if (Max_Auto_Risk > 0 && Max_Auto_Risk >= Auto_Risk) maxautorisklot = (Balance * (Max_Auto_Risk / 100)) / (Stop_Loss*old_point/_Point) / TickValue; 
         //Print(lot + " " + StopLoss + " / " + MarketInfo(Symbol(), MODE_TICKSIZE)/0.00001);
         //return (lot);
         }
      else {
         double Balance = ::AccountInfoDouble(::ACCOUNT_BALANCE);
         if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) Balance = virtual_balance;      
         lot = NormalizeDouble(Lots * MathFloor(Balance/MM_Depo), 2);
         }
      } 
   
   if (LotMultAfterProfit > 0 || LotMultAfterLoss > 0) {
      double lastprofit,last_lots;
      double lot2=lot;
      getlastorderdata(lastprofit,last_lots);
      if (lastprofit > 0) { 
         if (LotMultAfterProfit > 0) lot2=last_lots*LotMultAfterProfit; else lot2=lot;
         }
      if (lastprofit <= LotMult_SizeLoss) { 
         if (LotMultAfterLoss > 0) lot2=last_lots*LotMultAfterLoss; else lot2=lot;
         }
      lot=lot2;
      }
   lot = lot * MathPow(MultLot, _orderCount);
   lot = NormalizeDouble(lot * globalRiskScale, 2);
   if (Max_Lots > 0 && lot>Max_Lots) lot=Max_Lots;
   if (maxautorisklot > 0 && lot>maxautorisklot) lot=maxautorisklot;
   if (MarketInfo(Symbol(), MODE_LOTSTEP) != 0) lot = MathFloor(lot/MarketInfo(Symbol(), MODE_LOTSTEP))* MarketInfo(Symbol(), MODE_LOTSTEP); //округление полученного лота вниз
   lot = MathMin(MathMax(lot, MarketInfo(Symbol(), MODE_MINLOT)), MarketInfo(Symbol(), MODE_MAXLOT)); //сравнение полученнго лота с минимальным/максимальным.
   return(lot);           
}

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void GetLastProfit(int ht){
   int changes=0;
   for(int iPos=ht-1; iPos >= 0; iPos--){
      if(OrderSelect(iPos, SELECT_BY_POS, MODE_HISTORY)==false){
         if (LogMode < 3) Print(Hour(),":",Minute()," | ",__FUNCTION__," ",fMyErDesc()); 
         continue;
      }
      if(OrderSymbol() != _Symbol || OrderMagicNumber() != MagicNumber) continue;
      
      if(OrderType() == OP_BUY){
         if(OrderCloseTime() > last_buy.time){
            ZeroMemory(last_buy);
            last_buy.time = OrderCloseTime();
            last_buy.profit = NormalizeDouble((OrderClosePrice() - OrderOpenPrice()) / old_point,1);
            changes++;
            if(_RealTrade){
               if(StringFind(OrderComment(), "[sl]", 0)!=-1){
                  last_buy.ticket = OrderTicket();
                  last_buy.sltp = "sl";
                  last_buy.slip = NormalizeDouble((OrderStopLoss() - OrderClosePrice())/old_point,1);
               }
               if(StringFind(OrderComment(), "[tp]", 0)!=-1){
                  last_buy.ticket = OrderTicket();
                  last_buy.sltp = "tp";
                  last_buy.slip = NormalizeDouble((OrderTakeProfit() - OrderClosePrice())/old_point,1);
               }
            }
         }
      }else{
         if(OrderCloseTime() > last_sell.time){
            ZeroMemory(last_sell);
            last_sell.time = OrderCloseTime();
            last_sell.profit = NormalizeDouble((OrderOpenPrice() - OrderClosePrice()) / old_point,1);
            changes++;
            if(_RealTrade){
               if(StringFind(OrderComment(), "[sl]", 0)!=-1){
                  last_sell.ticket = OrderTicket();
                  last_sell.sltp = "sl";
                  last_sell.slip = NormalizeDouble((OrderClosePrice() - OrderStopLoss())/old_point,1);
               }
               if(StringFind(OrderComment(), "[tp]", 0)!=-1){
                  last_sell.ticket = OrderTicket();
                  last_sell.sltp = "tp";
                  last_sell.slip = NormalizeDouble((OrderClosePrice() - OrderTakeProfit())/old_point,1);
               }
            }
         }
      }
   }
   
   ResetLastError();
   
   if(changes>0){
      //if(LogMode < 2) Print(__FUNCTION__,", LastBuyProfit: ",DoubleToString(last_buy.profit,1)," pips, LastSellProfit: ",DoubleToString(last_sell.profit,1)," pips");
      
      if(last_buy.ticket>0){
         if(LogMode < 2) Print(__FUNCTION__,", LastBuy: ",DoubleToString(last_buy.profit,1)," pips [",last_buy.sltp,"], slip = ",DoubleToString(last_buy.slip,1));
         BrokerStatWrite(last_buy.ticket,"close",last_buy.sltp,last_buy.slip,0,"0");
      }
      
      if(last_sell.ticket>0){
         if(LogMode < 2) Print(__FUNCTION__,", LastSell: ",DoubleToString(last_sell.profit,1)," pips [",last_sell.sltp,"], slip = ",DoubleToString(last_sell.slip,1));
         BrokerStatWrite(last_sell.ticket,"close",last_sell.sltp,last_sell.slip,0,"0");
      }
   }
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int lastloss()
{   
   int signal = 0; 
   int oldticket = 0;
   int ticket = 0;
   double priceopen = 0;
   double priceclose = 0;
   datetime closetime = 0;
   int otype = -1;   
    
   if ((bool)::MQLInfoInteger(::MQL_TESTER) || (bool)::MQLInfoInteger(::MQL_OPTIMIZATION)) {
   	if (lastticket > 0) {
   		oldticket = lastticket;
   	} else {
   	   if (LogMode < 2) {Print(__FUNCTION__ + ": no previously closed orders found, function skipped");}
   	}
   } 
   else {    
   	if (OrdersHistoryTotal() != lasthistorytotal) {
   		lasthistorytotal = OrdersHistoryTotal();
   		for(int i=lasthistorytotal;i>=1;i--) {
   	      if(OrderSelect(i-1,SELECT_BY_POS,MODE_HISTORY)) {
   	         if (TimeCurrent() - OrderCloseTime() > 60*60*24*14) break; //if the order is older than 2 weeks - stop searching.
   				if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
   				   ticket = OrderTicket();
                  if (ticket > oldticket) oldticket = ticket;			   
   	         }                 
   	      }
            else {
      	      if (LogMode < 3) {
   			      string q = (__FUNCTION__ + ": order not selected. Order selection error.");
                  Print(q);
                  #ifndef FOR_TESTER
                  fWriteDataToFile(q);
                  #endif
               }
            }		 
         }
   	} 
   	else {
   		if (lastticket > 0) oldticket = lastticket; // "The EA has not opened any orders yet" - not right. The last order could have been opened with an error, while the penultimate order could have been opened without an error.
   		else if (LogMode < 2) {/*Print("The EA has not opened any orders yet, the function "+__FUNCTION__ +" missed.");*/ return(0);}
   	}
   }
   
   if (oldticket > 0) {
   	 if(OrderSelect(oldticket,SELECT_BY_TICKET) && OrderCloseTime() != 0) {
   		if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
   		   priceopen = OrderOpenPrice();
   		   priceclose = OrderClosePrice();               
   		   closetime = OrderCloseTime();
   		   otype = OrderType();
   		}  
   		else {
   			if (LogMode < 3) {
   			   string q = (__FUNCTION__ + ": information about the last order does not match the parameters of the adviser.");
               Print(q);
               #ifndef FOR_TESTER
               fWriteDataToFile(q);   			   
               #endif
   			}
   		}
      }
   } 
   else {
   	if (OrdersHistoryTotal() > 0 && LogMode < 2) {Print(__FUNCTION__ + ": previous order ticket not found. Perhaps the adviser has not opened orders before.");}
   }
   
   if (otype == OP_BUY && priceopen-priceclose > sizeloss*old_point && TimeCurrent()-closetime < pause*60) signal = 1;
   
   if (otype == OP_SELL && priceclose-priceopen > sizeloss*old_point && TimeCurrent()-closetime < pause*60) signal = 2;        
   
   if (signal > 0) {
      if (LogMode<2 && lastbarwrite != Time[0]) {

         string q1 = __FUNCTION__ + ": The filter by the loss of the last closed order was triggered. New order has not been opened.";
         string q2 = __FUNCTION__ + ": Until the possibility of opening a new order left " + DoubleToString(pause-(TimeCurrent()-closetime)/60,0)+" minutes";
 
         Print(q1);
         Print(q2);
         #ifndef FOR_TESTER
         fWriteDataToFile(q1);
         fWriteDataToFile(q2);
         #endif
         lastbarwrite = Time[0];
      }
      last_closetime = closetime;
   }
       
   return (signal);   
}

void getlastorderdata(double& profit, double& lot)
{   
   int signal = 0; 
   int oldticket = 0;
   int ticket = 0;
   double priceopen = 0;
   double priceclose = 0;
   datetime closetime = 0;
   int otype = -1;   
    
   if ((bool)::MQLInfoInteger(::MQL_TESTER) || (bool)::MQLInfoInteger(::MQL_OPTIMIZATION)) {
   	if (lastticket > 0) {
   		oldticket = lastticket;
   	} else {
   	   if (LogMode < 2) {Print(__FUNCTION__ + ": no previously closed orders found, function skipped");}
   	}
   } 
   else {    
   	if (OrdersHistoryTotal() != lasthistorytotal2) {
   		lasthistorytotal2 = OrdersHistoryTotal();
   		for(int i=lasthistorytotal2;i>=1;i--) {
   	      if(OrderSelect(i-1,SELECT_BY_POS,MODE_HISTORY)) {
   	         if (TimeCurrent() - OrderCloseTime() > 60*60*24*14) break; //if the order is older than 2 weeks - stop searching.
   				if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
   				   ticket = OrderTicket();
                  if (ticket > oldticket) oldticket = ticket;			   
   	         }                 
   	      }
            else {
      	      if (LogMode < 3) {
   			      string q = (__FUNCTION__ + ": order not selected. Order selection error.");
                  Print(q);
                  #ifndef FOR_TESTER
                  fWriteDataToFile(q);
                  #endif
               }
            }		 
         }
   	} 
   	else {
   		if (lastticket > 0) oldticket = lastticket; // "The EA has not yet opened any orders" - incorrect. The last order could be opened with an error, and the penultimate one - without an error.
   		else if (LogMode < 2) {/*Print("The EA has not opened any orders yet, the function "+__FUNCTION__ +" missed.");*/ return;}
   	}
   }
   
   if (oldticket > 0) {
   	 if(OrderSelect(oldticket,SELECT_BY_TICKET) && OrderCloseTime() != 0) {
   		if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
   		   priceopen = OrderOpenPrice();
   		   priceclose = OrderClosePrice();               
   		   closetime = OrderCloseTime();
   		   otype = OrderType();
   		   lot = OrderLots();
   		}  
   		else {
   			if (LogMode < 3) {
   			   string q = (__FUNCTION__ + ": information about the last order does not match the parameters of the adviser.");
               Print(q);
               #ifndef FOR_TESTER
               fWriteDataToFile(q);   			   
               #endif
   			}
   		}
      }
   } 
   else {
   	if (OrdersHistoryTotal() > 0 && LogMode < 2) {Print(__FUNCTION__ + ": previous order ticket not found. Perhaps the adviser has not opened orders before.");}
   }
   
   if (otype == OP_BUY) profit = NormalizeDouble((priceclose - priceopen) / old_point,1);
   if (otype == OP_SELL) profit = NormalizeDouble((priceopen - priceclose) / old_point,1);
   
}

Stats CountVirtualBalance(double& virt_balance, double& virt_profit)
{   
   Stats stats1;
   ZeroMemory(stats1);

   /*#ifdef FOR_TESTER
   virt_profit = AccountProfit();
   if (VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0) {
      if (VirtualDepoPercent == 0) virt_balance = VirtualDepoForAutoRisk + AccountProfit();
      else virt_balance = ::AccountInfoDouble(::ACCOUNT_BALANCE) * VirtualDepoPercent / 100.0;
      }
   return(stats1);   
   #endif*/

   //#ifndef FOR_TESTER
   stats1.startdate=_TimeCurrent;
   
   virt_balance = VirtualDepoForAutoRisk;  
   
   if (VirtualDepoPercent > 0) {
      // calculate initial deposit at startdate
      virt_balance = ::AccountInfoDouble(::ACCOUNT_BALANCE);
		int lasthistorytotal3 = OrdersHistoryTotal();
		for(int i=lasthistorytotal3;i>=1;i--) {
	      if(OrderSelect(i-1,SELECT_BY_POS,MODE_HISTORY)) {
	         if (OrderCloseTime() < VirtualDepoStartDate) continue;
				if((OrderType() == 6) || (OrderType() == OP_BUY) || (OrderType() == OP_SELL)) {
   		      virt_balance -= OrderProfit()+OrderCommission()+OrderSwap();
	         }                 
	      }
      }   
      }    
      
      virt_profit = 0;
      double virt_profit_pips = 0;
      
	//if (OrdersHistoryTotal() != lasthistorytotal3) {
		int lasthistorytotal3 = OrdersHistoryTotal();
		for(int i=lasthistorytotal3;i>=1;i--) {
	      if(OrderSelect(i-1,SELECT_BY_POS,MODE_HISTORY)) {
	         if (OrderCloseTime() < VirtualDepoStartDate) continue;
				if((VirtualDepoPercent > 0 && OrderType() == 6) || (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType()<=OP_SELL)) {
				   double order_profit=OrderProfit()+OrderCommission()+OrderSwap();
   		      virt_balance += order_profit;
   		      if (OrderType() != 6) {
   		         virt_profit += order_profit;
   		         virt_profit_pips += (OrderType() == OP_BUY ? OrderClosePrice() - OrderOpenPrice() : OrderOpenPrice() - OrderClosePrice()) / old_point;
   		         if (OrderCloseTime()<stats1.startdate) stats1.startdate = OrderCloseTime();
   		         stats1.trades++;
   		         if (order_profit > 0) stats1.gross_profit += order_profit; else stats1.gross_loss += order_profit;
   		         }
	         }                 
	      }
      }
	//} 
	if (stats1.gross_loss!=0) stats1.pf = stats1.gross_profit / -stats1.gross_loss;
	if (stats1.trades != 0) stats1.expectancy = virt_profit / stats1.trades;
	if (stats1.trades != 0) stats1.expectancy_pips = virt_profit_pips / stats1.trades;
	stats1.profit_pips = virt_profit_pips;
	
	if (VirtualDepoPercent > 0 && virt_balance != 0) {
	   virt_balance = virt_balance * VirtualDepoPercent / 100.0;
	   }
	   
	return(stats1);
	//#endif
}

double CountOpenedProfit(double& _pips, double& _lots) {
   double profit = 0;
   _pips=0;
   _lots=0;
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
      if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
      
      profit += OrderProfit() + OrderCommission() + OrderSwap();
      _pips += (OrderType()==OP_BUY?Bid-OrderOpenPrice():OrderOpenPrice()-Ask);
      _lots += OrderLots();
   }
   _pips /= old_point;
   return(profit);
}

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
/*double candle()
{
   double c = 0;
   for (int i = 0; i<=barcount; i++) {
      if (iHigh (NULL,TimeFrame,i)-iLow(NULL,TimeFrame,i)>= c) c = iHigh(NULL,TimeFrame,i)-iLow(NULL,TimeFrame,i);
   }
return (c);
}*/

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void fTrailingStopFunc(){
   
   double tr_start = Trail_Start*old_point;
   double tr_size = Trail_Size*old_point;
   double tr_step = MathMax(Trail_Step*old_point, MarketInfo(Symbol(),MODE_TICKSIZE)*old_point);
   
   if(OrderType() == OP_BUY){
      double tr_pos=Bid - tr_size;
      if (((Trail_Minutes > 0 && _TimeCurrent - OrderOpenTime() > 60*Trail_Minutes) || (Trail_Start > 0 && Bid-OrderOpenPrice()>=tr_start)) && tr_pos-OrderStopLoss()>=tr_step && (!Trail_From_BE_Line || Bid-OrderOpenPrice()>=tr_size)) {
         fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(tr_pos,Digits),OrderTakeProfit(),0,clrGreen);
         return;
         }
      /*if(OrderStopLoss() < OrderOpenPrice() && Bid - OrderOpenPrice() >= tr_start){ //если SL еще не двигали
         fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(Bid - tr_start,Digits),OrderTakeProfit(),0,clrGreen);
         return;
      }
      if(OrderStopLoss() >= OrderOpenPrice()){ //если SL уже двигали
         double dif = Bid - OrderStopLoss() - tr_size;
         if(dif >= tr_step)
            fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderStopLoss() + dif,Digits),
                              OrderTakeProfit(),0,clrGreen);
         return;
      }*/
   }
   else if(OrderType() == OP_SELL){
      double tr_pos=Ask + tr_size;
      if (((Trail_Minutes > 0 && _TimeCurrent - OrderOpenTime() > 60*Trail_Minutes) || (Trail_Start > 0 && OrderOpenPrice()-Ask>=tr_start)) && OrderStopLoss()-tr_pos>=tr_step && (!Trail_From_BE_Line || OrderOpenPrice()-Ask>=tr_size)) {
         fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(tr_pos,Digits),OrderTakeProfit(),0,clrGreen);
         return;
         }
      /*if(OrderStopLoss() > OrderOpenPrice() && OrderOpenPrice() - Ask >= tr_start){ //если SL еще не двигали
         fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(Ask + tr_start,Digits),OrderTakeProfit(),0,clrTomato);
         return;
      }
      if(OrderStopLoss() <= OrderOpenPrice()){ //если SL уже двигали
         double dif = OrderStopLoss() - Ask - tr_size;
         if(dif >= tr_step)
            fModifyPosition(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderStopLoss() - dif,Digits),
                              OrderTakeProfit(),0,clrTomato);
         return;
      }*/
   }
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void fModifyPosition(int ticket,double price,double sl,double tp,datetime expir = 0,color col = clrNONE){
   #ifndef FOR_TESTER
   if (!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) return;
   #endif
   if (!VirtualSLTP) {  
   if (sl == OrderStopLoss() && tp == OrderTakeProfit()) return;
   if(!OrderModify(ticket, price, sl, tp, expir, col)){
	   if (LogMode < 3) {
		  string q = __FUNCTION__ + ": failed to modify order #" +
					  IntegerToString(ticket) + "! " + fMyErDesc();
		  Print(q);
		  #ifndef FOR_TESTER
		  fWriteDataToFile(q);
		  #endif
	   }
   }
   }
      if (VirtualSLTP) {
      ordersl[OrderType()]=sl;
      ordertp[OrderType()]=tp;
      return;
      }
   Sleep(1000);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int fGetCCISignal(int period,ENUM_APPLIED_PRICE typeprice,int toplevel,int sh){
   double cci = iCCI(NULL,TimeFrame_CCI,period,typeprice,sh);
   if(cci > toplevel) return(OP_SELL);
   if(cci < -toplevel) return(OP_BUY);
   return(-1);
}
//+------------------------------------------------------------------+
//    returns TRUE if it is rollover time                 +
//    otherwise - FALSE                                                   +
//+------------------------------------------------------------------+
bool fGetRollOver(void){
   //if(use_rollover_filter) { //Do not open trades in rollover.
      if(rtime1 > rtime2){
         if ((_TimeCurrent >= rtime1 && _TimeCurrent < rtime2+60*60*24) || (_TimeCurrent >= rtime1-60*60*24 && _TimeCurrent < rtime2)) { 
//         if(_TimeCurrent >= rtime1 || _TimeCurrent < rtime2)
            return(true);
      }
   }  
      else{
         if(_TimeCurrent >= rtime1 && _TimeCurrent < rtime2)
            return(true);
      }
   //}
   return(false);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
string timestr(int h,int m) {
   int hh=h;
   if (hh==24) hh=0;
   string h1,m1;
   h1=IntegerToString(hh,2,'0');
   m1=IntegerToString(m,2,'0');
   return h1+":"+m1;
}
//+------------------------------------------------------------------+
string PeriodString(int period) {
   string s = "";
   switch(period){
      case PERIOD_M1:   s = "M1"; break;
      case PERIOD_M5:   s = "M5"; break;
      case PERIOD_M15:  s = "M15"; break;
      case PERIOD_M30:  s = "M30"; break;
      case PERIOD_H1:   s = "H1"; break;
      case PERIOD_H4:   s = "H4"; break;
      case PERIOD_D1:   s = "D1"; break;
      case PERIOD_W1:   s = "W1"; break;
      case PERIOD_MN1:  s = "MN1"; break;
   }
   return(s);
}
//+------------------------------------------------------------------+
string fInfoTradeHours(){

int day=DayOfWeek();
string str="",dayupcase;
//bool showday;

dayupcase=daystring[day];
StringToUpper(dayupcase);

str  = "\n  "+dayupcase+"    (GMT "+StringFormat("%+d",GMT_Offset)+", DST " + dstStr[DSTMode] + ")";
//str  = "\n                 "+dayupcase;
//showday = (DayStart[day] != DayEnd[day]) || (DayStart[day] != day);
   if((Month() == 12 && Day() > LastTradeDayDecember) 
   || (Month() == 1 && Day() < FirstTradeDayJanuary)) {
      str += "\n  Merry Christmas!!!\n";
   }

if (DisableTradeOnHolidays && IsAroundHoliday(_TimeCurrent)) {
   str += "\n No trade on holliday \n";
}

if ((First_StartTimeStr != First_EndTimeStr) ||
   (Second_StartTimeStr != Second_EndTimeStr)) {
   if (First_StartTimeStr != First_EndTimeStr) {
      str += "\n  First Session:     " + First_StartTimeStr + " - " + First_EndTimeStr;
      }
   else str += "\n"; 
   
   if (Second_StartTimeStr != Second_EndTimeStr) {
      str += "\n  Second Session: " + Second_StartTimeStr + " - " + Second_EndTimeStr;
      }
   else str += "\n"; 
   }
else {
   str += "\n  No trade today\n";
   }

/*if (First_StartTimeStr[day] != First_EndTimeStr[day]) {
   str += "\n  Start Time: " + First_StartTimeStr[day];
   if (showday)    str += ", "+daystring[DayStart[day]];
   str += "\n  End Time:  " + First_EndTimeStr[day];
   if (showday)    str += ", "+daystring[DayEnd[day]];
   }
else {
   str += "\n  No trade today\n";
   }*/
   
return(str);
                  
}

//+------------------------------------------------------------------+
bool IsTime()
{

   if (_TimeCurrent >= _DisableTimeStart && _TimeCurrent < _DisableTimeEnd) return(false);
   if((Month() == 12 && Day() > LastTradeDayDecember) 
   || (Month() == 1 && Day() < FirstTradeDayJanuary))
      return (false);
      
   if (DisableTradeOnHolidays && IsAroundHoliday(_TimeCurrent)) return (false);

//   switch(DayOfWeek())
//   {                         
//        case 1: return(IsNow(MONDAY_Start_Trade_Hour,MONDAY_Start_Trade_Minute,MONDAY_End_Trade_Hour,MONDAY_End_Trade_Minute)); 
//        case 2: return(IsNow(TUESDAY_Start_Trade_Hour,TUESDAY_Start_Trade_Minute,TUESDAY_End_Trade_Hour,TUESDAY_End_Trade_Minute));
//        case 3: return(IsNow(WEDNESDAY_Start_Trade_Hour,WEDNESDAY_Start_Trade_Minute,WEDNESDAY_End_Trade_Hour,WEDNESDAY_End_Trade_Minute));
//        case 4: return(IsNow(THURSDAY_Start_Trade_Hour,THURSDAY_Start_Trade_Minute,THURSDAY_End_Trade_Hour,THURSDAY_End_Trade_Minute)); 
//        case 5: return(IsNow(FRIDAY_Start_Trade_Hour,FRIDAY_Start_Trade_Minute,FRIDAY_End_Trade_Hour,FRIDAY_End_Trade_Minute));
//        default: return(false);   
//        
//   }
   
   //_IsFirstSession=false;
   
/*   if(PrevDayStartTime > PrevDayEndTime) {
      if ((_TimeCurrent >= PrevDayStartTime && _TimeCurrent < PrevDayEndTime+60*60*24) || (_TimeCurrent >= PrevDayStartTime-60*60*24 && _TimeCurrent < PrevDayEndTime)) { 
         _IsFirstSession=true;
         return(true);
      }
   }*/
   if(PrevDayStartTime < PrevDayEndTime) {
      if (_TimeCurrent >= PrevDayStartTime && _TimeCurrent < PrevDayEndTime) { 
         //_IsFirstSession=true;
         return(true);
      }
   }

/*   if(StartTime > EndTime) {
      if ((_TimeCurrent >= StartTime && _TimeCurrent < EndTime+60*60*24) || (_TimeCurrent >= StartTime-60*60*24 && _TimeCurrent < EndTime)) { 
         return(true);
      }
   }*/
   if(StartTime < EndTime) {
      if (_TimeCurrent >= StartTime && _TimeCurrent < EndTime) { 
         return(true);
      }
   }
   
   return(false);
}
//+------------------------------------------------------------------+
//bool IsNow(int Start_Trade_Hour, int Start_Trade_Minute, int End_Trade_Hour, int End_Trade_Minute)
//{
//
//   if(Start_Trade_Hour > End_Trade_Hour) {
//      if ((_TimeCurrent >= StartTime && _TimeCurrent < EndTime+60*60*24) || (_TimeCurrent >= StartTime-60*60*24 && _TimeCurrent < EndTime)) { 
//
//         return(true);
//      }
//   }
//   else if(Start_Trade_Hour < End_Trade_Hour) {
//      if (_TimeCurrent >= StartTime && _TimeCurrent < EndTime) { 
//
//         return(true);
//      }
//   }
//   
//   return(false);
//}

//+------------------------------------------------------------------+
//int fGetGMTOffset() {
//   int time = (int)(TimeCurrent() - TimeGMT());
//   double offset = time;
//   offset *= 0.01;
//   offset = MathCeil(offset) * 100;
//   offset = offset/3600;
//   int gmtoffset = (int)NormalizeDouble(offset,0);
//   return(gmtoffset);
//}

int fGetDSTShift() {
   if(DSTMode == DST_NEW_YORK)
      return (0);
   int shift = 0;
   if(IsSummerTime(DST_NEW_YORK))
      shift++;
   if(IsSummerTime(DSTMode))
      shift--;
   return (shift);
}

bool IsSummerTime(DstMode _mode) {
   int day = Day();
   int month = Month();
   int weekday = DayOfWeek();
   
   switch(_mode) {
   case DST_NEW_YORK:
      return ((month > 3 && month < 11) 
           || (month == 3 && day - weekday > 7) 
           || (month == 11 && weekday - day >= 0));
   case DST_EUROPE:
      return ((month > 3 && month < 10) 
           || (month == 3 && 31 - day + weekday < 7) 
           || (month == 10 && 31 - day + weekday >= 7));
   case DST_AUSTRALIA: //remember, in Australia June to August is winter!
      return((month < 4 || month > 10) 
            || (month == 4 && weekday - day >= 0) 
            || (month == 10 && day - weekday > 0));
   }      
   return (false);
}



//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|          Writes the string 's' to a file InpFileName             |
//+------------------------------------------------------------------+
void fWriteDataToFile(string s){

   if (!WriteLogFile) return;
   if((bool)::MQLInfoInteger(::MQL_TESTER) || (bool)::MQLInfoInteger(::MQL_OPTIMIZATION)) return;
   //--- open a file for writing data (if it does not exist, it will be created automatically)
   ResetLastError();
   string data = "";
   data = IntegerToString(Day()) + "." + IntegerToString(Month()) + "." + IntegerToString(Year()) + "  " +
         IntegerToString(Hour()) + ":" + IntegerToString(Minute());
   int file_handle = FileOpen(InpDirectoryName+"//"+InpFileName,FILE_TXT|FILE_READ|FILE_WRITE);
   if(file_handle != INVALID_HANDLE){
      PrintFormat("File %s is open for writing",InpFileName);
      PrintFormat("The path to the file: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
      
      FileSeek(file_handle,0,SEEK_END); //move the cursor to the end of the file
      
      s = data + "   " + s;
      
      //--- write values ​​to file
      FileWrite(file_handle,s);
      //--- close the file
      FileClose(file_handle);
      PrintFormat("Data written, file %s closed",InpFileName);
     }
   else PrintFormat("Failed to open file %s, " + fMyErDesc(),InpFileName);
}
//+------------------------------------------------------------------+ 
//| Creates a rectangular label                                      | 
//+------------------------------------------------------------------+ 
bool fRectLabelCreate(const long             chart_ID    = 0,                 // Graphic ID 
                      const string           name        = "RectLabel",       // label name 
                      const int              sub_window  = 0,                 // subwindow number
                      const int              x           = 0,                 // the X-axis coordinate 
                      const int              y           = 0,                 // the Y-axis coordinate
                      const int              width       = 50,                // width 
                      const int              height      = 18,                // height 
                      const color            back_clr    = C'236,233,216',    // background color 
                      const ENUM_BORDER_TYPE border      = BORDER_SUNKEN,     // border type 
                      const ENUM_BASE_CORNER corner      = CORNER_LEFT_UPPER, // corner of the graph to anchor
                      const color            clr         = clrRed,            // flat border color (Flat) 
                      const ENUM_LINE_STYLE  style       = STYLE_SOLID,       // flat border style 
                      const int              line_width  = 1,                 // flat border thickness 
                      const bool             back        = false,             // on the background 
                      const bool             selection   = false,             // set aside for travel 
                      const bool             hidden      = true,              // hidden in the object list 
                      const long             z_order     = 0)                 // mouse click priority
{ 
//--- reset the error value 
   ResetLastError(); 
   if(ObjectFind(chart_ID,name)==0) return true;
//--- create a rectangle 
   if(!ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0)) 
     { 
	  if (LogMode<3) {
		  Print(__FUNCTION__, 
				": Failed to create rectangle label! " + fMyErDesc()); 
      } 
	  return(false); 
     } 
//--- set marker coordinates
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
//---set label size 
   ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width); 
   ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height); 
//--- set background color 
   ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr); 
//--- set border type 
   ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border); 
//--- set the angle of the graph, relative to which the coordinates of the point will be determined 
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); 
//--- set the color of the flat border (in Flat mode) 
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
//--- set line style to flat frame 
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); 
//--- set the thickness of the flat border 
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width); 
//--- display in foreground (false) or background (true) 
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
//--- enable (true) or disable (false) the label moving mode by mouse 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); 
//--- hide (true) or display (false) the name of the graphical object in the list of objects 
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); 
//--- set the priority for receiving the mouse click event on the chart 
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); 
//--- successful execution 
   return(true); 
}
//+------------------------------------------------------------------+ 
//| Deletes a rectangular label                                      | 
//+------------------------------------------------------------------+ 
bool fRectLabelDelete(const long   chart_ID   = 0,           // Graphic ID 
                      const string name       = "RectLabel") // label name 
{ 
//--- reset the error value 
   ResetLastError(); 
//--- remove the label 
   if (ObjectFind(chart_ID,name) != -1) {
      if(!ObjectDelete(chart_ID,name)) 
        { 
   	  if (LogMode<3) {
   		  Print(__FUNCTION__, 
   				": failed to delete rectangular label! " + fMyErDesc()); 
   	  }	
         return(false); 
        }
    }   
//--- successful execution 
   return(true); 
}
//+------------------------------------------------------------------+
//| Creates a text label                                             | 
//+------------------------------------------------------------------+ 
bool fLabelCreate(const long             chart_ID=0,               // Graphic ID 
                 const string            name="Label",             // label name 
                 const int               sub_window=0,             // subwindow number
                 const int               x=0,                      // the X-axis coordinate
                 const int               y=0,                      // the Y-axis coordinate 
                 const string            text="Label",             // text 
                 const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // corner of the graph to anchor 
                 const string            font="Arial",             // font 
                 const int               font_size=10,             // font size
                 const color             clr=clrDarkBlue,          // color 
                 const double            angle=0.0,                // text slope 
                 const ENUM_ANCHOR_POINT anchor=ANCHOR_CENTER,     // binding method 
                 const bool              back=false,               // on the background 
                 const bool              selection=false,          // set aside for travel 
                 const bool              hidden=true,              // hidden in the object list
                 const long              z_order=0)                // mouse click priority 
  { 
//--- reset the error value  
   ResetLastError(); 
   if(ObjectFind(chart_ID,name)==0) return true;
//--- create a text label 
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) 
     { 
      Print(__FUNCTION__, 
            ": was unable to create a text label! Error code = ",GetLastError()); 
      return(false); 
     } 
//--- set marker coordinates 
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
//--- set the angle of the graph, relative to which the coordinates of the point will be determined 
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); 
//--- we will establish the text 
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text); 
//--- set the text font
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font); 
//--- set the font size 
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size); 
//--- set the angle of the text 
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle); 
//--- set binding method 
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor); 
//--- set the color 
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
//--- display in foreground (false) or background (true) 
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
//--- enable (true) or disable (false) the label moving mode by mouse  
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); 
//--- hide (true) or display (false) the name of the graphical object in the list of objects 
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); 
//--- set the priority for receiving the mouse click event on the chart 
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); 
//--- successful execution
   return(true); 
  } 
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+ 
//| Deletes a text label                                            | 
//+------------------------------------------------------------------+ 
bool fLabelDelete(const long   chart_ID=0,   // Graphic ID 
                 const string name="Label") // label name 
  { 
//--- reset the error value
   ResetLastError(); 
//--- remove the label
   if(!ObjectDelete(chart_ID,name)) 
     { 
      Print(__FUNCTION__, 
            ": failed to remove the text label! Error code = ",GetLastError()); 
      return(false); 
     } 
//--- successful execution 
   return(true); 
  }
//+------------------------------------------------------------------+ 

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK){
      if(sparam == "sell_btn"){
         if (MessageBox(StringFormat(string("Sell %.2f %s at %."+IntegerToString(_Digits)+"f?"),lots,_Symbol,Bid),"Generic A-TLP",MB_YESNO|MB_ICONQUESTION) != IDYES) return;
         lots = AutoMM_Count(CountOrder(OP_SELL));
         OpenTrade("SELL", CountOrder(OP_SELL));
         }
      if(sparam == "buy_btn"){
         if (MessageBox(StringFormat(string("Buy %.2f %s at %."+IntegerToString(_Digits)+"f?"),lots,_Symbol,Ask),"Generic A-TLP",MB_YESNO|MB_ICONQUESTION) != IDYES) return;
         lots = AutoMM_Count(CountOrder(OP_BUY));
         OpenTrade("BUY", CountOrder(OP_BUY));
         }
   }
}

//+------------------------------------------------------------------+
void DrawChannel(string dir, double pr1, color clr=clrYellow){ //drawing lines for BB channel entries

   if (Bars<2) return;
   string name=_Symbol+" "+dir+TimeToString(Time[0]);
   string name_prev=_Symbol+" "+dir+TimeToString(Time[1]);
   
   if(ObjectFind(name) < 0){
      double pr2 = pr1;
      if(ObjectFind(name_prev) == 0) pr2 = ObjectGetDouble(0,name_prev,OBJPROP_PRICE,1);
      
      ObjectCreate(name, OBJ_TREND,0,Time[1],pr2,Time[0],pr1);
      ObjectSet(name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false); 
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      //ObjectSet(name,OBJPROP_BACK,true);
      //ObjectSet(name,OBJPROP_SELECTABLE,false);
   }
}
//+------------------------------------------------------------------+
void DrawWarn(string text, color col){
   if(!VisualDebug) return;
   
   string obid=_Symbol+TimeToString(Time[0]);
   if(ObjectFind(obid)!=-1) ObjectDelete(obid);
   
   ENUM_ANCHOR_POINT anc;
   double price;

   if((WindowPriceMax()+WindowPriceMin())/2 < Bid){
      price=channel_lower-MathAbs(Entry_Break)*2*old_point;
      anc=ANCHOR_RIGHT;
   }else{
      price=channel_upper+MathAbs(Entry_Break)*2*old_point;
      anc=ANCHOR_LEFT;
   }
   
   ObjectCreate(obid, OBJ_TEXT, 0, Time[0], price);
   ObjectSet(obid, OBJPROP_ANGLE, 90);
   ObjectSet(obid,OBJPROP_ANCHOR,anc);
   ObjectSet(obid,OBJPROP_BACK,false);
   ObjectSetText(obid,text,10,"Arial",col);
}

void UpdateInfoPanel(){
   if(_RealTrade || (bool)::MQLInfoInteger(::MQL_VISUAL_MODE)){
      //if(day_of_trade != DayOfWeek()){
//         if(TP_perc > 0) tp_info = "\n  Dynamic Take Profit = " + IntegerToString(TP_perc) + "%";
//         else tp_info = "\n  Dynamic Take Profit: OFF";
         TradeHoursFirst = fInfoTradeHours();
         if (_RealTrade && MaxAmountCurrency>0) {
            if (LastUpdateTime<TimeCurrent()) {
               CheckArbitrage();
               LastUpdateTime=TimeCurrent();
               }
            }
      //   day_of_trade = DayOfWeek();
      //}

      if(showinfopanel) {
         string warn_trading="";
         if (SetEqSymbol) warn_trading="Set name [OK] "; else warn_trading=(AllowTrade?"Set Name [WARNING]":"Set Name Warning. Trade is disabled.");
         if (/*_IsTime && */!trading_allowed_global) warn_trading = "Trading is disabled by Global Variables";
         if (!(bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)) warn_trading = "Trading is disabled !!!";
         info_panel =
              "\n ----------------------------------------------------" 
            + "\n              Generic A-TLP v12.29.23" 
            + "\n ----------------------------------------------------";
         if (!ManualTrading) {  
         info_panel = info_panel
            + "\n  A FREE PRODUCT POWERED BY" 
            + "\n       http://TRADELIKEAPRO.ru";
            }
         else {   
         info_panel = info_panel
            + "\n"
            + "\n";
            }
         info_panel = info_panel   
            + "\n ----------------------------------------------------" 
            + "\n "+set_name_info
            + "\n "+warn_trading
            + "\n ----------------------------------------------------" 
            + TradeHoursFirst
            + "\n  ---------------------------------------------------"
//            + tp_info
            + "\n  Take Profit = " + (TP_perc > 0?"Dynamic, "+IntegerToString(TP_perc) + "%":DoubleToString(Take_Profit,1) + " pips")
            + "\n  Stop Loss = " + DoubleToString(Stop_Loss,1) + " pips"
            + be_info
            + "\n  ---------------------------------------------------"
            + "\n  Max Spread = " + maxspread /*+ (Max_Spread_On_Close>0?" / Close: "+DoubleToString(Max_Spread_On_Close,1):"")*/
            + "\n  Spread = " + DoubleToString((Ask - Bid) / old_point, 1) + " pips";

         if (Max_Spread > 0) {
            if (Ask - Bid > Max_Spread * old_point) info_panel = info_panel + " - HIGH !!!";
            else info_panel = info_panel + " - NORMAL";
            }
         info_panel = info_panel
            + risk_info
            + risk_scale
            + "\n  Max Orders = "+IntegerToString(TotalOrders) + (TotalOrders>1?", Distance = "+DoubleToString(OrdersDistance,1):"")
            + "\n  Trading Lots = " + DoubleToString(lots, 2) + (TotalOrders>1?"*" + IntegerToString(TotalOrders) + " = " + DoubleToString(lots*TotalOrders, 2):"") /*+(Hedging?", hedg = "+DoubleToString(lots*TotalOrders*2, 2):"")*/
            + "\n  ---------------------------------------------------";
         bool show_virt_balance=(VirtualDepoForAutoRisk > 0 || VirtualDepoPercent > 0);
         double balance=(show_virt_balance ? virtual_balance : ::AccountInfoDouble(::ACCOUNT_BALANCE));
         if (show_virt_balance) info_panel = info_panel
            + "\n  Virtual Balance: "+DoubleToString(balance,2)+" "+AccountInfoString(ACCOUNT_CURRENCY);
//            + "\n  Virtual Equity: "+DoubleToString(virtual_balance+opened_profit,2)+" "+AccountInfoString(ACCOUNT_CURRENCY)
         info_panel = info_panel
            + "\n  Profit: "+DoubleToString(virtual_profit,2)+" "+AccountInfoString(ACCOUNT_CURRENCY)+" / "+DoubleToString(stats.profit_pips,2)+" pips"
            + "\n  Trades: "+IntegerToString(stats.trades)
            + "\n  Profit Factor: "+DoubleToString(stats.pf,2)
            + "\n  Expectancy: "+DoubleToString(stats.expectancy,2)+" "+AccountInfoString(ACCOUNT_CURRENCY)+" / "+DoubleToString(stats.expectancy_pips,2)+" pips"
            + "\n  Start Date: "+TimeToString(stats.startdate,TIME_DATE)
            + "\n  ---------------------------------------------------";
         int cnt_order=CountOrder();
         double _pips,_lots;
         opened_profit = CountOpenedProfit(_pips,_lots);
         info_panel = info_panel
            + "\n  Opened Trades: "+(cnt_order==0?"None":IntegerToString(cnt_order))
            + "\n  "+(cnt_order==0?"":StringFormat("%.2f lots / %+.1f pips / %+.2f %s",_lots,_pips,opened_profit,AccountInfoString(ACCOUNT_CURRENCY)))
            + "\n  ---------------------------------------------------";
         info_panel = info_panel
            + filter_info
            + "\n  7. News Filter: "+(UseNewsFilter?"ON"+(_IsNews?", Activated":""):"OFF");
          if (MaxAmountCurrency>0)  { info_panel = info_panel 
               + "\n  ---------------------------------------------------"
               +CheckString();
               }
          if (MaxAmountCurrencyPair>0) { info_panel = info_panel 
               + "\n  ---------------------------------------------------"
               + "\n  " + _Symbol + " BUY count: "+IntegerToString(CountOrder2(OP_BUY))
               + "\n  " + _Symbol + " SELL count: "+IntegerToString(CountOrder2(OP_SELL));
               }
            info_panel = info_panel 
            + "\n  ---------------------------------------------------";
         previnfopanelcolor=infopanelcolor;   
         infopanelcolor=((bool)::MQLInfoInteger(::MQL_TRADE_ALLOWED)?Col_info:Col_info2);
         if (infopanelcolor != previnfopanelcolor) {
            ObjectSetInteger(0,"info_panel",OBJPROP_BGCOLOR,infopanelcolor); 
            }

         Comment(info_panel);
      }
   }
}

void fATR(){
   if(iBars(_Symbol, TimeFrame) < ATR_P+1){
      Print(Hour(),":",Minute()," | Error: Not enough loaded history for ATR");
      return;
   }
   double atr=iATR(_Symbol ,TimeFrame, ATR_P, 1);
   Stop_Loss=MathMin(MathMax(MathMax(NormalizeDouble(atr*10000*Coof_ATR,1),Min_SL), NormalizeDouble(stoplevel * _Point / old_point,1)), orig_stoploss);
}


int CountOrder(int Order_Type = -1) {
   int orders=0;
   
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
      if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
      
      if(Order_Type == OrderType() || Order_Type == -1) orders++;
   }
   
   if (orders == 0) {
      if (Order_Type == OP_BUY) consecutive_orders_buy = 0;
      if (Order_Type == OP_SELL) consecutive_orders_sell = 0;
      if (Order_Type == -1) { consecutive_orders_buy = 0; consecutive_orders_sell = 0; }
      }
   return orders;
}

double GetMaxMinOpenPrice(int ordertype,_MaxMin maxtype){
   double maxminprice=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
         if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         if ((ordertype != -1) && (OrderType() != ordertype)) continue;
         if (maxminprice==0) maxminprice=OrderOpenPrice();
         if ((maxtype==MAX) && (OrderOpenPrice()>maxminprice)) maxminprice=OrderOpenPrice();
         if ((maxtype==MIN) && (OrderOpenPrice()<maxminprice)) maxminprice=OrderOpenPrice();
      }
   return maxminprice;
}

datetime GetLastOpenTime(int ordertype){
   datetime opentime=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
         if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         if ((ordertype != -1) && (OrderType() != ordertype)) continue;
         if (opentime==0) opentime=OrderOpenTime();
         if  (OrderOpenTime()>opentime) opentime=OrderOpenTime();
      }
   return opentime;
}

datetime GetFirstOpenTime(int ordertype){
   datetime opentime=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
         if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         if ((ordertype != -1) && (OrderType() != ordertype)) continue;
         if (opentime==0) opentime=OrderOpenTime();
         if  (OrderOpenTime()<opentime) opentime=OrderOpenTime();
      }
   return opentime;
}

int GetLastOrderTicket(int ordertype){
   datetime opentime=0;
   int last_order_ticket=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
         if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         if ((ordertype != -1) && (OrderType() != ordertype)) continue;
         if (opentime==0) { opentime=OrderOpenTime();last_order_ticket=OrderTicket(); }
         if  (OrderOpenTime()>opentime) { opentime=OrderOpenTime(); last_order_ticket=OrderTicket(); }
      }
   return last_order_ticket;
}


double GetOrdersTotalProfit(int ordertype){
   double orderprofit=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
         if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         if ((ordertype != -1) && (OrderType() != ordertype)) continue;
         if (OrderType()==OP_BUY) { orderprofit += Bid - OrderOpenPrice(); }
         if (OrderType()==OP_SELL) { orderprofit += OrderOpenPrice() - Ask; }
      }
   return orderprofit;
}
   
double OnTester(){
  double coefr = 1.0;  
  double coeff = 1.0;  
  double coefe = 1.0;  
  double recf = 0;
  double MaxDD = TesterStatistics(STAT_EQUITY_DD);
  if (MaxDD != 0)
      recf = TesterStatistics(STAT_PROFIT) / MaxDD;
  double proff = TesterStatistics(STAT_PROFIT_FACTOR);
  double trades_number = TesterStatistics(STAT_TRADES);
  double expectancy=0;
  int trades = 0;
  
  double TickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
  for(int i=OrdersHistoryTotal();i>=1;i--) {
     if(OrderSelect(i-1,SELECT_BY_POS,MODE_HISTORY)) {
        if(OrderSymbol() != _Symbol || OrderMagicNumber() != MagicNumber || OrderType() > OP_SELL) continue;
         
        expectancy += (OrderProfit()+OrderCommission()+OrderSwap()) / OrderLots() * _Point / old_point / TickValue;
        trades++;
        }                 
     }
  if (trades > 0) expectancy /= trades;
  
    
  if (recf < DesiredRecoveryFactor && recf > 0)
  {
    coefr = pow((recf/DesiredRecoveryFactor), RecoveryFactor_Power);
  }
  if(proff < DesiredProfitFactor && proff > 1)
  {
    coeff = pow((proff / DesiredProfitFactor), ProfitFactor_Power);
  }
  if(expectancy < DesiredExpectancy && expectancy > 0)
  {
    coefe = pow((expectancy / DesiredExpectancy), Expectancy_Power);
  }
  
  
  Print("Expectancy, pips: ",DoubleToString(expectancy,2));
  Print("Recovery Factor: ",recf);
    
  double Res = recf * coefr * coeff * coefe;

  if (trades_number < MinTrades) Res = -1000;
        
  return Res;
}

template<typename T>
bool IsError(string fname, T val, bool skipif0=true) {
   bool result=false;
   int Error = GetLastError(); 
   if (Error == 4066 || Error == 4073 || Error == 4074 || (skipif0 && val == 0)) result=true;
   else if (Error != 0) { 
      Print(fname," Error ",Error,": ",ErrorDescription(Error)); 
      Print(fname," = ",val); 
      result=true;
      }
   //if (Error != 0 && result) Print("IsError(): error ",Error,", function ",fname);   
   return(result);
}

//+------------------------------------------------------------------+

double Volumes(string Str) {
   for (int i=0;i<NumOfCurrencies;i++)
      if (Currency[i] == Str) return(VolumesArray[i]);

   return(0);
}

void CheckArbitrage() {
   int i;
   string Str1, Str2;
   int vol1, vol2;
  
   for (i = 0; i < NumOfCurrencies; i++)
      VolumesArray[i] = 0;
  
   for (i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
      if (OrderType() > OP_SELL) continue;
      if (MaxAmount_SkipManualTrades && OrderMagicNumber() == 0) continue;
      
      Str1 = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_BASE);
      Str2 = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_PROFIT);
      
      vol1=-1;vol2=-1;
      for (int j=0;j<NumOfCurrencies;j++) {
         if (Currency[j] == Str1) vol1=j;
         if (Currency[j] == Str2) vol2=j;
         if (vol1 != -1 && vol2 != -1) break;
         }

      if (OrderType() == OP_BUY) {
         if (vol1 != -1) VolumesArray[vol1] += 1; //OrderLots();
         if (vol2 != -1) VolumesArray[vol2] -= 1; //OrderLots();
         }
      else if (OrderType() == OP_SELL) {
         if (vol1 != -1) VolumesArray[vol1] -= 1; //OrderLots();
         if (vol2 != -1) VolumesArray[vol2] += 1; //OrderLots();
         }
      }
  return;
}

string CheckString() {
   //int i,x=1;
   string S1 = "", S2 = "", S;
   string Str1=SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
   string Str2=SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);
   S1 = S1 + "Max"+Str1+ " count " + DoubleToString(MaxAmountCurrency, 0) + "   Max"+Str2+ " count " + DoubleToString(MaxAmountCurrency, 0);
   if (Volumes(Str1) != 0) S2 = S2 + Str1 + " count = " + DoubleToString(Volumes(Str1),0)+ "   ";
   if (Volumes(Str2) != 0) S2 = S2 + Str2 + " count = " + DoubleToString(Volumes(Str2),0)+ "   ";
/*  for (i = 0; i < AmountCurrency; i++)
    if (VolumesArray[i] != 0)
       {
      if(x%2 != 0 ) Str = Str + "\n  ";
      x++;
      Str = Str + Currency[i] + " count = " + DoubleToString(VolumesArray[i], 0) + "   ";
      }*/
   S = "\n  " + S1 + "\n  " + S2;   
   return(S);
}

int CountOrder2(int Order_Type) {
   int orders=0;
   
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false) continue;
      if(OrderSymbol()!=_Symbol || OrderType() > OP_SELL) continue;
      if (MaxAmount_SkipManualTrades && OrderMagicNumber() == 0) continue;      
   
      if(Order_Type == OrderType() || Order_Type == -1) orders++;
   }
   return orders;
}

//+------------------------------------------------------------------+
void fSetTPbyExitChannel(){
   stoplevel = /*(int)*/MarketInfo(_Symbol, MODE_STOPLEVEL)*_Point/old_point;
   mintpb = NormalizeDouble(Ask+MathMax(stoplevel,0.1)*old_point,_Digits);
   mintps = NormalizeDouble(Bid-MathMax(stoplevel,0.1)*old_point,_Digits);
   tpb = NormalizeDouble(channel_upper+Exit_Distance*old_point,_Digits);
   tps = NormalizeDouble(channel_lower-(Exit_Distance*old_point)+(OnlyBid?MathMin(Max_Spread_On_Close*old_point, (Ask-Bid)):0),_Digits);

   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false){ Print(Hour(),":",Minute()," | ",__FUNCTION__," ",fMyErDesc()); continue; }
      if(OrderSymbol()!=_Symbol || OrderMagicNumber() != MagicNumber) continue;
      double newtp=0;
      if(OrderType()==OP_BUY){
         newtp = MathMax(MathMax(tpb, OrderOpenPrice()+Exit_Profit_Pips*old_point), mintpb); 
         DrawEPP(OrderTicket(), OrderOpenPrice(), OrderOpenPrice()+Exit_Profit_Pips*old_point, OrderOpenTime());
         DrawHistoryTP(OrderTicket(), newtp);
         if(!CompareDoubles(newtp,OrderTakeProfit()))
            fModifyPosition(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), newtp, 0, clrWhite);
      }else
      if(OrderType() == OP_SELL){
         newtp = MathMin(MathMin(tps, OrderOpenPrice()-Exit_Profit_Pips*old_point), mintps); 
         DrawEPP(OrderTicket(), OrderOpenPrice(), OrderOpenPrice()-Exit_Profit_Pips*old_point, OrderOpenTime());
         DrawHistoryTP(OrderTicket(), newtp);
         if(!CompareDoubles(newtp,OrderTakeProfit()))
            fModifyPosition(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), newtp, 0, clrWhite);
      }
   }
}

void DrawEPP(int ticket, double pr1, double pr2, datetime time){
   string name=IntegerToString(ticket)+"_epp_"+TimeToString(Time[0]);
   string name2=IntegerToString(ticket)+"_eppline_"+TimeToString(time);
   if(ObjectFind(name) < 0){
      ObjectCreate(name, OBJ_ARROW, 0, Time[0], pr2);
      ObjectSet(name, OBJPROP_COLOR, clrSalmon);
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_BOTTOM);   
      ObjectSetInteger(0,name,OBJPROP_ARROWCODE, 4);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
   }
   if(ObjectFind(name2) < 0){
      ObjectCreate(0,name2,OBJ_TREND,0,time,pr2,time,pr1);
      ObjectSetInteger(0,name2,OBJPROP_RAY_RIGHT,false); 
      ObjectSet(name2, OBJPROP_COLOR, clrSalmon);
   }
}

void DrawHistoryTP(int ticket, double pr1, color clr=clrWhite){
   string name=IntegerToString(ticket)+"_tp_"+TimeToString(Time[0]);
   if(ObjectFind(name) < 0){
      ObjectCreate(name, OBJ_ARROW, 0, Time[0], pr1);
      ObjectSet(name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_BOTTOM);   
      ObjectSetInteger(0,name,OBJPROP_ARROWCODE, 4);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
   }
}

void DrawHistorySL(int ticket, double pr1, color clr=clrYellowGreen){
   string name=IntegerToString(ticket)+"_sl_"+TimeToString(Time[0]);
   if(ObjectFind(name) < 0){
      ObjectCreate(name, OBJ_ARROW, 0, Time[0], pr1);
      ObjectSet(name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_BOTTOM);   
      ObjectSetInteger(0,name,OBJPROP_ARROWCODE, 4);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
   }
}
//+------------------------------------------------------------------+
string fMyErDesc(int err=-1){
   int aErrNum;
   if(err == -1){
      aErrNum = GetLastError();
   }
   else{
      aErrNum = err;
   }

   string pref="Ошибка №: "+IntegerToString(aErrNum)+" - ";
   switch(aErrNum){
      case 0:   return(pref+"No error. Trade operation was successful.");
      case 1:   return(pref+"No error, but the result is unknown. (OrderModify tries " +
                              "change already set values ​​with the same values. " +
                              "You need to change one or more values ​​and try again.)");
      case 2:   return(pref+"General error. Cease all trading attempts before " +
                              "clarification of the circumstances. It is possible to restart the operating system " +
                              "system and client terminal.");
      case 3:   return(pref+"Invalid settings. Wrong values ​​passed to trade function " +
                              "parameters, e.g. wrong symbol, unidentified trading " +
                              "operation, negative price tolerance, " +
                              "non-existent ticket number, etc. You need to change the logic of the program.");
      case 4:   return(pref+"The trading server is busy. You can try again after enough " +
                              "a long period of time (from several minutes).");
      case 5:   return(pref+"Old version of the client terminal. You need to install " +
                              "the latest version of the client terminal.");
      case 6:   return(pref+"There is no connection to the trade server. You need to make sure the connection " +
                              "not violated (for example, using the IsConnected function) and " +
                              "after a short period of time (from 5 seconds) try again.");
      case 7:   return(pref+"Not enough rights.");
      case 8:   return(pref+"Too frequent requests. Reduce the frequency of requests " +
                              "change program logic.");
      case 9:   return(pref+"Invalid operation that breaks the server");
      case 64:  return(pref+"The account is blocked. It is necessary to stop all attempts to trade.");
      case 65:  return(pref+"Invalid account number. All attempts must be stopped. " +
                              "trading operations.");
      case 128: return(pref+"The transaction has expired. Before producing " +
                              "try again (at least after 1 minute), you must " +
                              "make sure that the trade did not really go through " +
                              "(a new position has not been opened, or an existing order is not " +
                              "was changed or deleted, or the existing position was not closed)");
      case 129: return(pref+"Wrong bid or ask price, possibly not normalized " +
                              "price. It is necessary to update after a delay of 5 seconds " +
                              "data using the RefreshRates function and try again. " +
                              "If the error persists, you must stop all attempts " +
                              "trading operations and change the logic of the program.");
      case 130: return(pref+"Wrong feet. Feet too close or wrong " +
                              "calculated or unnormalized prices in stops (or in " +
                              "pending order opening price). The attempt can be repeated " +
                              "only if the error was due to deprecation " +
                              "prices. It is necessary to update the data after a delay of 5 seconds " +
                              "using the RefreshRates function and try again. If " +
                              "the error does not disappear, you must stop all attempts " +
                              "trading operations and change the logic of the program.");
      case 131: return(pref+"Wrong volume, error in volume granulation. Necessary " +
                              "stop all attempts to trade and change the program logic.");
      case 132: return(pref+"The market is closed. You can try again after a sufficiently large " +
                              "period of time (from several minutes).");
      case 133: return(pref+"Trading is prohibited. It is necessary to stop all attempts to trade.");
      case 134: return(pref+"Insufficient funds to complete the transaction. Repeat trade " +
                              "with the same settings is not possible. You can try again after " +
                              "delays from 5 seconds by reducing the volume, but one must be sure of " +
                              "sufficiency of funds for the operation.");
      case 135: return(pref+"The price has changed. You can update the data without delay using " +
                              "RefreshRates function and try again.");
      case 136: return(pref+"No prices. Broker for some reason (for example, at the beginning of the session " +
                              "no prices, unconfirmed prices, fast market) did not give prices or " +
                              "refused. It is necessary to update the data after a delay of 5 seconds " +
                              "using the RefreshRates function and try again.");
      case 137: return(pref+"The broker is busy");
      case 138: return(pref+"New prices. Asked price is outdated or bid and " +
                              "ask. You can update the data without delay using the function " +
                              "RefreshRates and try again. If the error persists, " +
                              "it is necessary to stop all attempts to trade and change " +
                              "program logic.");
      case 139: return(pref+"The order has been blocked and is already being processed. . Need to stop " +
                              "all attempts to trade operations and change the logic of the program.");
      case 140: return(pref+"Only purchase is allowed. You cannot repeat the SELL operation.");
      case 141: return(pref+"Too many requests. Need to reduce the frequency " +
                              "requests, change the logic of the program.");
      case 142: return(pref+"The order has been queued. This is not an error, but one of the codes " +
                              "interaction between the client terminal and trading " +
                              "server. This code can be obtained in the rare event that " +
                              "when, during the execution of a trading operation, " +
                              "interruption and subsequent restoration of communication. Necessary " +
                              "handle the same as error 128.");
      case 143: return(pref+"The order has been accepted by the dealer for execution. One of the interaction codes " +
                              "between the client terminal and the trading server. Maybe " +
                              "occur for the same reason as code 142. It is necessary " +
                              "handle the same as error 128.");
      case 144: return(pref+"The order was canceled by the client himself upon manual confirmation " +
                              "deals. One of the interaction codes between the client " +
                              "terminal and trading server.");
      case 145: return(pref+"Modification is prohibited because the order is too close to " +
                              "market and blocked due to possible early execution. " +
                              "It is possible not earlier than after 15 seconds to update the data when " +
                              "help of the RefreshRates function and try again.");
      case 146: return(pref+"The trading subsystem is busy. Retry only after " +
                              "how the IsTradeContextBusy function returns FALSE.");
      case 147: return(pref+"The use of the order expiration date is prohibited by the broker. " +
                              "The operation can only be repeated if " +
                              "reset the expiration parameter.");
      case 148: return(pref+"The number of open and pending orders has reached the limit, " +
                              "set by the broker. New open positions and " +
                              "pending orders are possible only after closing or " +
                              "deleting existing positions or orders.");
      case 149: return(pref+"An attempt to open an opposite position to an existing one " +
                              "if hedging is prohibited. First you need " +
                              "close the existing opposite position, or refuse " +
                              "from all attempts of such trading operations, or change " +
                              "program logic.");
      case 150: return(pref+"Attempt to close a position on an instrument contrary to the rule FIFO");
      //---- Error codes of execution of an MQL4 program (EA)
      case 4000: return(pref+"No error");
      case 4001: return(pref+"Invalid function pointer");
      case 4002: return(pref+"Array index - out of range");
      case 4003: return(pref+"No memory for function stack");
      case 4004: return(pref+"Stack overflow after recursive call");
      case 4005: return(pref+"There is no memory on the stack to pass parameters");
      case 4006: return(pref+"Out of memory for string parameter");
      case 4007: return(pref+"No memory for temporary string");
      case 4008: return(pref+"uninitialized string");
      case 4009: return(pref+"Uninitialized string in array");
      case 4010: return(pref+"No memory for string array");
      case 4011: return(pref+"Line too long");
      case 4012: return(pref+"Remainder of division by zero");
      case 4013: return(pref+"Division by zero");
      case 4014: return(pref+"Unknown team");
      case 4015: return(pref+"Wrong transition");
      case 4016: return(pref+"Uninitialized array");
      case 4017: return(pref+"DLL calls not allowed");
      case 4018: return(pref+"Unable to load library");
      case 4019: return(pref+"Unable to call function");
      case 4020: return(pref+"Calls to external library functions are not allowed");
      case 4021: return(pref+"Out of memory for string returned from function");
      case 4022: return(pref+"System busy");
      case 4050: return(pref+"Incorrect number of function parameters");
      case 4051: return(pref+"Invalid function parameter value");
      case 4052: return(pref+"String function internal error");
      case 4053: return(pref+"array error");
      case 4054: return(pref+"Incorrect use of a timeseries array");
      case 4055: return(pref+"Custom indicator error");
      case 4056: return(pref+"Arrays are incompatible");
      case 4057: return(pref+"Error handling global variables");
      case 4058: return(pref+"Global variable not found");
      case 4059: return(pref+"Feature not allowed in test mode");
      case 4060: return(pref+"Function not allowed");
      case 4061: return(pref+"Mail sending error");
      case 4062: return(pref+"Expected parameter of type string");
      case 4063: return(pref+"An integer parameter is expected");
      case 4064: return(pref+"Expected parameter of type double");
      case 4065: return(pref+"An array is expected as a parameter");
      case 4066: return(pref+"Requested historical data in update state");
      case 4067: return(pref+"Error while executing a trade operation");
      case 4099: return(pref+"End of file");
      case 4100: return(pref+"Error while working with file");
      case 4101: return(pref+"Wrong file name");
      case 4102: return(pref+"Too many open files");
      case 4103: return(pref+"Unable to open file");
      case 4104: return(pref+"Incompatible file access mode");
      case 4105: return(pref+"No order selected");
      case 4106: return(pref+"Unknown symbol");
      case 4107: return(pref+"Wrong price parameter for the trading function");
      case 4108: return(pref+"Invalid ticket number");
      case 4109: return(pref+"Trading is not allowed. You must enable the <Allow " +
                              "trade advisor> in the properties of the expert");
      case 4110: return(pref+"Long positions are not allowed - you need to check the properties of the expert");
      case 4111: return(pref+"Short positions are not allowed - you need to check the properties of the expert");
      case 4200: return(pref+"Object already exists");
      case 4201: return(pref+"An unknown object property was requested");
      case 4202: return(pref+"Object does not exist");
      case 4203: return(pref+"Unknown object type");
      case 4204: return(pref+"No object name");
      case 4205: return(pref+"Object coordinate error");
      case 4206: return(pref+"Specified subwindow not found");
      case 4207: return(pref+"Error while working with object");
      default:   return(pref+"Non-existent error number");
   }
}
//+------------------------------------------------------------------+
void BrokerStatWrite(int ticket, string openclose, string sltp, double slip, uint delay, string ontickdelay){
   if(!_RealTrade || !BrokerStatToFile) return;
   
   string slips=DoubleToString(slip,1);
   StringReplace(slips,".",",");
   StringReplace(ontickdelay,".",",");
   
   int file_handle;
   int a=0;
   do {
      file_handle=FileOpen("BrokerStat.csv", FILE_CSV|FILE_READ|FILE_WRITE);
      if (file_handle != INVALID_HANDLE) break;
      Sleep(200);
      a++;
   } while (file_handle == INVALID_HANDLE && a<10);
   if (file_handle!=INVALID_HANDLE){
       if(!FileSeek(file_handle, 0, SEEK_END)) ResetLastError();
       FileWrite(file_handle,TimeToString(TimeCurrent()),_Symbol,ticket,openclose,sltp,slips,delay,ontickdelay);
       FileClose(file_handle);
   }
   
   int Error = GetLastError(); //looking for errors at the end
   if(Error != 0) Print(__FUNCTION__," ",fMyErDesc(Error));
}
void IsNews(bool& isnews, bool& isclosebeforenews) {
   newsLoader.SetGMTOffset(GMT_Offset + (IsSummerTime(DSTMode) ? 1 : 0));
   newsLoader.CheckNewsStatus(newsCheckStatus);

   isnews =  (newsCheckStatus.minutesToNextNews <= TimeBeforeNews) || (newsCheckStatus.minutesSinceLastNews < TimeAfterNews);
   isclosebeforenews =  (newsCheckStatus.minutesToNextNews <= CloseTimeBeforeNews) || (newsCheckStatus.minutesSinceLastNews < TimeAfterNews);  

}  
bool IsUSFederalHoliday(datetime dt) {
   // ** for holiday descriptions: http://en.wikipedia.org/wiki/Bank_holidays_in_United_States#List_of_Federal_Holidays
   //                              http://en.wikipedia.org/wiki/Public_holidays_in_the_United_States#Federal_holidays
   // ** holidays that fall on a weekend are usually observed on the closest weekday
   
   #define Thursday   4
   #define Friday     5
   #define Sunday     0
   #define Monday     1
        
   int today_moy = TimeMonth(dt), today_dom = TimeDay(dt), today_dow = TimeDayOfWeek(dt),
       yesterday_moy = TimeMonth(dt - 86400), yesterday_dom = TimeDay(dt - 86400), yesterday_dow = TimeDayOfWeek(dt - 86400),
       tomorrow_moy = TimeMonth(dt + 86400), tomorrow_dom = TimeDay(dt + 86400), tomorrow_dow = TimeDayOfWeek(dt + 86400);
       
   if (today_moy == 1)
      return (
         // New Year's Day - part 1/2 (January 1st)
         ((today_dom == 1) || (today_dow == Monday && yesterday_dom == 1)) ||
         // Inauguration Day (Every fourth year on January 20th or, if the 20th is a Sunday, January 21st)
         (((TimeYear(dt) - 1) % 4 == 0) && ((today_dom == 20 && today_dow != Sunday) || (today_dom == 21 && today_dow == Monday))) ||
         // MLK's Birthday (Third Monday in January)
         (today_dow == Monday && MathCeil(today_dom / 7.0) == 3) );
   if (today_moy == 2)
      // President's Day (Third Monday in February)
      return (today_dow == Monday && MathCeil(today_dom / 7.0) == 3);
   if (today_moy == 5)
      // Memorial Day (Last Monday in May)
      return (today_dow == Monday && 31 - today_dom < 7);
   if (today_moy == 6)
      // Juneteenth National Independence Day (June 19)
      return ((today_dom == 19) || (today_dow == Friday && tomorrow_dom == 19) || (today_dow == Monday && yesterday_dom == 19));
   if (today_moy == 7)
      // Independence Day (July 4th)
      return ((today_dom == 4) || (today_dow == Friday && tomorrow_dom == 4) || (today_dow == Monday && yesterday_dom == 4));
   if (today_moy == 9)
      // Labor Day (First Monday in September)
      return (today_dow == Monday && MathCeil(today_dom / 7.0) == 1);
   if (today_moy == 10)
      // Columbus Day (Second Monday in October)
      return (today_dow == Monday && MathCeil(today_dom / 7.0) == 2);
   if (today_moy == 11)
      return (
         // Veterans Day (November 11th)
         ((today_dom == 11) || (today_dow == Friday && tomorrow_dom == 11) || (today_dow == Monday && yesterday_dom == 11)) ||
         // Thanksgiving Day (Fourth Thursday in November)
         (today_dow == Thursday && MathCeil(today_dom / 7.0) == 4) );
   if (today_moy == 12)
      return (
         // Christmas Day (December 25th)
         ((today_dom == 25) || (today_dow == Friday && tomorrow_dom == 25) || (today_dow == Monday && yesterday_dom == 25)) ||
         // New Year's Day - part 2/2 (January 1st)
         (today_dow == Friday && tomorrow_dom == 1) );
         
   return (false);
}

bool isHoliday(datetime dt) {
   return (IsUSFederalHoliday(dt));
}

bool IsAroundHoliday(datetime dt) {
   // Today is holiday
   if (isHoliday(dt)) {
      return (true);
   }
   int today_dow = TimeDayOfWeek(dt), today_hour = TimeHour(dt);
   
   datetime torrow = dt + 86400;
   // If today is Friday, next trade day is Monday
   if (today_dow == 5) {
      torrow += 86400 * 2;
   }
   // Tomorrow is holliday, no trade on second session
   if (isHoliday(torrow) && today_hour > 8) {
      return (true);
   }
   
   datetime yesterday = dt - 86400;
   // If today is Monday, previous trade day is Friday
   if (today_dow == 1) {
      yesterday -= 86400 * 2;
   }
   // Yesterday is holliday, no trade on first session
   if (isHoliday(yesterday) && today_hour < 8) {
      return (true);
   }
   
   return (false);
}
