//+------------------------------------------------------------------+
//|                                                 My-Functions.mqh |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property strict

// Include necessary libraries
#include <jason.mqh>
#include <Telegram.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>

// Global Variables
// ================

// Chart control
bool removeFromThisChartOnly = true;

// Time Functions

datetime timetostartopenchart = TimeCurrent();
datetime timetostartclosechart = TimeCurrent();
      
// Trade limits
int max_trades_same_type = 3;           // Maximum number of trades of same type

// Account tracking
double      MaxAccountBalance = AccountBalance();    // Maximum account balance
double      InitialAccountBalance = AccountBalance();// Initial account balance
double      MinAccountBalance = 1000000;            // Minimum account balance threshold

// Symbol and source arrays
string symbols[] = {
    "XAUUSD", "XAGUSD", "XTIUSD", "USDJPY", "EURJPY", "GBPJPY", "CHFJPY", 
    "USDCHF", "XAUEUR","XAUGBP","NZDUSD",
    "USDCAD", "AUDUSD", "EURUSD", "EURGBP", "EURNZD", "GBPUSD", "NZDCAD", 
    "GBPNZD", "GBPAUD", "EURAUD", "NZDCHF"
};

  
string sources[] = {"Own", "News", "Younus"};

int count_symbols = ArraySize(symbols);  // Number of symbols in array
int count_sources = ArraySize(sources);  // Number of sources in array


// Telegram bot configuration
CCustomBot bot;
string InpToken = "8181067618:AAGqA6S1y59CG5JgxX-c2rcgEt0kvpgCBvY"; // UK Bot
int check_telegram_updates = 2150; // Update check interval in milliseconds
int capture_previous_update_id = 0;
ulong chat_id = 0;

//+------------------------------------------------------------------+
//| Order Placement Functions                                        |
//+------------------------------------------------------------------+

/**
 * Places a buy stop order
 * @param MagicBuy The magic number to identify the order
 */

   void showbalance()
   {
            double  CurrentAccountBalance = AccountBalance();
            if (MaxAccountBalance < AccountBalance())  MaxAccountBalance = AccountBalance();
            if (MinAccountBalance > AccountBalance())  MinAccountBalance = AccountBalance();
            Comment ("Initial Account Balance was ",InitialAccountBalance,", Minimum Balance was ",MinAccountBalance,", Max Balance was ",
            MaxAccountBalance,", Current Balance is ",CurrentAccountBalance," and Current Equity is ",AccountEquity(),
            "");

   }

  void chartopenclose()
    {   

    if (TimeCurrent()-timetostartopenchart>20)
     {
        Print ("Trying to Open Chart in Use");
      timetostartopenchart=TimeCurrent();         
         // Open Symbol Chart 
         
           for (int b= OrdersTotal()-1;b>=0;b--)
                 {
                   if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
                    {
                          bool   found = false;
                           long   ID    = ChartFirst();
                             while(ID>=0) 
                              {
                               if(ChartSymbol(ID)==OrderSymbol()) 
                                { 
                                  found=true;
                                  
                                  break; 
                                }
                               ID=ChartNext(ID);
                              }
                              if(!found) ChartOpen(OrderSymbol(),0);
                  }}}
   
if (TimeCurrent() - timetostartclosechart > 30)
{
    Print("Trying to Close Chart not in use");
    timetostartclosechart = TimeCurrent();               
    
    long ID_chart = ChartFirst();
    ID_chart = ChartNext(ID_chart); // Skip the first chart
    
    while(ID_chart >= 0) 
    {
        bool shouldClose = true;
        string chartSymbol = ChartSymbol(ID_chart);
        
        // 1. Always keep these protected symbols
        if (chartSymbol == "XAUUSD" || chartSymbol == "Cocoa_K5" || chartSymbol == "CHINA50")
        {
            shouldClose = false;
            Print("Keeping protected symbol: ", chartSymbol);
        }
        
        // 2. Check for open trades on this symbol
        if (shouldClose)
        {
            for(int b = OrdersTotal() - 1; b >= 0; b--)
            {
                if (OrderSelect(b, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == chartSymbol)
                {
                    shouldClose = false;
                    Print("Keeping chart with open trade: ", chartSymbol);
                    break;
                }
            }
        }
        
        // 3. Ultimate EA Detection - Check for chart objects
        if (shouldClose)
        {
            int objTotal = ObjectsTotal(ID_chart);
            if (objTotal > 2) // Most EAs create at least 2-3 objects
            {
                shouldClose = false;
                Print("Keeping possible EA chart (", objTotal, " objects): ", chartSymbol);
            }
        }
        
        // 4. Final closing decision
        if (shouldClose) 
        {
            Print("Closing unused chart: ", chartSymbol);
            ChartClose(ID_chart);
        }
        
        ID_chart = ChartNext(ID_chart);
    }
}
       
      }
      
long GetChartIDSymbol(string symb) {
    bool found = false;
    long ID = ChartFirst();
    while (ID >= 0) {
        if (ChartSymbol(ID) == symb) {
            found = true;
            break;
        }
        ID = ChartNext(ID);
    }
    return ID;
}


void SendBuyOrder(string SymbolForOrder, double VolumeofTrade, double sl_points, double tp_points, int Magic) {
  
    double ask = MarketInfo(SymbolForOrder, MODE_ASK);
    double buyprice = NormalizeDouble(ask, (int)MarketInfo(SymbolForOrder, MODE_DIGITS));

    // Convert pips to price based on point size
    double point = MarketInfo(SymbolForOrder, MODE_POINT);
    double sl = buyprice - sl_points * point;
    double tp = buyprice + tp_points * point;
    
    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10; // Adjust as per broker conditions
    int ticket = OrderSend(SymbolForOrder, OP_BUY, VolumeofTrade, buyprice, slippage, sl, tp, "Buy Order", Magic, 0, clrBlue);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Buy order sent successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to send buy order. Error: ", GetLastError());
    }
}


