//+------------------------------------------------------------------+ //| Account.mqh| //| Copyright 2026, bandersoft | //| https://www.mql5.com/en/users/fats | //+------------------------------------------------------------------+ //| | //| Account metrics, compounding, summary string. | //| | //+------------------------------------------------------------------+ #ifndef STOPFIRST_ACCOUNT_MQH #define STOPFIRST_ACCOUNT_MQH #include //--- GetTradeStats reports position counts and profit #include "Positions.mqh" #include "Defs.mqh" //+------------------------------------------------------------------+ //| Calculate compound growth | //| | //| Returns: initial compounded at ratePercent over periods. | //+------------------------------------------------------------------+ double CalcCompoundGrowth(double initial, double ratePercent, int periods) { return initial * MathPow(1 + ratePercent / 100.0, periods); } //+------------------------------------------------------------------+ //| Does this account keep one position per ticket? | //| | //| Hedging accounts hold a position per ticket and can be long and | //| short the same symbol at once. Netting accounts hold one position | //| per symbol, so an opposing order reduces or reverses it. Several | //| operations, partial close among them, work differently on each. | //| | //| Returns: true for a retail hedging account, false otherwise. | //+------------------------------------------------------------------+ bool IsHedgingAccount() { return (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING; } //+------------------------------------------------------------------+ //| Open loss as a percentage of balance | //| | //| Not drawdown: balance minus equity is the CURRENT floating loss, | //| and drawdown is measured from peak equity - for that, see | //| GetPeakDrawdownPercent(). | //| | //| Returns: (balance - equity) / balance * 100, 2 decimals. | //| NEGATIVE when open trades are in profit - that is not an | //| error, it is what the quantity means. | //| 0 if balance is zero. | //+------------------------------------------------------------------+ double GetFloatingLossPercent() { CAccountInfo accountInfo; double balance = accountInfo.Balance(); double equity = accountInfo.Equity(); if(balance == 0) return 0; return NormalizeDouble(((balance - equity) / balance) * 100.0, 2); } //--- highest equity seen since tracking began, for GetPeakDrawdownPercent double g_peakEquity = 0; //+------------------------------------------------------------------+ //| Restart peak-equity tracking from the current equity | //| Returns: nothing. | //+------------------------------------------------------------------+ void ResetPeakEquity() { CAccountInfo accountInfo; g_peakEquity = accountInfo.Equity(); } //+------------------------------------------------------------------+ //| Drawdown from the highest equity seen so far | //| | //| The peak is built up from the first call onwards, so it measures | //| the run since the program started, not the account lifetime high | //| - call it on a schedule (each tick or each bar) or the peak means | //| little. | //| ResetPeakEquity() starts the measurement over. A withdrawal | //| lowers equity like a loss and reads as drawdown: call | //| ResetPeakEquity() after moving money out. | //| | //| Returns: (peak - equity) / peak * 100, 2 decimals. 0 at a new | //| high, and 0 if peak equity is not positive. | //+------------------------------------------------------------------+ double GetPeakDrawdownPercent() { CAccountInfo accountInfo; double equity = accountInfo.Equity(); if(equity > g_peakEquity) g_peakEquity = equity; if(g_peakEquity <= 0) return 0; return NormalizeDouble(((g_peakEquity - equity) / g_peakEquity) * 100.0, 2); } //+------------------------------------------------------------------+ //| Print trade statistics summary | //| | //| Returns: a multi-line summary of balance, equity, margin, | //| drawdown and open exposure. Never empty. | //+------------------------------------------------------------------+ string GetTradeStats(ulong magic = STOPFIRST_ANY_MAGIC) { CAccountInfo accountInfo; string stats = "=== Trade Statistics ===\n"; stats += "Balance: " + DoubleToString(accountInfo.Balance(), 2) + "\n"; stats += "Equity: " + DoubleToString(accountInfo.Equity(), 2) + "\n"; stats += "Free Margin: " + DoubleToString(accountInfo.FreeMargin(), 2) + "\n"; stats += "Margin Level: " + DoubleToString(accountInfo.MarginLevel(), 2) + "%\n"; stats += "Floating Loss: " + DoubleToString(GetFloatingLossPercent(), 2) + "%\n"; stats += "Open Positions: " + IntegerToString(GetPositionCount("", magic)) + "\n"; stats += "Total Profit: " + DoubleToString(GetTotalProfit("", magic), 2) + "\n"; return stats; } #endif // STOPFIRST_ACCOUNT_MQH //+------------------------------------------------------------------+