TG Mql5 Copy Trading
TG Mql5 Copy Trading
//| 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) |
//+------------------------------------------------------------------+
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;
}
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);
}
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]);
}
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;
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) |
//+------------------------------------------------------------------+
#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
//--- 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
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
}
Page 26/65
string strhex=StringSubstr(text,pos+2,4);
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;}
}
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.
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
}
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
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);
if(!FileIsExist(SCREENSHOT_FILE_NAME)){
Print("SPECIFIED SCREENSHOT DOES NOT EXIST. REVERTING NOW!");
return;
}
Page 35/65
}
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");
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;
}
}
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);
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.
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;
//+------------------------------------------------------------------+
//| 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
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
}
//--- 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];
Page 44/65
obj_msg.message_date=(datetime)obj_item["message"]["date"].ToInt();
//--- Get the message date
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
//--- 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){
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
StringToUpper(user_text);
Print("USER'S TRANSFORMED UPPERCASE TEXT IS AS BELOW:\n",user_text);
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
}
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
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!");
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!");
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";
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
// 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++){
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
//+------------------------------------------------------------------+
//| 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