#define PROJECT_ID "mt5-5961"
//--
// Point Format Rules
#define POINT_FORMAT_RULES "0.001=0.01,0.00001=0.0001,0.000001=0.0001" // this is deserialized in a special function later
#define ENABLE_SPREAD_METER true
#define ENABLE_STATUS true
#define ENABLE_TEST_INDICATORS true
//--
// Events On/Off
#define ENABLE_EVENT_TICK 1 // enable "Tick" event
#define ENABLE_EVENT_TRADE 1 // enable "Trade" event
#define ENABLE_EVENT_TIMER 0 // enable "Timer" event
//--
// Virtual Stops
#define VIRTUAL_STOPS_ENABLED 0 // enable virtual stops
#define VIRTUAL_STOPS_TIMEOUT 0 // virtual stops timeout
#define USE_EMERGENCY_STOPS "no" // "yes" to use emergency (hard stops) when virtual stops are in use.
// "always" to use EMERGENCY_STOPS_ADD as emergency stops when there is no virtual stop.
#define EMERGENCY_STOPS_REL 0 // use 0 to disable hard stops when virtual stops are enabled.
// Use a value >=0 to automatically set hard stops with virtual.
// Example: if 2 is used, then hard stops will be 2 times bigger than virtual ones.
#define EMERGENCY_STOPS_ADD 0 // add pips to relative size of emergency stops (hard stops)
//--
// Settings for events
#define ON_TIMER_PERIOD 60 // Timer event period (in seconds)

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// System constants (predefined constants) //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
//--
#define TLOBJPROP_TIME1 801
#define OBJPROP_TL_PRICE_BY_SHIFT 802
#define OBJPROP_TL_SHIFT_BY_PRICE 803
#define OBJPROP_FIBOVALUE 804
#define OBJPROP_FIBOPRICEVALUE 805
#define OBJPROP_FIRSTLEVEL 806
#define OBJPROP_TIME1 807
#define OBJPROP_TIME2 808
#define OBJPROP_TIME3 809
#define OBJPROP_PRICE1 810
#define OBJPROP_PRICE2 811
#define OBJPROP_PRICE3 812
#define OBJPROP_BARSHIFT1 813
#define OBJPROP_BARSHIFT2 814
#define OBJPROP_BARSHIFT3 815
#define SEL_CURRENT 0
#define SEL_INITIAL 1

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// Enumerations, Imports, Constants, Variables //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//


//--
// Constants (Input Parameters)
input string EA_Name = "News Snowball (Trailing Stop)";
input double Lots_fix = 0.01;  // Ajuste o lote fixo para 0.01
input int SL_pips = 10;
input int Grid_distance_pips = 4;
input int Time_bomb_pips = 5;
input int Time_bomb_seconds = 12;
input int Trailing_stop_pips = 20;
input int MagicStart = 5961; // Magic Number, kind of...
class c
{
                public:
        static string EA_Name;
        static double Lots_fix;
        static int SL_pips;
        static int Grid_distance_pips;
        static int Time_bomb_pips;
        static int Time_bomb_seconds;
        static int Trailing_stop_pips;
        static int MagicStart;
};
string c::EA_Name;
double c::Lots_fix;
int c::SL_pips;
int c::Grid_distance_pips;
int c::Time_bomb_pips;
int c::Time_bomb_seconds;
int c::Trailing_stop_pips;
int c::MagicStart;


//--
// Variables (Global Variables)

class v
{
                public:
        static double Grid_distance_pips_BS;
};
double v::Grid_distance_pips_BS;


//--
// Externs (Global Variables)
input color inp25_ObjTitleFontColor = clrGold;
input color inp25_ObjLabelsFontColor = clrDarkGray;
input color inp25_ObjFontColor = clrWhite;
class _externs
{
                public:
        static color inp25_ObjTitleFontColor;
        static color inp25_ObjLabelsFontColor;
        static color inp25_ObjFontColor;
};
color _externs::inp25_ObjTitleFontColor;
color _externs::inp25_ObjLabelsFontColor;
color _externs::inp25_ObjFontColor;

//VVVVVVVVVVVVVVVVVVVVVVVVV//
// System global variables //
//^^^^^^^^^^^^^^^^^^^^^^^^^//
//--
// Blocks Lookup Functions
string fxdBlocksLookupTable[];

int FXD_CURRENT_FUNCTION_ID = 0;
double FXD_MILS_INIT_END    = 0;
int FXD_TICKS_FROM_START    = 0;
int FXD_MORE_SHIFT          = 0;
bool FXD_DRAW_SPREAD_INFO   = false;
bool FXD_FIRST_TICK_PASSED  = false;
bool FXD_BREAK              = false;
bool FXD_CONTINUE           = false;
bool USE_VIRTUAL_STOPS = VIRTUAL_STOPS_ENABLED;
string FXD_CURRENT_SYMBOL   = "";
int FXD_BLOCKS_COUNT        = 25;
datetime FXD_TICKSKIP_UNTIL = 0;

int FXD_ICUSTOM_HANDLES_IDS[]; // only used in MQL5
string FXD_ICUSTOM_HANDLES_KEYS[]; // only used in MQL5

//- for use in OnChart() event
struct fxd_onchart
{
        int id;
        long lparam;
        double dparam;
        string sparam;
};
fxd_onchart FXD_ONCHART;

/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                                                 EVENT FUNCTIONS                                                  | //
// |                           These are the main functions that controls the whole project                           | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

