//+------------------------------------------------------------------+ //| Warrior_EA | //| AnimateDread | //| | //+------------------------------------------------------------------+ #include "..\Expert\ExpertMoneyCustom.mqh" #include class CMoneyIntelligent : public CExpertMoneyCustom { protected: double m_factor; public: // Constructor CMoneyIntelligent() : m_factor(1.0) {} // Default decrease factor is set to 1 virtual double CheckOpenLong(double price, double sl); virtual double CheckOpenShort(double price, double sl); virtual double CheckClose(CPositionInfo *position) { return(0.0); } void Factor(double factor) { m_factor = factor; } private: double CalculatePotentialLoss(ENUM_ORDER_TYPE orderType, double price, double sl); double CalculateLotSize(double loss); double Optimize(double lots); }; //+------------------------------------------------------------------+ //| Getting lot size for open long position. | //+------------------------------------------------------------------+ double CMoneyIntelligent::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 = CalculateLotSize(loss); lot = Optimize(lot); 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; } //+------------------------------------------------------------------+ //| Getting lot size for open short position. | //+------------------------------------------------------------------+ double CMoneyIntelligent::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 = CalculateLotSize(loss); lot = Optimize(lot); 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; } //+------------------------------------------------------------------+ //| Calculate potential loss | //+------------------------------------------------------------------+ double CMoneyIntelligent::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 CMoneyIntelligent::CalculateLotSize(double loss) { double riskAmount = m_account.Balance() * m_percent / 100.0; double stepvol = m_symbol.LotsStep(); return MathFloor(riskAmount / loss / stepvol) * stepvol; } //+------------------------------------------------------------------+ //| Optimizing lot size for open based on trade history. | //+------------------------------------------------------------------+ double CMoneyIntelligent::Optimize(double lots) { double lot = lots; // Calculate number of consecutive winning and losing orders without a break int orders = HistoryDealsTotal(); // Total history deals int streak = 0; // Number of consecutive winning or losing orders int streakDirection = 0; // 1 for winning streak, -1 for losing streak CDealInfo deal; for(int i = orders - 1; i >= 0; i--) { deal.Ticket(HistoryDealGetTicket(i)); if(deal.Ticket() == 0) { Print(__FUNCTION__, ": HistoryDealGetTicket failed, no trade history"); break; } // Check symbol if(deal.Symbol() != m_symbol.Name()) continue; // Check profit double profit = deal.Profit(); if(profit > 0.0) { if(streakDirection == -1) // if the previous streak was a losing streak { // Adjust the lot based on the number of consecutive losses if(streak > 1) lot = NormalizeDouble(lot + lot * streak / m_factor, m_symbol.Digits()); streak = 1; // reset streak count } else { streak++; // increment winning streak count } streakDirection = 1; // set direction to winning streak } else if(profit < 0.0) { if(streakDirection == 1) // if the previous streak was a winning streak { // Adjust the lot based on the number of consecutive losses if(streak > 1) lot = NormalizeDouble(lot - lot * streak / m_factor, m_symbol.Digits()); streak = 1; // reset streak count } else { streak++; // increment losing streak count } streakDirection = -1; // set direction to losing streak } } return lot; } //+------------------------------------------------------------------+