//+------------------------------------------------------------------+ //| Positions.mqh| //| Copyright 2026, bandersoft | //| https://www.mql5.com/en/users/fats | //+------------------------------------------------------------------+ //| | //| Read-only queries on open positions. | //| | //+------------------------------------------------------------------+ #ifndef STOPFIRST_POSITIONS_MQH #define STOPFIRST_POSITIONS_MQH #include #include "Defs.mqh" //+------------------------------------------------------------------+ //| Commission and fees already charged on an open position | //| | //| MT5 charges commission on DEALS. POSITION_COMMISSION, which | //| CPositionInfo::Commission() reads, is deprecated and reports 0, | //| so "profit + swap + commission" silently leaves commission out. | //| This sums DEAL_COMMISSION and DEAL_FEE over the position's deals | //| instead. | //| | //| Side effect: replaces the history selection, as any | //| HistorySelectByPosition call does. | //| | //| Returns: the total, normally negative. 0 when the broker charges | //| none or the history cannot be selected. | //+------------------------------------------------------------------+ double PositionCommission(const ulong ticket) { if(!HistorySelectByPosition(ticket)) return 0; double total = 0; for(int i = HistoryDealsTotal() - 1; i >= 0; i--) { ulong deal = HistoryDealGetTicket(i); if(deal == 0) continue; total += HistoryDealGetDouble(deal, DEAL_COMMISSION) + HistoryDealGetDouble(deal, DEAL_FEE); } return total; } //+------------------------------------------------------------------+ //| Get total profit/loss for symbol | //| | //| Returns: profit plus swap plus commission over matching | //| positions, 2 decimals. 0 if nothing matches, which reads | //| the same as a flat P/L. | //+------------------------------------------------------------------+ double GetTotalProfit(string symbol = "", ulong magic = STOPFIRST_ANY_MAGIC) { //--- "" here means EVERY symbol, not the chart symbol CPositionInfo positionInfo; double totalProfit = 0; for(int i = 0; i < PositionsTotal(); i++) { if(positionInfo.SelectByIndex(i)) { if(symbol == "" || positionInfo.Symbol() == symbol) { if(magic == STOPFIRST_ANY_MAGIC || positionInfo.Magic() == magic) { totalProfit += positionInfo.Profit() + positionInfo.Swap() + PositionCommission(positionInfo.Ticket()); } } } } return NormalizeDouble(totalProfit, 2); } //+------------------------------------------------------------------+ //| Get position count for symbol | //| | //| Returns: how many open positions match the filter. 0 if none. | //+------------------------------------------------------------------+ int GetPositionCount(string symbol = "", ulong magic = STOPFIRST_ANY_MAGIC, int posType = -1) { //--- "" here means EVERY symbol, not the chart symbol CPositionInfo positionInfo; int count = 0; for(int i = 0; i < PositionsTotal(); i++) { if(positionInfo.SelectByIndex(i)) { if(symbol == "" || positionInfo.Symbol() == symbol) { if(magic == STOPFIRST_ANY_MAGIC || positionInfo.Magic() == magic) { if(posType == -1 || positionInfo.PositionType() == (ENUM_POSITION_TYPE)posType) count++; } } } } return count; } //+------------------------------------------------------------------+ //| Get total volume for symbol | //| | //| Returns: summed volume of matching positions, unrounded. Long | //| and short both count positive, so this is gross exposure,| //| not net. 0 if nothing matches. | //+------------------------------------------------------------------+ double GetTotalVolume(string symbol = "", ulong magic = STOPFIRST_ANY_MAGIC) { //--- "" here means EVERY symbol, not the chart symbol CPositionInfo positionInfo; double totalVolume = 0; for(int i = 0; i < PositionsTotal(); i++) { if(positionInfo.SelectByIndex(i)) { if(symbol == "" || positionInfo.Symbol() == symbol) { if(magic == STOPFIRST_ANY_MAGIC || positionInfo.Magic() == magic) { totalVolume += positionInfo.Volume(); } } } } //--- not rounded to 2 decimals: on a 0.001 step, 3 x 0.005 is 0.015 //--- and rounding would give 0.02 or 0.01 return NormalizeDouble(totalVolume, 8); } #endif // STOPFIRST_POSITIONS_MQH //+------------------------------------------------------------------+