derivado de animatedread/Warrior_EA
Optimize() scaled lot size off account trade-history streaks with no Magic-number filter (picked up other EAs'/manual trades) and an unconfigurable m_factor stuck at 1.0 (Factor() was never wired from an input), so a 3-trade streak could triple lot size or send it negative. It was also entirely disconnected from what the AI model actually knows about the current setup. Replaced both AdjustRiskAmount()'s linear confidence-only scale and Optimize()'s streak multiplier with one edge-based model: p from the empirically calibrated AI/DB confidence magnitude, b from the trade's real reward:risk ratio (newly bridged from OpenParams() via g_TradeRewardRiskRatio), quarter-Kelly applied and clamped so risk% can only ever scale down from its configured ceiling, never above it.
91 linhas
4,8 KiB
MQL5
91 linhas
4,8 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MoneyRiskBase.mqh |
|
|
//| AnimateDread |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\Expert\ExpertMoneyCustom.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Class CMoneyRiskBase. |
|
|
//| Shared risk-based lot-sizing core for every money-management |
|
|
//| strategy that sizes a trade off a fixed account-risk percentage |
|
|
//| (CMoneyFixedRisk, CMoneyIntelligent) - CalculatePotentialLoss()/ |
|
|
//| CheckOpenLong()/CheckOpenShort()/CalculateLotSize() used to be |
|
|
//| duplicated near-verbatim across both. AdjustRiskAmount()/ |
|
|
//| AdjustLotSize() are the two points a subclass can diverge at |
|
|
//| (CMoneyIntelligent overrides AdjustRiskAmount() for its Kelly- |
|
|
//| criterion, confidence-and-reward:risk-based sizing) - override |
|
|
//| only those, everything else here is shared as-is. |
|
|
//+------------------------------------------------------------------+
|
|
class CMoneyRiskBase : public CExpertMoneyCustom
|
|
{
|
|
public:
|
|
virtual double CheckOpenLong(double price, double sl);
|
|
virtual double CheckOpenShort(double price, double sl);
|
|
virtual double CheckClose(CPositionInfo *position) { return(0.0); }
|
|
|
|
protected:
|
|
double CalculatePotentialLoss(ENUM_ORDER_TYPE orderType, double price, double sl);
|
|
double CalculateLotSize(double loss);
|
|
//--- Hook for CMoneyIntelligent's Kelly-criterion risk% scaling (see its own
|
|
//--- AdjustRiskAmount() override for the rationale); default no-op keeps CMoneyFixedRisk's
|
|
//--- behavior exactly as it was before this base class existed.
|
|
virtual double AdjustRiskAmount(double riskAmount) { return riskAmount; }
|
|
//--- Reserved extension point for a future lot-size-level adjustment (e.g. equity-curve-
|
|
//--- based scaling); no current subclass overrides this - default is a no-op.
|
|
virtual double AdjustLotSize(double lot) { return lot; }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Getting lot size for open long position. |
|
|
//+------------------------------------------------------------------+
|
|
double CMoneyRiskBase::CheckOpenLong(double price, double sl)
|
|
{
|
|
if(m_symbol == NULL)
|
|
return 0.0;
|
|
double loss = CalculatePotentialLoss(ORDER_TYPE_BUY, price, sl);
|
|
if(loss <= 0.0)
|
|
return m_symbol.LotsMin();
|
|
double lot = AdjustLotSize(CalculateLotSize(loss));
|
|
string description;
|
|
// Adjust the lot size within allowed bounds and ensure sufficient margin
|
|
if(CheckAndCorrectVolumeValue(lot, description) && CheckAndAdjustMoneyForTrade(m_symbol.Name(), lot, ORDER_TYPE_BUY))
|
|
return lot;
|
|
else
|
|
return 0.0; // Handle as needed or inform the user
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Getting lot size for open short position. |
|
|
//+------------------------------------------------------------------+
|
|
double CMoneyRiskBase::CheckOpenShort(double price, double sl)
|
|
{
|
|
if(m_symbol == NULL)
|
|
return 0.0;
|
|
double loss = CalculatePotentialLoss(ORDER_TYPE_SELL, price, sl);
|
|
if(loss <= 0.0)
|
|
return m_symbol.LotsMin();
|
|
double lot = AdjustLotSize(CalculateLotSize(loss));
|
|
string description;
|
|
// Adjust the lot size within allowed bounds and ensure sufficient margin
|
|
if(CheckAndCorrectVolumeValue(lot, description) && CheckAndAdjustMoneyForTrade(m_symbol.Name(), lot, ORDER_TYPE_SELL))
|
|
return lot;
|
|
else
|
|
return 0.0; // Handle as needed or inform the user
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate potential loss |
|
|
//+------------------------------------------------------------------+
|
|
double CMoneyRiskBase::CalculatePotentialLoss(ENUM_ORDER_TYPE orderType, double price, double sl)
|
|
{
|
|
if(price == 0.0)
|
|
price = (orderType == ORDER_TYPE_BUY) ? m_symbol.Ask() : m_symbol.Bid();
|
|
return -m_account.OrderProfitCheck(m_symbol.Name(), orderType, 1.0, price, sl);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate the lot size based on potential loss and account balance|
|
|
//+------------------------------------------------------------------+
|
|
double CMoneyRiskBase::CalculateLotSize(double loss)
|
|
{
|
|
double riskAmount = AdjustRiskAmount(m_account.Balance() * m_percent / 100.0);
|
|
double stepvol = m_symbol.LotsStep();
|
|
return MathFloor(riskAmount / loss / stepvol) * stepvol;
|
|
}
|
|
//+------------------------------------------------------------------+
|