// Function to calculate the optimal trailing stop based on ATR
double CalculateOptimalTrailingStop(string symbol) {
    double atrValue = iATR(symbol, PERIOD_M15, 14, 0);  // ATR de 14 períodos como exemplo
    return atrValue;  // Use ATR diretamente para ajustar a trailing stop
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed once when the program starts //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
int OnInit()
{

        // Initiate Constants
        c::EA_Name = EA_Name;
        c::Lots_fix = Lots_fix;
        c::SL_pips = SL_pips;
        c::Grid_distance_pips = Grid_distance_pips;
        c::Time_bomb_pips = Time_bomb_pips;
        c::Time_bomb_seconds = Time_bomb_seconds;
        c::Trailing_stop_pips = Trailing_stop_pips;
        c::MagicStart = MagicStart;




        // Initiate Externs
        _externs::inp25_ObjTitleFontColor = inp25_ObjTitleFontColor;
        _externs::inp25_ObjLabelsFontColor = inp25_ObjLabelsFontColor;
        _externs::inp25_ObjFontColor = inp25_ObjFontColor;



        // do or do not not initilialize on reload
        if (UninitializeReason() != 0)
        {
                if (UninitializeReason() == REASON_CHARTCHANGE)
                {
                        // if the symbol is the same, do not reload, otherwise continue below
                        if (FXD_CURRENT_SYMBOL == Symbol()) {return INIT_SUCCEEDED;}
                }
                else
                {
                        return INIT_SUCCEEDED;
                }
        }
        FXD_CURRENT_SYMBOL = Symbol();

        CurrentSymbol(FXD_CURRENT_SYMBOL); // CurrentSymbol() has internal memory that should be set from here when the symboll is changed
        CurrentTimeframe(PERIOD_CURRENT);

        v::Grid_distance_pips_BS = 0.0;




        Comment("");
        for (int i=ObjectsTotal(ChartID()); i>=0; i--)
        {
                string name = ObjectName(ChartID(), i);
                if (StringSubstr(name,0,8) == "fxd_cmnt") {ObjectDelete(ChartID(), name);}
        }
        ChartRedraw();



        //-- disable virtual stops in optimization, because graphical objects does not work
        // http://docs.mql4.com/runtime/testing
        if (MQLInfoInteger(MQL_OPTIMIZATION)) {
                USE_VIRTUAL_STOPS = false;
        }

        //-- set initial local and server time
        TimeAtStart("set");

        //-- set initial balance
        AccountBalanceAtStart();

        //-- draw the initial spread info meter
        if (ENABLE_SPREAD_METER == false) {
                FXD_DRAW_SPREAD_INFO = false;
        }
        else {
                FXD_DRAW_SPREAD_INFO = !(MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_VISUAL_MODE));
        }
        if (FXD_DRAW_SPREAD_INFO) DrawSpreadInfo();

        //-- draw initial status
        if (ENABLE_STATUS) DrawStatus("waiting for tick...");

        //-- draw indicators after test
        TesterHideIndicators(!ENABLE_TEST_INDICATORS);

        if (ENABLE_EVENT_TIMER) {
                OnTimerSet(ON_TIMER_PERIOD);
        }


        //-- Initialize blocks classes
        ArrayResize(_blocks_, 25);

        _blocks_[0] = new Block0();
        _blocks_[1] = new Block1();
        _blocks_[2] = new Block2();
        _blocks_[3] = new Block3();
        _blocks_[4] = new Block4();
        _blocks_[5] = new Block5();
        _blocks_[6] = new Block6();
        _blocks_[7] = new Block7();
        _blocks_[8] = new Block8();
        _blocks_[9] = new Block9();
        _blocks_[10] = new Block10();
        _blocks_[11] = new Block11();
        _blocks_[12] = new Block12();
        _blocks_[13] = new Block13();
        _blocks_[14] = new Block14();
        _blocks_[15] = new Block15();
        _blocks_[16] = new Block16();
        _blocks_[17] = new Block17();
        _blocks_[18] = new Block18();
        _blocks_[19] = new Block19();
        _blocks_[20] = new Block20();
        _blocks_[21] = new Block21();
        _blocks_[22] = new Block22();
        _blocks_[23] = new Block23();
        _blocks_[24] = new Block24();

        // fill the lookup table
        ArrayResize(fxdBlocksLookupTable, ArraySize(_blocks_));
        for (int i=0; i<ArraySize(_blocks_); i++)
        {
                fxdBlocksLookupTable[i] = _blocks_[i].__block_user_number;
        }

        // fill the list of inbound blocks for each BlockCalls instance
        for (int i=0; i<ArraySize(_blocks_); i++)
        {
                _blocks_[i].__announceThisBlock();
        }

        // List of initially disabled blocks
        int disabled_blocks_list[] = {};
        for (int l = 0; l < ArraySize(disabled_blocks_list); l++) {
                _blocks_[disabled_blocks_list[l]].__disabled = true;
        }



        FXD_MILS_INIT_END     = (double)GetTickCount();
        FXD_FIRST_TICK_PASSED = false; // reset is needed when changing inputs

        return(INIT_SUCCEEDED);
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on every incoming tick //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnTick()
{
        FXD_TICKS_FROM_START++;

        if (ENABLE_STATUS && FXD_TICKS_FROM_START == 1) DrawStatus("working");

        //-- special system actions
        if (FXD_DRAW_SPREAD_INFO) DrawSpreadInfo();
        TicksData(""); // Collect ticks (if needed)
        TicksPerSecond(false, true); // Collect ticks per second
        if (USE_VIRTUAL_STOPS) {VirtualStopsDriver();}

        if (false) ExpirationWorker * expirationDummy = new ExpirationWorker();
        expirationWorker.Run();

        OCODriver(); // Check and close OCO orders

        // skip ticks
        if (TimeLocal() < FXD_TICKSKIP_UNTIL) {return;}

        //-- run blocks
        int blocks_to_run[] = {0,5,11,19,23};
        for (int i=0; i<ArraySize(blocks_to_run); i++) {
                _blocks_[blocks_to_run[i]].run();
        }


        return;
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on trade events - open, close, modify //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnTrade()
{
        // This is needed so that the OnTradeEventDetector class is added into the code
        if (false) OnTradeEventDetector * dummy = new OnTradeEventDetector();

        while (onTradeEventDetector.Start() == true)
        {
        //-- run blocks
        int blocks_to_run[] = {17};
        for (int i=0; i<ArraySize(blocks_to_run); i++) {
                _blocks_[blocks_to_run[i]].run();
        }

        }

        onTradeEventDetector.End();

}


//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on a period basis //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnTimer()
{

}


//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed when chart event happens //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnChartEvent(
        const int id,         // Event ID
        const long& lparam,   // Parameter of type long event
        const double& dparam, // Parameter of type double event
        const string& sparam  // Parameter of type string events
)
{
        //-- write parameter to the system global variables
        FXD_ONCHART.id     = id;
        FXD_ONCHART.lparam = lparam;
        FXD_ONCHART.dparam = dparam;
        FXD_ONCHART.sparam = sparam;


        return;
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed once when the program ends //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnDeinit(const int reason)
{
        int reson = UninitializeReason();
        if (reson == REASON_CHARTCHANGE || reson == REASON_PARAMETERS || reason == REASON_TEMPLATE || reason == REASON_ACCOUNT) {return;}

        //-- if Timer was set, kill it here
        EventKillTimer();

        if (ENABLE_STATUS) DrawStatus("stopped");
        if (ENABLE_SPREAD_METER) DrawSpreadInfo();
        ChartSetString(0, CHART_COMMENT, "");



        if (MQLInfoInteger(MQL_TESTER)) {
                Print("Backtested in "+DoubleToString((GetTickCount()-FXD_MILS_INIT_END)/1000, 2)+" seconds");
                double tc = GetTickCount()-FXD_MILS_INIT_END;
                if (tc > 0)
                {
                        Print("Average ticks per second: "+DoubleToString(FXD_TICKS_FROM_START/tc, 0));
                }
        }

        if (MQLInfoInteger(MQL_PROGRAM_TYPE) == PROGRAM_EXPERT)
        {
                switch(UninitializeReason())
                {
                        case REASON_PROGRAM             : Print("Expert Advisor self terminated"); break;
                        case REASON_REMOVE              : Print("Expert Advisor removed from the chart"); break;
                        case REASON_RECOMPILE   : Print("Expert Advisor has been recompiled"); break;
                        case REASON_CHARTCHANGE : Print("Symbol or chart period has been changed"); break;
                        case REASON_CHARTCLOSE  : Print("Chart has been closed"); break;
                        case REASON_PARAMETERS  : Print("Input parameters have been changed by a user"); break;
                        case REASON_ACCOUNT             : Print("Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings"); break;
                        case REASON_TEMPLATE            : Print("A new template has been applied"); break;
                        case REASON_INITFAILED  : Print("OnInit() handler has returned a nonzero value"); break;
                        case REASON_CLOSE                       : Print("Terminal has been closed"); break;
                }
        }

        // delete dynamic pointers
        for (int i=0; i<ArraySize(_blocks_); i++)
        {
                delete _blocks_[i];
                _blocks_[i] = NULL;
        }
        ArrayResize(_blocks_, 0);

        return;
}

/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                                             Classes of blocks                                                    | //
// |              Classes that contain the actual code of the blocks and their input parameters as well               | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

/**
        The base class for all block calls
   */
class BlockCalls
{
        public:
                bool __disabled; // whether or not the block is disabled

                string __block_user_number;
        int __block_number;
                int __block_waiting;
                int __parent_number;
                int __inbound_blocks[];
                int __outbound_blocks[];

                void __addInboundBlock(int id = 0) {
                        int size = ArraySize(__inbound_blocks);
                        for (int i = 0; i < size; i++) {
                                if (__inbound_blocks[i] == id) {
                                        return;
                                }
                        }
                        ArrayResize(__inbound_blocks, size + 1);
                        __inbound_blocks[size] = id;
                }

                void BlockCalls() {
                        __disabled          = false;
                        __block_user_number = "";
                        __block_number      = 0;
                        __block_waiting     = 0;
                        __parent_number     = 0;
                }

                /**
                   Announce this block to the list of inbound connections of all the blocks to which this block is connected to
                   */
                void __announceThisBlock()
                {
                   // add the current block number to the list of inbound blocks
                   // for each outbound block that is provided
                        for (int i = 0; i < ArraySize(__outbound_blocks); i++)
                        {
                                int block = __outbound_blocks[i]; // outbound block number
                                int size  = ArraySize(_blocks_[block].__inbound_blocks); // the size of its inbound list

                                // skip if the current block was already added
                                for (int j = 0; j < size; j++) {
                                        if (_blocks_[block].__inbound_blocks[j] == __block_number)
                                        {
                                                return;
                                        }
                                }

                                // add the current block number to the list of inbound blocks of the other block
                                ArrayResize(_blocks_[block].__inbound_blocks, size + 1);
                                _blocks_[block].__inbound_blocks[size] = __block_number;
                        }
                }

                // this is here, because it is used in the "run" function
                virtual void _execute_() = 0;

                /**
                        In the derived class this method should be used to set dynamic parameters or other stuff before the main execute.
                        This method is automatically called within the main "run" method below, before the execution of the main class.
                        */
                virtual void _beforeExecute_() {return;};
                bool _beforeExecuteEnabled; // for speed

                /**
                        Same as _beforeExecute_, but to work after the execute method.
                        */
                virtual void _afterExecute_() {return;};
                bool _afterExecuteEnabled; // for speed

                /**
                        This is the method that is used to run the block
                        */
                virtual void run(int _parent_=0) {
                        __parent_number = _parent_;
                        if (__disabled || FXD_BREAK) {return;}
                        FXD_CURRENT_FUNCTION_ID = __block_number;

                        if (_beforeExecuteEnabled) {_beforeExecute_();}
                        _execute_();
                        if (_afterExecuteEnabled) {_afterExecute_();}

                        if (__block_waiting && FXD_CURRENT_FUNCTION_ID == __block_number) {fxdWait.Accumulate(FXD_CURRENT_FUNCTION_ID);}
                }
};

BlockCalls *_blocks_[];


// "No position" model
template<typename T1,typename T2,typename T3,typename T4,typename T5>
class MDL_NoOpenedOrders: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_NoOpenedOrders()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                bool exist = false;
                
                for (int index = TradesTotal()-1; index >= 0; index--)
                {
                        if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells))
                        {
                                exist = true;
                                break;
                        }
                }
                
                if (exist == false) {_callback_(1);} else {_callback_(0);}
        }
};

// "Time Bomb Up" model
template<typename T1,typename T2,typename T3>
class MDL_TimeBombUp: public BlockCalls
{
        public: /* Input Parameters */
        T1 Symbol;
        T2 PipsInTime;
        T3 TimeToWait;
        /* Static Parameters */
        double levl_last;
        datetime time_last;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_TimeBombUp()
        {
                Symbol = (string)CurrentSymbol();
                PipsInTime = (double)5.0;
                TimeToWait = (double)10.0;
                /* Static Parameters (initial value) */
                levl_last =  0;
                time_last =  0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                double levl_diff   = 0;
                datetime time_diff = 0;
                bool reset         = false;
                bool next          = false;
                datetime time_now  = (int)TimeCurrent();
                double levl_now    = (double)SymbolAsk(Symbol);
                
                if (levl_last > 0)
                {
                        levl_diff = toPips(levl_now - levl_last, Symbol);
                        time_diff = (int)time_now - (int)time_last;
                
                        if (levl_diff >= PipsInTime && time_diff <= TimeToWait)
                        {
                                if (levl_now > levl_last /* raises up */)
                                {
                                        next = true;
                                }
                
                                reset = true;
                        }
                
                        if (time_diff >= TimeToWait)
                        {
                                reset = true;
                        }
                }
                else
                {
                        reset = true;
                }
                
                if (reset == true)
                {
                        levl_last = levl_now;
                        time_last = time_now;
                }
                
                if (next == true) {_callback_(1);} else {_callback_(0);}
        }
};

