They referred to project documents that are not part of this repository. Comments only; PriceToPips is now documented as not rounding, which is what it does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
142 lines
5.6 KiB
MQL5
142 lines
5.6 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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 <Trade\PositionInfo.mqh>
|
|
#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
|
|
//+------------------------------------------------------------------+
|