Warrior_EA/Money/MoneyFixedLot.mqh
Jason Binet Lafontaine a228d1bde7 feat(trade): implement trade safety checks per Article 2555 and resource limits
Add freeze-level checks, no-change modification skipping, entry price routing, and per-tick/memory budget monitoring. Override trade actions (Open, Close, Reverse, TrailingStop, TrailingOrder) to validate at the final gate before sending orders.
2026-07-26 23:08:32 -04:00

85 lines
4.4 KiB
MQL5

//+------------------------------------------------------------------+
//| MoneyFixedLot.mqh |
//| Copyright 2000-2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Expert\ExpertMoneyCustom.mqh"
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class |
//| Title=Trading with fixed trade volume |
//| Type=Money |
//| Name=FixLot |
//| Class=CMoneyFixedLot |
//| Page= |
//| Parameter=Percent,double,10.0,Percent |
//| Parameter=Lots,double,0.1,Fixed volume |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CMoneyFixedLot. |
//| Purpose: Class of money management with fixed lot. |
//| Derives from class CExpertMoney. |
//+------------------------------------------------------------------+
class CMoneyFixedLot : public CExpertMoneyCustom
{
protected:
//--- input parameters
double m_lots;
//--- declared ahead of the inline CheckOpenLong/Short bodies below that call it
double CheckedLot(ENUM_ORDER_TYPE type);
public:
//---
void Lots(double lots) { m_lots=lots; }
virtual bool ValidationSettings(void);
//--- The fixed lot from the input is a REQUEST, not a guarantee: it still has to clear the
//--- broker's volume grid, the per-symbol SYMBOL_VOLUME_LIMIT and free margin before it can be
//--- sent (article 2555 #2/#3/#5). Returning m_lots raw - as this class used to - meant a
//--- Money_FixLot_Lots that a small/loaded account cannot margin was handed straight to
//--- OrderSend() and rejected server-side with "not enough money" every single signal.
virtual double CheckOpenLong(double price,double sl) { return(CheckedLot(ORDER_TYPE_BUY)); }
virtual double CheckOpenShort(double price,double sl) { return(CheckedLot(ORDER_TYPE_SELL)); }
};
//+------------------------------------------------------------------+
//| Run the configured fixed lot through the shared pre-OrderSend |
//| volume gate; 0.0 means "no legal volume right now", which |
//| CExpert::OpenLong/OpenShort treat as "do not trade this tick". |
//+------------------------------------------------------------------+
double CMoneyFixedLot::CheckedLot(ENUM_ORDER_TYPE type)
{
double lot = m_lots;
string description;
if(!ValidateLotForTrade(MoneySymbol(), lot, type, description))
return(0.0);
return(lot);
}
//+------------------------------------------------------------------+
//| Validation settings protected data. |
//+------------------------------------------------------------------+
bool CMoneyFixedLot::ValidationSettings(void)
{
if(!CExpertMoney::ValidationSettings())
return(false);
//--- initial data checks
if(m_lots<m_symbol.LotsMin() || m_lots>m_symbol.LotsMax())
{
printf(__FUNCTION__+": lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
return(false);
}
//--- article 2555 #10: LotsStep() is 0 until the broker syncs SYMBOL_VOLUME_STEP, and the
//--- multiple-of-step test below divides by it twice
if(m_symbol.LotsStep()<=0.0)
{
printf(__FUNCTION__+": SYMBOL_VOLUME_STEP for %s is not available yet (%f)",m_symbol.Name(),m_symbol.LotsStep());
return(false);
}
if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
{
printf(__FUNCTION__+": lots amount is not corresponding with lot step %f",m_symbol.LotsStep());
return(false);
}
//--- ok
return(true);
}
//+------------------------------------------------------------------+