// "Time Bomb Down" model
template<typename T1,typename T2,typename T3>
class MDL_TimeBombDown: public BlockCalls
{
        public: /* Input Parameters */
        T1 Symbol;
        T2 PipsInTime;
        T3 TimeToWait;
        /* Static Parameters */
        double levl_last;
        datetime time_last;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_TimeBombDown()
        {
                Symbol = (string)CurrentSymbol();
                PipsInTime = (double)5.0;
                TimeToWait = (double)10.0;
                /* Static Parameters (initial value) */
                levl_last =  0;
                time_last =  0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                double levl_diff   = 0;
                datetime time_diff = 0;
                bool reset         = false;
                bool next          = false;
                datetime time_now  = (int)TimeCurrent();
                double levl_now    = (double)SymbolBid(Symbol);
                
                if (levl_last > 0)
                {
                        levl_diff = toPips(levl_last - levl_now, Symbol);
                        time_diff = (int)time_now - (int)time_last;
                
                        if (levl_diff >= PipsInTime && time_diff <= TimeToWait)
                        {
                                if (levl_now < levl_last /* falls down */)
                                {
                                        next = true;
                                }
                
                                reset = true;
                        }
                
                        if (time_diff >= TimeToWait)
                        {
                                reset = true;
                        }
                }
                else
                {
                        reset = true;
                }
                
                if (reset == true)
                {
                        levl_last = levl_now;
                        time_last = time_now;
                }
                
                if (next == true) {_callback_(1);} else {_callback_(0);}
        }
};

// "Buy now" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename _T9_,typename T10,typename T11,typename T12,typename T13,typename T14,typename T15,typename T16,typename T17,typename T18,typename T19,typename T20,typename T21,typename T22,typename T23,typename T24,typename T25,typename T26,typename T27,typename T28,typename T29,typename T30,typename T31,typename T32,typename T33,typename T34,typename T35,typename T36,typename T37,typename _T37_,typename T38,typename _T38_,typename T39,typename _T39_,typename T40,typename T41,typename T42,typename T43,typename T44,typename _T44_,typename T45,typename _T45_,typename T46,typename _T46_,typename T47,typename T48,typename T49,typename T50,typename T51,typename _T51_,typename T52,typename T53,typename T54>
class MDL_BuyNow: public BlockCalls
{
        public: /* Input Parameters */
        T1 Group;
        T2 Symbol;
        T3 VolumeMode;
        T4 VolumeSize;
        T5 VolumeSizeRisk;
        T6 VolumeRisk;
        T7 VolumePercent;
        T8 VolumeBlockPercent;
        T9 dVolumeSize; virtual _T9_ _dVolumeSize_(){return(_T9_)0;}
        T10 FixedRatioUnitSize;
        T11 FixedRatioDelta;
        T12 mmTradesPool;
        T13 mmMgInitialLots;
        T14 mmMgMultiplyOnLoss;
        T15 mmMgMultiplyOnProfit;
        T16 mmMgAddLotsOnLoss;
        T17 mmMgAddLotsOnProfit;
        T18 mmMgResetOnLoss;
        T19 mmMgResetOnProfit;
        T20 mm1326InitialLots;
        T21 mm1326Reverse;
        T22 mmFiboInitialLots;
        T23 mmDalembertInitialLots;
        T24 mmDalembertReverse;
        T25 mmLabouchereInitialLots;
        T26 mmLabouchereList;
        T27 mmLabouchereReverse;
        T28 mmSeqBaseLots;
        T29 mmSeqOnLoss;
        T30 mmSeqOnProfit;
        T31 mmSeqReverse;
        T32 VolumeUpperLimit;
        T33 StopLossMode;
        T34 StopLossPips;
        T35 StopLossPercentPrice;
        T36 StopLossPercentTP;
        T37 dlStopLoss; virtual _T37_ _dlStopLoss_(){return(_T37_)0;}
        T38 dpStopLoss; virtual _T38_ _dpStopLoss_(){return(_T38_)0;}
        T39 ddStopLoss; virtual _T39_ _ddStopLoss_(){return(_T39_)0;}
        T40 TakeProfitMode;
        T41 TakeProfitPips;
        T42 TakeProfitPercentPrice;
        T43 TakeProfitPercentSL;
        T44 dlTakeProfit; virtual _T44_ _dlTakeProfit_(){return(_T44_)0;}
        T45 dpTakeProfit; virtual _T45_ _dpTakeProfit_(){return(_T45_)0;}
        T46 ddTakeProfit; virtual _T46_ _ddTakeProfit_(){return(_T46_)0;}
        T47 ExpMode;
        T48 ExpDays;
        T49 ExpHours;
        T50 ExpMinutes;
        T51 dExp; virtual _T51_ _dExp_(){return(_T51_)0;}
        T52 Slippage;
        T53 MyComment;
        T54 ArrowColorBuy;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_BuyNow()
        {
                Group = (string)"";
                Symbol = (string)CurrentSymbol();
                VolumeMode = (string)"fixed";
                VolumeSize = (double)Lots_fix;  // Ajuste fixo para o tamanho do lote
                VolumeSizeRisk = (double)50.0;
                VolumeRisk = (double)2.5;
                VolumePercent = (double)100.0;
                VolumeBlockPercent = (double)3.0;
                FixedRatioUnitSize = (double)0.01;
                FixedRatioDelta = (double)20.0;
                mmTradesPool = (int)0;
                mmMgInitialLots = (double)0.1;
                mmMgMultiplyOnLoss = (double)2.0;
                mmMgMultiplyOnProfit = (double)1.0;
                mmMgAddLotsOnLoss = (double)0.0;
                mmMgAddLotsOnProfit = (double)0.0;
                mmMgResetOnLoss = (int)0;
                mmMgResetOnProfit = (int)1;
                mm1326InitialLots = (double)0.1;
                mm1326Reverse = (bool)false;
                mmFiboInitialLots = (double)0.1;
                mmDalembertInitialLots = (double)0.1;
                mmDalembertReverse = (bool)false;
                mmLabouchereInitialLots = (double)0.1;
                mmLabouchereList = (string)"1,2,3,4,5,6";
                mmLabouchereReverse = (bool)false;
                mmSeqBaseLots = (double)0.1;
                mmSeqOnLoss = (string)"3,2,6";
                mmSeqOnProfit = (string)"1";
                mmSeqReverse = (bool)false;
                VolumeUpperLimit = (double)0.0;
                StopLossMode = (string)"fixed";
                StopLossPips = (double)50.0;
                StopLossPercentPrice = (double)0.55;
                StopLossPercentTP = (double)100.0;
                TakeProfitMode = (string)"fixed";
                TakeProfitPips = (double)50.0;
                TakeProfitPercentPrice = (double)0.55;
                TakeProfitPercentSL = (double)100.0;
                ExpMode = (string)"GTC";
                ExpDays = (int)0;
                ExpHours = (int)1;
                ExpMinutes = (int)0;
                Slippage = (ulong)4;
                MyComment = (string)"";
                ArrowColorBuy = (color)clrBlue;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                //-- stops ------------------------------------------------------------------
                double sll = 0, slp = 0, tpl = 0, tpp = 0;
                
                     if (StopLossMode == "fixed")         {slp = StopLossPips;}
                else if (StopLossMode == "dynamicPips")   {slp = _dpStopLoss_();}
                else if (StopLossMode == "dynamicDigits") {slp = toPips(_ddStopLoss_(),Symbol);}
                else if (StopLossMode == "dynamicLevel")  {sll = _dlStopLoss_();}
                else if (StopLossMode == "percentPrice")  {sll = SymbolAsk(Symbol) - (SymbolAsk(Symbol) * StopLossPercentPrice / 100);}
                
                     if (TakeProfitMode == "fixed")         {tpp = TakeProfitPips;}
                else if (TakeProfitMode == "dynamicPips")   {tpp = _dpTakeProfit_();}
                else if (TakeProfitMode == "dynamicDigits") {tpp = toPips(_ddTakeProfit_(),Symbol);}
                else if (TakeProfitMode == "dynamicLevel")  {tpl = _dlTakeProfit_();}
                else if (TakeProfitMode == "percentPrice")  {tpl = SymbolAsk(Symbol) + (SymbolAsk(Symbol) * TakeProfitPercentPrice / 100);}
                
                if (StopLossMode == "percentTP") {
                   if (tpp > 0) {slp = tpp*StopLossPercentTP/100;}
                   if (tpl > 0) {slp = toPips(MathAbs(SymbolAsk(Symbol) - tpl), Symbol)*StopLossPercentTP/100;}
                }
                if (TakeProfitMode == "percentSL") {
                   if (slp > 0) {tpp = slp*TakeProfitPercentSL/100;}
                   if (sll > 0) {tpp = toPips(MathAbs(SymbolAsk(Symbol) - sll), Symbol)*TakeProfitPercentSL/100;}
                }
                
                //-- lots -------------------------------------------------------------------
                double lots = Lots_fix;  // Valor fixo para os trades usando o lote fixo
                double pre_sll = sll;
                
                if (pre_sll == 0) {
                        pre_sll = SymbolAsk(Symbol);
                }
                
                double pre_sl_pips = toPips(SymbolAsk(Symbol)-(pre_sll-toDigits(slp,Symbol)), Symbol);
                
                lots = AlignLots(Symbol, lots, 0, VolumeUpperLimit);
                
                datetime exp = ExpirationTime(ExpMode,ExpDays,ExpHours,ExpMinutes,_dExp_());
                
                //-- send -------------------------------------------------------------------
                long ticket = BuyNow(Symbol, lots, sll, tpl, slp, tpp, Slippage, (MagicStart+(int)Group), MyComment, ArrowColorBuy, exp);
                
                if (ticket > 0) {_callback_(1);} else {_callback_(0);}
        }
};

