//+------------------------------------------------------------------+
//|                                             SimpleOrderPanel.mq5 |
//|                    Copyright 2022, Manuel Alejandro Cercós Pérez |
//|                         https://www.mql5.com/en/users/alexcercos |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Manuel Alejandro Cercós Pérez"
#property link "https://www.mql5.com/en/users/alexcercos"
// #property icon      "\\Images\\ProgramIcons\\simplePanelLogo.ico" //Not included
#property version "2.08"

//+------------------------------------------------------------------+
//| CHANGES NEEDED TO FIX ISSUES                                     |
//+------------------------------------------------------------------+

//  To avoid some errors, it's necessary to change code in Dialog.mqh
// file (to modify variables that are defined as private).
//  Take into consideration that changes made in standard library
// files are reverted with each terminal update. To avoid errors
// when recompiling you can:
//  - Track with git the changes made in the file to revert the deletion
//  - Copy the file "Dialog.mqh" into another folder and change
//   dependencies as needed, so it doesn't change later
//
// If you are using MT4, I recommend using the Controls classes from MT5
// To open the file, press "Alt + G" with the cursor set over the line
// "#include <Controls\Dialog.mqh>" below.
//
// The errors would appear when FIRST COMPILING or after RECOMPILING
//
//+------------------------------------------------------------------+
//| ISSUE 1: DUPLICATED OBJECTS WHEN USING TEMPLATES                 |
//+------------------------------------------------------------------+
#define M_NAME "12345" // Override in panel identifier
//
// Change the function "CreateInstanceId" to the one below:
//+-------------------------------------------------------------------+
//  string CAppDialog::CreateInstanceId(void)
//  {
//  #ifdef M_NAME
//    return M_NAME;
//  #else
//    return(IntegerToString(rand(),5,'0'));
//  #endif
//  }
//+-------------------------------------------------------------------+
//
// If you don't use templates and want to remove the macro M_NAME,
// delete also the following line in this file, at the beginning of
// OnInitEvent (line 1303):
//+-------------------------------------------------------------------+
//  ObjectsDeleteAll(0, M_NAME);
//+-------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| ISSUE 2: HEADER FONT SIZE                                        |
//+------------------------------------------------------------------+
// This issue is not as common (only if your PC has a different text
// size setting than default). You can modify manually the font sizes
// with the input "fontSize". If you want the header text size to
// change too:
//
// Uncomment this line (465) in CControlsDialog::Create
//+-------------------------------------------------------------------+
//  CaptionFontSize(fontSize);
//+-------------------------------------------------------------------+
//
// Add the function definition to the class CDialog (in public or
// protected sections, between lines ~45-85)
//+-------------------------------------------------------------------+
//  void CaptionFontSize(const int size) { m_caption.FontSize(size); }
//+-------------------------------------------------------------------+

#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>

#ifdef __MQL5__

#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\Trade.mqh>

#define POS_TOTAL PositionsTotal()
#define ORD_TOTAL OrdersTotal()
#define ASK_PRICE SymbolInfoDouble(_Symbol, SYMBOL_ASK)
#define BID_PRICE SymbolInfoDouble(_Symbol, SYMBOL_BID)

#define POS_SELECT_BY_INDEX(i)        \
    if (!m_position.SelectByIndex(i)) \
        continue;
#define POS_SYMBOL m_position.Symbol()
#define POS_MAGIC m_position.Magic()
#define POS_TYPE m_position.PositionType()
#define POS_OPEN m_position.PriceOpen()
#define POS_STOP m_position.StopLoss()
#define POS_TAKE_PROFIT m_position.TakeProfit()
#define POS_TICKET m_position.Ticket()

#define ORD_SELECT_BY_INDEX(i)     \
    if (!m_order.SelectByIndex(i)) \
        continue;
#define ORD_SYMBOL m_order.Symbol()
#define ORD_MAGIC m_order.Magic()
#define ORD_TYPE m_order.OrderType()
#define ORD_OPEN m_order.PriceOpen()
#define ORD_STOP m_order.StopLoss()
#define ORD_TAKE_PROFIT m_order.TakeProfit()
#define ORD_TICKET m_order.Ticket()

#define POS_BUY(lots, price, sl, tp) m_trade.Buy(lots, _Symbol, price, sl, tp, trade_comment);
#define POS_SELL(lots, price, sl, tp) m_trade.Sell(lots, _Symbol, price, sl, tp, trade_comment);
#define ORDER_BUY_LIMIT(lots, price, sl, tp) m_trade.BuyLimit(lots, price, _Symbol, sl, tp, ORDER_TIME_GTC, 0, trade_comment);
#define ORDER_BUY_STOP(lots, price, sl, tp) m_trade.BuyStop(lots, price, _Symbol, sl, tp, ORDER_TIME_GTC, 0, trade_comment);
#define ORDER_SELL_LIMIT(lots, price, sl, tp) m_trade.SellLimit(lots, price, _Symbol, sl, tp, ORDER_TIME_GTC, 0, trade_comment);
#define ORDER_SELL_STOP(lots, price, sl, tp) m_trade.SellStop(lots, price, _Symbol, sl, tp, ORDER_TIME_GTC, 0, trade_comment);
#define POS_MODIFY(ticket, stop, take)               \
    if (!m_trade.PositionModify(ticket, stop, take)) \
        Print("Error modyfing position: ", GetLastError());
#define POS_CLOSE(ticket)               \
    if (!m_trade.PositionClose(ticket)) \
        Print("Error closing position, ", GetLastError());
#define POS_CLOSE_PARTIAL(ticket)                           \
    if (!m_trade.PositionClosePartial(ticket, partialLots)) \
        Print("Error closing partial position, ", GetLastError());

#define ORD_DELETE(ticket)            \
    if (!m_trade.OrderDelete(ticket)) \
        Print("Error deleting order, ", GetLastError());
