0% found this document useful (0 votes)
78 views65 pages

TG Mql5 Copy Trading

The document is a source code for a free Expert Advisor (EA) for trading, created by Allan Munene Mutiiria. It includes a JSON handling class, CJSONValue, which provides methods for serialization and deserialization of JSON data. Users can access the source code via the provided link and are encouraged to contact the developer for any inquiries.

Uploaded by

gowes13595
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
78 views65 pages

TG Mql5 Copy Trading

The document is a source code for a free Expert Advisor (EA) for trading, created by Allan Munene Mutiiria. It includes a JSON handling class, CJSONValue, which provides methods for serialization and deserialization of JSON data. Users can access the source code via the provided link and are encouraged to contact the developer for any inquiries.

Uploaded by

gowes13595
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 65

//+------------------------------------------------------------------+

//| TELEGRAM_MQL5_COPY_TRADING_PART7.mq5 |
//| Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader. |
//| https://youtube.com/@ForexAlgo-Trader? |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader"
#property link "https://youtube.com/@ForexAlgo-Trader?"
#property description "======= IMPORTANT =======\n"
#property description "1. This is a FREE EA."
#property description "2. To get the source code of the EA, follow the Copyright link."
#property description "3. Incase of anything, contact developer via the link provided."
"Hope you will enjoy the EA Logic.\n"
#property description "*** HAPPY TRADING! ***"
#property version "1.00"

//+------------------------------------------------------------------+
//| START OF THE JSON CODE SNIPPET (FROM LINE 15 TO LINE 737) |
//+------------------------------------------------------------------+

#define DEBUG_PRINT false


//------------------------------------------------------------------ enum JSONValueType
enum JSONValueType {jv_UNDEF,jv_NULL,jv_BOOL,jv_INT,jv_DBL,jv_STR,jv_ARRAY,jv_OBJ};
//------------------------------------------------------------------ class CJSONValue
class CJSONValue{
public:
// CONSTRUCTOR
virtual void Clear(){
m_parent=NULL;
m_key="";
m_type=jv_UNDEF;
m_bool_val=false;

Page 1/65
m_int_val=0;
m_double_val=0;
m_string_val="";
ArrayResize(m_elements,0);
}
virtual bool Copy(const CJSONValue &source){
m_key=source.m_key;
CopyData(source);
return true;
}
virtual void CopyData(const CJSONValue &source){
m_type=source.m_type;
m_bool_val=source.m_bool_val;
m_int_val=source.m_int_val;
m_double_val=source.m_double_val;
m_string_val=source.m_string_val;
CopyArr(source);
}
virtual void CopyArr(const CJSONValue &source){
int n=ArrayResize(m_elements,ArraySize(source.m_elements));
for(int i=0; i<n; i++){
m_elements[i]=source.m_elements[i];
m_elements[i].m_parent=GetPointer(this);
}
}

public:
CJSONValue m_elements[];
string m_key;
string m_lkey;
CJSONValue *m_parent;
JSONValueType m_type;

Page 2/65
bool m_bool_val;
long m_int_val;
double m_double_val;
string m_string_val;
static int code_page;

public:
CJSONValue(){
Clear();
}
CJSONValue(CJSONValue *parent,JSONValueType type){
Clear();
m_type=type;
m_parent=parent;
}
CJSONValue(JSONValueType type,string value){
Clear();
FromStr(type,value);
}
CJSONValue(const int intValue){
Clear();
m_type=jv_INT;
m_int_val=intValue;
m_double_val=(double)m_int_val;
m_string_val=IntegerToString(m_int_val);
m_bool_val=m_int_val!=0;
}
CJSONValue(const long longValue){
Clear();
m_type=jv_INT;
m_int_val=longValue;
m_double_val=(double)m_int_val;

Page 3/65
m_string_val=IntegerToString(m_int_val);
m_bool_val=m_int_val!=0;
}
CJSONValue(const double doubleValue){
Clear();
m_type=jv_DBL;
m_double_val=doubleValue;
m_int_val=(long)m_double_val;
m_string_val=DoubleToString(m_double_val);
m_bool_val=m_int_val!=0;
}
CJSONValue(const bool boolValue){
Clear();
m_type=jv_BOOL;
m_bool_val=boolValue;
m_int_val=m_bool_val;
m_double_val=m_bool_val;
m_string_val=IntegerToString(m_int_val);
}
CJSONValue(const CJSONValue &other){
Clear();
Copy(other);
}
// DECONSTRUCTOR
~CJSONValue(){
Clear();
}

public:
virtual bool IsNumeric(){
return (m_type==jv_DBL || m_type==jv_INT);
}

Page 4/65
virtual CJSONValue *FindKey(string key){
for(int i=ArraySize(m_elements)-1; i>=0; --i){
if(m_elements[i].m_key==key){
return GetPointer(m_elements[i]);
}
}
return NULL;
}
virtual CJSONValue *HasKey(string key,JSONValueType type=jv_UNDEF);
virtual CJSONValue *operator[](string key);
virtual CJSONValue *operator[](int i);
void operator=(const CJSONValue &value){
Copy(value);
}
void operator=(const int intVal){
m_type=jv_INT;
m_int_val=intVal;
m_double_val=(double)m_int_val;
m_bool_val=m_int_val!=0;
}
void operator=(const long longVal){
m_type=jv_INT;
m_int_val=longVal;
m_double_val=(double)m_int_val;
m_bool_val=m_int_val!=0;
}
void operator=(const double doubleVal){
m_type=jv_DBL;
m_double_val=doubleVal;
m_int_val=(long)m_double_val;
m_bool_val=m_int_val!=0;
}

Page 5/65
void operator=(const bool boolVal){
m_type=jv_BOOL;
m_bool_val=boolVal;
m_int_val=(long)m_bool_val;
m_double_val=(double)m_bool_val;
}
void operator=(string stringVal){
m_type=(stringVal!=NULL)?jv_STR:jv_NULL;
m_string_val=stringVal;
m_int_val=StringToInteger(m_string_val);
m_double_val=StringToDouble(m_string_val);
m_bool_val=stringVal!=NULL;
}

bool operator==(const int intVal){return m_int_val==intVal;}


bool operator==(const long longVal){return m_int_val==longVal;}
bool operator==(const double doubleVal){return m_double_val==doubleVal;}
bool operator==(const bool boolVal){return m_bool_val==boolVal;}
bool operator==(string stringVal){return m_string_val==stringVal;}

bool operator!=(const int intVal){return m_int_val!=intVal;}


bool operator!=(const long longVal){return m_int_val!=longVal;}
bool operator!=(const double doubleVal){return m_double_val!=doubleVal;}
bool operator!=(const bool boolVal){return m_bool_val!=boolVal;}
bool operator!=(string stringVal){return m_string_val!=stringVal;}

long ToInt() const{return m_int_val;}


double ToDbl() const{return m_double_val;}
bool ToBool() const{return m_bool_val;}
string ToStr(){return m_string_val;}

virtual void FromStr(JSONValueType type,string stringVal){

Page 6/65
m_type=type;
switch(m_type){
case jv_BOOL:
m_bool_val=(StringToInteger(stringVal)!=0);
m_int_val=(long)m_bool_val;
m_double_val=(double)m_bool_val;
m_string_val=stringVal;
break;
case jv_INT:
m_int_val=StringToInteger(stringVal);
m_double_val=(double)m_int_val;
m_string_val=stringVal;
m_bool_val=m_int_val!=0;
break;
case jv_DBL:
m_double_val=StringToDouble(stringVal);
m_int_val=(long)m_double_val;
m_string_val=stringVal;
m_bool_val=m_int_val!=0;
break;
case jv_STR:
m_string_val=Unescape(stringVal);
m_type=(m_string_val!=NULL)?jv_STR:jv_NULL;
m_int_val=StringToInteger(m_string_val);
m_double_val=StringToDouble(m_string_val);
m_bool_val=m_string_val!=NULL;
break;
}
}
virtual string GetStr(char &jsonArray[],int startIndex,int length){
#ifdef __MQL4__
if(length<=0) return "";

Page 7/65
#endif
char temporaryArray[];
ArrayCopy(temporaryArray,jsonArray,0,startIndex,length);
return CharArrayToString(temporaryArray, 0, WHOLE_ARRAY, CJSONValue::code_page);
}

virtual void Set(const CJSONValue &value){


if(m_type==jv_UNDEF) {m_type=jv_OBJ;}
CopyData(value);
}
virtual void Set(const CJSONValue &list[]);
virtual CJSONValue *Add(const CJSONValue &item){
if(m_type==jv_UNDEF){m_type=jv_ARRAY;}
return AddBase(item);
}
virtual CJSONValue *Add(const int intVal){
CJSONValue item(intVal);
return Add(item);
}
virtual CJSONValue *Add(const long longVal){
CJSONValue item(longVal);
return Add(item);
}
virtual CJSONValue *Add(const double doubleVal){
CJSONValue item(doubleVal);
return Add(item);
}
virtual CJSONValue *Add(const bool boolVal){
CJSONValue item(boolVal);
return Add(item);
}
virtual CJSONValue *Add(string stringVal){

Page 8/65
CJSONValue item(jv_STR,stringVal);
return Add(item);
}
virtual CJSONValue *AddBase(const CJSONValue &item){
int currSize=ArraySize(m_elements);
ArrayResize(m_elements,currSize+1);
m_elements[currSize]=item;
m_elements[currSize].m_parent=GetPointer(this);
return GetPointer(m_elements[currSize]);
}
virtual CJSONValue *New(){
if(m_type==jv_UNDEF) {m_type=jv_ARRAY;}
return NewBase();
}
virtual CJSONValue *NewBase(){
int currSize=ArraySize(m_elements);
ArrayResize(m_elements,currSize+1);
return GetPointer(m_elements[currSize]);
}

virtual string Escape(string value);


virtual string Unescape(string value);
public:
virtual void Serialize(string &jsonString,bool format=false,bool includeComma=false);
virtual string Serialize(){
string jsonString;
Serialize(jsonString);
return jsonString;
}
virtual bool Deserialize(char &jsonArray[],int length,int &currIndex);
virtual bool ExtrStr(char &jsonArray[],int length,int &currIndex);
virtual bool Deserialize(string jsonString,int encoding=CP_ACP){

Page 9/65
int currIndex=0;
Clear();
CJSONValue::code_page=encoding;
char charArray[];
int length=StringToCharArray(jsonString,charArray,0,WHOLE_ARRAY,CJSONValue::code_page);
return Deserialize(charArray,length,currIndex);
}
virtual bool Deserialize(char &jsonArray[],int encoding=CP_ACP){
int currIndex=0;
Clear();
CJSONValue::code_page=encoding;
return Deserialize(jsonArray,ArraySize(jsonArray),currIndex);
}
};

