//+------------------------------------------------------------------+ //| blTelegramToMT4.mq4 | //| Copyright 2025, MQL Development | //| https://www.mqldevelopment.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MQL Development" #property link "https://www.mqldevelopment.com/" #property version "1.1" #property strict #define buy "buy" #define sell "sell" #define MaxOrders 10000 struct msgDetails { int msgid; ulong tickt; msgDetails() { msgid = -1; tickt = -1; } }; msgDetails od[MaxOrders]; input string Settings = " ------------- General Settings ------------- "; //_ input int magic_no = 333; // Magic no input string symbolMatch = "GOLD:XAUUSD,BitCoin:BTCUSD"; // Symbol Mapping (Telegram:MT4) input string suffix = ""; // Account Suffix input string prefix = ""; // Account Prefix input double lotSize = 0.1; // Lot Size input double partialClose = 20; // Partial Closing % //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ // Global Variables string url1 = "http://127.0.0.1"; // "http://myapp.local"; string header = "Content-Type: application/json\r\nAccept: application/json\r\n"; string symbolChart[]; string symbolSnd[]; string symbolsListUserInput[]; uchar sym1[]; uchar sym2[]; int last_message_id = INT_MIN; int OnInit() { //--- create timer ushort u_sep = StringGetCharacter(",",0); StringSplit(symbolMatch,u_sep,symbolsListUserInput); ArrayResize(symbolChart,0); ArrayResize(symbolSnd,0); for(int i = 0; i < ArraySize(symbolsListUserInput); i++) { string str = symbolsListUserInput[i]; int index = StringFind(str,":"); int index2 = StringLen(str); ArrayResize(sym1,0); ArrayResize(sym2,0); for(int j = 0; j < index; j++) { ArrayResize(sym1,ArraySize(sym1)+1); sym1[j] = uchar(str[j]); } int k = 0; for(int j = index + 1 ; j < index2; j++) { ArrayResize(sym2,ArraySize(sym2)+1); sym2[k] = uchar(str[j]); k++; } ArrayResize(symbolChart,ArraySize(symbolChart)+1); ArrayResize(symbolSnd,ArraySize(symbolSnd)+1); symbolChart[i] = CharArrayToString(sym1); symbolSnd[i] = CharArrayToString(sym2); } string jsonString = GET_function(url1 + "/get-latest-message-id", header); StringReplace(jsonString,"},", "*"); last_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN; string message = getJsonStringValue(jsonString, "message"); if(last_message_id != INT_MIN) { Print(" latest_message_id = ",last_message_id); Print(" result found against get-latest-message-id = ",message); } EventSetTimer(1); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- if(last_message_id == INT_MIN) { string jsonString = GET_function(url1 + "/get-latest-message-id", header); StringReplace(jsonString,"},", "*"); last_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN; if(last_message_id != INT_MIN) { string message = getJsonStringValue(jsonString, "message"); if(last_message_id != INT_MIN) { Print(" latest_message_id = ",last_message_id); Print(" result found against get-latest-message-id = ",message); } execute_functionality_on_new_message(last_message_id); } } else { string jsonString = GET_function(url1 + "/get-latest-message-id", header); StringReplace(jsonString,"},", "*"); int latest_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN; if(last_message_id != latest_message_id) { for(int i = latest_message_id; i > last_message_id; i--) { execute_functionality_on_new_message(i); } last_message_id = latest_message_id; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string GET_function(string url,string headers) { string result_string = NULL; int timeout = 10; // Set the timeout value in seconds char result[],data[]; string resultHeaders; int res = WebRequest("GET",url,headers,timeout,data,result,resultHeaders); if(res == 200) { result_string = CharArrayToString(result); } else { Print("content GETT: ", result_string," Error: ",GetLastError(), " res: ",res); } return result_string; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool checkExistingTrade(int message_id) { for(int i=0; i < MaxOrders; i++) { if(od[i].msgid == message_id) { return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string getJsonStringValue(string json,string key,int addUp,string endSign) { int indexStart = StringFind(json,key)+StringLen(key)+addUp; int indexEnd = StringFind(json,endSign,indexStart); return StringSubstr(json,indexStart,indexEnd-indexStart); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string getJsonStringValue(string json, string key) { int start = StringFind(json, "\""+key+"\""); if(start == -1) return ""; // Find colon after key int colon = StringFind(json, ":", start); if(colon == -1) return ""; // Find next comma or closing brace int endComma = StringFind(json, ",", colon); int endBrace = StringFind(json, "}", colon); int end = (endComma != -1 && (endComma < endBrace || endBrace == -1)) ? endComma : endBrace; if(end == -1) end = StringLen(json); string value = trim(StringSubstr(json, colon+1, end-colon-1)); // remove quotes if exist StringReplace(value, "\"", ""); return value; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string trim(string text) { StringTrimLeft(text); StringTrimRight(text); return text; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void execute_functionality_on_new_message(int i) { string url = url1 + "/get-message/" + IntegerToString(i); string jsonString = GET_function(url, header); StringReplace(jsonString,"},", "*"); string message = getJsonStringValue(jsonString,"message",4,"\""); int group_message_id = (int)getJsonStringValue(jsonString, "message_id"); StringToLower(message); StringReplace(message,"~","#"); if(checkExistingTrade(group_message_id) == false) { string isReplyValue = getJsonStringValue(jsonString, "is_reply"); StringReplace(isReplyValue," ",""); if(isReplyValue == "True") { int reply_to_msg_id = (int)getJsonStringValue(jsonString, "reply_to_msg_id"); message = getJsonStringValue(jsonString, "message"); StringToLower(message); Print(" ================ Replied Message found of message_id ================ ",reply_to_msg_id); Print(" ================ Message: ================ ",message); int ticket = getTicket(reply_to_msg_id); if(ticket != -1) { if(StringFind(message,"take") != -1 && StringFind(message,"some") != -1 && StringFind(message,"partial") != -1 && StringFind(message,"profit") != -1) { if(OrderSelect(ticket,SELECT_BY_TICKET)) { double lot = NormalizeDouble(OrderLots()*(partialClose/100),2); bool result = OrderClose(ticket,lot,OrderOpenPrice(),10, clrNONE); if(result) { Print("Partially closed ", lot, " lots from order ", ticket); for(int j = OrdersTotal()-1; j>=0; j--) { if(OrderSelect(j, SELECT_BY_POS)) { if(OrderComment() != "") { string ticketToBeReplace = OrderComment(); StringReplace(ticketToBeReplace,"from #",""); if(int(ticketToBeReplace) == ticket) { findAndreplaceTicketFromStructure(OrderTicket(),reply_to_msg_id); } } } } } else { Print("Error closing partial order: ", GetLastError()," lot = ",lot," OrderLots() = ",OrderLots()); } } } if(StringFind(message,"set") != -1 && StringFind(message,"stop") != -1 && StringFind(message,"loss") != -1 && StringFind(message,"entry") != -1) { if(OrderSelect(ticket,SELECT_BY_TICKET)) { bool result = OrderModify(ticket,OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,clrNONE); if(result) { Print("Order Sl Modify to Open Price ", ticket); } else { Print("Error in Modify order SL : ", GetLastError()); } } } } } else { if(checkExistingTrade(group_message_id) == false) { Print(" --------------- New Trade Message Found ----------------- ", " Message Id: ", group_message_id); StringReplace(message,"~","#"); StringReplace(message,"##", "#"); StringToLower(message); message = removeExtraSpaces(message); Print("Message is ",message); string result[]; string tempResult[]; int indexTemp = 0; StringSplit(message,'#',tempResult); for(int j=0; j= 1) { StringSplit(result[0], ' ', lineOne); if(((StringFind(result[0], "buy", 0) != -1) || (StringFind(result[0], "sell", 0) != -1))) { for(int i=0; i= 2) { if(direction_index == 0) { symbol = lineOne[1]; StringToUpper(symbol); //Print(" This is Message format One (1). Where Direction is: ", direction, " Symbol: ", symbol); } else if(direction_index > 0) { symbol = lineOne[0]; StringToUpper(symbol); //Print(" This is Message format One (1). Where Direction is: ", direction, " Symbol: ", symbol); } } symbol = symbolMapping(symbol); double sl = 0; double tp = 0; // = result[0]; for(int i=0 ; i < ArraySize(result); i++) { // result[i] = StringTrimLeft(result[i]); // result[i] = StringTrimRight(result[i]); // Print("Result : ", result[i], " index is: ", i); if((StringFind(result[i], "sl", 0) != -1)) { string tempSl[]; StringReplace(result[i],":", " "); result[i] = trimString(result[i]); result[i] = spaceRemove(result[i]); //Print(" Sl String: ", result[i]); StringSplit(result[i], ' ', tempSl); if(ArraySize(tempSl) >= 2) sl = (double) tempSl[1]; Print("Sl : ", sl); } if((StringFind(result[i], "tp", 0) != -1)) { Print("Tp : ", result[i], " index is: ", i); string tempTp[]; StringReplace(result[i],":", " "); result[i] = trimString(result[i]); result[i] = spaceRemove(result[i]); Print("Tp After String Replace : ", result[i], " index is: ", i); StringSplit(result[i], ' ', tempTp); //double tp = (double) tempTp[1]; for(int j=0 ; j < ArraySize(tempTp); j++) { Print(" Data is: ", tempTp[j]); } if(ArraySize(tempTp) >= 2) tp = (double) tempTp[1]; Print("Tp : ", tp); } } Print("Side:", direction, " Symbol: ", symbol, " Tp: ", tp, " Sl: ", sl, " Message Id: ", message_id); if(direction == buy) { tickt = placeBuyTrade(symbol, tp, sl, message_id, lotSize); } if(direction == sell) { tickt = placeSellTrade(symbol, tp, sl, message_id, lotSize); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int placeBuyTrade(string symbol,double tp,double sl, int messageId, double lot_size) { double ask = SymbolInfoDouble(symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(symbol,SYMBOL_BID); double buySl = sl; double buyTp = tp; int ticket = OrderSend(symbol, OP_BUY, lot_size, ask, 3, buySl, buyTp, "Buy Trade Placed.", magic_no, 0, clrBlue); Print("Buy order Print: Stop Loss: ", buySl, " Take profit: ", buyTp); if(ticket < 0) { Print("Buy Order Failed ", GetLastError()); } else { Print(" Buy Order Is Placed Sucessfully "); } return ticket; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int placeSellTrade(string symbol,double tp,double sl, int messageId, double lot_size) { double ask = SymbolInfoDouble(symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(symbol,SYMBOL_BID); double sellSl = sl; double sellTp = tp; int ticket = OrderSend(symbol, OP_SELL, lot_size, bid, 3, sellSl, sellTp, "Sell Trade Placed.", magic_no, 0, clrRed); if(ticket < 0) { Print("Sell Order Failed ", GetLastError()); } else { Print(" Sell Order Is Placed Sucessfully "); } return ticket; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void addtoMessageStructure(int message_id,string message,ulong ticket) { for(int i=0; i < MaxOrders; i++) { if(od[i].msgid == -1) { od[i].msgid = message_id; od[i].tickt = ticket; StringToLower(message); Print(" Message ID ",message_id," of Message = ",message," Having Ticket ",ticket," is added To Structure :: "); break; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string trimString(string inputt) { // Remove spaces from the left and right sides int startt = 0; int end = StringLen(inputt) - 1; // Find the first non-space character while(startt <= end && StringGetCharacter(inputt, startt) == ' ') startt++; // Find the last non-space character while(end >= startt && StringGetCharacter(inputt, end) == ' ') end--; // Extract the substring without leading or trailing spaces return StringSubstr(inputt, startt, end - startt + 1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string spaceRemove(string inputt) { int len = StringLen(inputt); string out = ""; bool inSpace = false; for(int i = 0; i < len; i++) { ushort ch = StringGetCharacter(inputt, i); // treat space, tab, CR, LF as whitespace bool isSpace = (ch == 32 || ch == 9 || ch == 10 || ch == 13); if(isSpace) { // mark that we are inside a whitespace run, but don't append yet inSpace = true; continue; } // when we hit a non-space after whitespace, add a single space (if out not empty) if(inSpace && StringLen(out) > 0) out += " "; // append the non-space character (use substr to preserve unicode chars) out += StringSubstr(inputt, i, 1); inSpace = false; } return(out); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string removeExtraSpaces(string str) { string result = ""; int len = StringLen(str); bool lastWasSpace = false; for(int i = 0; i < len; i++) { string currentChar = StringSubstr(str, i, 1); if(currentChar == " ") { // Skip adding this space if the last character was also a space if(lastWasSpace) continue; lastWasSpace = true; } else { lastWasSpace = false; } result += currentChar; } return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool HasAlphanumeric(string str) { //Print("String Length: ", StringLen(str)); for(int i = 0; i <= StringLen(str); i++) { //Print("Here ", StringLen(str)); if(IsAlphanumeric((char)str[i])) { return true; break; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool IsAlphanumeric(char c) { if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) return true; return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string symbolMapping(string symbol) { for(int k = 0; k < ArraySize(symbolChart); k++) { StringToUpper(symbolChart[k]); if(symbol == symbolChart[k]) { symbol = symbolSnd[k]; } } symbol = prefix + symbol + suffix; return symbol; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //+------------------------------------------------------------------+