#define ORD_MODIFY(ticket, stop, take)                                         \
    if (!m_trade.OrderModify(ticket, ORD_OPEN, stop, take, ORDER_TIME_GTC, 0)) \
        Print("Error modyfing order: ", GetLastError());

#define TRIM_STRING_LEFT(param) StringTrimLeft(param)
#define TRIM_STRING_RIGHT(param) StringTrimRight(param)

CTrade m_trade;
CPositionInfo m_position;
COrderInfo m_order;

#else //__MQL4__

#define POSITION_TYPE_BUY OP_BUY
#define POSITION_TYPE_SELL OP_SELL

#define POS_TOTAL OrdersTotal()
#define ORD_TOTAL OrdersTotal()
#define ASK_PRICE Ask
#define BID_PRICE Bid

#define POS_SELECT_BY_INDEX(i)                       \
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) \
        continue;
#define POS_SYMBOL OrderSymbol()
#define POS_MAGIC OrderMagicNumber()
#define POS_TYPE OrderType()
#define POS_OPEN OrderOpenPrice()
#define POS_STOP OrderStopLoss()
#define POS_TAKE_PROFIT OrderTakeProfit()
#define POS_TICKET OrderTicket()

#define ORD_SELECT_BY_INDEX(i)                       \
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) \
        continue;
#define ORD_SYMBOL OrderSymbol()
#define ORD_MAGIC OrderMagicNumber()
#define ORD_TYPE OrderType()
#define ORD_OPEN OrderOpenPrice()
#define ORD_STOP OrderStopLoss()
#define ORD_TAKE_PROFIT OrderTakeProfit()
#define ORD_TICKET OrderTicket()

#define POS_BUY(lots, price, sl, tp) OrderSend(_Symbol, OP_BUY, lots, price, expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define POS_SELL(lots, price, sl, tp) OrderSend(_Symbol, OP_SELL, lots, price, expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define ORDER_BUY_LIMIT(lots, price, sl, tp) OrderSend(_Symbol, OP_BUYLIMIT, lots, NormalizeDouble(price, _Digits), expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define ORDER_BUY_STOP(lots, price, sl, tp) OrderSend(_Symbol, OP_BUYSTOP, lots, NormalizeDouble(price, _Digits), expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define ORDER_SELL_LIMIT(lots, price, sl, tp) OrderSend(_Symbol, OP_SELLLIMIT, lots, NormalizeDouble(price, _Digits), expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define ORDER_SELL_STOP(lots, price, sl, tp) OrderSend(_Symbol, OP_SELLSTOP, lots, NormalizeDouble(price, _Digits), expertDeviation, sl, tp, trade_comment, expertMagic, 0, clrNONE);
#define POS_MODIFY(ticket, stop, take)                                          \
    if (!OrderModify(ticket, POS_OPEN, stop, take, OrderExpiration(), clrNONE)) \
        Print("Error modyfing position: ", GetLastError());
#define POS_CLOSE(ticket)                                                 \
    if (POS_TYPE == POSITION_TYPE_BUY)                                    \
    {                                                                     \
        if (!OrderClose(ticket, OrderLots(), BID_PRICE, expertDeviation)) \
            Print("Error closing position, ", GetLastError());            \
    }                                                                     \
    else if (POS_TYPE == POSITION_TYPE_SELL)                              \
    {                                                                     \
        if (!OrderClose(ticket, OrderLots(), ASK_PRICE, expertDeviation)) \
            Print("Error closing position, ", GetLastError());            \
    }
#define POS_CLOSE_PARTIAL(ticket)                                                               \
    if (POS_TYPE == POSITION_TYPE_BUY)                                                          \
    {                                                                                           \
        if (!OrderClose(ticket, MathMin(partialLots, OrderLots()), BID_PRICE, expertDeviation)) \
            Print("Error closing partial position, ", GetLastError());                          \
    }                                                                                           \
    else if (POS_TYPE == POSITION_TYPE_SELL)                                                    \
    {                                                                                           \
        if (!OrderClose(ticket, MathMin(partialLots, OrderLots()), ASK_PRICE, expertDeviation)) \
            Print("Error closing partial position, ", GetLastError());                          \
    }

#define ORD_DELETE(ticket)    \
    if (!OrderDelete(ticket)) \
        Print("Error deleting order, ", GetLastError());
#define ORD_MODIFY(ticket, stop, take)                                          \
    if (!OrderModify(ticket, ORD_OPEN, stop, take, OrderExpiration(), clrNONE)) \
        Print("Error modyfing order: ", GetLastError());

#define TRIM_STRING_LEFT(param) param = StringTrimLeft(param)
#define TRIM_STRING_RIGHT(param) param = StringTrimRight(param)

#endif

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT (11)    // indent from left (with allowance for border width)
#define INDENT_TOP (11)     // indent from top (with allowance for border width)
#define INDENT_RIGHT (11)   // indent from right (with allowance for border width)
#define INDENT_BOTTOM (11)  // indent from bottom (with allowance for border width)
#define CONTROLS_GAP_X (10) // gap by X coordinate
#define CONTROLS_GAP_Y (10) // gap by Y coordinate
//--- for buttons
#define BUTTON_WIDTH (100) // size by X coordinate
#define BUTTON_HEIGHT (25) // size by Y coordinate

#define RISK_LABEL "RISK"
#define STOP_EDIT "SL_EDIT"
#define TAKE_EDIT "TP_EDIT"
#define RISK_EDIT "R_EDIT"
#define BUY_BUTTON "BUY"
#define SELL_BUTTON "SELL"
#define BREAKEVEN_BUTTON "SL BREAKEVEN"
#define CLOSE_BUTTON "CLOSE ALL"
#define CLOSE_BUY_BUTTON "CLOSE BUYS"
#define CLOSE_SELL_BUTTON "CLOSE SELLS"
#define STOP_BUTTON "MODIFY SL"
#define TAKE_BUTTON "MODIFY TP"
#define PARTIAL_EDIT "PARTIAL_EDIT"
#define PARTIAL_BUTTON "CLOSE PARTIAL"
#define COMMENT_EDIT "COMM_EDIT"
#define BUY_PEND_BUTTON "PENDING BUY"
#define SELL_PEND_BUTTON "PENDING SELL"
#define DELETE_BUY_PEND_BUTTON "DEL BUY ORD."
#define DELETE_SELL_PEND_BUTTON "DEL SELL ORD."