int CJSONValue::code_page=CP_ACP;

//------------------------------------------------------------------ HasKey
CJSONValue *CJSONValue::HasKey(string key,JSONValueType type){
for(int i=0; i<ArraySize(m_elements); i++) if(m_elements[i].m_key==key){
if(type==jv_UNDEF || type==m_elements[i].m_type){
return GetPointer(m_elements[i]);
}
break;
}
return NULL;
}
//------------------------------------------------------------------ operator[]
CJSONValue *CJSONValue::operator[](string key){
if(m_type==jv_UNDEF){m_type=jv_OBJ;}
CJSONValue *value=FindKey(key);
if(value){return value;}

Page 10/65
CJSONValue newValue(GetPointer(this),jv_UNDEF);
newValue.m_key=key;
value=Add(newValue);
return value;
}
//------------------------------------------------------------------ operator[]
CJSONValue *CJSONValue::operator[](int i){
if(m_type==jv_UNDEF) m_type=jv_ARRAY;
while(i>=ArraySize(m_elements)){
CJSONValue newElement(GetPointer(this),jv_UNDEF);
if(CheckPointer(Add(newElement))==POINTER_INVALID){return NULL;}
}
return GetPointer(m_elements[i]);
}
//------------------------------------------------------------------ Set
void CJSONValue::Set(const CJSONValue &list[]){
if(m_type==jv_UNDEF){m_type=jv_ARRAY;}
int elementsSize=ArrayResize(m_elements,ArraySize(list));
for(int i=0; i<elementsSize; ++i){
m_elements[i]=list[i];
m_elements[i].m_parent=GetPointer(this);
}
}
//------------------------------------------------------------------ Serialize
void CJSONValue::Serialize(string &jsonString,bool key,bool includeComma){
if(m_type==jv_UNDEF){return;}
if(includeComma){jsonString+=",";}
if(key){jsonString+=StringFormat("\"%s\":", m_key);}
int elementsSize=ArraySize(m_elements);
switch(m_type){
case jv_NULL:
jsonString+="null";

Page 11/65
break;
case jv_BOOL:
jsonString+=(m_bool_val?"true":"false");
break;
case jv_INT:
jsonString+=IntegerToString(m_int_val);
break;
case jv_DBL:
jsonString+=DoubleToString(m_double_val);
break;
case jv_STR:
{
string value=Escape(m_string_val);
if(StringLen(value)>0){jsonString+=StringFormat("\"%s\"",value);}
else{jsonString+="null";}
}
break;
case jv_ARRAY:
jsonString+="[";
for(int i=0; i<elementsSize; i++){m_elements[i].Serialize(jsonString,false,i>0);}
jsonString+="]";
break;
case jv_OBJ:
jsonString+="{";
for(int i=0; i<elementsSize; i++){m_elements[i].Serialize(jsonString,true,i>0);}
jsonString+="}";
break;
}
}
//------------------------------------------------------------------ Deserialize
bool CJSONValue::Deserialize(char &jsonArray[],int length,int &currIndex){
string validNumberChars="0123456789+-.eE";

Page 12/65
int startIndex=currIndex;
for(; currIndex<length; currIndex++){
char currChar=jsonArray[currIndex];
if(currChar==0){break;}
switch(currChar){
case '\t':
case '\r':
case '\n':
case ' ': // skip
startIndex=currIndex+1;
break;

case '[': // the beginning of the object. create an object and take it from js
{
startIndex=currIndex+1;
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
// if the value already has a type, then this is an error
return false;
}
m_type=jv_ARRAY; // set the type
currIndex++;
CJSONValue val(GetPointer(this),jv_UNDEF);
while(val.Deserialize(jsonArray,length,currIndex)){
if(val.m_type!=jv_UNDEF){Add(val);}
if(val.m_type==jv_INT || val.m_type==jv_DBL || val.m_type==jv_ARRAY){currIndex++;}
val.Clear();
val.m_parent=GetPointer(this);
if(jsonArray[currIndex]==']'){break;}
currIndex++;
if(currIndex>=length){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}

Page 13/65
return false;
}
}
return (jsonArray[currIndex]==']' || jsonArray[currIndex]==0);
}
break;
case ']':
if(!m_parent){return false;}
return (m_parent.m_type==jv_ARRAY); // end of array, current value must be an array

case ':':
{
if(m_lkey==""){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false;
}
CJSONValue val(GetPointer(this),jv_UNDEF);
CJSONValue *oc=Add(val); // object type is not defined yet
oc.m_key=m_lkey;
m_lkey=""; // set the key name
currIndex++;
if(!oc.Deserialize(jsonArray,length,currIndex)){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false;
}
break;
}
case ',': // value separator // value type must already be defined
startIndex=currIndex+1;
if(!m_parent && m_type!=jv_OBJ){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false;

Page 14/65
}
else if(m_parent){
if(m_parent.m_type!=jv_ARRAY && m_parent.m_type!=jv_OBJ){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false;
}
if(m_parent.m_type==jv_ARRAY && m_type==jv_UNDEF){return true;}
}
break;

// primitives can ONLY be in an array / or on their own


case '{': // the beginning of the object. create an object and take it from js
startIndex=currIndex+1;
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // type error
return false;
}
m_type=jv_OBJ; // set type of value
currIndex++;
if(!Deserialize(jsonArray,length,currIndex)){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // pull it out
return false;
}
return (jsonArray[currIndex]=='}' || jsonArray[currIndex]==0);
break;
case '}':
return (m_type==jv_OBJ); // end of object, current value must be object

case 't':
case 'T': // start true
case 'f':
case 'F': // start false