void SendBuyLimitOrder(string SymbolForOrder, double VolumeofTrade, double sdforbuy, double sl_points, double tp_points, int Magic) {
    
    double ask = MarketInfo(SymbolForOrder, MODE_ASK);
    int digits = (int)MarketInfo(SymbolForOrder, MODE_DIGITS);
    double point = MarketInfo(SymbolForOrder, MODE_POINT);

    double buyprice = NormalizeDouble(ask, digits);  // Current ask price

    // Buy Limit price: a set distance below current ask
    double buyLimitPrice = NormalizeDouble(buyprice - sdforbuy * point, digits);

    // SL and TP based on buy limit price
    double sl = NormalizeDouble(buyLimitPrice - sl_points * point, digits);
    double tp = NormalizeDouble(buyLimitPrice + tp_points * point, digits);

    // If SL or TP points are 0, set price to 0 to disable
    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10; // Max allowed slippage
    datetime expiration = 0; // 0 means no expiration

    int ticket = OrderSend(SymbolForOrder, OP_BUYLIMIT, VolumeofTrade, buyLimitPrice, slippage, sl, tp,
                           "Buy Limit Order", Magic, expiration, clrBlue);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Buy Limit order placed successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to place Buy Limit order. Error: ", GetLastError());
    }
}

void SendBuyStopOrder(string SymbolForOrder, double VolumeofTrade, double sdforbuy, double sl_points, double tp_points, int Magic) {

    double ask = MarketInfo(SymbolForOrder, MODE_ASK);
    int digits = (int)MarketInfo(SymbolForOrder, MODE_DIGITS);
    double point = MarketInfo(SymbolForOrder, MODE_POINT);

    double buyprice = NormalizeDouble(ask, digits);
    double buyStopPrice = NormalizeDouble(buyprice + sdforbuy * point, digits);

    double sl = NormalizeDouble(buyStopPrice - sl_points * point, digits);
    double tp = NormalizeDouble(buyStopPrice + tp_points * point, digits);

    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10;
    datetime expiration = 0;  // No expiration

    int ticket = OrderSend(SymbolForOrder, OP_BUYSTOP, VolumeofTrade, buyStopPrice, slippage, sl, tp,
                           "Buy Stop Order", Magic, expiration, clrGreen);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Buy Stop order placed successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to place Buy Stop order. Error: ", GetLastError());
    }
}

