//+------------------------------------------------------------------+ //| Warrior_EA | //| AnimateDread | //| | //+------------------------------------------------------------------+ #include #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); } //+------------------------------------------------------------------+