// "Sell now" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename _T9_,typename T10,typename T11,typename T12,typename T13,typename T14,typename T15,typename T16,typename T17,typename T18,typename T19,typename T20,typename T21,typename T22,typename T23,typename T24,typename T25,typename T26,typename T27,typename T28,typename T29,typename T30,typename T31,typename T32,typename T33,typename T34,typename T35,typename T36,typename T37,typename _T37_,typename T38,typename _T38_,typename T39,typename _T39_,typename T40,typename T41,typename T42,typename T43,typename T44,typename _T44_,typename T45,typename _T45_,typename T46,typename _T46_,typename T47,typename T48,typename T49,typename T50,typename T51,typename _T51_,typename T52,typename T53,typename T54>
class MDL_SellNow: public BlockCalls
{
        public: /* Input Parameters */
        T1 Group;
        T2 Symbol;
        T3 VolumeMode;
        T4 VolumeSize;
        T5 VolumeSizeRisk;
        T6 VolumeRisk;
        T7 VolumePercent;
        T8 VolumeBlockPercent;
        T9 dVolumeSize; virtual _T9_ _dVolumeSize_(){return(_T9_)0;}
        T10 FixedRatioUnitSize;
        T11 FixedRatioDelta;
        T12 mmTradesPool;
        T13 mmMgInitialLots;
        T14 mmMgMultiplyOnLoss;
        T15 mmMgMultiplyOnProfit;
        T16 mmMgAddLotsOnLoss;
        T17 mmMgAddLotsOnProfit;
        T18 mmMgResetOnLoss;
        T19 mmMgResetOnProfit;
        T20 mm1326InitialLots;
        T21 mm1326Reverse;
        T22 mmFiboInitialLots;
        T23 mmDalembertInitialLots;
        T24 mmDalembertReverse;
        T25 mmLabouchereInitialLots;
        T26 mmLabouchereList;
        T27 mmLabouchereReverse;
        T28 mmSeqBaseLots;
        T29 mmSeqOnLoss;
        T30 mmSeqOnProfit;
        T31 mmSeqReverse;
        T32 VolumeUpperLimit;
        T33 StopLossMode;
        T34 StopLossPips;
        T35 StopLossPercentPrice;
        T36 StopLossPercentTP;
        T37 dlStopLoss; virtual _T37_ _dlStopLoss_(){return(_T37_)0;}
        T38 dpStopLoss; virtual _T38_ _dpStopLoss_(){return(_T38_)0;}
        T39 ddStopLoss; virtual _T39_ _ddStopLoss_(){return(_T39_)0;}
        T40 TakeProfitMode;
        T41 TakeProfitPips;
        T42 TakeProfitPercentPrice;
        T43 TakeProfitPercentSL;
        T44 dlTakeProfit; virtual _T44_ _dlTakeProfit_(){return(_T44_)0;}
        T45 dpTakeProfit; virtual _T45_ _dpTakeProfit_(){return(_T45_)0;}
        T46 ddTakeProfit; virtual _T46_ _ddTakeProfit_(){return(_T46_)0;}
        T47 ExpMode;
        T48 ExpDays;
        T49 ExpHours;
        T50 ExpMinutes;
        T51 dExp; virtual _T51_ _dExp_(){return(_T51_)0;}
        T52 Slippage;
        T53 MyComment;
        T54 ArrowColorSell;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_SellNow()
        {
                Group = (string)"";
                Symbol = (string)CurrentSymbol();
                VolumeMode = (string)"fixed";
                VolumeSize = (double)Lots_fix;  // Ajuste fixo para o tamanho do lote
                VolumeSizeRisk = (double)50.0;
                VolumeRisk = (double)2.5;
                VolumePercent = (double)100.0;
                VolumeBlockPercent = (double)3.0;
                FixedRatioUnitSize = (double)0.01;
                FixedRatioDelta = (double)20.0;
                mmTradesPool = (int)0;
                mmMgInitialLots = (double)0.1;
                mmMgMultiplyOnLoss = (double)2.0;
                mmMgMultiplyOnProfit = (double)1.0;
                mmMgAddLotsOnLoss = (double)0.0;
                mmMgAddLotsOnProfit = (double)0.0;
                mmMgResetOnLoss = (int)0;
                mmMgResetOnProfit = (int)1;
                mm1326InitialLots = (double)0.1;
                mm1326Reverse = (bool)false;
                mmFiboInitialLots = (double)0.1;
                mmDalembertInitialLots = (double)0.1;
                mmDalembertReverse = (bool)false;
                mmLabouchereInitialLots = (double)0.1;
                mmLabouchereList = (string)"1,2,3,4,5,6";
                mmLabouchereReverse = (bool)false;
                mmSeqBaseLots = (double)0.1;
                mmSeqOnLoss = (string)"3,2,6";
                mmSeqOnProfit = (string)"1";
                mmSeqReverse = (bool)false;
                VolumeUpperLimit = (double)0.0;
                StopLossMode = (string)"fixed";
                StopLossPips = (double)50.0;
                StopLossPercentPrice = (double)0.55;
                StopLossPercentTP = (double)100.0;
                TakeProfitMode = (string)"fixed";
                TakeProfitPips = (double)50.0;
                TakeProfitPercentPrice = (double)0.55;
                TakeProfitPercentSL = (double)100.0;
                ExpMode = (string)"GTC";
                ExpDays = (int)0;
                ExpHours = (int)1;
                ExpMinutes = (int)0;
                Slippage = (ulong)4;
                MyComment = (string)"";
                ArrowColorSell = (color)clrRed;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                //-- stops ------------------------------------------------------------------
                double sll = 0, slp = 0, tpl = 0, tpp = 0;
                
                     if (StopLossMode == "fixed")         {slp = StopLossPips;}
                else if (StopLossMode == "dynamicPips")   {slp = _dpStopLoss_();}
                else if (StopLossMode == "dynamicDigits") {slp = toPips(_ddStopLoss_(),Symbol);}
                else if (StopLossMode == "dynamicLevel")  {sll = _dlStopLoss_();}
                else if (StopLossMode == "percentPrice")  {sll = SymbolBid(Symbol) + (SymbolBid(Symbol) * StopLossPercentPrice / 100);}
                
                     if (TakeProfitMode == "fixed")         {tpp = TakeProfitPips;}
                else if (TakeProfitMode == "dynamicPips")   {tpp = _dpTakeProfit_();}
                else if (TakeProfitMode == "dynamicDigits") {tpp = toPips(_ddTakeProfit_(),Symbol);}
                else if (TakeProfitMode == "dynamicLevel")  {tpl = _dlTakeProfit_();}
                else if (TakeProfitMode == "percentPrice")  {tpl = SymbolBid(Symbol) - (SymbolBid(Symbol) * TakeProfitPercentPrice / 100);}
                
                if (StopLossMode == "percentTP") {
                   if (tpp > 0) {slp = tpp*StopLossPercentTP/100;}
                   if (tpl > 0) {slp = toPips(MathAbs(SymbolBid(Symbol) - tpl), Symbol)*StopLossPercentTP/100;}
                }
                if (TakeProfitMode == "percentSL") {
                   if (slp > 0) {tpp = slp*TakeProfitPercentSL/100;}
                   if (sll > 0) {tpp = toPips(MathAbs(SymbolBid(Symbol) - sll), Symbol)*TakeProfitPercentSL/100;}
                }
                
                //-- lots -------------------------------------------------------------------
                double lots = Lots_fix;  // Valor fixo para os trades usando o lote fixo
                double pre_sll = sll;
                
                if (pre_sll == 0) {
                        pre_sll = SymbolBid(Symbol);
                }
                
                double pre_sl_pips = toPips((pre_sll+toDigits(slp,Symbol))-SymbolBid(Symbol), Symbol);
                
                lots = AlignLots(Symbol, lots, 0, VolumeUpperLimit);
                
                datetime exp = ExpirationTime(ExpMode,ExpDays,ExpHours,ExpMinutes,_dExp_());
                
                //-- send -------------------------------------------------------------------
                long ticket = SellNow(Symbol, lots, sll, tpl, slp, tpp, Slippage, (MagicStart+(int)Group), MyComment, ArrowColorSell, exp);
                
                if (ticket > 0) {_callback_(1);} else {_callback_(0);}
        }
};

// "If position" model
template<typename T1,typename T2,typename T3,typename T4,typename T5>
class MDL_IfOpenedOrders: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_IfOpenedOrders()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                bool exist = false;
                
                for (int index = TradesTotal()-1; index >= 0; index--)
                {
                        if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells))
                        {
                                exist = true;
                                break;
                        }
                }
                
                if (exist == true) {_callback_(1);} else {_callback_(0);}
        }
};