void SendSellOrder(string SymbolForOrder, double VolumeofTrade, double sl_points, double tp_points, int Magic) {

    double bid = MarketInfo(SymbolForOrder, MODE_BID);
    int digits = (int)MarketInfo(SymbolForOrder, MODE_DIGITS);
    double point = MarketInfo(SymbolForOrder, MODE_POINT);

    double sellprice = NormalizeDouble(bid, digits);

    double sl = NormalizeDouble(sellprice + sl_points * point, digits);
    double tp = NormalizeDouble(sellprice - tp_points * point, digits);

    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10;

    int ticket = OrderSend(SymbolForOrder, OP_SELL, VolumeofTrade, sellprice, slippage, sl, tp,
                           "Sell Order", Magic, 0, clrRed);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Sell order sent successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to send sell order. Error: ", GetLastError());
    }
}

void SendSellLimitOrder(string SymbolForOrder, double VolumeofTrade, double sdforsell, double sl_points, double tp_points, int Magic) {

    double bid = MarketInfo(SymbolForOrder, MODE_BID);
    int digits = (int)MarketInfo(SymbolForOrder, MODE_DIGITS);
    double point = MarketInfo(SymbolForOrder, MODE_POINT);

    double sellprice = NormalizeDouble(bid, digits);
    double sellLimitPrice = NormalizeDouble(sellprice + sdforsell * point, digits);

    double sl = NormalizeDouble(sellLimitPrice + sl_points * point, digits);
    double tp = NormalizeDouble(sellLimitPrice - tp_points * point, digits);

    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10;
    datetime expiration = 0;  // No expiration

    int ticket = OrderSend(SymbolForOrder, OP_SELLLIMIT, VolumeofTrade, sellLimitPrice, slippage, sl, tp,
                           "Sell Limit Order", Magic, expiration, clrOrangeRed);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Sell Limit order placed successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to place Sell Limit order. Error: ", GetLastError());
    }
}


void SendSellStopOrder(string SymbolForOrder, double VolumeofTrade, double sdforsell, double sl_points, double tp_points, int Magic) {

    double bid = MarketInfo(SymbolForOrder, MODE_BID);
    int digits = (int)MarketInfo(SymbolForOrder, MODE_DIGITS);
    double point = MarketInfo(SymbolForOrder, MODE_POINT);

    double sellprice = NormalizeDouble(bid, digits);
    double sellStopPrice = NormalizeDouble(sellprice - sdforsell * point, digits);

    double sl = NormalizeDouble(sellStopPrice + sl_points * point, digits);
    double tp = NormalizeDouble(sellStopPrice - tp_points * point, digits);

    if (sl_points == 0) sl = 0;
    if (tp_points == 0) tp = 0;

    int slippage = 10;
    datetime expiration = 0;  // No expiration

    int ticket = OrderSend(SymbolForOrder, OP_SELLSTOP, VolumeofTrade, sellStopPrice, slippage, sl, tp,
                           "Sell Stop Order", Magic, expiration, clrRed);

    if (ticket > 0) {
        if (OrderSelect(ticket, SELECT_BY_TICKET)) {
            Print("Sell Stop order placed successfully. Ticket: ", ticket);
        }
    } else {
        Print("Failed to place Sell Stop order. Error: ", GetLastError());
    }
}




bool CheckBuyOpenOrders(int MagicBuy) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderBO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_BUY && OrderMagicNumber() == MagicBuy) return true;
    }
    return false;
}


bool CountBuyOpenOrders(string symb) {
    int ordercount = 0;
    
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderSymbol() == symb && (OrderType() == OP_BUY)) ordercount = ordercount + 1;
    }
    
    if (ordercount < max_trades_same_type) return true;
    else return false;
}


bool CheckBuyStopOpenOrders(int MagicBuy) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderBO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_BUYSTOP && OrderMagicNumber() == MagicBuy) return true;
    }
    return false;
}

bool CheckBuyLimitOpenOrders(int MagicBuy) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderBO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_BUYLIMIT && OrderMagicNumber() == MagicBuy) return true;
    }
    return false;
}


