417 lines
15 KiB
MQL5
417 lines
15 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| Telegram.mq5 |
|
||
|
//| Copyright 2020, QUADRELION |
|
||
|
//| https://www.quadrelion.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "Copyright 2020, QUADRELION"
|
||
|
#property link "https://www.quadrelion.com"
|
||
|
#property version "2.06"
|
||
|
|
||
|
#define KEYBOARD1 "[[\"\xF5A8 Reporting\"],[\"\xF4B9 Trading\"]]"
|
||
|
|
||
|
|
||
|
input uint percentage = 20; //[Margin change in percentage]
|
||
|
input double equity_change = 1.0; //[Equity change in percentage]
|
||
|
|
||
|
/************************************************
|
||
|
1093872535:AAHxmV_VJ_opVnEM3Qyg0zzU79sKi6dpw6s
|
||
|
MT5 Notification bot uses: 1072805610:AAEUeJJZ-mMr_7-2erUOuC6MVuyC1Fdr6QE
|
||
|
*************************************************/
|
||
|
|
||
|
input string botToken = "1145259342:AAFHCX6AMM7a3vgNVD9bOQ5fsyTXhX7-_Wg";
|
||
|
input string channelName = "VINITERON:Varchev"; // [Channel or Group name]
|
||
|
|
||
|
/*
|
||
|
input string botToken = "951743402:AAFk5Wqzg5X4hvba-nSQGKy6nXtCfslFhYs";
|
||
|
input string channelName = "VINITERON:BenchMark"; // [Channel or Group name]
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
input string botToken = "1116038453:AAGF-dvzHZxKlCZpwuJa3MGqjldn4pFFzh8";
|
||
|
input string channelName = "Nick:BenchMark"; // [Channel or Group name]
|
||
|
*/
|
||
|
|
||
|
double old_margin = 0;
|
||
|
double old_equity = 0;
|
||
|
|
||
|
bool trading_clicked = false;
|
||
|
bool show_weekly_report = false;
|
||
|
|
||
|
struct output_data_array
|
||
|
{
|
||
|
string symbol;
|
||
|
double net_lots;
|
||
|
double profit;
|
||
|
double open_price;
|
||
|
double short_price_volume ;
|
||
|
double short_volume;
|
||
|
double long_price_volume ;
|
||
|
double long_volume;
|
||
|
string tickets;
|
||
|
};
|
||
|
|
||
|
struct TelegramMessage
|
||
|
{
|
||
|
long MessageId;
|
||
|
string Text;
|
||
|
datetime TimestampGMT;
|
||
|
};
|
||
|
|
||
|
#import "Telegram Connector MT5.ex5"
|
||
|
bool TelegramInit(const string botToken, const long channelId);
|
||
|
bool TelegramInit(const string botToken, const string channelName);
|
||
|
void TelegramGetUpdates(TelegramMessage& messages[]);
|
||
|
string BuildReplyMarkup(const string keyboard, const bool resize = false,const bool selective = false);
|
||
|
string BuildReplyKeyboardHide();
|
||
|
bool TelegramSendText(const string text, const bool htmlMode = false, const string replyMarkup = NULL);
|
||
|
bool TelegramSendPhoto(const string path, const string title, const bool useCommonFlag = false, const int timeout = 10000);
|
||
|
#import
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert initialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int OnInit()
|
||
|
{
|
||
|
if(!TelegramInit(botToken, channelName))
|
||
|
{
|
||
|
return INIT_FAILED;
|
||
|
}
|
||
|
|
||
|
TelegramSendText("---=== "+AccountInfoString(ACCOUNT_NAME)+" ===---", false, BuildReplyMarkup(KEYBOARD1));
|
||
|
//OnTick();
|
||
|
EventSetTimer(3);
|
||
|
return(INIT_SUCCEEDED);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert deinitialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnDeinit(const int reason)
|
||
|
{
|
||
|
//--- destroy timer
|
||
|
EventKillTimer();
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert tick function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTick()
|
||
|
{
|
||
|
//double margin = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
|
||
|
double margin_level = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
|
||
|
double changeMargin = 0;
|
||
|
|
||
|
if(margin_level==0)
|
||
|
{
|
||
|
if(show_weekly_report)
|
||
|
{
|
||
|
datetime end_date = TimeCurrent();
|
||
|
datetime start_date =iTime(_Symbol,PERIOD_W1,0);
|
||
|
out_deals(start_date,end_date);
|
||
|
show_weekly_report = false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
changeMargin = MathAbs(1 - double(old_margin/margin_level));
|
||
|
show_weekly_report = true;
|
||
|
}
|
||
|
|
||
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
||
|
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||
|
double account_pnl = equity - balance;
|
||
|
if(old_equity ==0)
|
||
|
old_equity = equity;
|
||
|
double changeEq = MathAbs(equity/old_equity - 1);
|
||
|
|
||
|
|
||
|
//Print("change: ",changeMargin);
|
||
|
// Print("percentage: ",percentage);
|
||
|
double perc = percentage/100.0;
|
||
|
//Print(perc);
|
||
|
//Print("Send:",(changeMargin >= perc || changeEq >= perc));
|
||
|
//Print("changeMargin: ",changeMargin);
|
||
|
//Print("changeEq: ",changeEq);
|
||
|
|
||
|
if(changeMargin >= perc || changeEq >= (double)(equity_change/100.0) || trading_clicked == true)
|
||
|
{
|
||
|
|
||
|
|
||
|
output_data_array data_array[];
|
||
|
|
||
|
|
||
|
int sizer = 1;
|
||
|
int totalPositions = PositionsTotal();
|
||
|
|
||
|
|
||
|
for(int i =0; i < totalPositions; i++)
|
||
|
{
|
||
|
bool exists = false;
|
||
|
string currentSym = PositionGetSymbol(i);
|
||
|
|
||
|
for(int j =0; j<ArrayRange(data_array,0); j++)
|
||
|
{
|
||
|
|
||
|
if(currentSym == data_array[j].symbol)
|
||
|
{
|
||
|
|
||
|
if(PositionGetInteger(POSITION_TYPE)==0)
|
||
|
{
|
||
|
data_array[j].net_lots = data_array[j].net_lots + 1*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[j].long_price_volume += PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[j].long_volume += PositionGetDouble(POSITION_VOLUME);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
data_array[j].net_lots = data_array[j].net_lots - 1*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[j].short_price_volume += PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[j].short_volume += PositionGetDouble(POSITION_VOLUME);
|
||
|
}
|
||
|
|
||
|
data_array[j].tickets += ", " + IntegerToString(PositionGetInteger(POSITION_TICKET));
|
||
|
data_array[j].profit = data_array[j].profit + (PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP));
|
||
|
|
||
|
|
||
|
exists = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(exists == false)
|
||
|
{
|
||
|
int size = ArraySize(data_array);
|
||
|
ArrayResize(data_array, size + 1);
|
||
|
|
||
|
data_array[size].symbol = currentSym;
|
||
|
|
||
|
if(PositionGetInteger(POSITION_TYPE)==0)
|
||
|
{
|
||
|
data_array[size].net_lots = PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[size].short_volume = 0;
|
||
|
data_array[size].short_price_volume = 0;
|
||
|
data_array[size].long_price_volume = PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[size].long_volume = PositionGetDouble(POSITION_VOLUME);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
data_array[size].long_volume = 0;
|
||
|
data_array[size].long_price_volume = 0;
|
||
|
data_array[size].net_lots = 0 - PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[size].short_price_volume = PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
|
||
|
data_array[size].short_volume = PositionGetDouble(POSITION_VOLUME);
|
||
|
}
|
||
|
data_array[size].tickets = IntegerToString(PositionGetInteger(POSITION_TICKET));
|
||
|
data_array[size].profit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
sort(data_array);
|
||
|
|
||
|
|
||
|
|
||
|
string output = "";
|
||
|
|
||
|
double toEUR = EUR_ConversionRate();
|
||
|
|
||
|
//output+= AccountInfoString(ACCOUNT_COMPANY)+" : "+AccountInfoString(ACCOUNT_NAME)+"\n";
|
||
|
//output+= StringFormat("Balance: %.2f Equity: %.2f Margin level: %.2f%%\n", balance*toEUR,equity*toEUR,margin_level);
|
||
|
output+= StringFormat("%.2f [Equity]\n%.2f [Balance]\n%.2f %% [Margin]\n==========================", equity*toEUR,balance*toEUR,margin_level);
|
||
|
|
||
|
for(int j = 0; j < ArraySize(data_array); j++)
|
||
|
{
|
||
|
|
||
|
if(data_array[j].net_lots>0)
|
||
|
data_array[j].open_price = data_array[j].long_price_volume/data_array[j].long_volume;
|
||
|
else
|
||
|
if(data_array[j].net_lots<0)
|
||
|
data_array[j].open_price = data_array[j].short_price_volume/data_array[j].short_volume;
|
||
|
|
||
|
output+= StringFormat("\n[%+.2f] %s ",data_array[j].profit*toEUR, data_array[j].symbol);
|
||
|
|
||
|
if(data_array[j].net_lots!=0)
|
||
|
{
|
||
|
string helper_digits = StringFormat("\n........................%%.2f @ %%.%df",decimalPlacesForPairs(data_array[j].symbol));
|
||
|
output+= StringFormat(helper_digits,data_array[j].net_lots,data_array[j].open_price);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
output+= StringFormat("\n==========================\n%+.2f [Floating]", account_pnl*toEUR);
|
||
|
|
||
|
old_margin = margin_level;
|
||
|
old_equity = equity;
|
||
|
trading_clicked = false;
|
||
|
|
||
|
TelegramSendText(output);
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Timer function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTimer()
|
||
|
{
|
||
|
TelegramMessage messages[];
|
||
|
TelegramGetUpdates(messages);
|
||
|
|
||
|
for(int i = 0; i < ArraySize(messages); i++)
|
||
|
{
|
||
|
if(StringFind(messages[i].Text, " Trading") >= 0)
|
||
|
{
|
||
|
trading_clicked = true;
|
||
|
//OnTick();
|
||
|
//TelegramSendText("Trading callback");
|
||
|
}
|
||
|
|
||
|
if(StringFind(messages[i].Text, " Reporting") >= 0)
|
||
|
{
|
||
|
datetime end_date = TimeCurrent();
|
||
|
datetime start_date =iTime(_Symbol,PERIOD_W1,0);
|
||
|
//Print(start_date+"-"+end_date);
|
||
|
out_deals(start_date,end_date);
|
||
|
//TelegramSendText("", false, BuildReplyKeyboardHide());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Trade function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTrade()
|
||
|
{
|
||
|
//---
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| TradeTransaction function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTradeTransaction(const MqlTradeTransaction& trans,
|
||
|
const MqlTradeRequest& request,
|
||
|
const MqlTradeResult& result)
|
||
|
{
|
||
|
//---
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| ChartEvent function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnChartEvent(const int id,
|
||
|
const long &lparam,
|
||
|
const double &dparam,
|
||
|
const string &sparam)
|
||
|
{
|
||
|
//---
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double EUR_ConversionRate()
|
||
|
{
|
||
|
string CCY = AccountInfoString(ACCOUNT_CURRENCY);
|
||
|
//Print("Account CCY: ", CCY);
|
||
|
if(CCY == "USD")
|
||
|
return(1/ SymbolInfoDouble("EURUSD", SYMBOL_ASK));
|
||
|
else
|
||
|
if(CCY == "BGN")
|
||
|
return(1/1.95583);
|
||
|
else
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
long decimalPlacesForPairs(string sPair)
|
||
|
{
|
||
|
return SymbolInfoInteger(sPair,SYMBOL_DIGITS);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void sort(output_data_array& array[])
|
||
|
{
|
||
|
bool sorted = false;
|
||
|
while(!sorted)
|
||
|
{
|
||
|
sorted = true;
|
||
|
for(int i = 1; i<ArraySize(array); i++)
|
||
|
{
|
||
|
if(array[i].profit >= array[i-1].profit)
|
||
|
{
|
||
|
output_data_array tmp = array[i];
|
||
|
array[i] = array[i-1];
|
||
|
array[i-1] = tmp;
|
||
|
sorted = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void out_deals(datetime start_date, datetime end_date)
|
||
|
{
|
||
|
output_data_array out_deals_array[];
|
||
|
HistorySelect(start_date,end_date);
|
||
|
int total = HistoryDealsTotal();
|
||
|
for(int i =0; i<total; i++)
|
||
|
{
|
||
|
ulong ticket = HistoryDealGetTicket(i);
|
||
|
bool exists = false;
|
||
|
string current_symbol = HistoryDealGetString(ticket,DEAL_SYMBOL);
|
||
|
int entry = (int)HistoryDealGetInteger(ticket,DEAL_ENTRY);
|
||
|
|
||
|
if(entry == 1)
|
||
|
{
|
||
|
for(int j = 0; j < ArrayRange(out_deals_array,0); j++)
|
||
|
{
|
||
|
if(current_symbol == out_deals_array[j].symbol)
|
||
|
{
|
||
|
out_deals_array[j].net_lots = out_deals_array[j].net_lots + HistoryDealGetDouble(ticket,DEAL_VOLUME);
|
||
|
out_deals_array[j].short_price_volume += HistoryDealGetDouble(ticket,DEAL_PRICE)*HistoryDealGetDouble(ticket,DEAL_VOLUME);
|
||
|
out_deals_array[j].profit += (HistoryDealGetDouble(ticket,DEAL_PROFIT) + HistoryDealGetDouble(ticket,DEAL_SWAP));
|
||
|
exists = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(exists == false)
|
||
|
{
|
||
|
int size = ArraySize(out_deals_array);
|
||
|
ArrayResize(out_deals_array, size + 1);
|
||
|
|
||
|
out_deals_array[size].symbol = current_symbol;
|
||
|
out_deals_array[size].net_lots = HistoryDealGetDouble(ticket,DEAL_VOLUME);
|
||
|
out_deals_array[size].long_price_volume = HistoryDealGetDouble(ticket,DEAL_PRICE)*HistoryDealGetDouble(ticket,DEAL_VOLUME);
|
||
|
out_deals_array[size].profit = HistoryDealGetDouble(ticket,DEAL_PROFIT) + HistoryDealGetDouble(ticket,DEAL_SWAP);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
sort(out_deals_array);
|
||
|
string output = "";
|
||
|
double totalprofit = 0;
|
||
|
double toEUR = EUR_ConversionRate();
|
||
|
|
||
|
for(int j = 0; j < ArraySize(out_deals_array); j++)
|
||
|
{
|
||
|
//output+= AccountInfoString(ACCOUNT_COMPANY)+" : "+AccountInfoString(ACCOUNT_NAME)+"\n";
|
||
|
totalprofit+=out_deals_array[j].profit;
|
||
|
|
||
|
output+= StringFormat("\n[%+.2f] %s ",out_deals_array[j].profit*toEUR, out_deals_array[j].symbol);
|
||
|
string helper_digits = StringFormat("%%.2f lots",decimalPlacesForPairs(out_deals_array[j].symbol));
|
||
|
output+= StringFormat(helper_digits,out_deals_array[j].net_lots,out_deals_array[j].profit);
|
||
|
}
|
||
|
output+=StringFormat("\n================\n[%+.2f]", totalprofit*toEUR);
|
||
|
|
||
|
if(ArraySize(out_deals_array) == 0)
|
||
|
output = "No deals were made since the start of the week.";
|
||
|
TelegramSendText(output);
|
||
|
|
||
|
}
|