// "For each Position" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename T10>
class MDL_LoopStartTrades: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        T6 LoopDirection;
        T7 LoopSkip;
        T8 LoopEvery;
        T9 LoopLimit;
        T10 PassEnd;
        /* Static Parameters */
        double trades[][2];
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_LoopStartTrades()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                LoopDirection = (string)"newest-to-oldest";
                LoopSkip = (int)0;
                LoopEvery = (int)0;
                LoopLimit = (int)0;
                PassEnd = (int)0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                // used when sorting by profit
                
                int saved_type     = attrTypeInLoop();
                ulong saved_ticket = attrTicketInLoop(); // This ticket number will be reloaded at the end of this loop, so if we are in another overlapping loop - it will continue using it's last used ticket number
                
                int total = TradesTotal();
                int count = 0;
                int skip  = -1;
                int every = 0;
                
                bool get_from_array = false;
                
                int i_start = 0, i_stop = 0, i_inc = 0, i = 0;
                
                if (LoopDirection == "newest-to-oldest")
                {
                        i_start = total-1;
                        i_stop  = 0;
                        i_inc   = -1;
                }
                else if (LoopDirection == "oldest-to-newest")
                {
                        i_start = 0;
                        i_stop  = total-1;
                        i_inc   = 1;
                }
                else if (LoopDirection == "profitable-first" || LoopDirection == "profitable-last")
                {
                        int last_index = -1;
                        get_from_array = true;
                        
                        // Collect data
                        ArrayResize(trades,0);
                        int size = 0;
                
                        for (int pos=0; pos < total; pos++)
                        {
                                if (!TradeSelectByIndex(pos, GroupMode, Group, SymbolMode, Symbol, BuysOrSells)) continue;
                
                                size++;
                                ArrayResize(trades,size);
                
                                trades[size-1][0] = OrderProfit();
                                trades[size-1][1] = (double)OrderTicket();
                        }
                
                        // Sort
                        if (size > 0)
                        {
                                ArraySort(trades);
                                last_index = size - 1;
                        }
                
                        // At this moment the array is sorted starting from the least profitable trade
                
                        i_start = last_index;
                        i_stop  = 0;
                        i_inc   = -1;
                        
                        if (LoopDirection == "profitable-last")
                        {
                                i_start = 0;
                                i_stop  = last_index;
                                i_inc   = 1;
                        }
                }
                
                i = i_start - i_inc;
                
                while (true)
                {
                        if (i == i_stop) break;
                        i = i + i_inc;
                        
                        // simulate break and continue functionality in loop blocks
                        if (FXD_CONTINUE == true)
                        {
                                FXD_BREAK    = false;
                                FXD_CONTINUE = false;
                        }
                        else if (FXD_BREAK == true)
                        {
                                FXD_BREAK    = false;
                                FXD_CONTINUE = false;
                                break;
                        }
                        
                        if (get_from_array)
                        {
                                if (!TradeSelectByTicket((ulong)trades[i][1])) continue;
                        }
                        else
                        {
                                if (!TradeSelectByIndex(i, GroupMode, Group, SymbolMode, Symbol, BuysOrSells)) continue;
                        }
                
                        skip++;
                
                        if (LoopSkip <= skip && (count < LoopLimit || LoopLimit == 0))
                        {
                                if (LoopEvery > 0)
                                {
                                        every++;
                
                                        if (every < LoopEvery) {continue;} else {every = 0;}
                                }
                                
                                count++;
                                attrTypeInLoop(1);
                                attrTicketInLoop(OrderTicket());
                
                                _callback_(1);
                                
                                if (count == LoopLimit) break;
                        }
                        
                        if (LoopDirection == "oldest-to-newest")
                        {
                                // if trade was closed meanwhile
                                if (i_stop > TradesTotal()-1)
                                {
                                        i_stop = TradesTotal()-1;
                                        i--;
                                }
                        }
                }
                
                attrTypeInLoop(saved_type);
                attrTicketInLoop(saved_ticket); // Reloading Ticket number from the overlapping loop (if any)
                
                FXD_BREAK    = false;
                FXD_CONTINUE = false;
                
                if (
                           (PassEnd == 0)
                        || (PassEnd == 1 && count > 0)
                        || (PassEnd == 2 && count == 0)
                ) {
                        _callback_(0);
                }
        }
};

// "Condition" model
template<typename T1,typename _T1_,typename T2,typename T3,typename _T3_,typename T4>
class MDL_Condition: public BlockCalls
{
        public: /* Input Parameters */
        T1 Lo; virtual _T1_ _Lo_(){return(_T1_)0;}
        T2 compare;
        T3 Ro; virtual _T3_ _Ro_(){return(_T3_)0;}
        T4 crosswidth;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_Condition()
        {
                compare = (string)">";
                crosswidth = (int)1;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                bool output1 = false, output2 = false; // output 1 and output 2
                int crossover = 0;
                
                if (compare == "x>" || compare == "x<") {crossover = 1;}
                
                for (int i = 0; i <= crossover; i++)
                {
                        // i=0 - normal pass, i=1 - crossover pass
                
                        // Left operand of the condition
                        FXD_MORE_SHIFT = i * crosswidth;
                        _T1_ lo = _Lo_();
                        if (MathAbs(lo) == EMPTY_VALUE) {return;}
                
                        // Right operand of the condition
                        FXD_MORE_SHIFT = i * crosswidth;
                        _T3_ ro = _Ro_();
                        if (MathAbs(ro) == EMPTY_VALUE) {return;}
                
                        // Conditions
                        if (CompareValues(compare, lo, ro))
                        {
                                if (i == 0)
                                {
                                        output1 = true;
                                }
                        }
                        else
                        {
                                if (i == 0)
                                {
                                        output2 = true;
                                }
                                else
                                {
                                        output2 = false;
                                }
                        }
                
                        if (crossover == 1)
                        {
                                if (CompareValues(compare, ro, lo))
                                {
                                        if (i == 0)
                                        {
                                                output2 = true;
                                        }
                                }
                                else
                                {
                                        if (i == 1)
                                        {
                                                output1 = false;
                                        }
                                }
                        }
                }
                
                FXD_MORE_SHIFT = 0; // reset
                
                          if (output1 == true) {_callback_(1);}
                else if (output2 == true) {_callback_(0);}
        }
};

// "Formula" model
template<typename T1,typename _T1_,typename T2,typename T3,typename _T3_>
class MDL_Formula_1: public BlockCalls
{
        public: /* Input Parameters */
        T1 Lo; virtual _T1_ _Lo_(){return(_T1_)0;}
        T2 compare;
        T3 Ro; virtual _T3_ _Ro_(){return(_T3_)0;}
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_Formula_1()
        {
                compare = (string)"+";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                _T1_ lo = _Lo_();
                if (typename(_T1_) != "string" && MathAbs(lo) == EMPTY_VALUE) {return;}
                
                _T3_ ro = _Ro_();
                if (typename(_T3_) != "string" && MathAbs(ro) == EMPTY_VALUE) {return;}
                
                v::Grid_distance_pips_BS = formula(compare, lo, ro);
                
                _callback_(1);
        }
};

// "No position nearby" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename _T6_,typename T7,typename _T7_,typename T8,typename T9,typename _T9_,typename T10,typename T11,typename T12,typename T13>
class MDL_NoNearbyRunning: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        T6 Time1; virtual _T6_ _Time1_(){return(_T6_)0;}
        T7 Time2; virtual _T7_ _Time2_(){return(_T7_)0;}
        T8 ModeBasePrice;
        T9 BasePrice; virtual _T9_ _BasePrice_(){return(_T9_)0;}
        T10 ModeRange;
        T11 RangePips;
        T12 RangeFraction;
        T13 RangePosition;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_NoNearbyRunning()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                ModeBasePrice = (string)"current";
                ModeRange = (string)"pips";
                RangePips = (double)10.0;
                RangeFraction = (double)0.0010;
                RangePosition = (int)0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                int next               = true;
                double price           = 0;
                bool use_current_price = (ModeBasePrice == "current");
                
                // prepare the time filters
                datetime t1 = _Time1_();
                datetime t2 = _Time2_();
                
                if (t1 >= TimeCurrent()) t1 = 0;
                
                if (!use_current_price)
                {
                        price = _BasePrice_();
                }
                
                for (int index = TradesTotal()-1; index >= 0; index--)
                {
                        if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells))
                        {
                                // filter by time
                                if ((t1 < t2 && OrderOpenTime() < t1) || OrderOpenTime() > t2)
                                {
                                        continue;
                                }
                
                                // what is the distance?
                                double distance = RangeFraction;
                
                                if (ModeRange == "pips") {distance = toDigits(RangePips, Symbol);}
                
                                // checking the position
                                if (OrderType() == 0) // buy?
                                {
                                        if (use_current_price) {price = SymbolInfoDouble(Symbol, SYMBOL_ASK);}
                
                                        switch (RangePosition)
                                        {
                                                case 0: if (price <= (OrderOpenPrice() + distance/2) && price >= (OrderOpenPrice() - distance/2)) {next = false;} break;
                                                case 1: if (price <= OrderOpenPrice() + distance && price >= OrderOpenPrice()) {next = false;} break;
                                                case 2: if (price <= OrderOpenPrice() && price >= OrderOpenPrice() - distance) {next = false;} break;
                                        }
                                }
                                else
                                {
                                        if (use_current_price) {price = SymbolInfoDouble(Symbol, SYMBOL_BID);}
                
                                        switch (RangePosition)
                                        {
                                                case 0: if (price <= (OrderOpenPrice() + distance/2) && price >= (OrderOpenPrice() - distance/2)) {next = false;} break;
                                                case 1: if (price <= OrderOpenPrice() && price >= OrderOpenPrice() - distance) {next = false;} break;
                                                case 2: if (price <= OrderOpenPrice() + distance && price >= OrderOpenPrice()) {next = false;} break;
                                        }
                                }
                
                                if (next == false) {break;}
                        }
                }
                
                if (next == true) {_callback_(1);} else {_callback_(0);}
        }
};

// "Formula" model
template<typename T1,typename _T1_,typename T2,typename T3,typename _T3_>
class MDL_Formula_2: public BlockCalls
{
        public: /* Input Parameters */
        T1 Lo; virtual _T1_ _Lo_(){return(_T1_)0;}
        T2 compare;
        T3 Ro; virtual _T3_ _Ro_(){return(_T3_)0;}
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_Formula_2()
        {
                compare = (string)"+";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                _T1_ lo = _Lo_();
                if (typename(_T1_) != "string" && MathAbs(lo) == EMPTY_VALUE) {return;}
                
                _T3_ ro = _Ro_();
                if (typename(_T3_) != "string" && MathAbs(ro) == EMPTY_VALUE) {return;}
                
                v::Grid_distance_pips_BS = formula(compare, lo, ro);
                
                _callback_(1);
        }
};