Page 15/65
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // type error
return false;
}
m_type=jv_BOOL; // set type
if(currIndex+3<length){
if(StringCompare(GetStr(jsonArray, currIndex, 4), "true", false)==0){
m_bool_val=true;
currIndex+=3;
return true;
}
}
if(currIndex+4<length){
if(StringCompare(GetStr(jsonArray, currIndex, 5), "false", false)==0){
m_bool_val=false;
currIndex+=4;
return true;
}
}
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false; //wrong type or end of line
break;
case 'n':
case 'N': // start null
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // type error
return false;
}
m_type=jv_NULL; // set type of value
if(currIndex+3<length){
if(StringCompare(GetStr(jsonArray,currIndex,4),"null",false)==0){
currIndex+=3;

Page 16/65
return true;
}
}
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false; // not NULL or end of line
break;

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
case '+':
case '.': // start of number
{
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // type error
return false;
}
bool dbl=false;// set typo of value
int is=currIndex;
while(jsonArray[currIndex]!=0 && currIndex<length){
currIndex++;
if(StringFind(validNumberChars,GetStr(jsonArray,currIndex,1))<0){break;}
if(!dbl){dbl=(jsonArray[currIndex]=='.' || jsonArray[currIndex]=='e' || jsonArray[
currIndex]=='E');}

Page 17/65
}
m_string_val=GetStr(jsonArray,is,currIndex-is);
if(dbl){
m_type=jv_DBL;
m_double_val=StringToDouble(m_string_val);
m_int_val=(long)m_double_val;
m_bool_val=m_int_val!=0;
}
else{
m_type=jv_INT; // clarified the value type
m_int_val=StringToInteger(m_string_val);
m_double_val=(double)m_int_val;
m_bool_val=m_int_val!=0;
}
currIndex--;
return true; // moved back a character and exited
break;
}
case '\"': // start or end of line
if(m_type==jv_OBJ){ // if the type is still undefined and the key is not set
currIndex++;
int is=currIndex;
if(!ExtrStr(jsonArray,length,currIndex)){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
// this is the key, go to the end of line
return false;
}
m_lkey=GetStr(jsonArray,is,currIndex-is);
}
else{
if(m_type!=jv_UNDEF){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} // type error

Page 18/65
return false;
}
m_type=jv_STR; // set type of value
currIndex++;
int is=currIndex;
if(!ExtrStr(jsonArray,length,currIndex)){
if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));}
return false;
}
FromStr(jv_STR,GetStr(jsonArray,is,currIndex-is));
return true;
}
break;
}
}
return true;
}
//------------------------------------------------------------------ ExtrStr
bool CJSONValue::ExtrStr(char &jsonArray[],int length,int &i){
for(; jsonArray[i]!=0 && i<length; i++){
char currChar=jsonArray[i];
if(currChar=='\"') break; // end if line
if(currChar=='\\' && i+1<length){
i++;
currChar=jsonArray[i];
switch(currChar){
case '/':
case '\\':
case '\"':
case 'b':
case 'f':
case 'r':

Page 19/65
case 'n':
case 't':
break; // allowed
case 'u': // \uXXXX
{
i++;
for(int j=0; j<4 && i<length && jsonArray[i]!=0; j++,i++){
if(!((jsonArray[i]>='0' && jsonArray[i]<='9') || (jsonArray[i]>='A' && jsonArray[i]<=
'F') || (jsonArray[i]>='a' && jsonArray[i]<='f'))){
if(DEBUG_PRINT){Print(m_key+" "+CharToString(jsonArray[i])+" "+string(__LINE__));}
// not hex
return false;
}
}
i--;
break;
}
default:
break; /*{ return false; } // unresolved escaped character */
}
}
}
return true;
}
//------------------------------------------------------------------ Escape
string CJSONValue::Escape(string stringValue){
ushort inputChars[], escapedChars[];
int inputLength=StringToShortArray(stringValue, inputChars);
if(ArrayResize(escapedChars, 2*inputLength)!=2*inputLength){return NULL;}
int escapedIndex=0;
for(int i=0; i<inputLength; i++){
switch(inputChars[i]){

Page 20/65
case '\\':
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='\\';
escapedIndex++;
break;
case '"':
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='"';
escapedIndex++;
break;
case '/':
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='/';
escapedIndex++;
break;
case 8:
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='b';
escapedIndex++;
break;
case 12:
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='f';
escapedIndex++;
break;
case '\n':
escapedChars[escapedIndex]='\\';

Page 21/65
escapedIndex++;
escapedChars[escapedIndex]='n';
escapedIndex++;
break;
case '\r':
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='r';
escapedIndex++;
break;
case '\t':
escapedChars[escapedIndex]='\\';
escapedIndex++;
escapedChars[escapedIndex]='t';
escapedIndex++;
break;
default:
escapedChars[escapedIndex]=inputChars[i];
escapedIndex++;
break;
}
}
stringValue=ShortArrayToString(escapedChars,0,escapedIndex);
return stringValue;
}
//------------------------------------------------------------------ Unescape
string CJSONValue::Unescape(string stringValue){
ushort inputChars[], unescapedChars[];
int inputLength=StringToShortArray(stringValue, inputChars);
if(ArrayResize(unescapedChars, inputLength)!=inputLength){return NULL;}
int j=0,i=0;
while(i<inputLength){

Page 22/65
ushort currChar=inputChars[i];
if(currChar=='\\' && i<inputLength-1){
switch(inputChars[i+1]){
case '\\':
currChar='\\';
i++;
break;
case '"':
currChar='"';
i++;
break;
case '/':
currChar='/';
i++;
break;
case 'b':
currChar=8;
i++;
break;
case 'f':
currChar=12;
i++;
break;
case 'n':
currChar='\n';
i++;
break;
case 'r':
currChar='\r';
i++;
break;
case 't':

Page 23/65
currChar='\t';
i++;
break;
}
}
unescapedChars[j]=currChar;
j++;
i++;
}
stringValue=ShortArrayToString(unescapedChars,0,j);
return stringValue;
}

//+------------------------------------------------------------------+
//| END OF THE JSON CODE SNIPPET (FROM LINE 15 TO LINE 737) |
//+------------------------------------------------------------------+

#define TELEGRAM_BASE_URL "https://api.telegram.org"


#define WEB_TIMEOUT 5000
//#define InpToken "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"
#define InpToken "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"

#include <Trade/Trade.mqh>
#include <Arrays/List.mqh>
#include <Arrays/ArrayString.mqh>

//+------------------------------------------------------------------+

Page 24/65
//| Function to send a POST request and get the response |
//+------------------------------------------------------------------+
int postRequest(string &response, const string url, const string params,
const int timeout=5000){
char data[]; //--- Array to store the data to be sent in the request
int data_size=StringLen(params); //--- Get the length of the parameters
StringToCharArray(params, data, 0, data_size); //--- Convert the parameters string to a char array

uchar result[]; //--- Array to store the response data


string result_headers; //--- Variable to store the response headers

//--- Send a POST request to the specified URL with the given parameters and timeout
int response_code=WebRequest("POST", url, NULL, NULL, timeout, data, data_size, result,
result_headers);
if(response_code==200){ //--- If the response code is 200 (OK)
//--- Remove Byte Order Mark (BOM) if present
int start_index=0; //--- Initialize the starting index for the response
int size=ArraySize(result); //--- Get the size of the response data array
// Loop through the first 8 bytes of the 'result' array or the entire array if it's smaller
for(int i=0; i<fmin(size,8); i++){
// Check if the current byte is part of the BOM
if(result[i]==0xef || result[i]==0xbb || result[i]==0xbf){
// Set 'start_index' to the byte after the BOM
start_index=i+1;
}
else {break;}
}
//--- Convert the response data from char array to string, skipping the BOM
response=CharArrayToString(result, start_index, WHOLE_ARRAY, CP_UTF8);
//Print(response); //--- Optionally print the response for debugging

return(0); //--- Return 0 to indicate success

Page 25/65
}
else{
if(response_code==-1){ //--- If there was an error with the WebRequest
return(_LastError); //--- Return the last error code
}
else{
//--- Handle HTTP errors
if(response_code>=100 && response_code<=511){
response=CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
//--- Convert the result to string
Print(response); //--- Print the response for debugging
Print("ERR: HTTP"); //--- Print an error message indicating an HTTP error
return(-1); //--- Return -1 to indicate an HTTP error
}
return(response_code); //--- Return the response code for other errors
}
}
return(0); //--- Return 0 in case of an unexpected error
}

// FUNCTION TO DECODE A STRING THAT CONTAINS ENCODED & UNICODE CHARACTERS


//+------------------------------------------------------------------+
string decodeStringCharacters(string text){
//--- replace \n with its ASCII equivalent (hexadecimal 0x0A)
StringReplace(text,"\n",ShortToString(0x0A));

//--- replace \u0000


int highSurrogate=0; // used to store the high surrogate of a Unicode character pair.
int pos=StringFind(text,"\\u");
while(pos!=-1){
string strcode=StringSubstr(text,pos,6);

Page 26/65
string strhex=StringSubstr(text,pos+2,4);

StringToUpper(strhex);//Convert to uppercase to standardize the processing.

int total=StringLen(strhex);
int result=0;
//loop to calculate the decimal value of the hexadecimal number
for(int i=0,k=total-1; i<total; i++,k--){
int coef=(int)pow(2,4*k); //coefficient rep place value of each hex digit.
ushort character=StringGetCharacter(strhex,i);
//convert the hexadecimal characters to their decimal equivalents.
if(character>='0' && character<='9'){result+=(character-'0')*coef;}
if(character>='A' && character<='F'){result+=(character-'A'+10)*coef;}
}

if(highSurrogate!=0){//it means a high surrogate was previously found


if(result>=0xDC00 && result<=0xDFFF){//if result is a low surrogate
int dec=((highSurrogate-0xD800)<<10)+(result-0xDC00);//+0x10000;
getStringReplacement(text,pos,6,ShortToString((ushort)dec));
highSurrogate=0;
}
else{
//If result is not a valid low surrogate, it resets haut to 0,
//indicating an error in the sequence.
//--- error: Second byte out of range
highSurrogate=0;
}
}
else{
//if result is a high surrogate, we store result for use with the next
//surrogate pair and removes the high surrogate from the text.
if(result>=0xD800 && result<=0xDBFF){

Page 27/65
highSurrogate=result;
getStringReplacement(text,pos,6,"");
}
else{
//If result is not part of a surrogate pair, we replace the escape
//sequence with the corresponding character.
getStringReplacement(text,pos,6,ShortToString((ushort)result));
}
}
//Update pos to find the next Unicode escape sequence and continue the loop.
pos=StringFind(text,"\\u",pos);
}
return(text);
}

//+------------------------------------------------------------------+
int getStringReplacement(string &string_var,const int start_pos,const int length,
const string replacement){
string temporaryString=(start_pos==0)?"":StringSubstr(string_var,0,start_pos);
temporaryString+=replacement;
temporaryString+=StringSubstr(string_var,start_pos+length);
string_var=temporaryString;
return(StringLen(replacement));
}

