//+------------------------------------------------------------------+ //| Risk Management.mqh | //| Your name | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Your name " #property link "https://www.mql5.com" #property strict #include //+-------------------------------------------------------------------------------------------------+ //+----------------------------------- 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ón de comprobació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ó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ón ha tenido é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; }