// "Position closed" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7>
class MDL_eTrade_TradeClosed: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        T6 CloseMode;
        T7 ClosePartialMode;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_eTrade_TradeClosed()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                CloseMode = (string)"";
                ClosePartialMode = (int)0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                bool next = false;
                
                if (
                           (e_Reason() == "close" || e_Reason() == "decrement")
                        && e_attrType() < 2
                        && FilterEventTrade(GroupMode, Group, SymbolMode, Symbol, BuysOrSells)
                )
                {
                        string closedBy = e_ReasonDetail();
                
                        if (
                                (
                                                (CloseMode == "")
                                        || (CloseMode == closedBy)
                                        || (CloseMode == "sltp" && (closedBy == "sl" || closedBy == "tp"))
                                        || (CloseMode == "nosltp" && (closedBy != "sl" && closedBy != "tp"))
                                        || (CloseMode == "exp" && closedBy == "expiration")
                                )
                                && (
                                           (ClosePartialMode == 0)
                                        || (ClosePartialMode == 1 && e_Reason() == "close") // fully closed
                                        || (ClosePartialMode == 2 && e_Reason() == "decrement") // partially closed
                                )
                        )
                        {next = true;}
                }
                
                if (next) {_callback_(1);} else {_callback_(0);}
        }
};

// "Close positions" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8>
class MDL_CloseOpened: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        T6 OrderMinutes;
        T7 Slippage;
        T8 ArrowColor;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_CloseOpened()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                OrderMinutes = (int)0;
                Slippage = (ulong)4;
                ArrowColor = (color)clrDeepPink;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                int closed_count = 0;
                bool finished    = false;
                
                while (finished == false)
                {
                        int count = 0;
                
                        for (int index = TradesTotal()-1; index >= 0; index--)
                        {
                                if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells))
                                {
                                        datetime time_diff = TimeCurrent() - OrderOpenTime();
                
                                        if (time_diff < 0) {time_diff = 0;} // this actually happens sometimes
                
                                        if (time_diff >= 60 * OrderMinutes)
                                        {
                                                if (CloseTrade(OrderTicket(), Slippage, ArrowColor))
                                                {
                                                        closed_count++;
                                                }
                
                                                count++;
                                        }
                                }
                        }
                
                        if (count == 0) {finished = true;}
                }
                
                _callback_(1);
        }
};

// "Check positions count" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7>
class MDL_CheckTradesCount: public BlockCalls
{
        public: /* Input Parameters */
        T1 Compare;
        T2 CompareCount;
        T3 GroupMode;
        T4 Group;
        T5 SymbolMode;
        T6 Symbol;
        T7 BuysOrSells;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_CheckTradesCount()
        {
                Compare = (string)">";
                CompareCount = (int)3;
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                int count = 0;
                
                for (int index = TradesTotal()-1; index >= 0; index--)
                {
                        if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells))
                        {
                                count++;
                        }
                }
                
                if (compare(Compare, count, CompareCount)) {_callback_(1);} else {_callback_(0);}
        }
};

// "Check profit (unrealized)" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename T10,typename T11,typename T12,typename T13>
class MDL_CheckUProfit: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 SymbolMode;
        T4 Symbol;
        T5 BuysOrSells;
        T6 EachProfitMode;
        T7 EachCompare;
        T8 EachProfitAmount;
        T9 EachProfitAmountPips;
        T10 ProfitMode;
        T11 Compare;
        T12 ProfitAmount;
        T13 ProfitAmountPips;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_CheckUProfit()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                SymbolMode = (string)"symbol";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                EachProfitMode = (string)"";
                EachCompare = (string)">";
                EachProfitAmount = (double)0.0;
                EachProfitAmountPips = (double)10.0;
                ProfitMode = (string)"money";
                Compare = (string)">";
                ProfitAmount = (double)0.0;
                ProfitAmountPips = (double)10.0;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                double avgPrice    = 0;
                double avgLoad     = 0;
                double avgLots     = 0;
                double profitMoney = 0;
                double profitPips  = 0;
                double pipsSum     = 0;
                int tradesCount    = 0;
                
                for (int index = TradesTotal()-1; index >= 0; index--) {
                        if (TradeSelectByIndex(index, GroupMode, Group, SymbolMode, Symbol, BuysOrSells)) {
                                double OrderOpenPrice = OrderChildOpenPrice();
                                double tradeProfit    = NormalizeDouble(OrderProfit() + OrderSwap() + OrderCommission(), 2);
                
                                // Filter out individual trades
                                if (EachProfitMode == "money") {
                                        if (compare(EachCompare, tradeProfit, EachProfitAmount)) {/* do nothing */} else {continue;}
                                }
                                else if (EachProfitMode == "pips") {
                                        double individual_profit = toPips(OrderClosePrice() - OrderOpenPrice, OrderSymbol());
                
                                        if (OrderType() == 1) {individual_profit = -1 * individual_profit;}
                
                                        if (compare(EachCompare, individual_profit, EachProfitAmountPips)) {/* do nothing*/} else {continue;}
                                }
                
                                profitMoney += tradeProfit;
                
                                if (ProfitMode == "pips" || ProfitMode == "pips-sum") {
                                        if (IsOrderTypeBuy()) {
                                                pipsSum += toPips(OrderClosePrice() - OrderOpenPrice, OrderSymbol());
                                                avgLoad += OrderOpenPrice * OrderLots();
                                                avgLots += OrderLots();
                                        }
                                        else {
                                                pipsSum += toPips(OrderOpenPrice - OrderClosePrice(), OrderSymbol());
                                                avgLoad -= OrderOpenPrice * OrderLots();
                                                avgLots -= OrderLots();
                                        }
                                }
                
                                tradesCount += 1;
                        }
                }
                
                if (ProfitMode == "pips") {
                        avgPrice = 0;
                
                        if (avgLots != 0) {
                                avgPrice = (avgLoad / avgLots);
                        }
                
                        if (avgPrice != 0) {
                                if (avgLots > 0) {
                                        profitPips = SymbolInfoDouble(Symbol, SYMBOL_BID) - avgPrice;
                                }
                                else {
                                        profitPips = avgPrice - SymbolInfoDouble(Symbol, SYMBOL_ASK);
                                }
                
                                profitPips = toPips(profitPips, Symbol);
                        }
                }
                
                if (
                           (ProfitMode == "money"    && (CompareValues(Compare, profitMoney, ProfitAmount)))
                        || (ProfitMode == "pips"     && (CompareValues(Compare, profitPips, ProfitAmountPips)))
                        || (ProfitMode == "pips-sum" && (CompareValues(Compare, pipsSum, ProfitAmountPips)))
                ) {
                        _callback_(1);
                }
                else {
                        _callback_(0);
                }
        }
};

// "Trailing stop (group of trades)" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename _T8_,typename T9,typename T10,typename T11,typename T12,typename T13,typename T14,typename T15,typename T16,typename _T16_,typename T17,typename T18,typename T19,typename T20,typename T21,typename _T21_,typename T22>
class MDL_TrailingStopAvgPrice: public BlockCalls
{
        public: /* Input Parameters */
        T1 GroupMode;
        T2 Group;
        T3 Symbol;
        T4 BuysOrSells;
        T5 TrailWhat;
        T6 TrailingStopMode;
        T7 tStopPips;
        T8 ftStop; virtual _T8_ _ftStop_(){return(_T8_)0;}
        T9 tStopMoney;
        T10 TrailingStepMode;
        T11 tStepPips;
        T12 tStepPercentTS;
        T13 TrailingStartMode;
        T14 tStartPips;
        T15 tStartPercentTS;
        T16 ftStart; virtual _T16_ _ftStart_(){return(_T16_)0;}
        T17 resetOnTrade;
        T18 TrailingTPmode;
        T19 tTPpips;
        T20 tTPpercentTS;
        T21 ftTP; virtual _T21_ _ftTP_(){return(_T21_)0;}
        T22 LevelColor;
        /* Static Parameters */
        double avg_lots0;
        double group_stop;
        string change_detect0;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_TrailingStopAvgPrice()
        {
                GroupMode = (string)"group";
                Group = (string)"";
                Symbol = (string)CurrentSymbol();
                BuysOrSells = (string)"both";
                TrailWhat = (int)1;
                TrailingStopMode = (string)"fixed";
                tStopPips = CalculateOptimalTrailingStop(Symbol);  // Trailing stop ideal usando o ATR
                tStopMoney = (double)10.0;
                TrailingStepMode = (string)"fixed";
                tStepPips = (double)1.0;
                tStepPercentTS = (double)10.0;
                TrailingStartMode = (string)"none";
                tStartPips = (double)10.0;
                tStartPercentTS = (double)100.0;
                resetOnTrade = (bool)true;
                TrailingTPmode = (string)"none";
                tTPpips = (double)20.0;
                tTPpercentTS = (double)200.0;
                LevelColor = (color)clrDeepPink;
                /* Static Parameters (initial value) */
                avg_lots0 =  0;
                group_stop =  0;
                change_detect0 =  "";
        }