#define GVAR_POSITION_X "SimplePanel_positionX"
#define GVAR_POSITION_Y "SimplePanel_positionY"
#define GVAR_RISK_NAME "SimplePanel_risk_percent"
#define GVAR_CALC_TYPE "SimplePanel_calc_mode"
#define GVAR_STOP_LOSS "SimplePanel_stop_loss"
#define GVAR_TAKE_PROFIT "SimplePanel_take_profit"
#define GVAR_PARTIAL_LOTS "SimplePanel_partial_close"

//+------------------------------------------------------------------+
//| Enumerators (for inputs)                                         |
//+------------------------------------------------------------------+
enum RiskMode
{
    BALANCE_PERCENT, // Percentage of balance
    FIXED_LOTS       // Fixed lots
};

enum SLTPMode
{
    ST_PRICE,   // Price
    ST_DISTANCE // Distance to open price (>0)
};

enum BidAskMode
{
    BA_NORMAL,   // Bid for sell/Ask for buy
    BA_INVERT,   // Ask for sell/Bid for buy (inv)
    BA_ONLY_ASK, // Only Ask price
    BA_ONLY_BID  // Only Bid price
};

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
#ifdef __MQL5__
input group "Trade Settings"
#endif
    input RiskMode riskCalculation = FIXED_LOTS; // Risk calculation mode
input SLTPMode stop_takeMode = ST_DISTANCE;      // SL/TP Mode
input BidAskMode bidAskReference = BA_NORMAL;    // Price reference for SL and TP
input int expertDeviation = 20;                  // Maximum slippage
input int expertMagic = 10001;                   // Expert Magic number
input bool affectOtherTrades = false;            // Modify external trades (not opened by the panel)

#ifdef __MQL5__
input group "Buttons"
#endif
    input bool showBuySellButtons = true;  // Show Buy/Sell buttons
input bool showCloseSepButtons = false;    // Show Close Buy/Sell buttons
input bool showSLBECloseAllButtons = true; // Show SL to BE and Close All buttons
input bool showModifyButtons = false;      // Show Modify SL/TP buttons
input bool showPartialClose = false;       // Show Partial Close
input bool showPendingOrder = false;       // Show Pending Orders
input bool showDeleteOrder = false;        // Show Delete Pending Orders
input bool showCommentEdit = false;        // Show Edit Comment

#ifdef __MQL5__
input group "Other settings"
#endif
    input bool grabSLwithDrag = false; // Pick SL values with crosshair drag (Dist. mode)
input int fontSize = 10;               // Font size
input double autoSetTP = 0.0;          // Auto-set TP to SL ratio (0=don't use)
input bool autoSetSL = true;           // Auto-set SL to ratio from TP change
#ifdef __MQL5__
input bool asyncOperations = false; // Use asynchronous orders
#endif

int lot_digits = 2;
double riskAmount = 2.0;
double stopLoss = 0.0;
double takeProfit = 0.0;
double partialLots = 1.0;

