forked from animatedread/Warrior_EA
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.
79 lines
4.9 KiB
MQL5
79 lines
4.9 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Warrior_EA |
|
|
//| AnimateDread |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include <Expert\ExpertMoney.mqh>
|
|
#include "..\System\TradeChecks.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Class CExpertMoneyCustom. |
|
|
//| Common base for every money-management strategy in this EA. Its |
|
|
//| single job beyond CExpertMoney is to make sure NO strategy can |
|
|
//| ever hand CExpert a volume that would be rejected by the server - |
|
|
//| ValidateLotForTrade() below is the one gate all of them go |
|
|
//| through, and it applies, in order, every volume-related rule from |
|
|
//| https://www.mql5.com/en/articles/2555: |
|
|
//| #14 the symbol is real, selected, quoted and open for trading; |
|
|
//| #3 the volume sits on the SYMBOL_VOLUME_STEP grid inside |
|
|
//| [SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX]; |
|
|
//| #5 the volume fits inside whatever SYMBOL_VOLUME_LIMIT still |
|
|
//| allows on this symbol in this direction; |
|
|
//| #2 OrderCalcMargin() against ACCOUNT_MARGIN_FREE, stepping the |
|
|
//| volume down by the symbol's own volume step until it fits. |
|
|
//| The implementations live in System\TradeChecks.mqh so the signal |
|
|
//| and expert layers apply the identical rules - see that header. |
|
|
//+------------------------------------------------------------------+
|
|
class CExpertMoneyCustom : public CExpertMoney
|
|
{
|
|
protected:
|
|
//--- The full #14/#3/#5/#2 gate. Returns the corrected volume in `lots`, or 0.0 with a
|
|
//--- populated `description` when no legal volume exists for this trade right now.
|
|
bool ValidateLotForTrade(const string symb, double &lots, ENUM_ORDER_TYPE type, string &description);
|
|
//--- Kept as thin wrappers over the shared library so the two names the existing money
|
|
//--- strategies already call (Money\MoneyRiskBase.mqh) keep working unchanged.
|
|
bool CheckAndCorrectVolumeValue(double &volume, string &description);
|
|
bool CheckAndAdjustMoneyForTrade(string symb, double &lots, ENUM_ORDER_TYPE type);
|
|
//--- Symbol this money object is sizing for. m_symbol is set by CExpertMoney::Init(); fall back
|
|
//--- to the chart symbol only if a strategy is used stand-alone before Init() has run.
|
|
string MoneySymbol(void) { return (m_symbol != NULL) ? m_symbol.Name() : _Symbol; }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Article #14/#3/#5/#2 - the complete pre-OrderSend volume gate. |
|
|
//+------------------------------------------------------------------+
|
|
bool CExpertMoneyCustom::ValidateLotForTrade(const string symb, double &lots, ENUM_ORDER_TYPE type, string &description)
|
|
{
|
|
if(!TCValidateVolumeForTrade(symb, lots, type, description))
|
|
{
|
|
//--- throttled: an exhausted margin/volume limit is true on every tick until it changes, and
|
|
//--- an unthrottled Print here floods the journal for as long as the condition lasts
|
|
TCLog("money:" + symb + ":" + EnumToString(type),
|
|
StringFormat("%s: no tradeable volume for %s %s - %s", __FUNCTION__, symb, EnumToString(type), description));
|
|
lots = 0.0;
|
|
return false;
|
|
}
|
|
if(description != "")
|
|
TCLog("money-adjust:" + symb + ":" + EnumToString(type),
|
|
StringFormat("%s: volume adjusted for %s %s - %s", __FUNCTION__, symb, EnumToString(type), description));
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Article #3 - check and correct the order volume. |
|
|
//| Delegates to TCNormalizeVolume(), which snaps to the volume step |
|
|
//| BEFORE clamping to [min,max] (see its comment for why the reverse |
|
|
//| order can emit an out-of-range volume) and then re-verifies the |
|
|
//| corrected value against all three properties. |
|
|
//+------------------------------------------------------------------+
|
|
bool CExpertMoneyCustom::CheckAndCorrectVolumeValue(double &volume, string &description)
|
|
{
|
|
return TCNormalizeVolume(MoneySymbol(), volume, description);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Article #2/#5 - fit the trade size to free margin and to the |
|
|
//| per-symbol aggregate volume limit. |
|
|
//+------------------------------------------------------------------+
|
|
bool CExpertMoneyCustom::CheckAndAdjustMoneyForTrade(string symb, double &lots, ENUM_ORDER_TYPE type)
|
|
{
|
|
string description;
|
|
return ValidateLotForTrade(symb, lots, type, description);
|
|
}
|
|
//+------------------------------------------------------------------+
|