Files
2025-02-07 19:13:59 +03:30

467 lines
19 KiB
Plaintext

#include <Trade/DealInfo.mqh>
#include <Arrays/ArrayDouble.mqh>
#include <Generic/HashSet.mqh>
#include "FileSave.mqh"
#include "Translations/English.mqh"
enum deal_result
{
NO_VALUE=0,
WIN=1,
LOSS
};
enum ENUM_HISTORY_SORT
{
HISTORY_SORT_OPENTIME, // Open time
HISTORY_SORT_CLOSETIME // Close time
};
class CHistory
{
private:
CFileSaving m_FileSave;
CDealInfo m_deal;
CArrayDouble m_profit_data;
CArrayDouble m_balance_data;
CArrayDouble m_sharp_balance;
CArrayDouble m_balance_line;
double m_max_lot;
double m_initial_deposit;
double m_withdrawal;
double m_volume;
double m_swap;
double m_commission;
double m_profit;
double m_gross_profit;
double m_gross_loss;
double m_profit_factor;
double m_expected_payoff;
double m_balance;
double m_maxdraw_MDD;
double m_maxdraw_percent;
// double m_balance_min;
// double m_balance_dd;
// double m_balance_dd_percent;
// double m_balance_dd_relative;
// double m_balance_dd_relative_percent;
// double m_balance_dd_absolute;
double m_min_peak;
double m_max_peak;
long arr_Positions[];
long m_type;
long m_magic;
int m_deals;
int m_trades;
int m_profit_trades;
double m_profit_trades_percent;
int m_loss_trades;
string m_symbol;
string m_comment;
string m_openTime_str;
string m_closeTime_str;
datetime m_openTime_dt;
datetime m_closeTime_dt;
string m_mqlName;
public:
CHistory(void);
~CHistory(void);
bool Calculate(const string Symbl,const long Mgc,datetime time_start,datetime time_end);
double MaxLots() {return(m_max_lot);}
// double InitialDeposit() {return(m_initial_deposit);}
// double Withdrawal() {return(m_withdrawal);}
double Profit() {return(m_profit);};
double GrossProfit() {return(m_gross_profit);}
double GrossLoss() {return(m_gross_loss);}
double MDD() {return(m_maxdraw_MDD);}
double ProfitFactor() {return(m_profit_factor);}
int Trades() {return(m_trades);}
int ProfitTrades() {return(m_profit_trades);};
double ExpectedPayoff() {return(m_expected_payoff);}
string OpenTime() {return(m_openTime_str);}
string CloseTime() {return(m_closeTime_str);}
double Percent(double value,double divider);
bool AppendDataToCSV(datetime open_time, string symbol, ulong magic, string posType, double volume, double openPric, double Sl, double Tp, double closePrice, datetime close_time, double Commis, double Swp, double profit);
bool CheckIsFileBot() {return(FileIsExist(m_mqlName + " EA" + "\\" + AccountInfoString(ACCOUNT_COMPANY) +"\\"+ IntegerToString(GenerateMagicNumbers())+"\\AnalysisOutput\\"+"Transaction11209.csv"));}
string AnalyzePathFile() {return(m_mqlName + " EA" + "\\" + AccountInfoString(ACCOUNT_COMPANY) +"\\"+ IntegerToString(GenerateMagicNumbers())+"\\AnalysisOutput\\"+"Transaction11209.csv");}
protected:
bool HistorySelectByPositionProcess(const long position_id);
};
//m_withdrawal(0.0), m_max_lot(0.0), m_symbol(NULL), m_type(-1), m_magic(-1), m_volume(0.0),
// m_openTime_str("-"), m_closeTime_str("-"), m_profit(0.0), m_gross_loss(0.0), m_gross_profit(0.0)
CHistory::CHistory(void) : m_max_lot(0.0), m_openTime_str("-"), m_closeTime_str("-"), m_balance(0.0), m_max_peak(0.0), m_min_peak(0.0), m_trades(0),
m_expected_payoff(0.0)
{
m_mqlName = MQLInfoString(MQL_PROGRAM_NAME);
// datetime timestart = D'2024.12.24';
// if(!CheckIsFileBot())
// {
// Calculate(Symbol(), GenerateMagicNumbers(), timestart, TimeCurrent());
// AppendDataToCSV(OpenTime(), Symbol(), GenerateMagicNumbers(), )
// }
}
CHistory::~CHistory(void)
{
}
bool CHistory::Calculate(const string Symbl, const long Mgc,datetime time_start,datetime time_end)
{
deal_result result = NO_VALUE;
int sort_by = HISTORY_SORT_OPENTIME;
datetime first_entry_time = 0;
datetime overall_first_entry_time = 0;
m_profit=0;
m_gross_profit=0;
m_gross_loss=0;
if(!HistorySelect(time_start,time_end))
{
ResetLastError();
string txt = " ⚠ "+ TRANSLATION_HISTORY_GET_TRADE + TRANSLATION_MESSAGE_ERROR + IntegerToString(GetLastError());
m_FileSave.IniFileSave(__FUNCTION__+"::"+txt,false);
m_FileSave.IniFileSaveRun(txt,false);
return(false);
}
int deals_total = HistoryDealsTotal();
if(sort_by==HISTORY_SORT_OPENTIME)
{
for(int i = 0; i < deals_total && !IsStopped(); i++)
if(m_deal.SelectByIndex(i))
if(m_deal.Entry()==DEAL_ENTRY_IN)
if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
{
if(m_deal.Symbol() != Symbl)
continue;
if(m_deal.Magic() != Mgc)
continue;
//--- save position ids to the array
long position_id=m_deal.PositionId();
int arr_size=ArraySize(arr_Positions);
if(ArrayResize(arr_Positions,arr_size+1)==arr_size+1)
arr_Positions[arr_size]=position_id;
m_trades++;
if (first_entry_time == 0 || m_deal.Time() < first_entry_time) {first_entry_time = m_deal.Time();}
}
}
if(sort_by==HISTORY_SORT_CLOSETIME)
{
//--- define a hashset to collect position IDs (with no duplicates)
CHashSet<long>hashset;
//--- handle the case when a position has multiple deals out.
for(int i = deals_total-1; i >= 0 && !IsStopped(); i--)
if(m_deal.SelectByIndex(i))
if(m_deal.Entry()==DEAL_ENTRY_OUT || m_deal.Entry()==DEAL_ENTRY_OUT_BY)
if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
{
if(m_deal.Symbol() != Symbl)
continue;
if(m_deal.Magic() != Mgc)
continue;
hashset.Add(m_deal.PositionId());
}
//--- copy the elements from the set to a compatible one-dimensional array
hashset.CopyTo(arr_Positions,0);
//ArrayReverse(arr_Positions);
ArraySetAsSeries(arr_Positions,true);
}
deals_total = ArraySize(arr_Positions);
for(int i=0; i<deals_total; i++)
{
long position_id = arr_Positions[i];
HistorySelectByPositionProcess(position_id);
}
if (first_entry_time > 0)
{
if (overall_first_entry_time == 0 || first_entry_time < overall_first_entry_time)
{
overall_first_entry_time = first_entry_time;
m_openTime_dt = overall_first_entry_time;
m_openTime_str = TimeToString(overall_first_entry_time, TIME_DATE);
}
}
return true;
}
//+------------------------------------------------------------------+
//| Select history of orders and deals by position ID and |
//| prints a list of orders and deals for the position in the journal|
//+------------------------------------------------------------------+
bool CHistory::HistorySelectByPositionProcess(const long position_id)
{
double profit=0, profit_close=0;
m_profit_factor = 0;
datetime last_exit_time = 0;
datetime overall_last_exit_time = 0;
if(!HistorySelectByPosition(position_id))
{
ResetLastError();
string txt = " ⚠ "+ TRANSLATION_HISTORY_SELECTPOSITION_ERR + "(#"+IntegerToString(position_id,0)+") " + TRANSLATION_HISTORY_SELECTPOSITION_FAILED + TRANSLATION_MESSAGE_ERROR + IntegerToString(GetLastError());
m_FileSave.IniFileSave(__FUNCTION__+"::"+txt,false);
m_FileSave.IniFileSaveRun(txt,false);
return(false);
}
int orders_total=HistoryOrdersTotal();
for(int i=0; i<orders_total; i++)
{
ulong ticket = HistoryOrderGetTicket(i);
string ordersymbol = HistoryOrderGetString(ticket, ORDER_SYMBOL);
long ordermagic = HistoryOrderGetInteger(ticket, ORDER_MAGIC);
if(ticket==0)
continue;
}
int deals_total =HistoryDealsTotal();
for(int i=0; i<deals_total; i++)
{
ulong ticket=HistoryDealGetTicket(i);
double dealprofit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
string dealsymbl = HistoryDealGetString(ticket, DEAL_SYMBOL);
ulong dealmagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
double dealswap = HistoryDealGetDouble(ticket, DEAL_SWAP);
double dealcomision = HistoryDealGetDouble(ticket, DEAL_COMMISSION);
double dealvolume = HistoryDealGetDouble(ticket, DEAL_VOLUME);
datetime dealtimeClose = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);
if(ticket==0)
continue;
ENUM_DEAL_ENTRY deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket, DEAL_ENTRY);
ENUM_DEAL_TYPE deal_type= (ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket, DEAL_TYPE);
if(deal_type == DEAL_TYPE_BUY || deal_type == DEAL_TYPE_SELL)
{
profit = NormalizeDouble(dealprofit + dealswap + dealcomision, 2);
if(profit >= 0.0) {m_gross_profit += profit;}
else {m_gross_loss += profit;}
// Print(dealprofit," |in| ",dealswap," |in| ",dealcomision);
if(dealvolume > m_max_lot) {m_max_lot = dealvolume;}
if (last_exit_time < dealtimeClose) {last_exit_time = dealtimeClose;}
}
if(deal_entry == DEAL_ENTRY_OUT || deal_entry == DEAL_ENTRY_OUT_BY || deal_entry == DEAL_ENTRY_IN || deal_entry == DEAL_ENTRY_INOUT)
{
profit_close = NormalizeDouble(dealprofit + dealswap + dealcomision,2);
m_balance += profit_close;
// m_trades++;
// Print(dealprofit," |out| ",dealswap," |out| ",dealcomision);
if(profit >= 0.0)
{
m_profit_trades++;
}
}
}
if (last_exit_time > 0)
{
if (overall_last_exit_time == 0 || last_exit_time > overall_last_exit_time)
{
overall_last_exit_time = last_exit_time;
m_closeTime_dt = overall_last_exit_time;
m_closeTime_str = TimeToString(overall_last_exit_time, TIME_DATE);
}
}
if (m_balance > max_balance)
{
max_balance = m_balance;
}
drawdown = NormalizeDouble(max_balance - m_balance, 2);
if(drawdown > m_maxdraw_MDD) {m_maxdraw_MDD = drawdown;}
// Print("balance ",m_balance," | ",max_balance," | ",drawdown," | ",m_maxdraw_MDD);
m_profit = m_gross_profit+m_gross_loss;
if(MathAbs(m_gross_loss) > FLT_EPSILON) {m_profit_factor = MathAbs(m_gross_profit/m_gross_loss);}
if(m_trades > 0)
{
m_expected_payoff=m_profit/m_trades;
m_profit_trades_percent = (double)m_profit_trades / m_trades * 100;
}
return true;
}
double CHistory::Percent(double value,double divider)
{
if(MathAbs(value)<=FLT_EPSILON)
return(0);
return(100*value/divider);
}
bool CHistory::AppendDataToCSV(datetime open_time, string symbol, ulong magic, string posType, double volume, double openPric, double Sl, double Tp, double closePrice, datetime close_time, double Commis, double Swp, double profit)
{
int fh;
// Save to new format only.
fh = FileOpen(AnalyzePathFile(), FILE_WRITE|FILE_CSV|FILE_ANSI,',');
if (fh == INVALID_HANDLE)
{
ResetLastError();
string txt = TRANSLATION_FILED_TO_OPEN_FILE_WRITING + AnalyzePathFile() + TRANSLATION_MESSAGE_ERROR + IntegerToString(GetLastError());
m_FileSave.IniFileSaveRun(txt,false);
m_FileSave.IniFileSave(__FUNCTION__+":: "+ txt, false);
return false;
}
FileWrite(fh, "Open Time", "Symbol", "Magic Number", "Type", "Volume", "Open Price", "S/L", "T/P", "Close Price", "Close Time", "Commission", "Swap", "Profit");
FileWrite(fh, open_time, symbol, magic, posType, volume, openPric, Sl, Tp, closePrice, close_time, Commis, Swp, profit);
FileClose(fh);
return true;
}
//--- global variable
double max_balance = -DBL_MAX;
double drawdown = 0.0;
/*
bool CHistory::Calculate(const string Symbl, const long Mgc,datetime time_start,datetime time_end,double initial_deposit=0.0)
{
if(!HistorySelect(time_start,time_end))
{
ResetLastError();
string txt = " ⚠ "+ TRANSLATION_HISTORY_GET_TRADE + TRANSLATION_MESSAGE_ERROR + IntegerToString(GetLastError());
m_FileSave.IniFileSave(__FUNCTION__+"::"+txt,false);
m_FileSave.IniFileSaveRun(txt,false);
return(false);
}
for(int i = HistoryDealsTotal()-1; i >=0; i--)
{
// deals
ulong dealticket = HistoryDealGetTicket(i);
if (dealticket <= 0) {
ResetLastError();
string txt = " ⚠ "+ TRANSLATION_DEAL_ERROR_TICKT + TRANSLATION_MESSAGE_ERROR + IntegerToString(GetLastError());
m_FileSave.IniFileSave(__FUNCTION__+"::"+txt,false);
m_FileSave.IniFileSaveRun(txt,false);
return(false);
}
datetime first_entry_time = 0;
datetime last_exit_time = 0;
datetime overall_first_entry_time = 0;
datetime overall_last_exit_time = 0;
long dealID = 0;
double dealprice = HistoryDealGetDouble(dealticket,DEAL_PRICE);
double dealvolume = HistoryDealGetDouble(dealticket,DEAL_VOLUME);
double dealprofit = HistoryDealGetDouble(dealticket,DEAL_PROFIT);
double dealcommision = HistoryDealGetDouble(dealticket,DEAL_COMMISSION);
double dealswap = HistoryDealGetDouble(dealticket,DEAL_SWAP);
ulong dealmagic = HistoryDealGetInteger(dealticket,DEAL_MAGIC);
string dealcomment = HistoryDealGetString(dealticket,DEAL_COMMENT);
datetime dealtimed = (datetime)HistoryDealGetInteger(dealticket, DEAL_TIME);
string dealDate = TimeToString(dealtimed, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
string dealsymbol = HistoryDealGetString(dealticket,DEAL_SYMBOL);
ENUM_DEAL_ENTRY dealentry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(dealticket,DEAL_ENTRY);
ENUM_DEAL_TYPE dealtype = (ENUM_DEAL_TYPE)HistoryDealGetInteger(dealticket,DEAL_TYPE);
long dealreason = HistoryDealGetInteger(dealticket,DEAL_REASON);
long posID = 0;
// orders
ulong orderticket = HistoryDealGetInteger(dealticket,DEAL_ORDER);
long orderID = HistoryOrderGetInteger(orderticket, ORDER_POSITION_ID);
double orderprice = HistoryOrderGetDouble(orderticket,ORDER_PRICE_OPEN);
double ordervolume = HistoryOrderGetDouble(dealticket,ORDER_VOLUME_INITIAL);
datetime ordertimed = (datetime)HistoryOrderGetInteger(orderticket,ORDER_TIME_DONE);
string orderDate = TimeToString(ordertimed, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
string ordersymbol = HistoryOrderGetString(orderticket,ORDER_SYMBOL);
ENUM_ORDER_TYPE ordertype = (ENUM_ORDER_TYPE)HistoryOrderGetInteger(orderticket,ORDER_TYPE);
if((dealsymbol == Symbl) && (dealmagic == Mgc))
{
if(dealentry == DEAL_ENTRY_IN)
{
if(dealvolume > m_max_lot) {m_max_lot = dealvolume;}
if (first_entry_time == 0 || dealtimed < first_entry_time) {first_entry_time = dealtimed;}
dealID = HistoryDealGetInteger(dealticket,DEAL_POSITION_ID);
posID = dealID;
// Print(dealsymbol," in| ",dealcommision," | ",dealprofit," | ",dealmagic," | ",dealticket," | ",dealvolume," |id| ",dealID);
// Print(ordersymbol," in| ",0," | ",0," | ",0," | ",orderticket," | ",ordervolume," |id| ",orderID);
}
// else if (dealentry == DEAL_ENTRY_OUT)
// {
// if(orderticket == dealID)
// {
// Print("tick ",dealticket, " | ",orderticket);
// }
// // Print(dealsymbol," | ",dealcommision," | ",dealprofit," | ",dealmagic," | ",dealticket," | ",dealvolume);
// // Print(ordersymbol," | ",0," | ",0," | ",0," | ",orderticket," | ",ordervolume);
// }
// Print(dealsymbol," in| ",dealcommision," | ",dealprofit," | ",dealmagic," | ",dealticket," | ",dealvolume," |id| ",dealID);
// Print(ordersymbol," in| ",0," | ",0," | ",0," | ",orderticket," | ",ordervolume," |id| ",orderID);
}
if(dealticket == posID)
{
Print(dealticket," | ",orderticket);
// Print(dealsymbol," in| ",dealcommision," | ",dealprofit," | ",dealmagic," | ",dealticket," | ",dealvolume," |id| ",dealID);
// Print(ordersymbol," in| ",0," | ",0," | ",0," | ",orderticket," | ",ordervolume," |id| ",orderID);
}
// if(dealID == posID)
// {
// Print(dealsymbol," in| ",dealcommision," | ",dealprofit," | ",dealmagic," | ",dealticket," | ",dealvolume," |id| ",dealID);
// Print(ordersymbol," in| ",0," | ",0," | ",0," | ",orderticket," | ",ordervolume," |id| ",orderID);
// }
if (first_entry_time > 0)
{
if (overall_first_entry_time == 0 || first_entry_time < overall_first_entry_time)
{
overall_first_entry_time = first_entry_time;
m_openTime_str = TimeToString(overall_first_entry_time, TIME_DATE);
}
}
}
// Print("maxlot ",m_max_lot," open time ",m_openTime_str," close time ",m_closeTime_str);
return true;
}