140 lines
5.8 KiB
MQL5
140 lines
5.8 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Warrior_EA |
|
|
//| AnimateDread |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\Expert\ExpertMoneyCustom.mqh"
|
|
#include <Trade\DealInfo.mqh>
|
|
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|