MQLArticles/RM/AccountStatus.mqh

738 lines
55 KiB
MQL5

2025-09-22 09:09:20 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| AccountStatus.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
2025-11-10 09:33:30 -05:00
#property copyright "Copyright 2025, Niquel Mendoza."
2025-09-22 09:09:20 -05:00
2025-11-23 19:15:34 -05:00
#property link "https://www.mql5.com"
#property strict
2025-09-22 09:09:20 -05:00
#ifndef MQLARTICLES_RM_ACCOUNTSTATUS_MQH
2025-11-23 19:15:34 -05:00
#define MQLARTICLES_RM_ACCOUNTSTATUS_MQH
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| |
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
#include "RM_Functions.mqh"
2025-09-24 14:00:58 -05:00
#include <Math/Stat/Stat.mqh>
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-23 08:04:37 -05:00
//| |
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP 1
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_SL 2
2025-09-22 09:09:20 -05:00
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP_SL (ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP|ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_SL)
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//| Global Variables |
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
double account_status_curr_profit; // Profit en flotante - profit in float
bool account_status_positions_open; // Flag indicating if there are open positions in the account
//+------------------------------------------------------------------+
//| Class for account management |
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
class CAccountStatus : public CManagerBase<CAccountGestor>
{
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
private:
//---
2025-11-23 08:04:37 -05:00
CTicketsInfo* open_positions; // CTicketsInfo type object for efficient ticket management
2025-09-22 09:09:20 -05:00
bool init; // Flag indicating if it has been initialized correctly
//---
2025-11-26 07:03:20 -05:00
double account_daily_profit; // Account profit (adding EAs and user etc, total) daily
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
double account_weekly_profit; // Account profit (adding EAs and user etc, total) weekly
double account_monthly_profit; // Account profit (adding EAs and user etc, total) monthly
double account_gross_profit; // Account profit (adding EAs and user etc, total) total
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-11-23 08:04:37 -05:00
datetime last_day_time; // Opening time of the current daily candle
datetime last_weekly_time; // Opening time of the current weekly candle
2025-09-22 09:09:20 -05:00
datetime last_monthly_time; // Opening time of the current monthly candle
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//---
ROrder last_order_struct;
2025-11-23 08:04:37 -05:00
//--- Most recent structure of the opened or closed position
ROnOpenClosePosition last_struct;
// Variables that store a property of the last deal (when adding a deal, TRADE_TRANSACTION_DEAL_ADD)
ulong last_deal_ticket; // Ticket
ENUM_DEAL_TYPE last_deal_type; // Deal type
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
// Variable that stores the last symbol for specific events (TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_ORDER_DELETE)
2025-09-22 09:09:20 -05:00
string last_trans_symbol; // Symbol
//--- Function to update profits
void UpdateProfitInit();
void UpdateProfit(const double& new_profit);
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
public:
CAccountStatus();
~CAccountStatus();
2025-09-24 14:00:58 -05:00
//--- Getter
2025-09-22 09:09:20 -05:00
__forceinline Position GetPosition(ulong ticket) { return open_positions.GetByTicket(ticket); } // Get Position by ticket
__forceinline int16_t GetPositionsTotal() const { return open_positions.Total(); } // Get total number of open positions
__forceinline bool TheTicketExists(const ulong ticket) const { return open_positions.Exists(ticket); } // Check if ticket exists in positions array
inline double AccountGrossProfit() const { return account_gross_profit; }
inline double AccountDailyProfit() const { return account_daily_profit; }
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
inline double AccountWeeklyProfit() const { return account_weekly_profit; }
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
inline double AccountMonthlyProfit() const { return account_monthly_profit; }
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
inline bool IsInitialized() const { return init; }
inline string LastTransctionSymbol() const { return last_trans_symbol; }
__forceinline ROnOpenClosePosition LastStructPosition() const { return last_struct; }
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
__forceinline Position LastPosition() const { return last_struct.position; }
2025-09-22 09:09:20 -05:00
//--- Events
void OnTradeTransactionEvent(const MqlTradeTransaction& trans); // Should be executed in OnTradeTransaction
void OnInitEvent(); // Should be executed in OnInit, at the end
inline void OnNewDay(); // The function should be called every new day
inline void OnNewWeek(); // The function should be called every new week
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
inline void OnNewMonth(); // The function should be called every new month
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//--- Ticket logs
inline void AddLogFlagTicket(uint8_t flags) { open_positions.AddLogFlags(flags); }
2025-09-22 09:09:20 -05:00
inline void RemoveLogFlagTicket(uint8_t flags) { open_positions.RemoveLogFlags(flags); }
2025-11-28 20:21:30 -05:00
//--- Info functions
void PrintLastOrder();
2025-09-22 09:09:20 -05:00
void PrintLastPosition();
};
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-28 20:21:30 -05:00
//| Constructor |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
CAccountStatus::CAccountStatus(void)
: CManagerBase<CAccountGestor>(true), account_daily_profit(0.00), account_weekly_profit(0.00), account_gross_profit(0.00), account_monthly_profit(0.00), init(false)
{
account_status_curr_profit = 0.00;
account_status_positions_open = false;
2025-11-26 07:03:20 -05:00
open_positions = NULL;
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
open_positions = new CTicketsInfo();
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
//| Destructor |
//+------------------------------------------------------------------+
CAccountStatus::~CAccountStatus()
{
2025-09-22 09:09:20 -05:00
if(open_positions != NULL)
2025-11-26 07:03:20 -05:00
delete open_positions;
}
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
//| Function that executes every new day |
//+------------------------------------------------------------------+
inline void CAccountStatus::OnNewDay(void)
{
this.last_day_time = iTime(_Symbol, PERIOD_D1, 0);
this.account_daily_profit = 0.0;
for(int i = 0; i < total; i++)
2025-09-22 09:09:20 -05:00
items[i].OnNewDay(this.last_day_time);
}
//+------------------------------------------------------------------+
//| Function that executes every new month |
//+------------------------------------------------------------------+
2025-11-28 20:21:30 -05:00
inline void CAccountStatus::OnNewMonth(void)
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
{
this.last_monthly_time = iTime(_Symbol, PERIOD_MN1, 0);
2025-11-23 08:04:37 -05:00
this.account_monthly_profit = 0.0;
for(int i = 0; i < total; i++)
items[i].OnNewMonth(this.last_monthly_time);
}
//+------------------------------------------------------------------+
//| Function that executes weekly |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
inline void CAccountStatus::OnNewWeek(void)
2025-11-23 08:04:37 -05:00
{
2025-09-22 09:09:20 -05:00
this.last_weekly_time = iTime(_Symbol, PERIOD_W1, 0);
2025-11-23 08:04:37 -05:00
this.account_weekly_profit = 0.0;
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
for(int i = 0; i < total; i++)
items[i].OnNewWeek(this.last_weekly_time);
}
2025-09-22 09:09:20 -05:00
2025-11-23 19:15:34 -05:00
//+------------------------------------------------------------------+
//| Function that executes in OnInit |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-23 19:15:34 -05:00
void CAccountStatus::OnInitEvent(void)
{
//--- Initialize the profit collection variables
this.last_day_time = iTime(_Symbol, PERIOD_D1, 0);
this.last_weekly_time = iTime(_Symbol, PERIOD_W1, 0);
2025-09-22 09:09:20 -05:00
this.last_monthly_time = iTime(_Symbol, PERIOD_MN1, 0);
2025-11-23 19:15:34 -05:00
this.init = true;
//--- Initialize the managers with the new profit
UpdateProfitInit();
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//---
ROnOpenClosePosition profit;
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
profit.account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
profit.account_profit_diario = this.account_daily_profit;
2025-09-22 09:09:20 -05:00
profit.account_profit_mensual = this.account_monthly_profit;
2025-11-23 08:04:37 -05:00
profit.account_profit_semanal = this.account_weekly_profit;
profit.account_profit_total = this.account_gross_profit;
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
2025-11-23 19:15:34 -05:00
for(int i = 0; i < total; i++)
items[i].OnNewProfit(profit);
2025-09-22 09:09:20 -05:00
2025-11-23 19:15:34 -05:00
//--- Check if there are open trades
const int pos_total = PositionsTotal();
//--- If there are open positions we add them
if(pos_total > 0)
2025-09-22 09:09:20 -05:00
2025-11-23 19:15:34 -05:00
{
for(int i = pos_total - 1; i >= 0; i--)
{
const ulong position_ticket = PositionGetTicket(i);
2025-09-22 09:09:20 -05:00
if(!PositionSelectByTicket(position_ticket))
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
continue;
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-11-23 08:04:37 -05:00
last_trans_symbol = PositionGetString(POSITION_SYMBOL);
//---
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
Position new_pos;
new_pos.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
2025-11-23 19:15:34 -05:00
new_pos.ticket = position_ticket;
new_pos.profit = GetTotalPositionProfitNoCurrent(position_ticket);
new_pos.magic = (ulong)PositionGetInteger(POSITION_MAGIC);
new_pos.tp = PositionGetDouble(POSITION_TP);
new_pos.sl = PositionGetDouble(POSITION_SL);
new_pos.open_time = (datetime)PositionGetInteger(POSITION_TIME);
new_pos.open_price = PositionGetDouble(POSITION_PRICE_OPEN);
new_pos.volume = PositionGetDouble(POSITION_VOLUME);
open_positions.Add(new_pos);
//---
profit.position = new_pos;
for(int k = 0; k < total; k++)
items[k].OnInitNewPos(profit);
}
}
2025-11-23 08:04:37 -05:00
}
//+------------------------------------------------------------------+
//| Function to update profits |
//+------------------------------------------------------------------+
void CAccountStatus::UpdateProfit(const double &new_profit)
{
//---
if(!init)
2025-11-26 07:03:20 -05:00
{
2025-11-23 08:04:37 -05:00
LogFatalError("CAccountStatus.OnInit must be called before executing any CAccountStatus function", FUNCION_ACTUAL);
Remover();
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
return;
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
}
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-11-23 08:04:37 -05:00
this.account_gross_profit += new_profit;
2025-09-22 09:09:20 -05:00
this.account_daily_profit += new_profit;
2025-11-23 08:04:37 -05:00
2025-11-26 07:03:20 -05:00
this.account_weekly_profit += new_profit;
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
this.account_monthly_profit += new_profit;
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//---
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
if(IsInfoLogEnabled())
{
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
2025-11-26 07:03:20 -05:00
Print("Daily profit: ", this.account_daily_profit);
2025-11-23 08:04:37 -05:00
Print("Weekly profit: ", this.account_weekly_profit);
2025-11-26 07:03:20 -05:00
Print("Monthly profit: ", this.account_monthly_profit);
2025-11-23 11:01:56 -05:00
Print("Gross profit: ", this.account_gross_profit);
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
}
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
//---
2025-09-22 09:09:20 -05:00
for(int i = 0; i < total; i++)
2025-09-24 14:00:58 -05:00
2025-11-23 08:04:37 -05:00
items[i].OnLossProfit(new_profit);
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
}
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
void CAccountStatus::UpdateProfitInit()
2025-11-23 08:04:37 -05:00
{
//---
2025-09-22 09:09:20 -05:00
this.account_gross_profit = GetNetProfitSince(true, 0, D'1972.01.01 00:00');
2025-11-23 08:04:37 -05:00
this.account_daily_profit = GetNetProfitSince(true, 0, this.last_day_time);
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
this.account_weekly_profit = GetNetProfitSince(true, 0, this.last_weekly_time);
2025-09-22 09:09:20 -05:00
this.account_monthly_profit = GetNetProfitSince(true, 0, this.last_monthly_time);
2025-11-23 08:04:37 -05:00
//---
if(IsInfoLogEnabled())
{
2025-11-26 07:03:20 -05:00
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
Print("Daily profit: ", this.account_daily_profit);
Print("Weekly profit: ", this.account_weekly_profit);
2025-11-28 20:21:30 -05:00
Print("Monthly profit: ", this.account_monthly_profit);
2025-11-26 07:03:20 -05:00
Print("Gross profit: ", this.account_gross_profit);
2025-11-23 08:04:37 -05:00
}
2025-11-26 07:03:20 -05:00
}
2025-11-23 08:04:37 -05:00
//+------------------------------------------------------------------+
//| Function to execute in OnTick |
//+------------------------------------------------------------------+
#define CAccountStatus_OnTickEvent account_status_curr_profit = AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE);
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
//| OnTradeTransaction event |
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
2025-11-23 08:04:37 -05:00
//--- Activa el evento de OnOrderAdd
//#define CACCOUNT_STATUS_ACTIVE_ON_ORDER_ADD
//--- Activa el evento de OnOrderUpdate
//#define CACCOUNT_STATUS_ACTIVE_ON_ORDER_UPDATE
//--- Activa el evento de OnOrderDelete
//#define CACCOUNT_STATUS_ACTIVE_ON_ORDER_DELETE
//--- Activa el evento de OnPositionModifed
2025-11-26 07:03:20 -05:00
//#define CACCOUNT_STATUS_ACTIVE_ON_POSITION_MODIFIED
2025-11-23 08:04:37 -05:00
2025-11-26 07:03:20 -05:00
//--- En los evenots de ordenes, su definicion activa que tamiben cuenten las ordenes de compra y venta
//#define CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
2025-11-23 08:04:37 -05:00
2025-11-26 07:03:20 -05:00
//---
void CAccountStatus::OnTradeTransactionEvent(const MqlTradeTransaction &trans)
{
//---
switch(trans.type)
{
2025-11-23 08:04:37 -05:00
//---
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
case TRADE_TRANSACTION_ORDER_ADD: // 0
{
2025-11-23 08:04:37 -05:00
#ifdef CACCOUNT_STATUS_ACTIVE_ON_ORDER_ADD
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
#ifndef CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
if(!EsUnaOrderPendiente[trans.order_type])
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
return;
#endif // CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
2025-11-26 07:03:20 -05:00
2025-11-23 08:04:37 -05:00
//---
2025-11-26 07:03:20 -05:00
if(OrderSelect(trans.order))
2025-11-23 08:04:37 -05:00
{
//---
last_trans_symbol = trans.symbol;
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//---
last_order_struct.order_open_price = trans.price;
last_order_struct.order_stop_loss = trans.price_sl;
last_order_struct.order_take_profit = trans.price_tp;
last_order_struct.order_magic = OrderGetInteger(ORDER_MAGIC);
last_order_struct.order_ticket = trans.order;
2025-09-22 09:09:20 -05:00
last_order_struct.order_time_expiration = trans.time_expiration;
2025-11-23 08:04:37 -05:00
2025-11-28 20:21:30 -05:00
last_order_struct.order_reason = (ENUM_ORDER_REASON)OrderGetInteger(ORDER_REASON);
last_order_struct.order_type = trans.order_type;
2025-11-23 19:15:34 -05:00
2025-09-22 09:09:20 -05:00
last_order_struct.order_state = trans.order_state;
2025-11-23 08:04:37 -05:00
last_order_struct.order_type_time = trans.time_type;
//---
2025-11-23 19:15:34 -05:00
2025-11-23 08:04:37 -05:00
for(int i = 0; i < total; i++)
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
items[i].OnOrderAdd(last_order_struct);
}
else
2025-11-23 19:15:34 -05:00
{
2025-11-23 08:04:37 -05:00
LogError(StringFormat("Error al seleccionar la orden %I64u", trans.order), FUNCION_ACTUAL);
2025-11-23 19:15:34 -05:00
}
2025-11-23 08:04:37 -05:00
2025-11-23 19:15:34 -05:00
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
#endif // CACCOUNT_STATUS_ACTIVE_ON_ORDER_ADD
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//---
2025-09-22 09:09:20 -05:00
break;
2025-11-23 08:04:37 -05:00
}
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
//---
case TRADE_TRANSACTION_ORDER_UPDATE: // 1
2025-09-22 09:09:20 -05:00
2025-11-23 08:04:37 -05:00
{
#ifdef CACCOUNT_STATUS_ACTIVE_ON_ORDER_UPDATE
#ifndef CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
if(!EsUnaOrderPendiente[trans.order_type])
return;
#endif // CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
//---
if(OrderSelect(trans.order))
{
//---
last_trans_symbol = trans.symbol;
//---
last_order_struct.order_open_price = trans.price;
2025-09-22 09:09:20 -05:00
last_order_struct.order_stop_loss = trans.price_sl;
2025-11-26 07:03:20 -05:00
last_order_struct.order_take_profit = trans.price_tp;
2025-09-22 09:09:20 -05:00
last_order_struct.order_magic = OrderGetInteger(ORDER_MAGIC);
2025-09-22 12:18:57 -05:00
2025-09-22 09:09:20 -05:00
last_order_struct.order_ticket = trans.order;
last_order_struct.order_time_expiration = trans.time_expiration;
2025-11-23 08:04:37 -05:00
2025-09-22 09:09:20 -05:00
last_order_struct.order_reason = (ENUM_ORDER_REASON)OrderGetInteger(ORDER_REASON);
2025-11-26 07:03:20 -05:00
last_order_struct.order_type = trans.order_type;
2025-09-22 09:09:20 -05:00