void CloseBuyOrders(int MagicBuy) {
    Comment("Buy Orders are Closed");
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        int OrderAll = OrderSelect(i, SELECT_BY_POS);
        if (OrderSymbol() != Symbol() && removeFromThisChartOnly) continue;
        
        if (OrderType() == OP_BUY && OrderMagicNumber() == MagicBuy) {
            double price = MarketInfo(OrderSymbol(), MODE_BID);
            int OpenDelete = OrderClose(OrderTicket(), OrderLots(), price, 5);
        }
        Sleep(100);
        int error = GetLastError();
        if (error > 0) Print("Unanticipated error: ");
        RefreshRates();
    }
}


bool CheckSellOpenOrders(int MagicSell) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_SELL && OrderMagicNumber() == MagicSell) return true;
    }
    return false;
}

bool CountSellOpenOrders(string symb) {
    int ordercount = 0;
    
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderSymbol() == symb && (OrderType() == OP_SELL)) ordercount = ordercount + 1;
    }
    
    if (ordercount < max_trades_same_type) return true;
    else return false;
}

bool CheckSellStopOpenOrders(int MagicSell) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_SELLSTOP && OrderMagicNumber() == MagicSell) return true;
    }
    return false;
}



bool CheckSellLimitOpenOrders(int MagicSell) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderType() == OP_SELLLIMIT && OrderMagicNumber() == MagicSell) return true;
    }
    return false;
}



void CloseSellOrders(int MagicSell) {
    Comment("Sell Orders are Closed");
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        int OrderAll = OrderSelect(i, SELECT_BY_POS);
        if (OrderSymbol() != Symbol() && removeFromThisChartOnly) continue;
        
        if (OrderType() == OP_SELL && OrderMagicNumber() == MagicSell) {
            double price = MarketInfo(OrderSymbol(), MODE_ASK);
            int OpenDelete = OrderClose(OrderTicket(), OrderLots(), price, 5);
        }
        Sleep(100);
        int error = GetLastError();
        if (error > 0) Print("Unanticipated error: ");
        RefreshRates();
    }
}

bool CheckOpenOrders(int Magic) {
    for (int i = 0; i < OrdersTotal(); i++) {
        int OrderSO = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if (OrderMagicNumber() == Magic) return true;
    }
    return false;
}

void ClosePendingOrders(int Magic) {
    Comment("All Pending Orders are Closed");
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        int OrderPending = OrderSelect(i, SELECT_BY_POS);
        double price = MarketInfo(OrderSymbol(), MODE_ASK);
        if (OrderType() == OP_BUY) price = MarketInfo(OrderSymbol(), MODE_BID);
        
        if (OrderMagicNumber() == Magic) {
            int PendingDelete = OrderDelete(OrderTicket());
        }
        Sleep(100);
        int error = GetLastError();
        if (error > 0) Print("Unanticipated error: ");
        RefreshRates();
    }
}


void CloseAllOrders(int Magic) {
    Comment("All Orders are Closed");
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        int OrderAll = OrderSelect(i, SELECT_BY_POS);
        if (OrderSymbol() != Symbol() && removeFromThisChartOnly) continue;
        
        double price = MarketInfo(OrderSymbol(), MODE_ASK);
        if (OrderType() == OP_BUY) price = MarketInfo(OrderSymbol(), MODE_BID);
        
        if ((OrderType() == OP_BUY && OrderMagicNumber() == Magic) || 
            (OrderType() == OP_SELL && OrderMagicNumber() == Magic)) {
            int OpenDelete = OrderClose(OrderTicket(), OrderLots(), price, 5);
        } else {
            int AllDelete = OrderDelete(OrderTicket());
        }
        Sleep(100);
        int error = GetLastError();
        if (error > 0) Print("Unanticipated error: ");
        RefreshRates();
    }
}


void CheckAndDeleteOldPendingOrders() {
   int totalOrders = OrdersTotal();
   for (int i = totalOrders - 1; i >= 0; i--) {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         int type = OrderType();
         int magic = OrderMagicNumber();
         datetime openTime = OrderOpenTime();

         // Check if it's a pending order with non-zero magic number
         if ((type == OP_BUYLIMIT || type == OP_BUYSTOP ||
              type == OP_SELLLIMIT || type == OP_SELLSTOP) && magic != 0) {

            if ((TimeCurrent() - openTime) > 600) { // 600 seconds = 10 minutes
               bool result = OrderDelete(OrderTicket());
               if (result) {
                  Print("Deleted old pending order. Ticket: ", OrderTicket());
               } else {
                  Print("Failed to delete pending order. Ticket: ", OrderTicket(), " Error: ", GetLastError());
               }
            }
         }
      }
   }
}