        public: /* The main method */
        virtual void _execute_()
        {
                int index        = 0;
                double avg_price = 0;
                double avg_load  = 0;
                double avg_lots  = 0; // Average sum of lots - it can be negative
                double profit    = 0;
                double askbid    = 0;
                double bidask    = 0;
                int trades_count = 0; // Count of Trades to work with
                bool resetSL     = false;
                ulong tickets[]; ArrayResize(tickets, 0); // Array with tickets to modify
                
                string change_detect         = "";
                
                int total = TradesTotal();
                
                //-- collect group data from trades
                for (index = 0; index < total; index++)
                {
                        if (!TradeSelectByIndex(index, GroupMode, Group, "symbol", Symbol, BuysOrSells)) {continue;}
                        
                        if (OrderType() == 0)
                        {
                                
				avg_load = avg_load + (OrderOpenPrice() * OrderLots());
                                avg_lots = avg_lots + OrderLots();
                        }
                        else
                        {
                                avg_load = avg_load - (OrderOpenPrice() * OrderLots());
                                avg_lots = avg_lots - OrderLots();
                        }
                        
                        ArrayEnsureValue(tickets, (ulong)OrderTicket());
                
                        profit        = profit + NormalizeDouble(OrderProfit() + OrderCommission() + OrderSwap(), 2);
                        change_detect = (string)OrderTicket() + change_detect;
                        trades_count++;
                }
                
                avg_price = 0;
                
                if (avg_lots != 0)
                {
                        avg_price = avg_load / avg_lots;
                }
                
                //-- check and set flag for reset (when new trade or when trade is gone)
                if (change_detect0 != change_detect)
                {
                        if (trades_count == 0)
                        {
                                avg_lots0  = 0;
                                group_stop = 0;
                        }
                        else
                        {
                                group_stop = 0;
                
                                if (resetOnTrade == true)
                                {
                                        avg_lots0 = avg_lots;
                                        resetSL   = true;
                                }
                        }
                
                        change_detect0 = change_detect;
                }
                
                //-- do trailing stop
                if (avg_lots != 0)
                {
                        int polarity = 0;
                
                        if (avg_lots > 0)
                        {
                                polarity = 1;
                                askbid   = SymbolAsk(Symbol);
                                bidask   = SymbolBid(Symbol);
                        }
                        else
                        {
                                polarity = -1;
                                askbid   = SymbolBid(Symbol);
                                bidask   = SymbolAsk(Symbol);
                        }
                
                        // Trailing Stop Size
                        double t_stop = 0;
                
                             if (TrailingStopMode == "fixed")       {t_stop = tStopPips;}
                        else if (TrailingStopMode == "dynamicSize") {t_stop = _ftStop_();}
                        else if (TrailingStopMode == "function")
                        {
                                t_stop = _ftStop_();
                                t_stop = toPips(MathAbs(askbid-t_stop), Symbol);
                        }
                        else if (TrailingStopMode == "money")
                        {
                                double tick_value = SymbolInfoDouble(Symbol, SYMBOL_TRADE_TICK_VALUE);
                                double tick_size  = SymbolInfoDouble(Symbol, SYMBOL_TRADE_TICK_SIZE);
                                double point      = SymbolInfoDouble(Symbol, SYMBOL_POINT);
                
                                double tickvalue = ((tick_value / tick_size) * point);
                
                                t_stop = tStopMoney;
                                t_stop = t_stop /  ((MathAbs(avg_lots) * PipValue(Symbol)));
                                t_stop = t_stop / tickvalue;
                        }
                
                        // Trailing Start Level
                        double t_start = 0;
                
                             if (TrailingStartMode == "none")      {t_start = -EMPTY_VALUE;}
                        else if (TrailingStartMode == "zero")      {t_start = 0;}
                        else if (TrailingStartMode == "fixed")     {t_start = tStartPips;}
                        else if (TrailingStartMode == "percentTS") {t_start = t_stop * (tStartPercentTS / 100);}
                        else if (TrailingStartMode == "function")  {t_start = _ftStart_();}
                
                        // Trailing Step Size
                        double t_step = 0;
                
                             if (TrailingStepMode == "fixed")      {t_step = tStepPips;}
                        else if (TrailingStepMode == "percentTS")  {t_step = t_stop * (tStepPercentTS / 100);}
                
                        // Trailing Take Profit
                        double t_opp = -1;
                
                             if (TrailingTPmode == "none")         {t_opp = -1;}
                        else if (TrailingTPmode == "clear")        {t_opp = 0;}
                        else if (TrailingTPmode == "fixed")        {t_opp = MathAbs(toPips(avg_price - group_stop, Symbol));}
                        else if (TrailingTPmode == "percentTS")    {t_opp = MathAbs(toPips(avg_price - t_stop, Symbol)) * (tTPpercentTS/100);}
                        else if (TrailingTPmode == "function")     {t_opp = _ftTP_();}
                
                        bool go_modify = false;
                
                        if (polarity == 1 && TrailWhat * (askbid - avg_price) > toDigits(t_start, Symbol))
                        {
                                if ((TrailWhat * (askbid - group_stop) >= toDigits(t_stop + t_step, Symbol)) || group_stop==0 || resetSL == true)
                                {
                                        group_stop = (askbid - TrailWhat * toDigits(t_stop, Symbol));
                                        go_modify  = true;
                                }
                        }
                        else if (polarity == -1 && TrailWhat * (avg_price - askbid) > toDigits(t_start, Symbol))
                        {
                                if ((TrailWhat * (group_stop - askbid) >= toDigits(t_stop + t_step, Symbol)) || group_stop == 0 || resetSL == true)
                                {
                                        group_stop = (askbid + TrailWhat * toDigits(t_stop, Symbol));
                                        go_modify  = true;
                                }
                        }
                
                        if (go_modify==true)
                        {
                                for (index = ArraySize(tickets) - 1; index >= 0; index--)
                                {
                                        if (TradeSelectByTicket(tickets[index]))
                                        {
                                                bool success = true;
                                                
                                                // calculate the future stop and the limit
                                                double stopslevel = (double)SymbolInfoInteger(OrderSymbol(), SYMBOL_TRADE_STOPS_LEVEL);
                                                stopslevel        = toDigits(stopslevel / PipValue(OrderSymbol()), OrderSymbol());
                                                double fsl        = MathAbs(group_stop); // future SL
                                                double limit      = 0;
                                                
                                                if (OrderType() == 0)
                                                {
                                                        limit = bidask - stopslevel * TrailWhat;
                                                        if (fsl > limit) {fsl = limit;}
                                                }
                                                else
                                                {
                                                        limit = bidask + stopslevel * TrailWhat;
                                                        if (fsl < limit) {fsl = limit;}
                                                }
                
                                                // trail SL
                                                if (TrailWhat == 1)
                                                {
                                                        if (t_opp < 0) {t_opp = attrTakeProfit();}
                                                        
                                                        // consider limits
                                                        if (
                                                                   attrStopLoss() == 0
                                                                || (OrderType() == 0 && (attrStopLoss() < fsl || resetSL == true))
                                                                || (OrderType() == 1 && (attrStopLoss() > fsl || resetSL == true))
                                                        )
                                                        {
                                                                success = ModifyStops(OrderTicket(), group_stop, t_opp, LevelColor);
                                                        }
                                                }
                                                // trail TP
                                                else
                                                {
                                                        if (t_opp < 0) {t_opp = attrStopLoss();}
                                                        
                                                        // consider limits
                                                        if (
                                                                   attrTakeProfit() == 0
                                                                || (OrderType() == 0 && (attrTakeProfit() > fsl || resetSL == true))
                                                                || (OrderType() == 1 && (attrTakeProfit() < fsl || resetSL == true))
                                                        )
                                                        {
                                                                success = ModifyStops(OrderTicket(), t_opp, group_stop, LevelColor);
                                                        }
                                                }
                                        }
                                }
                        }
                }
                
                _callback_(1);
        }
};

// "Pass" model
class MDL_Pass: public BlockCalls
{
        virtual void _callback_(int r) {return;}

        public: /* The main method */
        virtual void _execute_()
        {
                _callback_(1);
        }
};

// "Comment" model
template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename T10,typename T11,typename T12,typename T13,typename T14,typename T15,typename T16,typename _T16_,typename T17,typename T18,typename T19,typename T20,typename _T20_,typename T21,typename T22,typename T23,typename T24,typename _T24_,typename T25,typename T26,typename T27,typename T28,typename _T28_,typename T29,typename T30,typename T31,typename T32,typename _T32_,typename T33,typename T34,typename T35,typename T36,typename _T36_,typename T37,typename T38,typename T39,typename T40,typename _T40_,typename T41,typename T42,typename T43,typename T44,typename _T44_,typename T45,typename T46>
class MDL_CommentEx: public BlockCalls
{
        public: /* Input Parameters */
        T1 Title;
        T2 ObjChartSubWindow;
        T3 ObjCorner;
        T4 ObjX;
        T5 ObjY;
        T6 ObjTitleFont;
        T7 ObjTitleFontColor;
        T8 ObjTitleFontSize;
        T9 ObjLabelsFont;
        T10 ObjLabelsFontColor;
        T11 ObjLabelsFontSize;
        T12 ObjFont;
        T13 ObjFontColor;
        T14 ObjFontSize;
        T15 Label1;
        T16 Value1; virtual _T16_ _Value1_(){return(_T16_)0;}
        T17 FormatNumber1;
        T18 FormatTime1;
        T19 Label2;
        T20 Value2; virtual _T20_ _Value2_(){return(_T20_)0;}
        T21 FormatNumber2;
        T22 FormatTime2;
        T23 Label3;
        T24 Value3; virtual _T24_ _Value3_(){return(_T24_)0;}
        T25 FormatNumber3;
        T26 FormatTime3;
        T27 Label4;
        T28 Value4; virtual _T28_ _Value4_(){return(_T28_)0;}
        T29 FormatNumber4;
        T30 FormatTime4;
        T31 Label5;
        T32 Value5; virtual _T32_ _Value5_(){return(_T32_)0;}
        T33 FormatNumber5;
        T34 FormatTime5;
        T35 Label6;
        T36 Value6; virtual _T36_ _Value6_(){return(_T36_)0;}
        T37 FormatNumber6;
        T38 FormatTime6;
        T39 Label7;
        T40 Value7; virtual _T40_ _Value7_(){return(_T40_)0;}
        T41 FormatNumber7;
        T42 FormatTime7;
        T43 Label8;
        T44 Value8; virtual _T44_ _Value8_(){return(_T44_)0;}
        T45 FormatNumber8;
        T46 FormatTime8;
        /* Static Parameters */
        bool initialized;
        virtual void _callback_(int r) {return;}