string trade_comment = NULL;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
{
private:
    CLabel m_label, m_stoploss_label, m_takeprofit_label;
    CEdit m_edit, m_stoploss_edit, m_takeprofit_edit;
    CButton m_buy_button, m_sell_button, m_breakeven_button, m_close_button, m_modify_sl_button, m_modify_tp_button;
    CButton m_close_buys_button, m_close_sell_button, m_buy_order_button, m_sell_order_button, m_delete_buy_button, m_delete_sell_button;
    CEdit m_partial_edit;
    CButton m_partial_button;
    CEdit m_comment_edit;

public:
    //--- create
    virtual bool Create(const string name);
    //--- chart event handler
    virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

    double GetRiskPercent();
    double GetStopLoss();
    double GetTakeProfit();
    double GetPartialLots();

    void SetStopLoss(int stop);

protected:
    //--- create dependent controls
    bool CreateButton(CButton &button, string name, int x1, int y1, int x2, int y2, color clr_back = clrDarkCyan);
    bool CreateEdit(CEdit &edit, string name, string editText, int x1, int y1, int x2, int y2);
    bool CreateLabel(CLabel &label, string name, int x1, int y1, int x2, int y2);
    //--- handlers of the dependent controls events
    void OnEndEditRisk(void);
    void OnEndEditSL(void);
    void OnEndEditTP(void);
    void OnClickBuyButton(void);
    void OnClickSellButton(void);
    void OnClickBreakevenButton(void);
    void OnClickCloseButton(void);
    void OnClickCloseBuyButton(void);
    void OnClickCloseSellButton(void);
    void OnClickModifySLButton(void);
    void OnClickModifyTPButton(void);
    void OnEditPartialClose(void);
    void OnClickPartialCloseButton(void);
    void OnEditComment(void);
    void OnClickBuyOrderButton(void);
    void OnClickSellOrderButton(void);
    void OnClickDeleteBuyOrders(void);
    void OnClickDeleteSellOrders(void);

    void WriteExpertSettings();
    void RestoreExpertSettings();
    void RestoreStopTakeValues();

    void RestoreComment();
    void SaveComment();

    double NormalizeLots(double lots);
};

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CControlsDialog)
ON_EVENT(ON_END_EDIT, m_edit, OnEndEditRisk)
ON_EVENT(ON_END_EDIT, m_stoploss_edit, OnEndEditSL)
ON_EVENT(ON_END_EDIT, m_takeprofit_edit, OnEndEditTP)
if (showBuySellButtons)
{
    ON_EVENT(ON_CLICK, m_buy_button, OnClickBuyButton)
    ON_EVENT(ON_CLICK, m_sell_button, OnClickSellButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showCloseSepButtons)
{
    ON_EVENT(ON_CLICK, m_close_buys_button, OnClickCloseBuyButton)
    ON_EVENT(ON_CLICK, m_close_sell_button, OnClickCloseSellButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showSLBECloseAllButtons)
{
    ON_EVENT(ON_CLICK, m_breakeven_button, OnClickBreakevenButton)
    ON_EVENT(ON_CLICK, m_close_button, OnClickCloseButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showModifyButtons)
{
    ON_EVENT(ON_CLICK, m_modify_sl_button, OnClickModifySLButton)
    ON_EVENT(ON_CLICK, m_modify_tp_button, OnClickModifyTPButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showPartialClose)
{
    ON_EVENT(ON_END_EDIT, m_partial_edit, OnEditPartialClose)
    ON_EVENT(ON_CLICK, m_partial_button, OnClickPartialCloseButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showCommentEdit)
{
    ON_EVENT(ON_END_EDIT, m_comment_edit, OnEditComment)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showPendingOrder)
{
    ON_EVENT(ON_CLICK, m_buy_order_button, OnClickBuyOrderButton)
    ON_EVENT(ON_CLICK, m_sell_order_button, OnClickSellOrderButton)
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if (showDeleteOrder)
{
    ON_EVENT(ON_CLICK, m_delete_buy_button, OnClickDeleteBuyOrders)
    ON_EVENT(ON_CLICK, m_delete_sell_button, OnClickDeleteSellOrders)
}
EVENT_MAP_END(CAppDialog)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const string name)
{
    stopLoss = 0.0;
    takeProfit = 0.0;
    partialLots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

    RestoreExpertSettings();

    int rows = 3;

    if (showBuySellButtons)
        rows++;
    if (showCloseSepButtons)
        rows++;
    if (showSLBECloseAllButtons)
        rows++;
    if (showModifyButtons)
        rows++;
    if (showPartialClose)
        rows++;
    if (showCommentEdit)
        rows++;
    if (showPendingOrder)
        rows++;
    if (showDeleteOrder)
        rows++;

    if (rows == 3)
    {
        Print("Error: no buttons are being shown");
        return false;
    }

    // Get position
    int x1 = 100;
    int y1 = 40;
    if (GlobalVariableCheck(GVAR_POSITION_X))
        x1 = (int)GlobalVariableGet(GVAR_POSITION_X);
    else
        GlobalVariableSet(GVAR_POSITION_X, x1);

    if (GlobalVariableCheck(GVAR_POSITION_Y))
        y1 = (int)GlobalVariableGet(GVAR_POSITION_Y);
    else
        GlobalVariableSet(GVAR_POSITION_Y, y1);

    int x2 = 8 + x1 + INDENT_LEFT + 2 * BUTTON_WIDTH + CONTROLS_GAP_X + INDENT_RIGHT;
    int y2 = 30 + y1 + INDENT_TOP + rows * BUTTON_HEIGHT + (rows - 1) * CONTROLS_GAP_Y + INDENT_BOTTOM;

    if (!CAppDialog::Create(0, name, 1, x1, y1, x2, y2))
        return (false);
    // CaptionFontSize(fontSize); //CUSTOM function defined in CDialog

    int bx1 = INDENT_LEFT;
    int by1 = INDENT_TOP;
    int bx2 = bx1 + BUTTON_WIDTH;
    int by2 = by1 + BUTTON_HEIGHT;

#define NEXT_COLUMN                         \
    bx1 += (BUTTON_WIDTH + CONTROLS_GAP_X); \
    bx2 += (BUTTON_WIDTH + CONTROLS_GAP_X);

#define PREV_COLUMN                         \
    bx1 -= (BUTTON_WIDTH + CONTROLS_GAP_X); \
    bx2 -= (BUTTON_WIDTH + CONTROLS_GAP_X);

#define NEXT_ROW                             \
    by1 += (BUTTON_HEIGHT + CONTROLS_GAP_Y); \
    by2 += (BUTTON_HEIGHT + CONTROLS_GAP_Y);

    if (!CreateLabel(m_label, riskCalculation == BALANCE_PERCENT ? "RISK %" : "LOTS", bx1 + BUTTON_WIDTH / 2, by1, bx2, by2))
        return (false);

    NEXT_COLUMN

    string riskText;
    if (riskCalculation == BALANCE_PERCENT)
        riskText = DoubleToString(riskAmount, 2) + " %";
    else
        riskText = DoubleToString(riskAmount, lot_digits);

    if (!CreateEdit(m_edit, RISK_EDIT, riskText, bx1, by1, bx2, by2))
        return (false);

    PREV_COLUMN
    NEXT_ROW

    if (!CreateLabel(m_stoploss_label, stop_takeMode == ST_DISTANCE ? "SL (points)" : "SL (price)", bx1 + BUTTON_WIDTH / 3, by1, bx2, by2))
        return (false);

    NEXT_COLUMN

    string sl_edit_str = stop_takeMode == ST_DISTANCE ? DoubleToString(stopLoss, 0) : DoubleToString(stopLoss, _Digits);

    if (!CreateEdit(m_stoploss_edit, STOP_EDIT, sl_edit_str, bx1, by1, bx2, by2))
        return (false);

    PREV_COLUMN
    NEXT_ROW

    if (!CreateLabel(m_takeprofit_label, stop_takeMode == ST_DISTANCE ? "TP (points)" : "TP (price)", bx1 + BUTTON_WIDTH / 3, by1, bx2, by2))
        return (false);

    NEXT_COLUMN

    string tp_edit_str = stop_takeMode == ST_DISTANCE ? DoubleToString(takeProfit, 0) : DoubleToString(takeProfit, _Digits);

    if (!CreateEdit(m_takeprofit_edit, TAKE_EDIT, tp_edit_str, bx1, by1, bx2, by2))
        return (false);

    if (showBuySellButtons)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_buy_button, BUY_BUTTON, bx1, by1, bx2, by2, clrGreen))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_sell_button, SELL_BUTTON, bx1, by1, bx2, by2, clrRed))
            return (false);
    }

    if (showCloseSepButtons)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_close_buys_button, CLOSE_BUY_BUTTON, bx1, by1, bx2, by2, clrDarkSlateGray))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_close_sell_button, CLOSE_SELL_BUTTON, bx1, by1, bx2, by2, clrDarkRed))
            return (false);
    }

    if (showSLBECloseAllButtons)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_breakeven_button, BREAKEVEN_BUTTON, bx1, by1, bx2, by2, clrGray))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_close_button, CLOSE_BUTTON, bx1, by1, bx2, by2, clrBlue))
            return (false);
    }

    if (showModifyButtons)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_modify_sl_button, STOP_BUTTON, bx1, by1, bx2, by2, clrIndianRed))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_modify_tp_button, TAKE_BUTTON, bx1, by1, bx2, by2, clrDarkCyan))
            return (false);
    }

    if (showPartialClose)
    {
        PREV_COLUMN
        NEXT_ROW

        string partialEdit = DoubleToString(partialLots, lot_digits);
        if (!CreateEdit(m_partial_edit, PARTIAL_EDIT, partialEdit, bx1, by1, bx2, by2))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_partial_button, PARTIAL_BUTTON, bx1, by1, bx2, by2, clrSlateBlue))
            return (false);
    }

    if (showPendingOrder)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_buy_order_button, BUY_PEND_BUTTON, bx1, by1, bx2, by2, clrLimeGreen))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_sell_order_button, SELL_PEND_BUTTON, bx1, by1, bx2, by2, clrOrangeRed))
            return (false);
    }

    if (showDeleteOrder)
    {
        PREV_COLUMN
        NEXT_ROW

        if (!CreateButton(m_delete_buy_button, DELETE_BUY_PEND_BUTTON, bx1, by1, bx2, by2, clrDarkGreen))
            return (false);

        NEXT_COLUMN

        if (!CreateButton(m_delete_sell_button, DELETE_SELL_PEND_BUTTON, bx1, by1, bx2, by2, clrMaroon))
            return (false);
    }

    if (showCommentEdit)
    {
        bx1 -= (BUTTON_WIDTH + CONTROLS_GAP_X); // Keep bx2 at the end
        NEXT_ROW

        if (!CreateEdit(m_comment_edit, COMMENT_EDIT, trade_comment, bx1, by1, bx2, by2))
            return (false);
    }

    //--- succeed
    return (true);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButton(CButton &button, string name, int x1, int y1, int x2, int y2, color clr_back = clrDarkCyan)
{
    //--- create
    if (!button.Create(m_chart_id, m_name + name, m_subwin, x1, y1, x2, y2))
        return (false);
    if (!button.Text(name))
        return (false);
    if (!button.FontSize(fontSize))
        return (false);
    button.ColorBorder(clrBlack);
    button.Color(clrWhite);
    button.ColorBackground(clr_back);

    if (!Add(button))
        return (false);
    //--- succeed
    return (true);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CControlsDialog::GetRiskPercent(void)
{
    if (riskCalculation == FIXED_LOTS)
        return NormalizeLots(StringToDouble(m_edit.Text()));
    return MathMin(MathMax(StringToDouble(m_edit.Text()), 0.0), 100.0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CControlsDialog::GetStopLoss(void)
{
    return MathMax(StringToDouble(m_stoploss_edit.Text()), 0.0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CControlsDialog::GetTakeProfit(void)
{
    return MathMax(StringToDouble(m_takeprofit_edit.Text()), 0.0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CControlsDialog::GetPartialLots(void)
{
    return NormalizeLots(StringToDouble(m_partial_edit.Text()));
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateEdit(CEdit &edit, string name, string editText, int x1, int y1, int x2, int y2)
{
    //--- create
    if (!edit.Create(m_chart_id, m_name + name, m_subwin, x1, y1, x2, y2))
        return (false);

    if (!edit.ReadOnly(false))
        return (false);

    if (!edit.Text(editText))
        return (false);
    if (!edit.FontSize(fontSize))
        return (false);
    if (!edit.TextAlign(ALIGN_CENTER))
        return (false);
    if (!Add(edit))
        return (false);
    //--- succeed
    return (true);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateLabel(CLabel &label, string name, int x1, int y1, int x2, int y2)
{
    //--- create
    if (!label.Create(m_chart_id, m_name + name, m_subwin, x1, y1, x2, y2))
        return (false);
    if (!label.Text(name))
        return (false);
    if (!label.FontSize(fontSize))
        return (false);
    if (!Add(label))
        return (false);
    //--- succeed
    return (true);
}

#define PENDING_SETLINE "SOP_setline"

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickBuyButton(void)
{
    Print("Buy pressed");

    RecalculateValues(POSITION_TYPE_BUY);

    if (!CheckLots())
        return;

    double ask = ASK_PRICE;

    double sl = 0.0;
    double tp = 0.0;

    if (stop_takeMode == ST_PRICE)
    {
        sl = stopLoss;
        tp = takeProfit;
    }
    else
    {
        double ref = (bidAskReference == BA_NORMAL || bidAskReference == BA_ONLY_ASK) ? ask : BID_PRICE;

        if (stopLoss != 0.0)
            sl = ref - stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
        if (takeProfit != 0.0)
            tp = ref + takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    }

    POS_BUY(totalLots, ask, sl, tp)
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickBuyOrderButton(void)
{
    Print("Pending Buy pressed");

    setting_buy = true;
    setting_sell = false;

    CreatePendingSetLine(clrGreen, ASK_PRICE);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickSellButton(void)
{
    Print("Sell pressed");

    RecalculateValues(POSITION_TYPE_SELL);

    if (!CheckLots())
        return;

    double bid = BID_PRICE;

    double sl = 0.0;
    double tp = 0.0;

    if (stop_takeMode == ST_PRICE)
    {
        sl = stopLoss;
        tp = takeProfit;
    }
    else
    {
        double ref = (bidAskReference == BA_NORMAL || bidAskReference == BA_ONLY_BID) ? bid : ASK_PRICE;

        if (stopLoss != 0.0)
            sl = ref + stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
        if (takeProfit != 0.0)
            tp = ref - takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    }

    POS_SELL(totalLots, bid, sl, tp)
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickSellOrderButton(void)
{
    Print("Pending Sell pressed");

    setting_sell = true;
    setting_buy = false;

    CreatePendingSetLine(clrRed, BID_PRICE);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickBreakevenButton(void)
{
    Print("Breakeven pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            if (POS_TYPE == POSITION_TYPE_BUY)
            {
                double bid = BID_PRICE;
                if (bid <= POS_OPEN)
                {
                    continue;
                }
            }
            else if (POS_TYPE == POSITION_TYPE_SELL)
            {
                double ask = ASK_PRICE;
                if (ask >= POS_OPEN)
                {
                    continue;
                }
            }
            else
                continue; // Pending orders

            if (POS_OPEN == POS_STOP)
            {
                continue;
            }

            POS_MODIFY(POS_TICKET, POS_OPEN, POS_TAKE_PROFIT)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickCloseButton(void)
{
    Print("Close pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            POS_CLOSE(POS_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickCloseBuyButton(void)
{
    Print("Close Buy pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_TYPE == POSITION_TYPE_SELL)
            continue;

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            POS_CLOSE(POS_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickDeleteBuyOrders(void)
{
    Print("Delete Pending Buys pressed");

    for (int j = ORD_TOTAL - 1; j >= 0; j--)
    {
        ORD_SELECT_BY_INDEX(j)

        if (ORD_TYPE != ORDER_TYPE_BUY_LIMIT && ORD_TYPE != ORDER_TYPE_BUY_STOP)
            continue;

        if (ORD_SYMBOL == _Symbol && (affectOtherTrades || ORD_MAGIC == expertMagic))
        {
            ORD_DELETE(ORD_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickCloseSellButton(void)
{
    Print("Close Sell pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_TYPE == POSITION_TYPE_BUY)
            continue;

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            POS_CLOSE(POS_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickDeleteSellOrders(void)
{
    Print("Delete Pending Sell pressed");

    for (int j = ORD_TOTAL - 1; j >= 0; j--)
    {
        ORD_SELECT_BY_INDEX(j)

        if (ORD_TYPE != ORDER_TYPE_SELL_LIMIT && ORD_TYPE != ORDER_TYPE_SELL_STOP)
            continue;

        if (ORD_SYMBOL == _Symbol && (affectOtherTrades || ORD_MAGIC == expertMagic))
        {
            ORD_DELETE(ORD_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickModifySLButton(void)
{
    Print("Modify Stop Loss pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            double sl = 0.0;

            if (stop_takeMode == ST_PRICE)
            {
                sl = stopLoss;
            }
            else
            {

                if (stopLoss != 0.0)
                {
                    if (POS_TYPE == POSITION_TYPE_BUY)
                        sl = BID_PRICE - stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
                    else if (POS_TYPE == POSITION_TYPE_SELL)
                        sl = ASK_PRICE + stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
                    else
                        continue; // Pending orders
                }
            }

            if (sl != POS_STOP)
            {
                POS_MODIFY(POS_TICKET, sl, POS_TAKE_PROFIT)
            }
            else
            {
                Print("Stop Loss is already " + (string)sl);
            }
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickModifyTPButton(void)
{
    Print("Modify Take Profit pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            double tp = 0.0;

            if (stop_takeMode == ST_PRICE)
            {
                tp = takeProfit;
            }
            else
            {

                if (takeProfit != 0.0)
                {
                    if (POS_TYPE == POSITION_TYPE_BUY)
                        tp = ASK_PRICE + takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
                    else if (POS_TYPE == POSITION_TYPE_SELL)
                        tp = BID_PRICE - takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
                    else
                        continue;
                }
            }

            if (tp != POS_TAKE_PROFIT)
            {
                POS_MODIFY(POS_TICKET, POS_STOP, tp)
            }
            else
            {
                Print("Take Profit is already " + (string)tp);
            }
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickPartialCloseButton(void)
{
    Print("Close Partial pressed");

    for (int i = POS_TOTAL - 1; i >= 0; i--)
    {
        POS_SELECT_BY_INDEX(i)

        if (POS_SYMBOL == _Symbol && (affectOtherTrades || POS_MAGIC == expertMagic))
        {
            POS_CLOSE_PARTIAL(POS_TICKET)
        }
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnEndEditRisk(void)
{
    riskAmount = GetRiskPercent();
    if (riskCalculation == BALANCE_PERCENT)
        m_edit.Text(DoubleToString(riskAmount, 2) + " %");
    else
        m_edit.Text(DoubleToString(riskAmount, lot_digits));
    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnEndEditSL(void)
{
    stopLoss = GetStopLoss();

    if (stop_takeMode == ST_PRICE)
        m_stoploss_edit.Text(DoubleToString(stopLoss, _Digits));
    else
        m_stoploss_edit.Text(DoubleToString(stopLoss, 0));

    if (autoSetTP > 0.0 && stop_takeMode == ST_DISTANCE)
    {
        takeProfit = MathRound(stopLoss * autoSetTP);
        m_takeprofit_edit.Text(DoubleToString(takeProfit, 0));
    }

    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnEndEditTP(void)
{
    takeProfit = GetTakeProfit();

    if (stop_takeMode == ST_PRICE)
        m_takeprofit_edit.Text(DoubleToString(takeProfit, _Digits));
    else
        m_takeprofit_edit.Text(DoubleToString(takeProfit, 0));

    if (autoSetSL && autoSetTP > 0.0 && stop_takeMode == ST_DISTANCE)
    {
        stopLoss = MathRound(takeProfit / autoSetTP);
        m_stoploss_edit.Text(DoubleToString(stopLoss, 0));
    }

    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnEditPartialClose(void)
{
    partialLots = GetPartialLots();

    m_partial_edit.Text(DoubleToString(partialLots, lot_digits));

    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::OnEditComment(void)
{
    trade_comment = m_comment_edit.Text();
    SaveComment();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::RestoreExpertSettings(void)
{
    if (showCommentEdit)
        RestoreComment();
    else
        trade_comment = NULL;

    if (GlobalVariableCheck(GVAR_RISK_NAME))
    {
        riskAmount = GlobalVariableGet(GVAR_RISK_NAME);
        if (riskCalculation == FIXED_LOTS)
            riskAmount = NormalizeLots(riskAmount);
        partialLots = NormalizeLots(GlobalVariableGet(GVAR_PARTIAL_LOTS));

        RestoreStopTakeValues();
    }
    else
    {
        WriteExpertSettings();
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::WriteExpertSettings(void)
{
    GlobalVariableSet(GVAR_RISK_NAME, riskAmount);
    GlobalVariableSet(GVAR_CALC_TYPE, stop_takeMode);
    GlobalVariableSet(GVAR_STOP_LOSS, stopLoss);
    GlobalVariableSet(GVAR_TAKE_PROFIT, takeProfit);
    GlobalVariableSet(GVAR_PARTIAL_LOTS, partialLots);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::RestoreStopTakeValues(void)
{
    if (GlobalVariableCheck(GVAR_CALC_TYPE))
    {
        int typeCalc = (int)GlobalVariableGet(GVAR_CALC_TYPE);

        if (typeCalc == stop_takeMode)
        {
            stopLoss = GlobalVariableGet(GVAR_STOP_LOSS);
            takeProfit = GlobalVariableGet(GVAR_TAKE_PROFIT);

            return;
        }
    }

    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::RestoreComment(void)
{
    if (!FileIsExist("SOP_SavedComment.txt"))
        return;

    int file = FileOpen("SOP_SavedComment.txt", FILE_READ | FILE_TXT | FILE_SHARE_READ);

    if (file == INVALID_HANDLE)
    {
        Print("Error reading comment in file");
        return;
    }
    trade_comment = FileReadString(file);
    FileClose(file);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::SaveComment(void)
{
    int file = FileOpen("SOP_SavedComment.txt", FILE_WRITE | FILE_TXT);

    if (file == INVALID_HANDLE)
    {
        Print("Error saving comment in file");
        return;
    }

    FileWrite(file, trade_comment);
    FileClose(file);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CControlsDialog::NormalizeLots(double lots)
{
    double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
    return MathMax(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN),
                   MathMin(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX),
                           MathFloor(lots / lotStep) * lotStep));
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CControlsDialog::SetStopLoss(int stop)
{
    stopLoss = stop;
    m_stoploss_edit.Text(IntegerToString(stop));

    if (autoSetTP > 0.0 && stop_takeMode == ST_DISTANCE)
    {
        takeProfit = MathRound(stopLoss * autoSetTP);
        m_takeprofit_edit.Text(DoubleToString(takeProfit, 0));
    }

    ChartRedraw();
    WriteExpertSettings();
}

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
CControlsDialog ExtDialog;

double totalLots;
MqlRates currentRates[2];

bool is_tracking = false;
double recorded_price = 0.0;

bool setting_buy = false;
bool setting_sell = false;
int xysub;
double xyprice;
datetime xytime;

//+------------------------------------------------------------------+
//| Event handlers                                                   |
//+------------------------------------------------------------------+
int OnInitEvent()
{
    ObjectsDeleteAll(0, M_NAME); // Remove elements in chart (for template issues)
    lot_digits = int(-MathLog10(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP)));

    if (!ExtDialog.Create("Simple Panel"))
        return (INIT_FAILED);

    ExtDialog.Run();

#ifdef __MQL5__
    m_trade.SetExpertMagicNumber(expertMagic);
    m_trade.SetDeviationInPoints(expertDeviation);
    if (asyncOperations)
        m_trade.SetAsyncMode(true);
#endif

    setting_buy = false;
    setting_sell = false;

    return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinitEvent(const int reason)
{
    GlobalVariableSet(GVAR_POSITION_X, ExtDialog.Left());
    GlobalVariableSet(GVAR_POSITION_Y, ExtDialog.Top());

    DeletePendingSetLine();
    Comment("");
    ExtDialog.Destroy(reason);
}

#define MASK_RIGHT_CLICK 2
#define MASK_RIGHT_MIDDLE 16

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CommonChartEvent(const int id,         // event ID
                      const long &lparam,   // event parameter of the long type
                      const double &dparam, // event parameter of the double type
                      const string &sparam) // event parameter of the string type
{
    if (setting_buy || setting_sell)
    {
        int smask = (int)StringToInteger(sparam);

        if ((id == CHARTEVENT_KEYDOWN && lparam == 27) || // ESC
            (id == CHARTEVENT_MOUSE_MOVE &&
             ((smask & MASK_RIGHT_CLICK) > 0 ||
              (smask & MASK_RIGHT_MIDDLE) > 0)))
        {
            DeletePendingSetLine();

            setting_buy = false;
            setting_sell = false;
            return;
        }
    }
    if (setting_buy)
    {
        if (id == CHARTEVENT_CLICK)
        {
            DeletePendingSetLine();

            ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);
            OpenBuyPendingOrder(xyprice);

            setting_buy = false;
            return;
        }
        if (id == CHARTEVENT_MOUSE_MOVE)
        {
            ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);
            MovePendingSetLine(xyprice);
            return;
        }
    }
    if (setting_sell)
    {
        if (id == CHARTEVENT_CLICK)
        {
            DeletePendingSetLine();

            ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);
            OpenSellPendingOrder(xyprice);

            setting_sell = false;
            return;
        }
        if (id == CHARTEVENT_MOUSE_MOVE)
        {
            ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);
            MovePendingSetLine(xyprice);
            return;
        }
    }

    if (!grabSLwithDrag || stop_takeMode == ST_PRICE)
        return;

    if (id == CHARTEVENT_CLICK)
    {
        if (!is_tracking)
            return;

        if (!(recorded_price > 0.0))
        {
            is_tracking = false;
            return;
        }

        ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);
#ifdef __MQL5__
        int pips = (int)MathRound(MathAbs(xyprice - recorded_price) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
#else
        int pips = (int)(MathAbs(xyprice - recorded_price) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
#endif

        if (pips > 0)
            ExtDialog.SetStopLoss(pips);

        is_tracking = false;
        recorded_price = 0.0;
    }

    if (id == CHARTEVENT_MOUSE_MOVE)
    {
        if (sparam != "1")
            return;

        if (is_tracking)
            return;

        ChartXYToTimePrice(ChartID(), (int)lparam, (int)dparam, xysub, xytime, xyprice);

        if (xysub > 0)
            return;

        recorded_price = xyprice;
        is_tracking = true;
    }

    if (id == CHARTEVENT_CHART_CHANGE || id == CHARTEVENT_CUSTOM + ON_DRAG_PROCESS) // Stop on drag panel
    {
        if (recorded_price > 0)
            recorded_price = 0.0;
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CreatePendingSetLine(color clr, double line_price)
{
    if (ObjectFind(ChartID(), PENDING_SETLINE) < 0)
        ObjectCreate(ChartID(), PENDING_SETLINE, OBJ_HLINE, 0, 0, line_price);
    ObjectSetInteger(ChartID(), PENDING_SETLINE, OBJPROP_COLOR, clr);
    ObjectSetInteger(ChartID(), PENDING_SETLINE, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(ChartID(), PENDING_SETLINE, OBJPROP_HIDDEN, false);
    ObjectSetString(ChartID(), PENDING_SETLINE, OBJPROP_TOOLTIP, "\n");

    ChartRedraw();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MovePendingSetLine(double line_price)
{
    ObjectSetDouble(ChartID(), PENDING_SETLINE, OBJPROP_PRICE, line_price);
    ChartRedraw();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DeletePendingSetLine()
{
    ObjectDelete(ChartID(), PENDING_SETLINE);
    ChartRedraw();
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void RecalculateValues(int position, double price_ref = 0.0)
{
    if (riskCalculation == FIXED_LOTS)
    {
        totalLots = riskAmount;
        return;
    }

    double riskTotal = AccountInfoDouble(ACCOUNT_BALANCE) * riskAmount / 100.0;
    // Si risk es 0, puede ser por cadena invalida

    double sl = 0.0;
    if (stop_takeMode == ST_PRICE)
    {
        if (stopLoss != 0.0)
        {
            if (price_ref > 0.0) // pending
                sl = MathAbs(price_ref - stopLoss);
            else
            {
                if (position == POSITION_TYPE_BUY)
                    sl = ASK_PRICE - stopLoss;
                else if (position == POSITION_TYPE_SELL)
                    sl = stopLoss - BID_PRICE;
            }
        }
    }
    else
    {
        sl = stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    }

    if (sl == 0.0)
    {
        totalLots = 0.0;
        Print("Stop Loss Cannot be 0 with risk percent");
        return;
    }

    sl /= SymbolInfoDouble(_Symbol, SYMBOL_POINT);

    double lotValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_LOSS);
    double pointValue = riskTotal / sl;

    if (pointValue < 0)
    {
        totalLots = 0.0;
        Print("Invalid stop");
        return;
    }

    double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

    totalLots = MathFloor((pointValue / lotValue) / lotStep) * lotStep;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CheckLots()
{
    if (totalLots < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN))
    {
        Print("Risk is too small to Open a trade");
        return false;
    }
    if (totalLots > SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX))
    {
        Print("Lots are too big to Open a trade");
        return false;
    }
    return true;
}

//+------------------------------------------------------------------+
//| Pending orders                                                   |
//+------------------------------------------------------------------+
void OpenBuyPendingOrder(double order_price)
{
    Print("Open Buy pending");

    RecalculateValues(POSITION_TYPE_BUY, order_price);

    if (!CheckLots())
        return;

    double sl = 0.0;
    double tp = 0.0;

    if (stop_takeMode == ST_PRICE)
    {
        sl = stopLoss;
        tp = takeProfit;
    }
    else
    {
        if (stopLoss != 0.0)
            sl = order_price - stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
        if (takeProfit != 0.0)
            tp = order_price + takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    }

    if (order_price > ASK_PRICE)
    {
        ORDER_BUY_STOP(totalLots, order_price, sl, tp)
    }
    else
    {
        ORDER_BUY_LIMIT(totalLots, order_price, sl, tp)
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OpenSellPendingOrder(double order_price)
{
    Print("Open Sell pending");

    RecalculateValues(POSITION_TYPE_SELL, order_price);

    if (!CheckLots())
        return;

    double sl = 0.0;
    double tp = 0.0;

    if (stop_takeMode == ST_PRICE)
    {
        sl = stopLoss;
        tp = takeProfit;
    }
    else
    {
        if (stopLoss != 0.0)
            sl = order_price + stopLoss * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
        if (takeProfit != 0.0)
            tp = order_price - takeProfit * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    }

    if (order_price < BID_PRICE)
    {
        ORDER_SELL_STOP(totalLots, order_price, sl, tp)
    }
    else
    {
        ORDER_SELL_LIMIT(totalLots, order_price, sl, tp)
    }
}
//+------------------------------------------------------------------+

int OnInit()
{
    return OnInitEvent();
}

void OnDeinit(const int reason)
{
    OnDeinitEvent(reason);
}

void OnChartEvent(const int id,         // event ID
                  const long &lparam,   // event parameter of the long type
                  const double &dparam, // event parameter of the double type
                  const string &sparam) // event parameter of the string type
{
    ExtDialog.ChartEvent(id, lparam, dparam, sparam);
    CommonChartEvent(id, lparam, dparam, sparam);
}
