//+------------------------------------------------------------------+ //| RiskInfo.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include "PositionInfo.mqh" int lastsOpenPositionsChecked = 0; struct RiskInfo { double MaxRiskByTradeInPercent; double MaxDrawdownInPercent; double moneyAllowToLoss; double moneyLoss; int consecutiveLossUmbral; int stopAfterConsecutiveLossTime; int currConsecutiveLoss; datetime currlossGreaterThanUmbralTime; datetime initTimeToAnalizeHistoryOrder; }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double moneyInRiskInOpenPosition (RiskInfo &riskInfoParam, int &periodInBarsParam[], PositionInfo &positionsInfoParam[], int periodInBarsLengthParam) { double moneyInOpenPosition = 0; for(int i=0; i= 0; i-- ) { ulong ticket = HistoryOrderGetTicket(i); if(HistoryOrderSelect(ticket) && HistoryOrderGetString(ticket,ORDER_SYMBOL) == Symbol() && HistoryOrderGetInteger(ticket,ORDER_MAGIC) == TOPO_MAGIC_PARAM) { if(HistoryDealSelect(ticket)) { double profit = HistoryDealGetDouble(ticket,DEAL_PROFIT); if(profit <= 0) { if(profit < 0) result += 1; } else { break; } } } } return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool canMakeTradeFromRiskInfo (RiskInfo &riskInfoParam, int &periodInBarsParam[], PositionInfo &positionsInfoParam[], int periodInBarsLengthParam, datetime initTimeParam) { double riskInMoney = NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*(riskInfoParam.MaxRiskByTradeInPercent/100),_Digits); double moneyInOpenPosition = moneyInRiskInOpenPosition(riskInfoParam,periodInBarsParam,positionsInfoParam,periodInBarsLengthParam); double moneyLossed = riskInfoParam.moneyLoss + riskInMoney + moneyInOpenPosition; if(riskInfoParam.moneyAllowToLoss < moneyLossed) { string msj = StringFormat("Alert: we can't make a new trade becouse constraint risk. money allow to loss(%f) ,money lossed:(%f) ,number of consecutive loss:(%d)", riskInfoParam.moneyAllowToLoss, riskInfoParam.moneyLoss, riskInfoParam.currConsecutiveLoss); Print(msj); Alert(msj); } if(riskInfoParam.currConsecutiveLoss >= riskInfoParam.consecutiveLossUmbral) { if(riskInfoParam.currlossGreaterThanUmbralTime == initTimeParam) { riskInfoParam.currlossGreaterThanUmbralTime = TimeCurrent(); } if((TimeCurrent() - riskInfoParam.currlossGreaterThanUmbralTime) < riskInfoParam.stopAfterConsecutiveLossTime) { return false; } else { riskInfoParam.currConsecutiveLoss = 0; riskInfoParam.currlossGreaterThanUmbralTime = initTimeParam; riskInfoParam.initTimeToAnalizeHistoryOrder = TimeCurrent(); return true; } } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void updateRiskInfo (RiskInfo &riskInfoParam, int TOPO_MAGIC_PARAM) { double currAccountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double accountBalanceFromMoneyAllowToLoss = (riskInfoParam.moneyAllowToLoss*100) / riskInfoParam.MaxDrawdownInPercent; double currRiskInMoney = NormalizeDouble(currAccountBalance*(riskInfoParam.MaxDrawdownInPercent/100),_Digits); int currentPositions = PositionsTotal(); // when accountBalanceFromMoneyAllowToLoss == currAccountBalance || currentPositions == lastsOpenPositionsChecked already analize this risk if(accountBalanceFromMoneyAllowToLoss == currAccountBalance || currentPositions == lastsOpenPositionsChecked) return; if(accountBalanceFromMoneyAllowToLoss <= currAccountBalance) { riskInfoParam.moneyAllowToLoss = currRiskInMoney; riskInfoParam.initTimeToAnalizeHistoryOrder = TimeCurrent(); } else { riskInfoParam.moneyLoss = accountBalanceFromMoneyAllowToLoss - currAccountBalance; } lastsOpenPositionsChecked = currentPositions; riskInfoParam.currConsecutiveLoss = getConsecutiveLosser(riskInfoParam, TOPO_MAGIC_PARAM); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ RiskInfo initRiskInfo(double MaxRiskByTradeInPercentParam, double MaxDrawdownInPercentParam, datetime initTimeParam, double moneyAllowToLossParam, int consecutiveLossUmbral, int stopAfterConsecutiveLossTimeInMinute) { RiskInfo riskInfoTmp; riskInfoTmp.MaxRiskByTradeInPercent = MaxRiskByTradeInPercentParam; riskInfoTmp.MaxDrawdownInPercent = MaxDrawdownInPercentParam; riskInfoTmp.currConsecutiveLoss = 0; riskInfoTmp.currlossGreaterThanUmbralTime = initTimeParam; riskInfoTmp.initTimeToAnalizeHistoryOrder = initTimeParam; riskInfoTmp.moneyAllowToLoss = moneyAllowToLossParam; riskInfoTmp.moneyLoss = 0; riskInfoTmp.consecutiveLossUmbral = consecutiveLossUmbral; riskInfoTmp.stopAfterConsecutiveLossTime = stopAfterConsecutiveLossTimeInMinute * 60; return riskInfoTmp; } //+------------------------------------------------------------------+