        public: /* Constructor */
        MDL_CommentEx()
        {
                Title = (string)"Comment Message";
                ObjChartSubWindow = (string)"";
                ObjCorner = (int)CORNER_LEFT_UPPER;
                ObjX = (int)5;
                ObjY = (int)24;
                ObjTitleFont = (string)"Georgia";
                ObjTitleFontColor = (color)clrGold;
                ObjTitleFontSize = (int)13;
                ObjLabelsFont = (string)"Verdana";
                ObjLabelsFontColor = (color)clrDarkGray;
                ObjLabelsFontSize = (int)10;
                ObjFont = (string)"Verdana";
                ObjFontColor = (color)clrWhite;
                ObjFontSize = (int)10;
                Label1 = (string)"";
                FormatNumber1 = (int)EMPTY_VALUE;
                FormatTime1 = (int)EMPTY_VALUE;
                Label2 = (string)"";
                FormatNumber2 = (int)EMPTY_VALUE;
                FormatTime2 = (int)EMPTY_VALUE;
                Label3 = (string)"";
                FormatNumber3 = (int)EMPTY_VALUE;
                FormatTime3 = (int)EMPTY_VALUE;
                Label4 = (string)"";
                FormatNumber4 = (int)EMPTY_VALUE;
                FormatTime4 = (int)EMPTY_VALUE;
                Label5 = (string)"";
                FormatNumber5 = (int)EMPTY_VALUE;
                FormatTime5 = (int)EMPTY_VALUE;
                Label6 = (string)"";
                FormatNumber6 = (int)EMPTY_VALUE;
                FormatTime6 = (int)EMPTY_VALUE;
                Label7 = (string)"";
                FormatNumber7 = (int)EMPTY_VALUE;
                FormatTime7 = (int)EMPTY_VALUE;
                Label8 = (string)"";
                FormatNumber8 = (int)EMPTY_VALUE;
                FormatTime8 = (int)EMPTY_VALUE;
                /* Static Parameters (initial value) */
                initialized =  false;
        }

        public: /* The main method */
        virtual void _execute_()
        {
                if (!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_VISUAL_MODE))
                {
                        long ObjChartID = 0;
                        int ObjAnchor   = ANCHOR_LEFT;
                
                        if (ObjCorner == CORNER_RIGHT_UPPER || ObjCorner == CORNER_RIGHT_LOWER)
                        {
                                ObjAnchor = ANCHOR_RIGHT;
                        }
                
                        string namebase = "fxd_cmnt_" + __block_user_number;
                
                        int subwindow = WindowFindVisible(ObjChartID, ObjChartSubWindow);
                
                        if (subwindow >= 0)
                        {
                                //-- draw comment title
                                if ((string)Title != "")
                                {
                                        string nametitle = namebase;
                
                                        if(ObjectFind(ObjChartID, nametitle) < 0)
                                        {
                                                if (!ObjectCreate(ObjChartID, nametitle, OBJ_LABEL, subwindow, 0, 0, 0, 0))
                                                {
                                                        Print(__FUNCTION__, ": failed to create text object! Error code = ", GetLastError());
                                                }
                                                else
                                                {
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_FONTSIZE, (int)(ObjTitleFontSize));
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_COLOR, ObjTitleFontColor);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_BACK, 0);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_SELECTABLE, 1);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_SELECTED, 0);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_HIDDEN, 1);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_CORNER, ObjCorner);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_ANCHOR, ObjAnchor);
                
                                                        ObjectSetString(ObjChartID, nametitle, OBJPROP_FONT, ObjTitleFont);
                
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_XDISTANCE, ObjX);
                                                        ObjectSetInteger(ObjChartID, nametitle, OBJPROP_YDISTANCE, ObjY);
                                                }
                                        }
                                        else
                                        {
                                                ObjX = (int)ObjectGetInteger(ObjChartID, nametitle, OBJPROP_XDISTANCE);
                                                ObjY = (int)ObjectGetInteger(ObjChartID, nametitle, OBJPROP_YDISTANCE);
                                        }
                
                                        ObjectSetString(ObjChartID, nametitle, OBJPROP_TEXT, (string)Title);
                
                                        ObjY = (int)(ObjY + ObjTitleFontSize / 3);
                                }
                
                                //-- draw comment rows
                                for (int i = 1; i <= 8; i++)
                                {
                                        string text    = "";
                                        string textlbl = "";
                
                                        switch(i)
                                        {
                                                case 1:
                                                {
                                                        if (Label1 != "")
                                                        {
                                                                textlbl = Label1;
                                                                text    = FormatValueForPrinting(_Value1_(), FormatNumber1, FormatTime1);
                                                        }
                
                                                        break;
                                                }
                                                case 2:
                                                {
                                                        if (Label2 != "")
                                                        {
                                                                textlbl = Label2;
                                                                text    = FormatValueForPrinting(_Value2_(), FormatNumber2, FormatTime2);
                                                        }
                
                                                        break;
                                                }
                                                case 3:
                                                {
                                                        if (Label3 != "")
                                                        {
                                                                textlbl = Label3;
                                                                text    = FormatValueForPrinting(_Value3_(), FormatNumber3, FormatTime3);
                                                        }
                
                                                        break;
                                                }
                                                case 4:
                                                {
                                                        if (Label4 != "")
                                                        {
                                                                textlbl = Label4;
                                                                text    = FormatValueForPrinting(_Value4_(), FormatNumber4, FormatTime4);
                                                        }
                
                                                        break;
                                                }
                                                case 5:
                                                {
                                                        if (Label5 != "")
                                                        {
                                                                textlbl = Label5;
                                                                text    = FormatValueForPrinting(_Value5_(), FormatNumber5, FormatTime5);
                                                        }
                
                                                        break;
                                                }
                                                case 6:
                                                {
                                                        if (Label6 != "")
                                                        {
                                                                textlbl = Label6;
                                                                text    = FormatValueForPrinting(_Value6_(), FormatNumber6, FormatTime6);
                                                        }
                
                                                        break;
                                                }
                                                case 7:
                                                {
                                                        if (Label7 != "")
                                                        {
                                                                textlbl = Label7;
                                                                text    = FormatValueForPrinting(_Value7_(), FormatNumber7, FormatTime7);
                                                        }
                
                                                        break;
                                                }
                                                case 8:
                                                {
                                                        if (Label8 != "")
                                                        {
                                                                textlbl = Label8;
                                                                text    = FormatValueForPrinting(_Value8_(), FormatNumber8, FormatTime8);
                                                        }
                
                                                        break;
                                                }
                                   }
                
                                        string name    = namebase + "_" + (string)i;
                                        string namelbl = name + "_l";
                
                                        if (textlbl == "")
                                        {
                                                if (!initialized)
                                                {
                                                        //-- pre-delete
                                                        ObjectDelete(ObjChartID, namelbl);
                                                        ObjectDelete(ObjChartID, name);
                                                }
                
                                                continue;
                                        }
                
                                        //-- draw initial objects
                                        if (ObjectFind(ObjChartID, name) < 0)
                                        {
                                                if (textlbl == "")
                                                {
                                                        continue;
                                                }
                
                                                if (ObjectCreate(ObjChartID, namelbl, OBJ_LABEL, subwindow, 0, 0, 0, 0))
                                                {
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_CORNER, ObjCorner);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_ANCHOR, ObjAnchor);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_BACK, 0);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_SELECTABLE, 0);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_SELECTED, 0);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_HIDDEN, 1);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_FONTSIZE, ObjLabelsFontSize);
                                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_COLOR, ObjLabelsFontColor);
                                                        ObjectSetString(ObjChartID, namelbl, OBJPROP_FONT, ObjLabelsFont);
                                                }
                                                else
                                                {
                                                        Print(__FUNCTION__, ": failed to create text object! Error code = ", GetLastError());
                                                }
                
                                                if (ObjectCreate(ObjChartID, name, OBJ_LABEL, subwindow, 0, 0, 0, 0))
                                                {
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_CORNER, ObjCorner);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_ANCHOR, ObjAnchor);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_BACK, 0);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_SELECTABLE, 0);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_SELECTED, 0);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_HIDDEN, 1);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_FONTSIZE, ObjFontSize);
                                                        ObjectSetInteger(ObjChartID, name, OBJPROP_COLOR, ObjFontColor);
                                                        ObjectSetString(ObjChartID, name, OBJPROP_FONT, ObjFont);
                                                }
                                                else
                                                {
                                                        Print(__FUNCTION__, ": failed to create text object! Error code = ", GetLastError());
                                                }
                                        }
                                        else
                                        {
                                                if (textlbl == "")
                                                {
                                                        ObjectDelete(ObjChartID, namelbl);
                                                        ObjectDelete(ObjChartID, name);
                                                        continue;
                                                }
                                        }
                
                                        ObjY  = (int)(ObjY + ObjFontSize + ObjFontSize/2);
                
                                        //-- update label objects
                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_XDISTANCE, ObjX);
                                        ObjectSetInteger(ObjChartID, namelbl, OBJPROP_YDISTANCE, ObjY);
                                        ObjectSetString(ObjChartID, namelbl, OBJPROP_TEXT, (string)textlbl);
                
                                        //-- update value objects
                                        int x        = 0;
                                        int xsizelbl = (int)ObjectGetInteger(ObjChartID, namelbl, OBJPROP_XSIZE);
                
                                        if (xsizelbl == 0) {
                                                //-- when the object is newly created, it returns 0 for XSIZE and YSIZE, so here we will trick it somehow
                                                xsizelbl = (int)(StringLen((string)textlbl) * ObjFontSize / 1.5 + ObjFontSize / 2);
                                        }
                
                                        x = ObjX + (xsizelbl + ObjFontSize/2);
                
                                        ObjectSetInteger(ObjChartID, name, OBJPROP_XDISTANCE, x);
                                        ObjectSetInteger(ObjChartID, name, OBJPROP_YDISTANCE, ObjY);
                                        ObjectSetString(ObjChartID, name, OBJPROP_TEXT, (string)text);
                                }
                                
                                ChartRedraw();
                        }
                
                        initialized = true;
                }
                
                _callback_(1);
        }
};
					



qual parte é responsavel por alterar tamanho do trailing stop  para proteger os ganhos da operação?