737 lines
55 KiB
MQL5
737 lines
55 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| AccountStatus.mqh |
|
|
//| Copyright 2025, Niquel Mendoza. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
|
#property link "https://www.mql5.com"
|
|
#property strict
|
|
|
|
#ifndef MQLARTICLES_RM_ACCOUNTSTATUS_MQH
|
|
#define MQLARTICLES_RM_ACCOUNTSTATUS_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "RM_Functions.mqh"
|
|
#include <Math/Stat/Stat.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP 1
|
|
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_SL 2
|
|
#define ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP_SL (ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP|ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_SL)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Global Variables |
|
|
//+------------------------------------------------------------------+
|
|
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 |
|
|
//+------------------------------------------------------------------+
|
|
class CAccountStatus : public CManagerBase<CAccountGestor>
|
|
{
|
|
private:
|
|
//---
|
|
CTicketsInfo* open_positions; // CTicketsInfo type object for efficient ticket management
|
|
bool init; // Flag indicating if it has been initialized correctly
|
|
|
|
//---
|
|
double account_daily_profit; // Account profit (adding EAs and user etc, total) daily
|
|
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
|
|
|
|
//---
|
|
datetime last_day_time; // Opening time of the current daily candle
|
|
datetime last_weekly_time; // Opening time of the current weekly candle
|
|
datetime last_monthly_time; // Opening time of the current monthly candle
|
|
|
|
//---
|
|
ROrder last_order_struct;
|
|
|
|
//--- 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
|
|
|
|
// Variable that stores the last symbol for specific events (TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_ORDER_DELETE)
|
|
string last_trans_symbol; // Symbol
|
|
|
|
//--- Function to update profits
|
|
void UpdateProfitInit();
|
|
void UpdateProfit(const double& new_profit);
|
|
|
|
public:
|
|
CAccountStatus();
|
|
~CAccountStatus();
|
|
|
|
//--- Getter
|
|
__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; }
|
|
inline double AccountWeeklyProfit() const { return account_weekly_profit; }
|
|
inline double AccountMonthlyProfit() const { return account_monthly_profit; }
|
|
inline bool IsInitialized() const { return init; }
|
|
inline string LastTransctionSymbol() const { return last_trans_symbol; }
|
|
__forceinline ROnOpenClosePosition LastStructPosition() const { return last_struct; }
|
|
__forceinline Position LastPosition() const { return last_struct.position; }
|
|
|
|
//--- 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
|
|
inline void OnNewMonth(); // The function should be called every new month
|
|
|
|
//--- Ticket logs
|
|
inline void AddLogFlagTicket(uint8_t flags) { open_positions.AddLogFlags(flags); }
|
|
inline void RemoveLogFlagTicket(uint8_t flags) { open_positions.RemoveLogFlags(flags); }
|
|
|
|
//--- Info functions
|
|
void PrintLastOrder();
|
|
void PrintLastPosition();
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
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;
|
|
open_positions = NULL;
|
|
open_positions = new CTicketsInfo();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CAccountStatus::~CAccountStatus()
|
|
{
|
|
if(open_positions != NULL)
|
|
delete open_positions;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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++)
|
|
items[i].OnNewDay(this.last_day_time);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function that executes every new month |
|
|
//+------------------------------------------------------------------+
|
|
inline void CAccountStatus::OnNewMonth(void)
|
|
{
|
|
this.last_monthly_time = iTime(_Symbol, PERIOD_MN1, 0);
|
|
this.account_monthly_profit = 0.0;
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnNewMonth(this.last_monthly_time);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function that executes weekly |
|
|
//+------------------------------------------------------------------+
|
|
inline void CAccountStatus::OnNewWeek(void)
|
|
{
|
|
this.last_weekly_time = iTime(_Symbol, PERIOD_W1, 0);
|
|
this.account_weekly_profit = 0.0;
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnNewWeek(this.last_weekly_time);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function that executes in OnInit |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
this.last_monthly_time = iTime(_Symbol, PERIOD_MN1, 0);
|
|
this.init = true;
|
|
|
|
//--- Initialize the managers with the new profit
|
|
UpdateProfitInit();
|
|
|
|
//---
|
|
ROnOpenClosePosition profit;
|
|
profit.account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
profit.account_profit_diario = this.account_daily_profit;
|
|
profit.account_profit_mensual = this.account_monthly_profit;
|
|
profit.account_profit_semanal = this.account_weekly_profit;
|
|
profit.account_profit_total = this.account_gross_profit;
|
|
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnNewProfit(profit);
|
|
|
|
//--- Check if there are open trades
|
|
const int pos_total = PositionsTotal();
|
|
|
|
//--- If there are open positions we add them
|
|
if(pos_total > 0)
|
|
{
|
|
for(int i = pos_total - 1; i >= 0; i--)
|
|
{
|
|
const ulong position_ticket = PositionGetTicket(i);
|
|
if(!PositionSelectByTicket(position_ticket))
|
|
continue;
|
|
|
|
//---
|
|
last_trans_symbol = PositionGetString(POSITION_SYMBOL);
|
|
|
|
//---
|
|
Position new_pos;
|
|
new_pos.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function to update profits |
|
|
//+------------------------------------------------------------------+
|
|
void CAccountStatus::UpdateProfit(const double &new_profit)
|
|
{
|
|
//---
|
|
if(!init)
|
|
{
|
|
LogFatalError("CAccountStatus.OnInit must be called before executing any CAccountStatus function", FUNCION_ACTUAL);
|
|
Remover();
|
|
return;
|
|
}
|
|
|
|
//---
|
|
this.account_gross_profit += new_profit;
|
|
this.account_daily_profit += new_profit;
|
|
this.account_weekly_profit += new_profit;
|
|
this.account_monthly_profit += new_profit;
|
|
|
|
//---
|
|
if(IsInfoLogEnabled())
|
|
{
|
|
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
|
|
Print("Daily profit: ", this.account_daily_profit);
|
|
Print("Weekly profit: ", this.account_weekly_profit);
|
|
Print("Monthly profit: ", this.account_monthly_profit);
|
|
Print("Gross profit: ", this.account_gross_profit);
|
|
}
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnLossProfit(new_profit);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CAccountStatus::UpdateProfitInit()
|
|
{
|
|
//---
|
|
this.account_gross_profit = GetNetProfitSince(true, 0, D'1972.01.01 00:00');
|
|
this.account_daily_profit = GetNetProfitSince(true, 0, this.last_day_time);
|
|
this.account_weekly_profit = GetNetProfitSince(true, 0, this.last_weekly_time);
|
|
this.account_monthly_profit = GetNetProfitSince(true, 0, this.last_monthly_time);
|
|
|
|
//---
|
|
if(IsInfoLogEnabled())
|
|
{
|
|
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
|
|
Print("Daily profit: ", this.account_daily_profit);
|
|
Print("Weekly profit: ", this.account_weekly_profit);
|
|
Print("Monthly profit: ", this.account_monthly_profit);
|
|
Print("Gross profit: ", this.account_gross_profit);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function to execute in OnTick |
|
|
//+------------------------------------------------------------------+
|
|
#define CAccountStatus_OnTickEvent account_status_curr_profit = AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OnTradeTransaction event |
|
|
//+------------------------------------------------------------------+
|
|
//--- 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
|
|
//#define CACCOUNT_STATUS_ACTIVE_ON_POSITION_MODIFIED
|
|
|
|
//--- En los evenots de ordenes, su definicion activa que tamiben cuenten las ordenes de compra y venta
|
|
//#define CACCOUNT_STATUS_COUNT_ORDERS_BUY_SELL
|
|
|
|
//---
|
|
void CAccountStatus::OnTradeTransactionEvent(const MqlTradeTransaction &trans)
|
|
{
|
|
//---
|
|
switch(trans.type)
|
|
{
|
|
//---
|
|
case TRADE_TRANSACTION_ORDER_ADD: // 0
|
|
{
|
|
#ifdef CACCOUNT_STATUS_ACTIVE_ON_ORDER_ADD
|
|
|
|
#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;
|
|
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;
|
|
last_order_struct.order_time_expiration = trans.time_expiration;
|
|
last_order_struct.order_reason = (ENUM_ORDER_REASON)OrderGetInteger(ORDER_REASON);
|
|
last_order_struct.order_type = trans.order_type;
|
|
last_order_struct.order_state = trans.order_state;
|
|
last_order_struct.order_type_time = trans.time_type;
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnOrderAdd(last_order_struct);
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("Error al seleccionar la orden %I64u", trans.order), FUNCION_ACTUAL);
|
|
}
|
|
|
|
#endif // CACCOUNT_STATUS_ACTIVE_ON_ORDER_ADD
|
|
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_ORDER_UPDATE: // 1
|
|
{
|
|
#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;
|
|
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;
|
|
last_order_struct.order_time_expiration = trans.time_expiration;
|
|
last_order_struct.order_reason = (ENUM_ORDER_REASON)OrderGetInteger(ORDER_REASON);
|
|
last_order_struct.order_type = trans.order_type;
|
|
last_order_struct.order_state = trans.order_state;
|
|
last_order_struct.order_type_time = trans.time_type;
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnOrderUpdate(last_order_struct);
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("Error al seleccionar la orden %I64u", trans.order), FUNCION_ACTUAL);
|
|
}
|
|
|
|
#endif // CACCOUNT_STATUS_ACTIVE_ON_ORDER_UPDATE
|
|
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_ORDER_DELETE: // 2
|
|
{
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_HISTORY_ADD: // 3
|
|
{
|
|
#ifdef CACCOUNT_STATUS_ACTIVE_ON_ORDER_DELETE
|
|
|
|
//---
|
|
if(EsUnaOrderPendiente[trans.order_type])
|
|
{
|
|
if(HistoryOrderSelect(trans.order))
|
|
{
|
|
// Se llama antes que historyadd
|
|
//---
|
|
last_trans_symbol = trans.symbol;
|
|
|
|
//---
|
|
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 = HistoryOrderGetInteger(trans.order, ORDER_MAGIC);
|
|
last_order_struct.order_ticket = trans.order;
|
|
last_order_struct.order_time_expiration = trans.time_expiration;
|
|
last_order_struct.order_reason = (ENUM_ORDER_REASON)HistoryOrderGetInteger(trans.order, ORDER_REASON);
|
|
last_order_struct.order_type = trans.order_type;
|
|
last_order_struct.order_state = trans.order_state;
|
|
last_order_struct.order_type_time = trans.time_type;
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnOrderDelete(last_order_struct);
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("Error al seleccionar la orden %I64u", trans.order), FUNCION_ACTUAL);
|
|
}
|
|
}
|
|
#endif // CACCOUNT_STATUS_ACTIVE_ON_ORDER_DELETE
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_HISTORY_UPDATE: // 4
|
|
{
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_HISTORY_DELETE: // 5
|
|
{
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_DEAL_ADD: // 6
|
|
{
|
|
//---
|
|
last_deal_type = trans.deal_type;
|
|
last_deal_ticket = trans.deal;
|
|
last_trans_symbol = trans.symbol;
|
|
|
|
//---
|
|
if(last_deal_type == DEAL_TYPE_BUY || last_deal_type == DEAL_TYPE_SELL)
|
|
{
|
|
HistoryDealSelect(trans.deal);
|
|
const ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(last_deal_ticket, DEAL_ENTRY);
|
|
const ulong deal_magic = (ulong)HistoryDealGetInteger(last_deal_ticket, DEAL_MAGIC);
|
|
const ulong position_ticket = trans.position;
|
|
|
|
//---
|
|
const double deal_profit = HistoryDealGetDouble(last_deal_ticket, DEAL_PROFIT); // Get deal profit
|
|
const double deal_commission = HistoryDealGetDouble(last_deal_ticket, DEAL_COMMISSION); // Get commission
|
|
|
|
//---
|
|
if(PositionSelectByTicket(trans.position) && entry == DEAL_ENTRY_IN)
|
|
{
|
|
//---
|
|
LogInfo(StringFormat("Position %I64u opened with magic %I64u", position_ticket, deal_magic), FUNCION_ACTUAL);
|
|
|
|
//--- Activate open positions flag
|
|
account_status_positions_open = true;
|
|
|
|
//--- Calculate the profit
|
|
const double deal_net_profit = deal_profit + deal_commission; // Calculate net profit
|
|
|
|
//--- Create a new position to add to the tickets
|
|
Position new_pos;
|
|
new_pos.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
new_pos.ticket = position_ticket;
|
|
new_pos.magic = deal_magic;
|
|
new_pos.profit = deal_net_profit;
|
|
new_pos.open_time = (datetime)PositionGetInteger(POSITION_TIME);
|
|
new_pos.open_price = trans.price;
|
|
new_pos.sl = trans.price_sl;
|
|
new_pos.tp = trans.price_tp;
|
|
new_pos.volume = trans.volume;
|
|
|
|
//---
|
|
UpdateProfit(deal_net_profit); //Update the profit
|
|
|
|
//--- Add to positions array
|
|
open_positions.Add(new_pos);
|
|
|
|
//--- Set the new structure
|
|
last_struct.position = new_pos;
|
|
|
|
// Account
|
|
last_struct.account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
last_struct.account_profit_diario = account_daily_profit;
|
|
last_struct.account_profit_total = account_gross_profit;
|
|
last_struct.account_profit_mensual = account_monthly_profit;
|
|
last_struct.account_profit_semanal = account_weekly_profit;
|
|
|
|
// Deal
|
|
last_struct.deal_entry_type = entry;
|
|
last_struct.deal_ticket = last_deal_ticket;
|
|
last_struct.deal_profit = deal_net_profit;
|
|
last_struct.deal_reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(last_deal_ticket, DEAL_REASON);
|
|
|
|
// Extra
|
|
last_struct.magic_number_closed = 0;
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnOpenClosePosition(last_struct);
|
|
|
|
//---
|
|
return;
|
|
}
|
|
|
|
if(entry != DEAL_ENTRY_OUT)
|
|
break;
|
|
|
|
//---
|
|
#define ACCOUNT_STATUS_MIN_VOL 0.00000001
|
|
|
|
//---
|
|
int16_t pos_idx;
|
|
if(open_positions.GetByTicket(position_ticket, last_struct.position, pos_idx))
|
|
{
|
|
// Print("Vol: ", DoubleToString(trans.volume));
|
|
|
|
//---
|
|
if((last_struct.position.volume - trans.volume) < ACCOUNT_STATUS_MIN_VOL) // Cierre completo
|
|
{
|
|
//---
|
|
open_positions.DeleteByIndex(pos_idx);
|
|
|
|
//---
|
|
LogCaution(StringFormat("Position with ticket %I64u has been closed", position_ticket), FUNCION_ACTUAL);
|
|
|
|
//--- Get the most recent profit
|
|
const double deal_swap = HistoryDealGetDouble(last_deal_ticket, DEAL_SWAP); // Get swap fees
|
|
const double deal_net_profit = deal_profit + deal_commission + deal_swap; // Calculate net profit
|
|
|
|
//---
|
|
if(GetPositionsTotal() == 0)
|
|
account_status_positions_open = false;
|
|
|
|
//--- Update its profit
|
|
last_struct.position.profit += deal_net_profit;
|
|
|
|
//--- Update the general profit
|
|
UpdateProfit(deal_net_profit);
|
|
|
|
//--- Set the new structure
|
|
// Ya se hace
|
|
|
|
// Account
|
|
last_struct.account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
last_struct.account_profit_diario = account_daily_profit;
|
|
last_struct.account_profit_total = account_gross_profit;
|
|
last_struct.account_profit_mensual = account_monthly_profit;
|
|
last_struct.account_profit_semanal = account_weekly_profit;
|
|
|
|
// Deal
|
|
last_struct.deal_entry_type = entry; //market entry type (ENTRY_OUT)
|
|
last_struct.deal_ticket = last_deal_ticket; //Closing deal ticket
|
|
last_struct.deal_profit = deal_net_profit; //Net profit (excluding commissions)
|
|
last_struct.deal_reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(last_deal_ticket, DEAL_REASON);
|
|
|
|
// Extra
|
|
last_struct.magic_number_closed = deal_magic; //Ticket with which the position was closed
|
|
|
|
//--- Execute in the inheritors
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnOpenClosePosition(last_struct);
|
|
|
|
//---
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//---
|
|
LogCaution(StringFormat("Possible partial closure of the position: %I64u", position_ticket), FUNCION_ACTUAL);
|
|
|
|
//---
|
|
const double deal_swap = HistoryDealGetDouble(last_deal_ticket, DEAL_SWAP); // Get swap fees
|
|
const double deal_net_profit = deal_profit + deal_commission + deal_swap; // Calculate net profit
|
|
|
|
//---
|
|
open_positions.UpdatePositionPartial(deal_net_profit, trans.volume, pos_idx); //Update the profit of the position that partially closed
|
|
|
|
//---
|
|
UpdateProfit(deal_net_profit);
|
|
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if(last_deal_type == DEAL_TYPE_BALANCE || last_deal_type == DEAL_TYPE_CHARGE) // Withdrawal or deposit
|
|
{
|
|
HistoryDealSelect(last_deal_ticket);
|
|
const double deal_profit = HistoryDealGetDouble(last_deal_ticket, DEAL_PROFIT); // Get deal profit
|
|
|
|
//---
|
|
if(fabs(deal_profit) < 0.0000000001)
|
|
break;
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnWithdrawalDeposit(deal_profit);
|
|
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_DEAL_UPDATE: // 7
|
|
{
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_DEAL_DELETE: // 8
|
|
{
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_POSITION: // 9
|
|
{
|
|
#ifdef CACCOUNT_STATUS_ACTIVE_ON_POSITION_MODIFIED
|
|
const ulong t = trans.position;
|
|
if(open_positions.GetByTicket(t, last_struct.position))
|
|
{
|
|
//---
|
|
last_trans_symbol = trans.symbol;
|
|
|
|
//---
|
|
uint8_t f = 0;
|
|
|
|
//--- Cambio tp
|
|
const double new_tp = trans.price_tp;
|
|
if(last_struct.position.tp != new_tp)
|
|
{
|
|
open_positions.UpdateTp(new_tp, t);
|
|
last_struct.position.tp = new_tp;
|
|
f |= ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_TP;
|
|
}
|
|
|
|
//--- Cambio sl
|
|
const double new_sl = trans.price_sl;
|
|
if(last_struct.position.sl != new_sl)
|
|
{
|
|
open_positions.UpdateSl(new_sl, t);
|
|
last_struct.position.sl = new_sl;
|
|
f |= ACCOUNTSTATUS_ON_POS_MODIFY_FLAG_CHANGE_SL;
|
|
}
|
|
|
|
//---
|
|
if(f)
|
|
for(int i = 0; i < total; i++)
|
|
items[i].OnPositionModify(last_struct.position, f);
|
|
}
|
|
#endif // CACCOUNT_STATUS_ACTIVE_ON_POSITION_MODIFIED
|
|
break;
|
|
}
|
|
|
|
//---
|
|
case TRADE_TRANSACTION_REQUEST: // 10
|
|
{
|
|
break;
|
|
}
|
|
|
|
//---
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Print last order values |
|
|
//+------------------------------------------------------------------+
|
|
void CAccountStatus::PrintLastOrder(void)
|
|
{
|
|
Print("--- Last Order ---");
|
|
Print("Ticket: ", last_order_struct.order_ticket);
|
|
Print("Type: ", EnumToString(last_order_struct.order_type));
|
|
Print("State: ", EnumToString(last_order_struct.order_state));
|
|
Print("Magic: ", last_order_struct.order_magic);
|
|
Print("Open Price: ", last_order_struct.order_open_price);
|
|
Print("Stop Loss: ", last_order_struct.order_stop_loss);
|
|
Print("Take Profit: ", last_order_struct.order_take_profit);
|
|
Print("Expiration: ", last_order_struct.order_time_expiration);
|
|
Print("Time Type: ", EnumToString(last_order_struct.order_type_time));
|
|
Print("Reason: ", EnumToString(last_order_struct.order_reason));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Print last position values |
|
|
//+------------------------------------------------------------------+
|
|
void CAccountStatus::PrintLastPosition(void)
|
|
{
|
|
Print("--- Last Position ---");
|
|
Print("Ticket: ", last_struct.position.ticket);
|
|
Print("Type: ", EnumToString(last_struct.position.type));
|
|
Print("Magic: ", last_struct.position.magic);
|
|
Print("Open Price: ", last_struct.position.open_price);
|
|
Print("Open Time: ", last_struct.position.open_time);
|
|
Print("Stop Loss: ", last_struct.position.sl);
|
|
Print("Take Profit: ", last_struct.position.tp);
|
|
Print("Profit: ", last_struct.position.profit);
|
|
}
|
|
|
|
|
|
/*
|
|
ADVERTENCIA: Si se añaden items a esta clase, esta las eliminara por defecto, NO propagara sus logs.. solko funcioan como container
|
|
WARNING: If items are added to this class, it will delete them by default, it will NOT propagate their logs. They only function as containers.
|
|
*/
|
|
|
|
CAccountStatus account_status;
|
|
#endif // MQLARTICLES_RM_ACCOUNTSTATUS_MQH
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|