bool lastlosscheck() {
    int OrderCheck = OrderSelect(OrdersHistoryTotal() - 1, SELECT_BY_POS, MODE_HISTORY);
    if (OrderProfit() < 0) return true;
    else return false;
}


int CreateMagicNumber(string source, string symb, string type, int ordernum) {
    int sourcenumber = 9900000;
    int symbnumber = 99900;
    int typenumber = 99;

    // Find source index
    for (int x = 0; x < count_sources; x++) {
        if (source == sources[x]) sourcenumber = 1000000 * (x + 1);
    }

    // Find symbol index
    for (int x = 0; x < count_symbols; x++) {
        if (symb == symbols[x]) symbnumber = 30000 + (x + 1) * 100;
    }
    
    // Set type number
    if (type == "Buy") typenumber = 10;
    if (type == "Sell") typenumber = 20;
    
    // Combine all components
    int magicnumber = sourcenumber + symbnumber + typenumber + ordernum;
    
    return magicnumber;
}


string GetMagicSource(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 0, 2);
    int sourcemagic = StrToInteger(tempmagic) / 10;
    string source = sources[sourcemagic - 1];
    return source;
}


string GetMagicSymbol(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 2, 3);
    int symbolmagic = StrToInteger(tempmagic) - 300;
    string symbol = symbols[symbolmagic - 1];
    return symbol;
}


string GetMagicType(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 5, 1);
    string type = "Buy";
    if (tempmagic == "2") type = "Sell";
    return type;
}


int GetMagicOrderNum(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 6, 1);
    int ordernum = StrToInteger(tempmagic);
    return ordernum;
}

int GetMagicSourceIndex(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 0, 2);
    int sourcemagic = StrToInteger(tempmagic) / 10;
    int source = sourcemagic - 1;
    return source;
}


int GetMagicSymbolIndex(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 2, 3);
    int symbolmagic = StrToInteger(tempmagic) - 300;
    int symbol = symbolmagic - 1;
    return symbol;
}

int GetMagicTypeNum(int Magic) {
    string tempmagic = IntegerToString(Magic);
    tempmagic = StringSubstr(tempmagic, 5, 1);
    int type = 0;
    if (tempmagic == "2") type = 1;
    return type;
}


string toUpper(string text) {
    StringToUpper(text);
    return text;
}


double PipsToPrice(double pips, string symb) {
    double price;
    if (symb == "XAUUSD" || symb == "XTIUSD" || symb == "XAUEUR" || symb == "XAUGBP") {
        price = pips / 100;
        return price;
    }
    if (symb == "USDJPY" || symb == "EURJPY" || symb == "GBPJPY" || symb == "CHFJPY" || symb == "XAGUSD") {
        price = pips / 1000;
        return price;
    }
    if (symb == "USDCAD" || symb == "AUDUSD" || symb == "EURUSD" || symb == "EURGBP" || symb == "EURNZD" || symb == "USDCHF" ||
        symb == "GBPUSD" || symb == "NZDCAD" || symb == "NZDUSD" || symb == "GBPNZD" || symb == "GBPAUD" || symb == "EURAUD" ) {
        price = pips / 100000;
        return price;
    }
    return 0;
}


