mql5/Include/Risk_Management.mqh

641 lines
60 KiB
MQL5
Raw Permalink Normal View History

2026-01-26 14:28:49 +03:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Risk Management.mqh |
//| Your name |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Your name "
#property link "https://www.mql5.com"
#property strict
#include <Trade/Trade.mqh>
//+-------------------------------------------------------------------------------------------------+
//+----------------------------------- Functions -------------------------------------+
//+-------------------------------------------------------------------------------------------------+
//+----------------------------------------------------------------------+
//| Function to check if you have the funds available to execute a trade |
//+----------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
{
//--- obtenemos el precio de apertura
MqlTick mqltick;
SymbolInfoTick(symb,mqltick);
double price=mqltick.ask;
if(type==ORDER_TYPE_SELL)
price=mqltick.bid;
//--- valores del margen libre imprescindible
double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- llamamos a la funci<EFBFBD>n de comprobaci<EFBFBD>n
if(!OrderCalcMargin(type,symb,lots,price,margin))
{
//--- algo no ha salido bien, informamos y retornamos false
Print("Error in ",__FUNCTION__," code=",GetLastError());
return(false);
}
//--- si los recursos para ejecutar una operaci<EFBFBD>n son insuficientes
if(margin>free_margin)
{
//--- informamos sobre el error y retornamos false
Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
return(false);
}
//--- la comprobaci<EFBFBD>n ha tenido <EFBFBD>xito
return(true);
}
//+----------------------------------------------------------------------------------------------+
//| Calculates the maximum lot size that can be traded based on free margin and symbol specifics |
//+----------------------------------------------------------------------------------------------+
double GetMaxLote(ENUM_ORDER_TYPE type, double DEVIATION = 100, double STOP_LIMIT = 50)
{
double VOLUME = 1.0; // Initial volume size
ENUM_ORDER_TYPE new_type = MarketOrderByOrderType(type);
double price = PriceByOrderType(_Symbol, type, DEVIATION, STOP_LIMIT); // Price for the given order type
double volume_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Volume step for the symbol
double margin = EMPTY_VALUE; // Required margin, initialized as empty
double max_lote = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
ResetLastError();
if(!OrderCalcMargin(new_type, _Symbol, VOLUME, price, margin))
{
Print("OrderCalcMargin() failed. Error ", GetLastError());
return 0.0; // Exit the function if margin calculation fails
}
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0)
{
PrintFormat("Free margin of %+.2f is invalid, you cannot open trades right now",AccountInfoDouble(ACCOUNT_MARGIN_FREE));
return 0.0;
}
double result = MathFloor((AccountInfoDouble(ACCOUNT_MARGIN_FREE) / margin) / volume_step) * volume_step;
for(int i = 1 ; i < 100 ; i++)
{
if(CheckMoneyForTrade(_Symbol,result,type) == true)
break;
result -= volume_step;
}
return result >= max_lote ? max_lote : result; // Return the calculated maximum lot size
}
//+------------------------------------------------------------------------+
//| Returns the market order type corresponding to the provided order type |
//+------------------------------------------------------------------------+
ENUM_ORDER_TYPE MarketOrderByOrderType(ENUM_ORDER_TYPE type)
{
switch(type)
{
case ORDER_TYPE_BUY:
case ORDER_TYPE_BUY_LIMIT:
case ORDER_TYPE_BUY_STOP:
case ORDER_TYPE_BUY_STOP_LIMIT:
return(ORDER_TYPE_BUY);
case ORDER_TYPE_SELL:
case ORDER_TYPE_SELL_LIMIT:
case ORDER_TYPE_SELL_STOP:
case ORDER_TYPE_SELL_STOP_LIMIT:
return(ORDER_TYPE_SELL);
}
return(WRONG_VALUE); // Return an invalid value if no match is found
}
//+---------------------------------------------------------------------------------+
//| Calculates the appropriate price based on order type, deviation, and stop limit |
//+---------------------------------------------------------------------------------+
double PriceByOrderType(const string symbol, const ENUM_ORDER_TYPE order_type, double DEVIATION = 100, double STOP_LIMIT = 50)
{
double point=0;
MqlTick tick= {};
ResetLastError();
if(!SymbolInfoDouble(symbol, SYMBOL_POINT, point))
{
Print("SymbolInfoDouble() failed. Error ", GetLastError());
return 0;
}
long value=0;
if(!SymbolInfoInteger(symbol, SYMBOL_DIGITS, value))
{
Print("SymbolInfoInteger() failed. Error ", GetLastError());
return 0;
}
int digits=(int)value;
if(!SymbolInfoTick(symbol, tick))
{
Print("SymbolInfoTick() failed. Error ", GetLastError());
return 0;
}
switch(order_type)
{
case ORDER_TYPE_BUY:
return(tick.ask);
case ORDER_TYPE_SELL:
return(tick.bid);
case ORDER_TYPE_BUY_LIMIT:
return(NormalizeDouble(tick.ask - DEVIATION * point, digits));
case ORDER_TYPE_SELL_LIMIT:
return(NormalizeDouble(tick.bid + DEVIATION * point, digits));
case ORDER_TYPE_BUY_STOP:
return(NormalizeDouble(tick.ask + DEVIATION * point, digits));
case ORDER_TYPE_SELL_STOP:
return(NormalizeDouble(tick.bid - DEVIATION * point, digits));
case ORDER_TYPE_BUY_STOP_LIMIT:
return(NormalizeDouble(tick.ask + DEVIATION * point - STOP_LIMIT * point, digits));
case ORDER_TYPE_SELL_STOP_LIMIT:
return(NormalizeDouble(tick.bid - DEVIATION * point + STOP_LIMIT * point, digits));
default:
return(0);
}
}
//+------------------------------------------------------------------+
//| Retrieve the magic number associated with a ticket |
//+------------------------------------------------------------------+
inline ulong GetMagic(const ulong ticket)
{
HistoryOrderSelect(ticket);
return HistoryOrderGetInteger(ticket, ORDER_MAGIC);
}
//+----------------------------------------------------------------------------------------+
//| Calculates the net profit since a given date for a specific magic number or all trades |
//+----------------------------------------------------------------------------------------+
double GetNetProfitSince(bool include_all_magic, ulong specific_magic, datetime start_date)
{
double total_net_profit = 0.0; // Initialize the total net profit
ResetLastError(); // Reset any previous errors
if(start_date > 0 && start_date != D'1971.01.01 00:00')
{
if(!HistorySelect(start_date, TimeCurrent()))
{
Print("Error when selecting orders: ", _LastError);
return 0.0; // Exit if unable to select the history
}
int total_deals = HistoryDealsTotal(); // Count total deals in the history
for(int i = 0; i < total_deals; i++)
{
ulong deal_ticket = HistoryDealGetTicket(i); // Get the deal ticket
if(HistoryDealGetInteger(deal_ticket, DEAL_TYPE) == DEAL_TYPE_BALANCE)
continue;
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket, DEAL_ENTRY); // Get deal entry type
datetime deal_close_time = (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME); // Get deal close time
ulong position_id = HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID); // Get the position ID
if(deal_close_time >= start_date && (deal_entry == DEAL_ENTRY_OUT || deal_entry == DEAL_ENTRY_IN))
{
if((HistoryDealGetInteger(deal_ticket, DEAL_MAGIC) == specific_magic || specific_magic == GetMagic(position_id))
|| include_all_magic)
{
double deal_profit = HistoryDealGetDouble(deal_ticket, DEAL_PROFIT); // Get deal profit
double deal_commission = HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION); // Get commission
double deal_swap = HistoryDealGetDouble(deal_ticket, DEAL_SWAP); // Get swap fees
double deal_net_profit = deal_profit + deal_commission + deal_swap; // Calculate net profit
total_net_profit += deal_net_profit; // Accumulate total net profit
}
}
}
}
return NormalizeDouble(total_net_profit, 2);
}
//+---------------------------------------------------------------------+
//| Determine the optimal lot size based on risk and current conditions |
//+---------------------------------------------------------------------+
void GetIdealLot(double& nlot, double glot, double max_risk_per_operation, double& new_risk_per_operation, long StopLoss)
{
if(StopLoss <= 0)
{
Print("[ERROR SL] Stop Loss distance is less than or equal to zero, now correct the stoploss distance: ", StopLoss);
nlot = 0.0;
return;
}
Print("Max Lot: ", glot, " | RiskPerOperation: ", max_risk_per_operation);
new_risk_per_operation = 0;
long spread = (long)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double rpo = (glot * (spread + 1 + (StopLoss * tick_value)));
if(rpo > max_risk_per_operation)
{
if(max_risk_per_operation <= 0)
return;
double new_lot = (max_risk_per_operation / rpo) * glot;
Print("prev lot: ", new_lot);
new_lot = MathRound(new_lot / step) * step;
Print("New lot: ",new_lot);
if(new_risk_per_operation > max_risk_per_operation)
{
new_lot -= step;
}
new_risk_per_operation = new_lot * (spread + 1 + (StopLoss * tick_value));
nlot = new_lot;
}
else
{
new_risk_per_operation = rpo;
nlot = glot;
}
if(nlot >= SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX))
{
nlot = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
}
PrintFormat("Risk per operation(%.2f) = %.2f * ( %i + 1 + (%i * %f)) ",new_risk_per_operation,nlot,spread,StopLoss,tick_value);
if(nlot <= 0)
PrintFormat("The lot %.2f is invalid, the risk %.2f increases or the sl %i decreases",nlot,max_risk_per_operation,StopLoss);
else
PrintFormat("For the stop loss %i in points and risk per operation: %.2f, the ideal lot is: %.2f",StopLoss,max_risk_per_operation,nlot);
}
//+-----------------------------------------------------------------------+
//| Calculate the stop loss distance in points based on risk and lot size |
//+-----------------------------------------------------------------------+
long CalculateSL(const ENUM_ORDER_TYPE type, double risk_per_operation, double &chosen_lot, double DEVIATION = 100, double STOP_LIMIT = 50)
{
double lot = GetLotByRiskPerOperation(risk_per_operation,type,DEVIATION,STOP_LIMIT);
chosen_lot = lot;
long spread = (long)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double result = ((risk_per_operation / lot) - spread - 1) / tick_value;
long ideal_sl = long(MathRound(result));
if(ideal_sl <= 0)
{
PrintFormat("Stop loss %i invalid, please increase the risk per trade %.2f",ideal_sl,risk_per_operation);
return 0;
}
return ideal_sl;
}
//+------------------------------------------------------------------+
//| Converts a distance in the base unit to a point-based measurement|
//+------------------------------------------------------------------+
inline int DistanceToPoint(double dist, string symbol = "_Symbol")
{
return (int)(dist / SymbolInfoDouble((symbol == "_Symbol" ? _Symbol : symbol), SYMBOL_POINT)); // Calculate and return the distance in points
}
//+--------------------------------------------------------------------+
//| Function to obtain the ideal lot based on your risk per operation |
//+--------------------------------------------------------------------+
// risk_per_operation in USD, not %
double GetLotByRiskPerOperation(double risk_per_operation, const ENUM_ORDER_TYPE order_type, double DEVIATION = 100, double STOP_LIMIT = 50)
{
double VOLUME = 1.0; // Initial volume size
ENUM_ORDER_TYPE new_type = MarketOrderByOrderType(order_type);
double price = PriceByOrderType(_Symbol, order_type, DEVIATION, STOP_LIMIT); // Price for the given order type
double volume_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Volume step for the symbol
double max_lote = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
double margin = EMPTY_VALUE; // Required margin, initialized as empty
ResetLastError();
if(!OrderCalcMargin(new_type, _Symbol, VOLUME, price, margin))
{
Print("OrderCalcMargin() failed. Error ", GetLastError());
return 0; // Exit the function if margin calculation fails
}
double result = MathFloor((risk_per_operation / margin) / volume_step) * volume_step;
if(result >= max_lote)
result = max_lote;
if(result <= 0)
{
PrintFormat("The lot %.2f is invalid, the risk %.2f increases",result,risk_per_operation);
return 0;
}
PrintFormat("The ideal lot for %.2f risk per trade is %.2f lots",risk_per_operation,result);
return result; // Return the calculated maximum lot size
}
//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+
#define NOT_MAGIC_NUMBER 0 //Not Magic Number
#define FLAG_CLOSE_ALL_PROFIT 2 //Flag indicating to close only operations with profit
#define FLAG_CLOSE_ALL_LOSS 4 //Flag indicating to close only operations without profit
//+------------------------------------------------------------------+
//| Enumerations |
//+------------------------------------------------------------------+
enum ENUM_LOTE_TYPE //lot type
{
Dinamico,//Dynamic
Fijo//Fixed
};
enum ENUM_RISK_CALCULATION_MODE //enumeration to define the types of calculation of the value of maximum profits and losses
{
money, //Money
percentage //Percentage %
};
enum ENUM_MODE_RISK_MANAGEMENT //enumeration to define the type of risk management
{
propfirm_ftmo, //Prop Firm FTMO
personal_account // Personal Account
};
enum ENUM_APPLIED_PERCENTAGES //enumeration to define the value to which the percentages will be applied
{
Balance, //Balance
ganancianeta,//Net profit
free_margin, //Free margin
equity //Equity
};
enum ENUM_GET_LOT
{
GET_LOT_BY_ONLY_RISK_PER_OPERATION, //Obtain the lot for the risk per operation
GET_LOT_BY_STOPLOSS_AND_RISK_PER_OPERATION //Obtain and adjust the lot through the risk per operation and stop loss respectively.
};
//+------------------------------------------------------------------+
//| Structures |
//+------------------------------------------------------------------+
struct Loss_Profit
{
double value; //value
double assigned_percentage; //percentage to apply
ENUM_RISK_CALCULATION_MODE mode_calculation_risk; //risk calculation method
ENUM_APPLIED_PERCENTAGES percentage_applied_to; //percentage applied to
};
//+------------------------------------------------------------------+
//| Class CRisk Management |
//+------------------------------------------------------------------+
class CRiskManagemet final
{
private:
//--- CTrade class pointer to be able to work with open positions
CTrade *trade;
//-- Main variables
double account_profit;
long StopLoss;
double lote;
//--- General variables
ENUM_MODE_RISK_MANAGEMENT mode_risk_managemet;
ulong magic_number;
//--- Variables to work with anchoring tests
double account_balance_propfirm;
//--- Variables to store the values of the maximum losses
double nmlpo;
//--- variables that store percentages and enumeration, which will be used for the subsequent calculation of losses
Loss_Profit mdl, mwl, ml, gmlpo, mdp;
//--- Variables to store the profit and the time from which they will be obtained
double daily_profit, weekly_profit, gross_profit;
datetime last_weekly_time, last_day_time, init_time;
//--- General function to assign values to loss variables
double GetValorWithApplied(const ENUM_APPLIED_PERCENTAGES applied,const double percentage_);
//--- Functions to assign values to internal variables
void SetMDL() {this.mdl.value = this.mdl.mode_calculation_risk == money ? this.mdl.value : (this.mdl.assigned_percentage > 0 ? GetValorWithApplied(this.mdl.percentage_applied_to,mdl.assigned_percentage) : 0); }
void SetMWL() {this.mwl.value = this.mwl.mode_calculation_risk == money ? this.mwl.value : (this.mwl.assigned_percentage > 0 ? GetValorWithApplied(this.mwl.percentage_applied_to,mwl.assigned_percentage) : 0); }
void SetML() {this.ml.value = this.ml.mode_calculation_risk == money ? this.ml.value : (this.ml.assigned_percentage > 0 ? GetValorWithApplied(this.ml.percentage_applied_to,ml.assigned_percentage): 0); }
void SetGMLPO() {this.gmlpo.value = this.gmlpo.mode_calculation_risk == money ? this.gmlpo.value : (this.gmlpo.assigned_percentage > 0 ? GetValorWithApplied(this.gmlpo.percentage_applied_to,gmlpo.assigned_percentage) : 0); }
void SetMDP() {this.mdp.value = this.mdp.mode_calculation_risk == money ? this.mdp.value : (this.mdp.assigned_percentage > 0 ? GetValorWithApplied(this.mdp.percentage_applied_to,mdp.assigned_percentage) : 0); }
void SetNMPLO(double& TLB_new, double tlb) { GetIdealLot(TLB_new,tlb,this.gmlpo.value,this.nmlpo,this.StopLoss); }
public:
//--- Builder and Destroyer
CRiskManagemet(ulong magic_number_ = NOT_MAGIC_NUMBER,ENUM_MODE_RISK_MANAGEMENT mode_risk_management_ = personal_account, double account_propfirm_balance=0);
~CRiskManagemet();
//--- Functions to assign values to variables for subsequent calculation of losses
void SetPorcentages(double percentage_or_money_mdl, double percentage_or_money_mwl,double percentage_or_money_gmlpo, double percentage_or_money_ml, double percentage_or_money_mdp_); //Obligatorio
void SetEnums(ENUM_RISK_CALCULATION_MODE mode_mdl_, ENUM_RISK_CALCULATION_MODE mode_mwl_, ENUM_RISK_CALCULATION_MODE mode_gmlpo_, ENUM_RISK_CALCULATION_MODE mode_ml_,
ENUM_RISK_CALCULATION_MODE mode_mdp_); //Opcional
void SetApplieds(ENUM_APPLIED_PERCENTAGES applied_mdl_, ENUM_APPLIED_PERCENTAGES applied_mwl_, ENUM_APPLIED_PERCENTAGES applied_gmlpo_, ENUM_APPLIED_PERCENTAGES applied_ml_,
ENUM_APPLIED_PERCENTAGES applied_mdp_); //Opcional
//--- Function to set the "StopLoss" variable, in points or distance
inline void SetStopLoss(double dist_open_sl) { this.StopLoss = DistanceToPoint(dist_open_sl); }
inline void SetStopLoss(long _sl_point_) { this.StopLoss = _sl_point_; }
//--- Events
void OnNewDay();
void OnNewWeek();
//--- Closing of positions
void CloseAllPositions(int flags = FLAG_CLOSE_ALL_LOSS | FLAG_CLOSE_ALL_PROFIT);
//--- Get the lot
double GetLote(const ENUM_ORDER_TYPE order_type, const ENUM_GET_LOT mode_get_lot);
//--- Obtain the SL by risk per operation
long GetSL(const ENUM_ORDER_TYPE type, double DEVIATION = 100, double STOP_LIMIT = 50);
//--- Obtain the value of maximum profits and losses:
inline double GetML() const { return this.ml.value; }
inline double GetMWL() const { return this.mwl.value; }
inline double GetMDL() const { return this.mdl.value; }
inline double GetGMLPO() const { return this.gmlpo.value; }
inline double GetNMLPO() const { return this.nmlpo; }
inline double GetMDP() const { return this.mdp.value; }
//--- Obtain only profits:
inline double GetGrossProfit() const { return this.gross_profit; }
inline double GetWeeklyProfit() const { return this.weekly_profit; }
inline double GetDailyProfit() const { return this.daily_profit; }
};
//+------------------------------------------------------------------------------------------+
//| Set the percentages to be used if the risk calculation mode was chosen as "percentage". |
//+------------------------------------------------------------------------------------------+
//Note: if you have chosen the "money" mode, it is not necessary to set this method.
void CRiskManagemet::SetPorcentages(double percentage_or_money_mdl,double percentage_or_money_mwl,double percentage_or_money_gmlpo,double percentage_or_money_ml,double percentage_or_money_mdp_)
{
this.gmlpo.assigned_percentage = percentage_or_money_gmlpo;
this.mdl.assigned_percentage = percentage_or_money_mdl;
this.ml.assigned_percentage = percentage_or_money_ml;
this.mdp.assigned_percentage = percentage_or_money_mdp_;
this.mwl.assigned_percentage = percentage_or_money_mwl;
}
//+----------------------------------------------------------------------------------------+
//| Function to set how losses or gains are calculated, |
//| by percentage applied to (balance, equity, free margin or net profit) or simply money. |
//+----------------------------------------------------------------------------------------+
//Note: This method is mandatory, it must be executed in the OnInit event.
void CRiskManagemet::SetEnums(ENUM_RISK_CALCULATION_MODE mode_mdl_,ENUM_RISK_CALCULATION_MODE mode_mwl_,ENUM_RISK_CALCULATION_MODE mode_gmlpo_,ENUM_RISK_CALCULATION_MODE mode_ml_,ENUM_RISK_CALCULATION_MODE mode_mdp_)
{
this.gmlpo.mode_calculation_risk = mode_gmlpo_;
this.mdl.mode_calculation_risk = mode_mdl_;
this.mdp.mode_calculation_risk = mode_mdp_;
this.ml.mode_calculation_risk = mode_ml_;
this.mwl.mode_calculation_risk = mode_mwl_;
//-- En caso se haya escojido el modo dinero, asignamos la variable que guarda el dinero o porcentage alas varialbes correspondientes
this.gmlpo.value = this.gmlpo.mode_calculation_risk == money ? this.gmlpo.percentage_applied_to : 0;
this.mdp.value = this.mdp.mode_calculation_risk == money ? this.mdp.percentage_applied_to : 0;
this.mdl.value = this.mdl.mode_calculation_risk == money ? this.mdl.percentage_applied_to : 0;
this.ml.value = this.ml.mode_calculation_risk == money ? this.ml.percentage_applied_to : 0;
this.mwl.value = this.mwl.mode_calculation_risk == money ? this.mwl.percentage_applied_to : 0;
}
//+----------------------------------------------------------------------------------------------------+
//| Function to set variables that will be used to know which account variable |
//| (free margin, balance, equity, net profit) will be applied to the percentages chosen by the user. |
//+----------------------------------------------------------------------------------------------------+
//Note: if you have chosen the "money" mode, it is not necessary to set this method.
void CRiskManagemet::SetApplieds(ENUM_APPLIED_PERCENTAGES applied_mdl_,ENUM_APPLIED_PERCENTAGES applied_mwl_,ENUM_APPLIED_PERCENTAGES applied_gmlpo_,ENUM_APPLIED_PERCENTAGES applied_ml_,ENUM_APPLIED_PERCENTAGES applied_mdp_)
{
this.gmlpo.percentage_applied_to = applied_gmlpo_;
this.mdl.percentage_applied_to = applied_mdl_;
this.mdp.percentage_applied_to = applied_mdp_;
this.mwl.percentage_applied_to = applied_mwl_;
this.ml.percentage_applied_to = applied_ml_;
}
//+---------------------------------------------------------------------------+
//| Function to close all positions opened by the magic number or by the user |
//+---------------------------------------------------------------------------+
void CRiskManagemet::CloseAllPositions(int flags = FLAG_CLOSE_ALL_LOSS | FLAG_CLOSE_ALL_PROFIT)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong position_ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(position_ticket))
continue; // If you don't select the position, continue
double profit = PositionGetDouble(POSITION_PROFIT);
// Check flags before closing the position
if((flags & FLAG_CLOSE_ALL_PROFIT) != 0 && profit > 0) // Close only profit positions
{
trade.PositionClose(position_ticket);
}
else
if((flags & FLAG_CLOSE_ALL_LOSS) != 0 && profit < 0) // Close only losing positions
{
trade.PositionClose(position_ticket);
}
}
}
//+----------------------------------------------------------------------------------+
//| Get the ideal stop loss based on a specified lot and the maximum loss per trade |
//+----------------------------------------------------------------------------------+
long CRiskManagemet::GetSL(const ENUM_ORDER_TYPE type, double DEVIATION = 100, double STOP_LIMIT = 50)
{
double lot;
return CalculateSL(type,this.gmlpo.value,lot,DEVIATION,STOP_LIMIT);
}
//+-----------------------------------------------------------------------------------------------+
//| Function to obtain the ideal lot based on the maximum loss per operation and the stop loss |
//+-----------------------------------------------------------------------------------------------+
double CRiskManagemet::GetLote(const ENUM_ORDER_TYPE order_type, const ENUM_GET_LOT mode_get_lot)
{
if(mode_get_lot == GET_LOT_BY_STOPLOSS_AND_RISK_PER_OPERATION)
{
double MaxLote = GetMaxLote(order_type);
SetNMPLO(this.lote,MaxLote);
PrintFormat("Maximum loss in case the next operation fails %.2f ", this.nmlpo);
}
else
{
this.lote = GetLotByRiskPerOperation(this.gmlpo.value,order_type);
}
return this.lote;
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CRiskManagemet::CRiskManagemet(ulong magic_number_ = NOT_MAGIC_NUMBER,ENUM_MODE_RISK_MANAGEMENT mode_risk_management_ = personal_account, double account_propfirm_balance =0)
{
if(magic_number_ == NOT_MAGIC_NUMBER)
{
Print("| Warning | No magic number has been chosen, taking into account all the magic numbers and the user's trades");
}
//---
this.account_balance_propfirm = account_propfirm_balance ;
trade = new CTrade();
this.account_profit = GetNetProfitSince(true,this.magic_number,D'1972.01.01 00:00');
this.magic_number = magic_number_;
this.mode_risk_managemet = mode_risk_management_;
//---
this.last_day_time = iTime(_Symbol,PERIOD_D1,0);
this.last_weekly_time = iTime(_Symbol,PERIOD_W1,0);
this.init_time =magic_number_ != NOT_MAGIC_NUMBER ? TimeCurrent() : D'1972.01.01 00:00';
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CRiskManagemet::~CRiskManagemet()
{
delete trade;
}
//+------------------------------------------------------------------+
//| Function that runs every new day |
//+------------------------------------------------------------------+
void CRiskManagemet::OnNewDay(void)
{
SetMWL();
SetMDL();
SetML();
SetMDP();
SetGMLPO();
this.daily_profit = 0;
this.last_day_time = iTime(_Symbol,PERIOD_D1,0);
Print(" New day ");
Print(StringFormat("%-6s| %s", "Losses", "Loss"));
Print(StringFormat("%-6s| %.2f", "MDP", this.mdp.value));
Print(StringFormat("%-6s| %.2f", "MWL", this.mwl.value));
Print(StringFormat("%-6s| %.2f", "ML", this.ml.value));
Print(StringFormat("%-6s| %.2f", "MDl", this.mdl.value));
Print(StringFormat("%-6s| %.2f", "GMLPO", this.gmlpo.value));
}
//+------------------------------------------------------------------+
//| Function that runs every new week |
//+------------------------------------------------------------------+
void CRiskManagemet::OnNewWeek(void)
{
this.last_weekly_time = iTime(_Symbol,PERIOD_W1,0);
this.weekly_profit = 0;
}
//+------------------------------------------------------------------+
//| Function to obtain the value of a loss or gain based |
//| on the applied value (balance, free margin, equity, net profit) |
//+------------------------------------------------------------------+
double CRiskManagemet::GetValorWithApplied(const ENUM_APPLIED_PERCENTAGES applied,const double percentage_)
{
if(this.mode_risk_managemet == propfirm_ftmo && percentage_ != this.mdp.assigned_percentage && percentage_ != this.gmlpo.assigned_percentage)
return this.account_balance_propfirm * (percentage_/100.0);
switch(applied)
{
case Balance:
return NormalizeDouble((percentage_/100.0) * AccountInfoDouble(ACCOUNT_BALANCE),2);
case ganancianeta:
{
if(this.account_profit <= 0)
{
PrintFormat("The total profit of the account which is %+.2f is invalid or negative",this.account_profit);
return 0;
}
else
return NormalizeDouble((percentage_/100.0) * this.account_profit,2);
}
case free_margin:
{
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0)
{
PrintFormat("free margin of %+.2f is invalid",AccountInfoDouble(ACCOUNT_MARGIN_FREE));
return 0;
}
else
return NormalizeDouble((percentage_/100.0) * AccountInfoDouble(ACCOUNT_MARGIN_FREE),2);
}
case equity:
return NormalizeDouble((percentage_/100.0) * AccountInfoDouble(ACCOUNT_EQUITY),2);
default:
Print("Critical Error | It was not found that: ", EnumToString(applied), " be part of the allowed enumeration");
}
return 0;
}