mql5/Include/Risk_Management.mqh
2026-01-26 14:28:49 +03:00

640 líneas
60 KiB
MQL5

Este archivo contiene caracteres Unicode invisibles

Este archivo contiene caracteres Unicode invisibles que son indistinguibles para los humanos, pero que pueden ser procesados de forma diferente por un ordenador. Si crees que esto es intencional, puedes ignorar esta advertencia. Usa el botón de Escape para revelarlos.

//+------------------------------------------------------------------+
//| 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ó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;
}