int telegram_to_mt4() {
    CJAVal js;
    string headers;
    char post[], result[];
    int res = WebRequest("GET", "https://api.telegram.org/bot" + InpToken + "/getUpdates?offset=-1", "", NULL, 10000, post, ArraySize(post), result, headers);
    string server_response_data = CharArrayToString(result);
    js.Deserialize(result);

    string update_id_str = js["result"][0]["update_id"].ToStr();
    int update_id = StrToInteger(update_id_str);
    string chat_id_str = js["result"][0]["message"]["chat"]["id"].ToStr();
    chat_id = (ulong)chat_id_str;

    string output[];
    string output2[];
    
    if (capture_previous_update_id < update_id) {
        capture_previous_update_id = update_id;

        string chat_message_text = js["result"][0]["message"]["text"].ToStr();
        string chat_message_caption = js["result"][0]["message"]["caption"].ToStr();
        
        StringSplit(chat_message_text, StringGetCharacter("\n", 0), output);
        StringSplit(chat_message_caption, StringGetCharacter("\n", 0), output2);

        if (res == -1) {
            Print("Error in WebRequest. Error code = ", GetLastError());
            MessageBox("Add the address in the list of allowed URLs on tab 'Expert Advisors'", "Error", MB_ICONINFORMATION);
        } else {
            // Save chat ID
            int filehandle11 = FileOpen("chat_id.txt", FILE_WRITE | FILE_TXT);
            FileWriteString(filehandle11, IntegerToString(chat_id));
            FileClose(filehandle11);

            // Save message details
            int filehandle2 = FileOpen("message_details.txt", FILE_WRITE | FILE_CSV);
            
            int count_lines = ArraySize(output);
            for (int x = 0; x < count_lines; x++) {
                FileWriteString(filehandle2, output[x]);
                FileWriteString(filehandle2, ",");
            }
            
            int count_lines2 = ArraySize(output2);
            for (int x = 0; x < count_lines2; x++) {
                FileWriteString(filehandle2, output2[x]);
                FileWriteString(filehandle2, ",");
            }
            FileClose(filehandle2);
        }
    }
    return capture_previous_update_id;
}

string TruncateNumber(string number) {
    int start_index = StringFind(number, ".");
    if (start_index == -1) return number;
    
    string vals[2] = {"", ""};
    StringSplit(number, '.', vals);
    
    if (StringLen(vals[1]) <= 3) return number;
    
    return StringConcatenate(vals[0], ".", StringSubstr(vals[1], 0, 4));
}

double updatetextboxdouble(string ssparam, string boxname, double boxvaluecurrent)
      {
       
                     double boxvalue=boxvaluecurrent;
                     if(ssparam == boxname) {
                     string volumeText = ObjectGetString(0, boxname, OBJPROP_TEXT);
                     boxvalue = StringToDouble(volumeText);
                     ObjectSetString(0, boxname, OBJPROP_TEXT, string(boxvalue));
                    
                     }
      return boxvalue;
      
      }
      
string updatetextboxstring(string s2param, string boxname, string boxvaluecurrent)
      {
                     string boxvalue=boxvaluecurrent;
                     if(s2param == boxname) {
                     string volumeText = ObjectGetString(0, boxname, OBJPROP_TEXT);
                     ObjectSetString(0, boxname, OBJPROP_TEXT, boxvalue);
                   
                     }
      
      return boxvalue;
      }
      
void createLabel(CLabel &labelCtrl,  CAppDialog &parent, string name, string text, int startx, int endx, int starty, int endy)
         {
               labelCtrl.Create(0,name,0,startx,starty,endx,endy);
               parent.Add(labelCtrl);
               labelCtrl.Text(text);
         }
         
void createInputBox(CEdit &editCtrl,  CAppDialog &parent, string name, string text, int startx, int endx, int starty, int endy)
         {
               editCtrl.Create(0,name,0,startx,starty,endx,endy);
               parent.Add(editCtrl);
               editCtrl.Text(string(text));
         }

string SecondsToHMS(int totalSeconds)
{
   int hours = totalSeconds / 3600;
   int minutes = (totalSeconds % 3600) / 60;
   int seconds = totalSeconds % 60;

   return StringFormat("%02d:%02d:%02d", hours, minutes, seconds);
}

int GetTextWidth(string text, int fontSize = 10)
{
   // Average width per character for basic fonts
   double avgCharWidth = fontSize * 0.6;  // You can tweak this multiplier if needed
   return (int)(StringLen(text) * avgCharWidth);
}

bool isbasecurrency(string symbol, string currency)
{
    if (StringLen(symbol) < 6 || StringLen(currency) != 3)
        return false; // Basic validation

    string base = StringSubstr(symbol, 0, 3); // First 3 letters are base currency
    return (base == currency);
}