//+------------------------------------------------------------------+
//| Function to get the Trimmed Bot's Token |
//+------------------------------------------------------------------+
string getTrimmedToken(const string bot_token){
string token=getTrimmedString(bot_token);
//--- Trim the bot_token using getTrimmedString function.
if(token==""){ //--- Check if the trimmed token is empty.

Page 28/65
Print("ERR: TOKEN EMPTY"); //--- Print an error message if the token is empty.
return("NULL"); //--- Return "NULL" if the token is empty.
}
return(token); //--- Return the trimmed token.
}

//+------------------------------------------------------------------+
//| Function to get a Trimmed string |
//+------------------------------------------------------------------+
string getTrimmedString(string text){
StringTrimLeft(text); //--- Remove leading whitespace from the string.
StringTrimRight(text); //--- Remove trailing whitespace from the string.
return(text); //--- Return the trimmed string.
}

//+------------------------------------------------------------------+
//| Create a custom reply keyboard markup for Telegram |
//+------------------------------------------------------------------+
string customReplyKeyboardMarkup(const string keyboard, const bool resize,
const bool one_time){
// Construct the JSON string for the custom reply keyboard markup.
// 'keyboard' specifies the layout of the custom keyboard.
// 'resize' determines whether the keyboard should be resized to fit the screen.
// 'one_time' specifies if the keyboard should disappear after being used once.

// 'resize' > true: Resize the keyboard to fit the screen.


// 'one_time' > true: The keyboard will disappear after the user has used it once.
// 'selective' > false: The keyboard will be shown to all users, not just specific ones.

string result = "{"

Page 29/65
"\"keyboard\": " + UrlEncode(keyboard) + ", "
//--- Encode and set the keyboard layout
"\"one_time_keyboard\": " + convertBoolToString(one_time) + ", "
//--- Set whether the keyboard should disappear after use
"\"resize_keyboard\": " + convertBoolToString(resize) + ", "
//--- Set whether the keyboard should be resized to fit the screen
"\"selective\": false" //--- Keyboard will be shown to all users
"}";

return(result); //--- Return the JSON string for the custom reply keyboard
}

// FUNCTION TO ENCODE A STRING FOR USE IN URL


string UrlEncode(const string text){
string result=NULL;
int length=StringLen(text);
for(int i=0; i<length; i++){
ushort character=StringGetCharacter(text,i);
// Check if the 'character' is a number, letter, or one of the specified
// symbols which do not need encoding.
if((character>=48 && character<=57) || // 0-9
(character>=65 && character<=90) || // A-Z
(character>=97 && character<=122) || // a-z
(character=='!') || (character=='\'') || (character=='(') ||
(character==')') || (character=='*') || (character=='-') ||
(character=='.') || (character=='_') || (character=='~')
){
// Append the 'character' to the 'result' string without encoding.
result+=ShortToString(character);
}
else{

Page 30/65
// If the 'character' is a space, append a '+' to the 'result' string.
if(character==' '){
result+=ShortToString('+');
}
else{
uchar array[];
int total=ShortToUtf8(character,array);
for(int k=0; k<total; k++){
// FORMAT SPECIFIER...
// %% = LITERAL PERCENT SIGN
// %02X = ACTUAL FORMAT SPECIFIER
// 02 = resulting hexadecimal string should be padded with zeros
// to ensure it is at least two characters long.
// X = the number should be converted to a hexadecimal string using
// uppercase letters.
result+=StringFormat("%%%02X",array[k]);
}
}
}
}
return result;
}

//+------------------------------------------------------------------+
int ShortToUtf8(const ushort character,uchar &output[]){
//---
if(character<0x80){
ArrayResize(output,1);
output[0]=(uchar)character;
return(1);
}
//---

Page 31/65
if(character<0x800){
ArrayResize(output,2);
output[0] = (uchar)((character >> 6)|0xC0);
output[1] = (uchar)((character & 0x3F)|0x80);
return(2);
}
//---
if(character<0xFFFF){
if(character>=0xD800 && character<=0xDFFF){//Ill-formed
ArrayResize(output,1);
output[0]=' ';
return(1);
}
else if(character>=0xE000 && character<=0xF8FF){//Emoji
int character_int=0x10000|character;
ArrayResize(output,4);
output[0] = (uchar)(0xF0 | (character_int >> 18));
output[1] = (uchar)(0x80 | ((character_int >> 12) & 0x3F));
output[2] = (uchar)(0x80 | ((character_int >> 6) & 0x3F));
output[3] = (uchar)(0x80 | ((character_int & 0x3F)));
return(4);
}
else{
ArrayResize(output,3);
output[0] = (uchar)((character>>12)|0xE0);
output[1] = (uchar)(((character>>6)&0x3F)|0x80);
output[2] = (uchar)((character&0x3F)|0x80);
return(3);
}
}
ArrayResize(output,3);
output[0] = 0xEF;

Page 32/65
output[1] = 0xBF;
output[2] = 0xBD;
return(3);
}

//+------------------------------------------------------------------+
//| Convert boolean value to string |
//+------------------------------------------------------------------+
string convertBoolToString(const bool _value){
if(_value)
return("true"); //--- Return "true" if the boolean value is true
return("false"); //--- Return "false" if the boolean value is false
}

//+------------------------------------------------------------------+
//| Create JSON for hiding custom reply keyboard |
//+------------------------------------------------------------------+
string hideCustomReplyKeyboard(){
return("{\"hide_keyboard\": true}"); //--- JSON to hide the custom reply keyboard
}

//+------------------------------------------------------------------+
//| Create JSON for forcing a reply to a message |
//+------------------------------------------------------------------+
string forceReplyCustomKeyboard(){
return("{\"force_reply\": true}"); //--- JSON to force a reply to the message
}

//+------------------------------------------------------------------+
//| Send a message to Telegram |
//+------------------------------------------------------------------+

Page 33/65
int sendMessageToTelegram(const long chat_id,const string text,
const string reply_markup=NULL){
string output; //--- Variable to store the response from the request
string url=TELEGRAM_BASE_URL+"/bot"+getTrimmedToken(InpToken)+"/sendMessage";
//--- Construct the URL for the Telegram API request

//--- Construct parameters for the API request


string params="chat_id="+IntegerToString(chat_id)+"&text="+UrlEncode(text);
//--- Set chat ID and message text
if(reply_markup!=NULL){ //--- If a reply markup is provided
params+="&reply_markup="+reply_markup; //--- Add reply markup to parameters
}
params+="&parse_mode=HTML"; //--- Set parse mode to HTML (can also be Markdown)
params+="&disable_web_page_preview=true"; //--- Disable web page preview in the message

//--- Send a POST request to the Telegram API


int res=postRequest(output,url,params,WEB_TIMEOUT); //--- Call postRequest to send the message
return(res); //--- Return the response code from the request
}

void sendScreenshotToTelegram(const long chat_id,string symbol, ENUM_TIMEFRAMES period,


string caption
){
const string SCREENSHOT_FILE_NAME = "My ScreenShot.jpg";

long chart_id=ChartOpen(symbol,period);
ChartSetInteger(ChartID(),CHART_BRING_TO_TOP,true);
// update chart
int wait=60;
while(--wait>0){//decrease the value of wait by 1 before loop condition check
if(SeriesInfoInteger(symbol,period,SERIES_SYNCHRONIZED)){

Page 34/65
break; // if prices up to date, terminate the loop and proceed
}
}

ChartRedraw(chart_id);
ChartSetInteger(chart_id,CHART_SHOW_GRID,false);
ChartSetInteger(chart_id,CHART_SHOW_PERIOD_SEP,false);

if(FileIsExist(SCREENSHOT_FILE_NAME)){
FileDelete(SCREENSHOT_FILE_NAME);
ChartRedraw(chart_id);
}

ChartScreenShot(chart_id,SCREENSHOT_FILE_NAME,1366,768,ALIGN_RIGHT);
//Sleep(10000); // sleep for 10 secs to see the opened chart
ChartClose(chart_id);

// waitng 30 sec for save screenshot if not yet saved


wait=60;
while(!FileIsExist(SCREENSHOT_FILE_NAME) && --wait>0){
Sleep(500);
}

if(!FileIsExist(SCREENSHOT_FILE_NAME)){
Print("SPECIFIED SCREENSHOT DOES NOT EXIST. REVERTING NOW!");
return;
}

int screenshot_Handle = FileOpen(SCREENSHOT_FILE_NAME,FILE_READ|FILE_BIN);


if(screenshot_Handle == INVALID_HANDLE){
Print("INVALID SCREENSHOT HANDLE. REVERTING NOW!");
return;

Page 35/65
}

int screenshot_Handle_Size = (int)FileSize(screenshot_Handle);


uchar photoArr_Data[];
ArrayResize(photoArr_Data,screenshot_Handle_Size);
FileReadArray(screenshot_Handle,photoArr_Data,0,screenshot_Handle_Size);
FileClose(screenshot_Handle);

uchar base64[];
uchar key[];
CryptEncode(CRYPT_BASE64,photoArr_Data,key,base64);
uchar temporaryArr[1024]= {0};
ArrayCopy(temporaryArr,base64,0,0,1024);
uchar md5[];
CryptEncode(CRYPT_HASH_MD5,temporaryArr,key,md5);
string hash=NULL;//Used to store the hexadecimal representation of MD5 hash
int total=ArraySize(md5);
for(int i=0; i<total; i++){
hash+=StringFormat("%02X",md5[i]);
}
hash=StringSubstr(hash,0,16);//truncate hash string to its first 16 characters

//--- WebRequest
string URL = TELEGRAM_BASE_URL+"/bot"+InpToken+"/sendPhoto";
string HEADERS = NULL;
char DATA[];
char RESULT[];
string RESULT_HEADERS = NULL;
string CAPTION = NULL;
const string METHOD = "POST";

ArrayAdd(DATA,"\r\n");

Page 36/65
ArrayAdd(DATA,"--"+hash+"\r\n");
ArrayAdd(DATA,"Content-Disposition: form-data; name=\"chat_id\"\r\n");
ArrayAdd(DATA,"\r\n");
ArrayAdd(DATA,IntegerToString(chat_id));
ArrayAdd(DATA,"\r\n");

CAPTION = caption;
if(StringLen(CAPTION) > 0){
ArrayAdd(DATA,"--"+hash+"\r\n");
ArrayAdd(DATA,"Content-Disposition: form-data; name=\"caption\"\r\n");
ArrayAdd(DATA,"\r\n");
ArrayAdd(DATA,CAPTION);
ArrayAdd(DATA,"\r\n");
}

ArrayAdd(DATA,"--"+hash+"\r\n");
ArrayAdd(DATA,
"Content-Disposition: form-data; name=\"photo\"; filename=\"Upload_ScreenShot.jpg\"\r\n");
ArrayAdd(DATA,"\r\n");
ArrayAdd(DATA,photoArr_Data);
ArrayAdd(DATA,"\r\n");
ArrayAdd(DATA,"--"+hash+"--\r\n");

HEADERS = "Content-Type: multipart/form-data; boundary="+hash+"\r\n";

int res_WebReq = WebRequest(METHOD,URL,HEADERS,WEB_TIMEOUT,DATA,RESULT,RESULT_HEADERS);

if(res_WebReq == 200){
//ArrayPrint(RESULT);
string result = CharArrayToString(RESULT,0,WHOLE_ARRAY,CP_UTF8);
Print(result);
Print("SUCCESS SENDING THE SCREENSHOT TO TELEGRAM");

Page 37/65
}
else{
if(res_WebReq == -1){
string result = CharArrayToString(RESULT,0,WHOLE_ARRAY,CP_UTF8);
Print(result);
Print("ERROR",_LastError," IN WEBREQUEST");
if (_LastError == 4014){
Print("API URL NOT LISTED. PLEASE ADD/ALLOW IT IN TERMINAL");
return;
}
}
else{
string result = CharArrayToString(RESULT,0,WHOLE_ARRAY,CP_UTF8);
Print(result);
Print("UNEXPECTED ERROR: ",_LastError);
return;
}
}

// ArrayAdd for uchar Array


void ArrayAdd(uchar &destinationArr[],const uchar &sourceArr[]){
int sourceArr_size=ArraySize(sourceArr);//get size of source array
if(sourceArr_size==0){
return;//if source array is empty, exit the function
}
int destinationArr_size=ArraySize(destinationArr);
//resize destination array to fit new data
ArrayResize(destinationArr,destinationArr_size+sourceArr_size,500);
// Copy the source array to the end of the destination array.
ArrayCopy(destinationArr,sourceArr,destinationArr_size,0,sourceArr_size);

Page 38/65
}

//+------------------------------------------------------------------+
// ArrayAdd for strings
void ArrayAdd(char &destinationArr[],const string text){
int length = StringLen(text);// get the length of the input text
if(length > 0){
uchar sourceArr[]; //define an array to hold the UTF-8 encoded characters
for(int i=0; i<length; i++){
// Get the character code of the current character
ushort character = StringGetCharacter(text,i);
uchar array[];//define an array to hold the UTF-8 encoded character
//Convert the character to UTF-8 & get size of the encoded character
int total = ShortToUtf8(character,array);

//Print("text @ ",i," > "text); // @ "B", IN ASCII TABLE = 66 (CHARACTER)


//Print("character = ",character);
//ArrayPrint(array);
//Print("bytes = ",total) // bytes of the character

int sourceArr_size = ArraySize(sourceArr);


//Resize the source array to accommodate the new character
ArrayResize(sourceArr,sourceArr_size+total);
//Copy the encoded character to the source array
ArrayCopy(sourceArr,array,sourceArr_size,0,total);
}
//Append the source array to the destination array
ArrayAdd(destinationArr,sourceArr);
}
}

Page 39/65
//+------------------------------------------------------------------+
//| Class_Message |
//+------------------------------------------------------------------+
class Class_Message : public CObject{
//--- Defines a class named Class_Message that inherits from CObject.
public:
Class_Message(); //--- Constructor declaration.
~Class_Message(){}; //--- Declares an empty destructor for the class.

//--- Member variables to track the status of the message.


bool done; //--- Indicates if a message has been processed.
long update_id; //--- Stores the update ID from Telegram.
long message_id; //--- Stores the message ID.

//--- Member variables to store sender-related information.


long from_id; //--- Stores the sender’s ID.
string from_first_name; //--- Stores the sender’s first name.
string from_last_name; //--- Stores the sender’s last name.
string from_username; //--- Stores the sender’s username.

//--- Member variables to store chat-related information.


long chat_id; //--- Stores the chat ID.
string chat_first_name; //--- Stores the chat first name.
string chat_last_name; //--- Stores the chat last name.
string chat_username; //--- Stores the chat username.
string chat_type; //--- Stores the chat type.

//--- Member variables to store message-related information.


datetime message_date; //--- Stores the date of the message.
string message_text; //--- Stores the text of the message.
};

Page 40/65
//+------------------------------------------------------------------+
//| Constructor to initialize class members |
//+------------------------------------------------------------------+
Class_Message::Class_Message(void){
//--- Initialize the boolean 'done' to false, indicating the message is not processed.
done = false;

//--- Initialize message-related IDs to zero.


update_id = 0;
message_id = 0;

//--- Initialize sender-related information.


from_id = 0;
from_first_name = NULL;
from_last_name = NULL;
from_username = NULL;

//--- Initialize chat-related information.


chat_id = 0;
chat_first_name = NULL;
chat_last_name = NULL;
chat_username = NULL;
chat_type = NULL;

//--- Initialize the message date and text.


message_date = 0;
message_text = NULL;
}

//+------------------------------------------------------------------+
//| Class_Chat |

Page 41/65
//+------------------------------------------------------------------+
class Class_Chat : public CObject{
public:
Class_Chat(){}; //Declares an empty constructor.
~Class_Chat(){}; // deconstructor
long member_id;//Stores the chat ID.
int member_state;//Stores the state of the chat.
datetime member_time;//Stores the time related to the chat.
Class_Message member_last;//An instance of Class_Message to store the last message.
Class_Message member_new_one;//An instance of Class_Message to store the new message.
};
//+------------------------------------------------------------------+
//| Class_Bot_EA |
//+------------------------------------------------------------------+
class Class_Bot_EA{
private:
string member_token; //--- Stores the bot’s token.
string member_name; //--- Stores the bot’s name.
long member_update_id; //--- Stores the last update ID processed by the bot.
CArrayString member_users_filter; //--- An array to filter users.
bool member_first_remove;
//--- A boolean to indicate if the first message should be removed.

protected:
CList member_chats; //--- A list to store chat objects.

public:
void Class_Bot_EA(); //--- Declares the constructor.
~Class_Bot_EA(){}; //--- Declares the destructor.
int getChatUpdates(); //--- Declares a function to get updates from Telegram.
void ProcessMessages(); //--- Declares a function to process incoming messages.
};

Page 42/65
void Class_Bot_EA::Class_Bot_EA(void){ //--- Constructor
member_token=NULL; //--- Initialize the bot's token as NULL.
member_token=getTrimmedToken(InpToken); //--- Assign the trimmed bot token from InpToken.
member_name=NULL; //--- Initialize the bot's name as NULL.
member_update_id=0; //--- Initialize the last update ID to 0.
member_first_remove=true; //--- Set the flag to remove the first message to true.
member_chats.Clear(); //--- Clear the list of chat objects.
member_users_filter.Clear(); //--- Clear the user filter array.
}
//+------------------------------------------------------------------+
int Class_Bot_EA::getChatUpdates(void){
//--- Check if the bot token is NULL
if(member_token==NULL){
Print("ERR: TOKEN EMPTY"); //--- Print an error message if the token is empty
return(-1); //--- Return with an error code
}

string out; //--- Variable to store the response from the request
string url=TELEGRAM_BASE_URL+"/bot"+member_token+"/getUpdates";
//--- Construct the URL for the Telegram API request
string params="offset="+IntegerToString(member_update_id);
//--- Set the offset parameter to get updates after the last processed ID

//--- Send a POST request to get updates from Telegram


int res=postRequest(out, url, params, WEB_TIMEOUT);
// THIS IS THE STRING RESPONSE WE GET // "ok":true,"result":[]}

//--- If the request was successful


if(res==0){
//Print(out); //--- Optionally print the response

//--- Create a JSON object to parse the response

Page 43/65
CJSONValue obj_json(NULL, jv_UNDEF);
//--- Deserialize the JSON response
bool done=obj_json.Deserialize(out);
//--- If JSON parsing failed
// Print(done);
if(!done){
Print("ERR: JSON PARSING"); //--- Print an error message if parsing fails
return(-1); //--- Return with an error code
}

//--- Check if the 'ok' field in the JSON is true


bool ok=obj_json["ok"].ToBool();
//--- If 'ok' is false, there was an error in the response
if(!ok){
Print("ERR: JSON NOT OK"); //--- Print an error message if 'ok' is false
return(-1); //--- Return with an error code
}

//--- Create a message object to store message details


Class_Message obj_msg;

//--- Get the total number of updates in the JSON array 'result'
int total=ArraySize(obj_json["result"].m_elements);
//--- Loop through each update
for(int i=0; i<total; i++){
//--- Get the individual update item as a JSON object
CJSONValue obj_item=obj_json["result"].m_elements[i];

//--- Extract message details from the JSON object


obj_msg.update_id=obj_item["update_id"].ToInt(); //--- Get the update ID
obj_msg.message_id=obj_item["message"]["message_id"].ToInt(); //--- Get the message ID

Page 44/65
obj_msg.message_date=(datetime)obj_item["message"]["date"].ToInt();
//--- Get the message date

obj_msg.message_text=obj_item["message"]["text"].ToStr(); //--- Get the message text


obj_msg.message_text=decodeStringCharacters(obj_msg.message_text);
//--- Decode any HTML entities in the message text

//--- Extract sender details from the JSON object


obj_msg.from_id=obj_item["message"]["from"]["id"].ToInt(); //--- Get the sender's ID
obj_msg.from_first_name=obj_item["message"]["from"]["first_name"].ToStr();
//--- Get the sender's first name
obj_msg.from_first_name=decodeStringCharacters(obj_msg.from_first_name);
//--- Decode the first name
obj_msg.from_last_name=obj_item["message"]["from"]["last_name"].ToStr();
//--- Get the sender's last name
obj_msg.from_last_name=decodeStringCharacters(obj_msg.from_last_name);
//--- Decode the last name
obj_msg.from_username=obj_item["message"]["from"]["username"].ToStr();
//--- Get the sender's username
obj_msg.from_username=decodeStringCharacters(obj_msg.from_username);
//--- Decode the username

//--- Extract chat details from the JSON object


obj_msg.chat_id=obj_item["message"]["chat"]["id"].ToInt(); //--- Get the chat ID
obj_msg.chat_first_name=obj_item["message"]["chat"]["first_name"].ToStr();
//--- Get the chat's first name
obj_msg.chat_first_name=decodeStringCharacters(obj_msg.chat_first_name);
//--- Decode the first name
obj_msg.chat_last_name=obj_item["message"]["chat"]["last_name"].ToStr();
//--- Get the chat's last name
obj_msg.chat_last_name=decodeStringCharacters(obj_msg.chat_last_name);
//--- Decode the last name

Page 45/65
obj_msg.chat_username=obj_item["message"]["chat"]["username"].ToStr();
//--- Get the chat's username
obj_msg.chat_username=decodeStringCharacters(obj_msg.chat_username);
//--- Decode the username
obj_msg.chat_type=obj_item["message"]["chat"]["type"].ToStr(); //--- Get the chat type

//--- Update the ID for the next request


member_update_id=obj_msg.update_id+1;

//--- If it's the first update, skip processing


if(member_first_remove){
continue;
}

//--- Filter messages based on username


if(member_users_filter.Total()==0 || //--- If no filter is applied, process all messages
(member_users_filter.Total()>0 &&
//--- If a filter is applied, check if the username is in the filter
member_users_filter.SearchLinear(obj_msg.from_username)>=0)){

//--- Find the chat in the list of chats


int index=-1;
for(int j=0; j<member_chats.Total(); j++){
Class_Chat *chat=member_chats.GetNodeAtIndex(j);
if(chat.member_id==obj_msg.chat_id){ //--- Check if the chat ID matches
index=j;
break;
}
}

//--- If the chat is not found, add a new chat to the list
if(index==-1){

Page 46/65
member_chats.Add(new Class_Chat); //--- Add a new chat to the list
Class_Chat *chat=member_chats.GetLastNode();
chat.member_id=obj_msg.chat_id; //--- Set the chat ID
chat.member_time=TimeLocal(); //--- Set the current time for the chat
chat.member_state=0; //--- Initialize the chat state
chat.member_new_one.message_text=obj_msg.message_text; //--- Set the new message text
chat.member_new_one.done=false; //--- Mark the new message as not processed
}
//--- If the chat is found, update the chat message
else{
Class_Chat *chat=member_chats.GetNodeAtIndex(index);
chat.member_time=TimeLocal(); //--- Update the chat time
chat.member_new_one.message_text=obj_msg.message_text; //--- Update the message text
chat.member_new_one.done=false; //--- Mark the new message as not processed
}
}

}
//--- After the first update, set the flag to false
member_first_remove=false;
}
//--- Return the result of the POST request
return(res);
}

void Class_Bot_EA::ProcessMessages(void){

//--- Define emoji and keyboard button constants


#define EMOJI_UP "\x2B06" //--- Upwards arrow emoji
#define EMOJI_PISTOL "\xF52B" //--- Pistol emoji

Page 47/65
#define EMOJI_CANCEL "\x274C" //--- Cross mark emoji
#define KEYB_MAIN "[[\"Name\"],[\"Account Info\"],[\"Quotes\"],[\"More\",\"Screenshot\",\""+
EMOJI_CANCEL+"\"]]" //--- Main keyboard layout
#define KEYB_MORE "[[\""+EMOJI_UP+"\"],[\"Buy\",\"Close\",\"Next\"]]"
//--- More options keyboard layout
#define KEYB_NEXT "[[\""+EMOJI_UP+"\",\"Contact\",\"Join\",\""+EMOJI_PISTOL+"\"]]"
//--- Next options keyboard layout
#define KEYB_SYMBOLS "[[\""+EMOJI_UP+
"\",\"AUDUSDm\",\"AUDCADm\"],[\"EURJPYm\",\"EURCHFm\",\"EURUSDm\"],[\"USDCHFm\",\"USDCADm\",\""+
EMOJI_PISTOL+"\"]]" //--- Symbol selection keyboard layout
#define KEYB_PERIODS "[[\""+EMOJI_UP+"\",\"M1\",\"M15\",\"M30\"],[\""+EMOJI_CANCEL+
"\",\"H1\",\"H4\",\"D1\"]]" //--- Period selection keyboard layout

//--- Define timeframes array for screenshot requests


const ENUM_TIMEFRAMES periods[] = {PERIOD_M1,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1};

//--- Loop through all chats


for(int i=0; i<member_chats.Total(); i++){
Class_Chat *chat=member_chats.GetNodeAtIndex(i); //--- Get the current chat
if(!chat.member_new_one.done){ //--- Check if the message has not been processed yet
chat.member_new_one.done=true; //--- Mark the message as processed
string text=chat.member_new_one.message_text; //--- Get the message text

string user_text = text;


Print("USER'S PLAIN TEXT IS AS BELOW:\n",user_text);

StringToUpper(user_text);
Print("USER'S TRANSFORMED UPPERCASE TEXT IS AS BELOW:\n",user_text);

//--- Initialize variables to hold extracted data


string signal_symbol = NULL;
string signal_direction = NULL;
double signal_price = 0.0;
Page 48/65
double signal_sl = 0.0;
double signal_tp = 0.0;

//--- Split the message by lines


string lines[];
StringSplit(user_text,'\n',lines);
Print("SPLIT TEXT SEGMENTS IS AS BELOW:");
ArrayPrint(lines,0,",");

//--- Iterate over each line to extract information


for (int i=0; i<ArraySize(lines); i++){
StringTrimLeft(lines[i]);
StringTrimRight(lines[i]);

string selected_line = lines[i];


//Print(i,". ",selected_line);

//--- Look for direction: Buy or Sell


if (StringFind(selected_line,"BUY") >= 0){ //--- Check if the line contains 'BUY'
signal_direction = "BUY"; //--- Set the signal direction as 'BUY'
signal_price = StringToDouble(StringSubstr(selected_line,5));
//--- Extract the price after 'BUY' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}
if (StringFind(selected_line,"SELL") >= 0){ //--- Check if the line contains 'SELL'
signal_direction = "SELL"; //--- Set the signal direction as 'SELL'
signal_price = StringToDouble(StringSubstr(selected_line,5+1));
//--- Extract the price after 'SELL' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}

Page 49/65
//--- Look for direction: Buy Stop or Sell Stop
if (StringFind(selected_line,"BUY STOP") >= 0){
//--- Check if the line contains 'BUY STOP'
signal_direction = "BUY STOP"; //--- Set the signal direction as 'BUY STOP'
signal_price = StringToDouble(StringSubstr(selected_line,10));
//--- Extract the price after 'BUY STOP' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}
if (StringFind(selected_line,"SELL STOP") >= 0){
//--- Check if the line contains 'SELL STOP'
signal_direction = "SELL STOP"; //--- Set the signal direction as 'SELL STOP'
signal_price = StringToDouble(StringSubstr(selected_line,10+1));
//--- Extract the price after 'SELL STOP' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}

//--- Look for direction: Buy Limit or Sell Limit


if (StringFind(selected_line,"BUY LIMIT") >= 0){
//--- Check if the line contains 'BUY LIMIT'
signal_direction = "BUY LIMIT"; //--- Set the signal direction as 'BUY LIMIT'
signal_price = StringToDouble(StringSubstr(selected_line,11));
//--- Extract the price after 'BUY LIMIT' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}
if (StringFind(selected_line,"SELL LIMIT") >= 0){
//--- Check if the line contains 'SELL LIMIT'
signal_direction = "SELL LIMIT"; //--- Set the signal direction as 'SELL LIMIT'

Page 50/65
signal_price = StringToDouble(StringSubstr(selected_line,11+1));
//--- Extract the price after 'SELL LIMIT' and convert it to double
Print("Line @ index ",i," Trade = ",signal_direction,", Price = ",signal_price);
//--- Print the extracted details
}

//--- Look for Stop Loss (SL) and extract the value
if (StringFind(selected_line,"SL:") >= 0){ //--- Check if the line contains 'SL:'
signal_sl = StringToDouble(StringSubstr(selected_line,5));
//--- Extract the Stop Loss value and convert it to double
Print("Line @ index ",i," SL = ",signal_sl); //--- Print the Stop Loss value
}

//--- Look for Take Profit (TP) and extract the value
if (StringFind(selected_line,"TP:") >= 0){ //--- Check if the line contains 'TP:'
signal_tp = StringToDouble(StringSubstr(selected_line,5));
//--- Extract the Take Profit value and convert it to double
Print("Line @ index ",i," TP = ",signal_tp); //--- Print the Take Profit value
}

//--- Check for symbol in the list of available symbols and assign it
for(int k = 0; k < SymbolsTotal(true); k++) { //--- Loop through all available symbols
string selected_symbol = SymbolName(k, true); //--- Get the symbol name
if (StringCompare(selected_line,selected_symbol,false) == 0){
//--- Compare the line with the symbol name
signal_symbol = selected_symbol; //--- Assign the symbol if a match is found
Print("Line @ index ",i," SYMBOL = ",signal_symbol); //--- Print the found symbol
}
}
}
//--- Final data

Page 51/65
Print("\nFINAL EXTRACTED DATA:"); //--- Print the final data for confirmation
Print("Symbol = ",signal_symbol); //--- Print the extracted symbol
Print("Direction = ",signal_direction); //--- Print the extracted trade direction
Print("Price = ",signal_price); //--- Print the extracted price
Print("Stop Loss = ",signal_sl); //--- Print the extracted Stop Loss
Print("Take Profit = ",signal_tp); //--- Print the extracted Take Profit

bool trade_result = false; //--- Initialize a flag to store trade result

double volume = 0.01; //--- Define a default trade volume


//--- If the signal direction is 'BUY' and valid data is present
if (signal_direction=="BUY"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0){
//--- Check if symbol, Stop Loss, and Take Profit are valid
Print("OKAY. We have the crucial data to open a BUY position!");
//--- Confirm valid data for a BUY trade

signal_price = SymbolInfoDouble(signal_symbol,SYMBOL_ASK);
//--- Get the current ask price for the symbol
CTrade obj_Trade; //--- Create a trade object
obj_Trade.Buy(volume,signal_symbol,signal_price,signal_sl,signal_tp);
//--- Execute a BUY trade with the extracted data
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}
//--- If the signal direction is 'SELL' and valid data is present
else if (signal_direction=="SELL"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0){
//--- Check if symbol, Stop Loss, and Take Profit are valid
Print("OKAY. We have the crucial data to open a SELL position!");
//--- Confirm valid data for a SELL trade

Page 52/65
signal_price = SymbolInfoDouble(signal_symbol,SYMBOL_BID);
//--- Get the current bid price for the symbol
CTrade obj_Trade; //--- Create a trade object
obj_Trade.Sell(volume,signal_symbol,signal_price,signal_sl,signal_tp);
//--- Execute a SELL trade with the extracted data
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}

//--- If the signal direction is 'BUY STOP' and valid data is present
else if (signal_direction=="BUY STOP"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0 && signal_price != 0.0
){
Print("OKAY. We have the crucial data to open a BUY STOP order!");

CTrade obj_Trade; //--- Create a trade object


obj_Trade.BuyStop(volume,signal_price,signal_symbol,signal_sl,signal_tp);
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}
//--- If the signal direction is 'SELL STOP' and valid data is present
else if (signal_direction=="SELL STOP"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0 && signal_price != 0.0
){
Print("OKAY. We have the crucial data to open a SELL STOP order!");

CTrade obj_Trade; //--- Create a trade object


obj_Trade.SellStop(volume,signal_price,signal_symbol,signal_sl,signal_tp);
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}
//--- If the signal direction is 'BUY LIMIT' and valid data is present

Page 53/65
else if (signal_direction=="BUY LIMIT"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0 && signal_price != 0.0
){
Print("OKAY. We have the crucial data to open a BUY LIMIT order!");

CTrade obj_Trade; //--- Create a trade object


obj_Trade.BuyLimit(volume,signal_price,signal_symbol,signal_sl,signal_tp);
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}
//--- If the signal direction is 'SELL LIMIT' and valid data is present
else if (signal_direction=="SELL LIMIT"){
if (signal_symbol != NULL && signal_sl != 0.0 && signal_tp != 0.0 && signal_price != 0.0
){
Print("OKAY. We have the crucial data to open a SELL LIMIT order!");

CTrade obj_Trade; //--- Create a trade object


obj_Trade.SellLimit(volume,signal_price,signal_symbol,signal_sl,signal_tp);
trade_result = obj_Trade.ResultOrder(); //--- Store the result of the trade
}
}

//--- If the trade was successful, send confirmation message to Telegram


if (trade_result){
string message = "SUCCESS! THE SIGNAL WAS EXECUTED WITH THE FOLLOWING DETAILS:\n";
//--- Prepare success message
message += "\nSymbol = "+signal_symbol+"\n"; //--- Add symbol to the message
message += "Direction = "+signal_direction+"\n"; //--- Add direction to the message
message += "Volume = "+DoubleToString(volume,2)+"\n"; //--- Add volume to the message
message += "Price = "+DoubleToString(signal_price,_Digits)+"\n";
//--- Add price to the message

Page 54/65
message += "Stop Loss = "+DoubleToString(signal_sl,_Digits)+"\n";
//--- Add Stop Loss to the message
message += "Take Profit = "+DoubleToString(signal_tp,_Digits)+"\n";
//--- Add Take Profit to the message
message+="\nHAPPY TRADING!"; //--- Add final message line
Print(message); //--- Print the message in the terminal
sendMessageToTelegram(chat.member_id,message,NULL);
//--- Send the success message to Telegram
}

//
// //--- If the message is "/start", "/help", "Start", or "Help"
// if(text=="/start" || text=="/help" || text=="Start" || text=="Help"){
// chat.member_state=0; //--- Reset the chat state
// string message="I am a BOT \xF680 and I work with your MT5 Forex trading account.\n";
// message+="You can control me by sending these commands \xF648 :\n";
// message+="\nInformation\n";
// message+="/name - get EA name\n";
// message+="/info - get account information\n";
// message+="/quotes - get quotes\n";
// message+="/screenshot - get chart screenshot\n";
// message+="\nTrading Operations\n";
// message+="/buy - open buy position\n";
// message+="/close - close a position\n";
// message+="\nMore Options\n";
// message+="/contact - contact developer\n";

Page 55/65
// message+="/join - join our MQL5 community\n";
//
// //--- Send the response message with the main keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_MAIN,false,false
// continue;
// }
//
// //--- If the message is "/name" or "Name"
// if (text=="/name" || text=="Name"){
// string message = "The file name of the EA that I control is:\n";
// message += "\xF50B"+__FILE__+" Enjoy.\n";
// sendMessageToTelegram(chat.member_id,message,NULL);
// }
//
// //--- If the message is "/info" or "Account Info"
// ushort MONEYBAG = 0xF4B0; //--- Define money bag emoji
// string MONEYBAGcode = ShortToString(MONEYBAG); //--- Convert emoji to string
// if(text=="/info" || text=="Account Info"){
// string currency=AccountInfoString(ACCOUNT_CURRENCY); //--- Get the account currency
// string message="\x2733\Account No: "+(string)AccountInfoInteger(ACCOUNT_LOGIN)+"\n";
// message+="\x23F0\Account Server: "+AccountInfoString(ACCOUNT_SERVER)+"\n";

// message+=MONEYBAGcode+"Balance: "+(string)AccountInfoDouble(ACCOUNT_BALANCE)+" "+currency+"\


// message+="\x2705\Profit: "+(string)AccountInfoDouble(ACCOUNT_PROFIT)+" "+currency+"\n";
//
// //--- Send the response message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;
// }
//
// //--- If the message is "/quotes" or "Quotes"

Page 56/65
// if(text=="/quotes" || text=="Quotes"){
// double Ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); //--- Get the current ask price
// double Bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); //--- Get the current bid price
// string message="\xF170 Ask: "+(string)Ask+"\n";
// message+="\xF171 Bid: "+(string)Bid+"\n";
//
// //--- Send the response message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;
// }
//
// //--- If the message is "/buy" or "Buy"
// if (text=="/buy" || text=="Buy"){
// CTrade obj_trade; //--- Create a trade object
// double Ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); //--- Get the current ask price
// double Bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); //--- Get the current bid price
// obj_trade.Buy(0.01,NULL,0,Bid-300*_Point,Bid+300*_Point); //--- Open a buy position
// double entry=0,sl=0,tp=0,vol=0;
// ulong ticket = obj_trade.ResultOrder(); //--- Get the ticket number of the new order
// if (ticket > 0){
// if (PositionSelectByTicket(ticket)){ //--- Select the position by ticket
// entry=PositionGetDouble(POSITION_PRICE_OPEN); //--- Get the entry price
// sl=PositionGetDouble(POSITION_SL); //--- Get the stop loss price
// tp=PositionGetDouble(POSITION_TP); //--- Get the take profit price
// vol=PositionGetDouble(POSITION_VOLUME); //--- Get the volume
// }
// }
// string message="\xF340\Opened BUY Position:\n";
// message+="Ticket: "+(string)ticket+"\n";
// message+="Open Price: "+(string)entry+"\n";
// message+="Lots: "+(string)vol+"\n";
// message+="SL: "+(string)sl+"\n";

Page 57/65
// message+="TP: "+(string)tp+"\n";
//
// //--- Send the response message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;
// }
//
// //--- If the message is "/close" or "Close"
// if (text=="/close" || text=="Close"){
// CTrade obj_trade; //--- Create a trade object

// int totalOpenBefore = PositionsTotal(); //--- Get the total number of open positions before
// obj_trade.PositionClose(_Symbol); //--- Close the position for the symbol

// int totalOpenAfter = PositionsTotal(); //--- Get the total number of open positions after cl
// string message="\xF62F\Closed Position:\n";
// message+="Total Positions (Before): "+(string)totalOpenBefore+"\n";
// message+="Total Positions (After): "+(string)totalOpenAfter+"\n";
//
// //--- Send the response message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;
// }
//
// //--- If the message is "/contact" or "Contact"
// if (text=="/contact" || text=="Contact"){
// string message="Contact the developer via link below:\n";
// message+="https://t.me/Forex_Algo_Trader";
//
// //--- Send the contact message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;

Page 58/65
// }
//
// //--- If the message is "/join" or "Join"
// if (text=="/join" || text=="Join"){
// string message="You want to be part of our MQL5 Community?\n";
// message+="Welcome! <a href=\"https://t.me/forexalgo_trading\">Click me</a> to join.\n";
// message+="<s>Civil Engineering</s> Forex AlgoTrading\n";//strikethrough
// message+="<pre>This is a sample of our MQL5 code</pre>\n";//preformat

// message+="<u><i>Remember to follow community guidelines!\xF64F\</i></u>\n";//italic, underli


// message+="<b>Happy Trading!</b>\n";//bold
//
// //--- Send the join message
// sendMessageToTelegram(chat.member_id,message,NULL);
// continue;
// }
//
// //--- If the message is "more" or "More"
// if (text=="more" || text=="More"){
// chat.member_state=1; //--- Update chat state to show more options
// string message="Choose More Options Below:";
//
// //--- Send the more options message with the more options keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_MORE,false,true)
// continue;
// }
//
// //--- If the message is the up emoji
// if(text==EMOJI_UP){
// chat.member_state=0; //--- Reset chat state
// string message="Choose a menu item:";

Page 59/65
//
// //--- Send the message with the main keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_MAIN,false,false
// continue;
// }
//
// //--- If the message is "next" or "Next"
// if(text=="next" || text=="Next"){
// chat.member_state=2; //--- Update chat state to show next options
// string message="Choose Still More Options Below:";
//
// //--- Send the next options message with the next options keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_NEXT,false,true)
// continue;
// }
//
// //--- If the message is the pistol emoji
// if (text==EMOJI_PISTOL){
// if (chat.member_state==2){
// chat.member_state=1; //--- Change state to show more options
// string message="Choose More Options Below:";
//
// //--- Send the message with the more options keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_MORE,false,tr
// }
// else {
// chat.member_state=0; //--- Reset chat state
// string message="Choose a menu item:";
//

Page 60/65
// //--- Send the message with the main keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_MAIN,false,fa
// }
// continue;
// }
//
// //--- If the message is the cancel emoji
// if (text==EMOJI_CANCEL){
// chat.member_state=0; //--- Reset chat state
// string message="Choose /start or /help to begin.";
//
// //--- Send the cancel message with hidden custom reply keyboard
// sendMessageToTelegram(chat.member_id,message,hideCustomReplyKeyboard());
// continue;
// }
//
// //--- If the message is "/screenshot" or "Screenshot"
// static string symbol = _Symbol; //--- Default symbol
// static ENUM_TIMEFRAMES period = _Period; //--- Default period
// if (text=="/screenshot" || text=="Screenshot"){
// chat.member_state = 10; //--- Set state to screenshot request
// string message="Provide a symbol like 'AUDUSDm'";
//
// //--- Send the message with the symbols keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_SYMBOLS,false,fa
// continue;
// }
//
// //--- Handle state 10 (symbol selection for screenshot)
// if (chat.member_state==10){

Page 61/65
// string user_symbol = text; //--- Get the user-provided symbol
// if (SymbolSelect(user_symbol,true)){ //--- Check if the symbol is valid
// chat.member_state = 11; //--- Update state to period request
// string message = "CORRECT: Symbol is found\n";
// message += "Now provide a Period like 'H1'";
// symbol = user_symbol; //--- Update symbol
//
// //--- Send the message with the periods keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_PERIODS,false
// }
// else {
// string message = "WRONG: Symbol is invalid\n";
// message += "Provide a correct symbol name like 'AUDUSDm' to proceed.";
//
// //--- Send the invalid symbol message with the symbols keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_SYMBOLS,false
// }
// continue;
// }
//
// //--- Handle state 11 (period selection for screenshot)
// if (chat.member_state==11){
// bool found=false; //--- Flag to check if period is valid
// int total=ArraySize(periods); //--- Get the number of defined periods
// for(int k=0; k<total; k++){

// string str_tf=StringSubstr(EnumToString(periods[k]),7); //--- Convert period enum to stri


// if(StringCompare(str_tf,text,false)==0){ //--- Check if period matches
// ENUM_TIMEFRAMES user_period=periods[k]; //--- Set user-selected period
// period = user_period; //--- Update period

Page 62/65
// found=true;
// break;
// }
// }
// if (found){
// string message = "CORRECT: Period is valid\n";
// message += "Screenshot sending process initiated \xF60E";
//
// //--- Send the valid period message with the periods keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_PERIODS,false
// string caption = "Screenshot of Symbol: "+symbol+
// " ("+EnumToString(ENUM_TIMEFRAMES(period))+
// ") @ Time: "+TimeToString(TimeCurrent());
//
// //--- Send the screenshot to Telegram
// sendScreenshotToTelegram(chat.member_id,symbol,period,caption);
// }
// else {
// string message = "WRONG: Period is invalid\n";
// message += "Provide a correct period like 'H1' to proceed.";
//
// //--- Send the invalid period message with the periods keyboard

// sendMessageToTelegram(chat.member_id,message,customReplyKeyboardMarkup(KEYB_PERIODS,false
// }
// continue;
// }

}
}
}

Page 63/65
//+------------------------------------------------------------------+
//| Telegram_Bot_EA.mq5 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
#property version "1.00"
#property strict

Class_Bot_EA obj_bot; //--- Create an instance of the Class_Bot_EA class

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
EventSetMillisecondTimer(3000);
//--- Set a timer event to trigger every 3000 milliseconds (3 seconds)
OnTimer(); //--- Call OnTimer() immediately to get the first update
return(INIT_SUCCEEDED); //--- Return initialization success
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
EventKillTimer(); //--- Kill the timer event to stop further triggering
ChartRedraw(); //--- Redraw the chart to reflect any changes
}

//+------------------------------------------------------------------+
//| Timer function |

Page 64/65
//+------------------------------------------------------------------+
void OnTimer(){
obj_bot.getChatUpdates(); //--- Call the function to get chat updates from Telegram
obj_bot.ProcessMessages(); //--- Call the function to process incoming messages
}

Page 65/65

You might also like