//+------------------------------------------------------------------+ //| Breakeven.mqh | //| Copyright 2025, Niquel y Leo. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Niquel y Leo." #property link "https://www.mql5.com" #property strict #ifndef BREAKEVEN_MQH #define BREAKEVEN_MQH #include "..\\RM\\RiskManagement.mqh" //+------------------------------------------------------------------+ //| Break Even Structs | //+------------------------------------------------------------------+ struct position_be { ulong ticket; //Position Ticket double breakeven_price; //Be price double price_to_beat; //Price to exceed to reach break even ENUM_POSITION_TYPE type;//Position type }; enum ENUM_BREAKEVEN_TYPE { BREAKEVEN_TYPE_RR = 0, //By RR BREAKEVEN_TYPE_FIXED_POINTS = 1, //By FixedPoints BREAKEVEN_TYPE_ATR = 2 //By Atr }; struct BreakEvenParams { long integer_value; string string_value; double double_value; CAtrUltraOptimized* atr_pointer_value; }; //--- class CBreakEvenBase; class CBreakEven; class CBreakEvenAtr; class CBreakEvenRR; class CBreakEvenSimple; //--- #define CBREAKEVEN_RESERVE_REMOVE_BE_ARR 3 #define CBREAKEVEN_RESERVE_ARR 3 //+------------------------------------------------------------------+ //| Main class to apply break even | //+------------------------------------------------------------------+ class CBreakEvenBase : public CAccountGestor { private: int m_indices_to_remove_be[]; protected: CTrade obj_trade; //CTrade object MqlTick tick; //tick structure string symbol; //current symbol double point_value; //value of the set symbol point position_be PostionsBe[]; //array of positions of type Positions ulong magic; //magic number of positions to make break even bool pause; //Boolean variable to activate the pause of the review, this is used to prevent the array from going out of range int num_params; //Number of parameters the class needs bool m_automatic; public: CBreakEvenBase(string symbol_, ulong magic_); //--- inline bool Automatic() const { return m_automatic; } void Automatic(bool auto) { m_automatic = auto; } //--- inline string Simbolo() const { return symbol; } inline ulong Magic() const { return magic; } //--- inline int GetNumParams() const { return num_params; } //--- General virtual bool Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) = 0; void BreakEven(); void OnOpenClosePosition(const ROnOpenClosePosition &pos) override; //--- Setter principal virtual void Set(BreakEvenParams ¶ms[]) = 0; }; //+------------------------------------------------------------------+ //| Contructor | //+------------------------------------------------------------------+ CBreakEvenBase::CBreakEvenBase(string symbol_, ulong magic_) : pause(false), m_automatic(true) { if(magic_ != NOT_MAGIC_NUMBER) obj_trade.SetExpertMagicNumber(magic_); obj_trade.LogLevel(LOG_LEVEL_NO); //--- this.symbol = symbol_; this.num_params = 0; this.magic = magic_; this.point_value = SymbolInfoDouble(symbol_, SYMBOL_POINT); //--- ArrayResize(PostionsBe, 0, CBREAKEVEN_RESERVE_ARR); } //+------------------------------------------------------------------+ //| OnTradeTransactionEvent | //+------------------------------------------------------------------+ void CBreakEvenBase::OnOpenClosePosition(const ROnOpenClosePosition &pos) { if(m_automatic && pos.deal_entry_type == DEAL_ENTRY_IN) { const ulong position_magic = pos.position.magic; if((this.magic == position_magic || this.magic == NOT_MAGIC_NUMBER)) { if(Add(pos.position.ticket, pos.position.open_price, pos.position.firt_sl, pos.position.type, pos.position.open_time)) LogInfo(StringFormat("Ticket %I64u has been added to the array of positions", pos.position.ticket), FUNCION_ACTUAL); } return; } if(pos.deal_entry_type == DEAL_ENTRY_OUT) { this.pause = true; if(RemoveIndexFromAnArrayOfPositions(PostionsBe, pos.position.ticket, CBREAKEVEN_RESERVE_ARR)) LogCaution(StringFormat("Ticket %I64u has been removed from the positions array, breakeven could not be applied", pos.position.ticket), FUNCION_ACTUAL); this.pause = false; } } //+------------------------------------------------------------------+ //| Function to make break even | //+------------------------------------------------------------------+ void CBreakEvenBase::BreakEven(void) { if(this.PostionsBe.Size() < 1 || pause) return; SymbolInfoTick(this.symbol, tick); //--- ArrayResize(m_indices_to_remove_be, 0, CBREAKEVEN_RESERVE_REMOVE_BE_ARR); //--- for(int i = 0 ; i < ArraySize(this.PostionsBe) ; i++) { ulong ticket = this.PostionsBe[i].ticket; if(tick.ask >= this.PostionsBe[i].price_to_beat && this.PostionsBe[i].type == POSITION_TYPE_BUY) { double position_tp = PositionGetDouble(POSITION_TP); obj_trade.PositionModify(ticket, this.PostionsBe[i].breakeven_price, position_tp); AddArrayNoVerification(m_indices_to_remove_be, i, CBREAKEVEN_RESERVE_REMOVE_BE_ARR); } else if(tick.bid <= this.PostionsBe[i].price_to_beat && this.PostionsBe[i].type == POSITION_TYPE_SELL) { double position_tp = PositionGetDouble(POSITION_TP); obj_trade.PositionModify(ticket, this.PostionsBe[i].breakeven_price, position_tp); AddArrayNoVerification(m_indices_to_remove_be, i, CBREAKEVEN_RESERVE_REMOVE_BE_ARR); } } RemoveMultipleIndexes(this.PostionsBe, m_indices_to_remove_be, CBREAKEVEN_RESERVE_REMOVE_BE_ARR); } //+------------------------------------------------------------------+ //| class CBreakEvenSimple | //+------------------------------------------------------------------+ class CBreakEvenSimple : public CBreakEvenBase { private: int extra_points_be, points_be; public: CBreakEvenSimple(string symbol_, ulong magic_) : CBreakEvenBase(symbol_, magic_) { this.extra_points_be = 0; this.points_be = 0; this.num_params = 2;} bool Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) override; void Set(BreakEvenParams ¶ms[]) override; void SetSetSimple(int points_be_, int extra_points_be_); }; //+----------------------------------------------------------------------------------------------+ //| Create a new structure and add it to the main array using the 'AddToArrayBe' function | //+----------------------------------------------------------------------------------------------+ bool CBreakEvenSimple::Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) { position_be new_pos; new_pos.breakeven_price = position_type == POSITION_TYPE_BUY ? open_price + (point_value * extra_points_be) : open_price - (point_value * extra_points_be); new_pos.type = position_type; new_pos.price_to_beat = position_type == POSITION_TYPE_BUY ? open_price + (point_value * points_be) : open_price - (point_value * points_be) ; new_pos.ticket = post_ticket; AddArrayNoVerification(this.PostionsBe, new_pos, CBREAKEVEN_RESERVE_ARR); return true; } //+------------------------------------------------------------------+ //| Set attributes of CBreakEvenSimple class with MqlParam array | //+------------------------------------------------------------------+ void CBreakEvenSimple::Set(BreakEvenParams ¶ms[]) { if(params.Size() < 2) { LogCriticalError(StringFormat("MqlParams array size is less than 2", params.Size()), FUNCION_ACTUAL); ExpertRemove(); return; } SetSetSimple(int(params[0].integer_value), int(params[1].integer_value)); } //+------------------------------------------------------------------+ //| Function to set member variables without using MalParams | //+------------------------------------------------------------------+ void CBreakEvenSimple::SetSetSimple(int points_be_, int extra_points_be_) { if(points_be_ <= 0) { LogError(StringFormat("The points to set the breakeven %I32d are invalid.", points_be_), FUNCION_ACTUAL); ExpertRemove(); return; } if(extra_points_be_ < 0) { LogFatalError(StringFormat("The extra points %I32d for the breakeven price are invalid.", extra_points_be_), FUNCION_ACTUAL); ExpertRemove(); return; } if(extra_points_be_ >= points_be_) { LogWarning("The break even points (breakeven_price) is greater than the breakeven points (price_to_beat)\nTherefore the value of the extra breakeven points will be modified 0.", FUNCION_ACTUAL); this.points_be = points_be_; //0 this.extra_points_be = 0; //1 return; } this.points_be = points_be_; //0 this.extra_points_be = extra_points_be_; //1 } //+------------------------------------------------------------------+ //| Class to apply break even based on atr | //+------------------------------------------------------------------+ #define POINTER_INSTEAD_OF_PERIOD 0 //--- class CBreakEvenAtr class CBreakEvenAtr : public CBreakEvenBase { private: CAtrUltraOptimized* atr_ultra; double atr_multiplier_be; double atr_multiplier_extra_be; public: CBreakEvenAtr(string symbol_, ulong magic_) : CBreakEvenBase(symbol_, magic_), atr_multiplier_be(1.0), atr_multiplier_extra_be(1.0) { this.num_params = 5; } bool Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) override; void Set(BreakEvenParams ¶ms[]) override; void SetSimple(CAtrUltraOptimized * atr_pointer, double atr_multiplier_extra_be_, double atr_multiplier_be_); void SetSimple(int atr_period, int atr_idx_, double atr_multiplier_extra_be_, double atr_multiplier_be_, ENUM_TIMEFRAMES timeframe); }; //+------------------------------------------------------------------+ //| Function to set CBreakEvenAtr variables with MqlParams array | //+------------------------------------------------------------------+ void CBreakEvenAtr::Set(BreakEvenParams ¶ms[]) { if(params.Size() < 5) { LogError(StringFormat("The size of the array MqlParams %I32u to set the atr is less than 5", params.Size()), FUNCION_ACTUAL); ExpertRemove(); return; } if(params[4].integer_value == POINTER_INSTEAD_OF_PERIOD) //4 { /* this.atr_pointer = (int)params[0].atr_pointer_value; //0 this.atr_multiplier_be = params[1].double_value; //1 this.atr_multiplier_extra_be = params[2].double_value; //2 */ SetSimple(params[0].atr_pointer_value, params[2].double_value, params[1].double_value); } else { /* this.atr_idx = (int)params[0].integer_value; //0 this.atr_multiplier_be = params[1].double_value; //1 this.atr_multiplier_extra_be = params[2].double_value; //2 ENUM_TIMEFRAMES timeframe = (ENUM_TIMEFRAMES)params[3].integer_value; //3 int period = (int)params[4].integer_value; //4 */ SetSimple((int)params[4].integer_value, (int)params[0].integer_value, params[2].double_value, params[1].double_value, (ENUM_TIMEFRAMES)params[3].integer_value); } } //+------------------------------------------------------------------------------------+ //| Function to set the values ​​of the CBreakEvenAtr class without using MqlParams | //| Using the handle instead of period and timeframe | //+------------------------------------------------------------------------------------+ void CBreakEvenAtr::SetSimple(CAtrUltraOptimized* atr_pointer, double atr_multiplier_extra_be_, double atr_multiplier_be_) { if(atr_multiplier_extra_be_ >= atr_multiplier_be_) { LogError("The multiplier of the atr to calculate the price be is greater than or equal to the multiplier to set the be", FUNCION_ACTUAL); Remover(); return; } if(CheckPointer(atr_pointer) == POINTER_INVALID) { LogFatalError("El puntero a CAtrUltraOptimized* es invaldio", FUNCION_ACTUAL); Remover(); return; } this.atr_ultra = atr_pointer; this.atr_multiplier_be = atr_multiplier_be_; this.atr_multiplier_extra_be = atr_multiplier_extra_be_; } //+------------------------------------------------------------------------------------+ //| Function to set the values ​​of the CBreakEvenAtr class without using MqlParams | //| Configuring the handle with the period and timeframe. | //+------------------------------------------------------------------------------------+ void CBreakEvenAtr::SetSimple(int atr_period, int atr_idx_, double atr_multiplier_extra_be_, double atr_multiplier_be_, ENUM_TIMEFRAMES timeframe) { CAtrUltraOptimized* atr_op = new CAtrUltraOptimized(); atr_op.SetVariables(timeframe, this.symbol, atr_idx_, atr_period); atr_op.SetInternalPointer(); SetSimple(atr_op, atr_multiplier_extra_be_, atr_multiplier_be_); } //+------------------------------------------------------------------+ //| Function to add an element to the positions array | //+------------------------------------------------------------------+ bool CBreakEvenAtr::Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) { double val = atr_ultra.base.GetAtrValue(open_time); position_be new_pos; new_pos.breakeven_price = position_type == POSITION_TYPE_BUY ? open_price + (val * atr_multiplier_extra_be) : open_price - (val * atr_multiplier_extra_be); new_pos.type = position_type; new_pos.price_to_beat = position_type == POSITION_TYPE_BUY ? open_price + (val * atr_multiplier_be) : open_price - (val * atr_multiplier_be); new_pos.ticket = post_ticket; AddArrayNoVerification(this.PostionsBe, new_pos, CBREAKEVEN_RESERVE_ARR); return true; } //+------------------------------------------------------------------+ //| CBreakEvenRR Class | //+------------------------------------------------------------------+ enum ENUM_TYPE_EXTRA_BE_BY_RRR { EXTRA_BE_RRR_BY_ATR, //By Atr EXTRA_BE_RRR_BY_FIXED_POINTS //By Fixed Points }; //--- class CBreakEvenRR class CBreakEvenRR : public CBreakEvenBase { private: CAtrUltraOptimized* atr_ultra; double coefficient_rr; //Coefficient of rr ENUM_TYPE_EXTRA_BE_BY_RRR type; double extra_value_be; //Extra value that will be added to the opening price of the position to obtain the breakeven price //Note: if the type is atr this will contain the atr multiplier, if not it will contain the value already multiplied by the point value public: CBreakEvenRR(string symbol_, ulong magic_); bool Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) override; void Set(BreakEvenParams ¶ms[]) override; void SetSimple(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, CAtrUltraOptimized * atr_ptr); void SetSimple(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, int idx_atr_, ENUM_TIMEFRAMES tf_atr, int atr_period_); }; //+------------------------------------------------------------------+ //| Contructor | //+------------------------------------------------------------------+ void CBreakEvenRR::CBreakEvenRR(string symbol_, ulong magic_) : CBreakEvenBase(symbol_, magic_), coefficient_rr(1.0), extra_value_be(100.0), type(EXTRA_BE_RRR_BY_FIXED_POINTS) { this.num_params = 6; } //+------------------------------------------------------------------+ //| Function to set break even values ​​by rr with MqlParams | //+------------------------------------------------------------------+ void CBreakEvenRR::Set(BreakEvenParams ¶ms[]) { if((int)params.Size() < num_params) { LogError(StringFormat("The size of the MqlParams array %I32u to set the be by rr is less than 2", params.Size()), FUNCION_ACTUAL); ExpertRemove(); return; } if(params[5].integer_value == POINTER_INSTEAD_OF_PERIOD) { //-> (0)double rr_a_put_the_break_even,(1) ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, (2)double atr_multiplier_or_extra_points, (3)int idx_atr_, (4)int atr_handle_ SetSimple(params[0].double_value, (ENUM_TYPE_EXTRA_BE_BY_RRR)params[1].integer_value, params[2].double_value, params[4].atr_pointer_value); } else { //-> (0)double rr_a_put_the_break_even,(1) ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, (2)double atr_multiplier_or_extra_points, (3)int idx_atr_, (4)ENUM_TIMEFRAMES tf_atr, (5)int atr_period_ SetSimple(params[0].double_value, (ENUM_TYPE_EXTRA_BE_BY_RRR)params[1].integer_value, params[2].double_value, (int)params[3].integer_value, (ENUM_TIMEFRAMES)params[4].integer_value, (int)params[5].integer_value); } } //+------------------------------------------------------------------+ //| Function to set break even values by rr without MqlParams | //+------------------------------------------------------------------+ void CBreakEvenRR::SetSimple(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, CAtrUltraOptimized* atr_ptr) { ResetLastError(); if(coefficient_rr <= 0.00) { LogCriticalError(StringFormat("The %+f coefficient of 'reward' is invalid", coefficient_rr), FUNCION_ACTUAL); ExpertRemove(); return; } if(atr_multiplier_or_extra_points <= 0.00) { LogCriticalError(StringFormat("The atr multiplier or extra points %f is less than or equal to 0", atr_multiplier_or_extra_points), FUNCION_ACTUAL); ExpertRemove(); return; } if(type_extra != EXTRA_BE_RRR_BY_ATR && type_extra != EXTRA_BE_RRR_BY_FIXED_POINTS) { LogCriticalError(StringFormat("The type of extra value %s is invalid", EnumToString(type_extra)), FUNCION_ACTUAL); ExpertRemove(); return; } this.type = type_extra; this.coefficient_rr = rr_a_put_the_break_even; if(type_extra == EXTRA_BE_RRR_BY_ATR) { if(CheckPointer(atr_ptr) == POINTER_INVALID) { LogFatalError("El puntero 'atr_ptr' es invalido", FUNCION_ACTUAL); ExpertRemove(); return; } this.atr_ultra = atr_ptr; this.extra_value_be = atr_multiplier_or_extra_points; } else this.extra_value_be = atr_multiplier_or_extra_points * this.point_value; } //+------------------------------------------------------------------+ //| Function to set break even values by rr without MqlParams | //+------------------------------------------------------------------+ void CBreakEvenRR::SetSimple(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, int idx_atr_, ENUM_TIMEFRAMES tf_atr, int atr_period_) { if(type_extra != EXTRA_BE_RRR_BY_ATR && type_extra != EXTRA_BE_RRR_BY_FIXED_POINTS) { LogCriticalError(StringFormat("The type of extra value %s is invalid", EnumToString(type_extra)), FUNCION_ACTUAL); ExpertRemove(); return; } if(atr_period_ < 0) { LogError(StringFormat("The atr period %d is invalid", atr_period_), FUNCION_ACTUAL); ExpertRemove(); return; } if(type_extra == EXTRA_BE_RRR_BY_ATR) { CAtrUltraOptimized* atr_ptr = new CAtrUltraOptimized(); atr_ptr.SetVariables(tf_atr, this.symbol, idx_atr_, atr_period_); atr_ptr.SetInternalPointer(); SetSimple(rr_a_put_the_break_even, type_extra, atr_multiplier_or_extra_points, atr_ptr); return; } SetSimple(rr_a_put_the_break_even, type_extra, atr_multiplier_or_extra_points, NULL); } //+------------------------------------------------------------------+ //| Function to add an element to the positions array | //+------------------------------------------------------------------+ bool CBreakEvenRR::Add(ulong post_ticket, double open_price, double sl_price, ENUM_POSITION_TYPE position_type, datetime open_time) { if(sl_price <= 0.00) { LogError(StringFormat("Position %I64u with stop loss %+f has sl less than 0", post_ticket, sl_price), FUNCION_ACTUAL); return false; } double val = this.extra_value_be; if(type == EXTRA_BE_RRR_BY_ATR) { val *= atr_ultra.base.GetAtrValue(open_time); } double diff = fabs(open_price - sl_price); if((diff * coefficient_rr) <= val) { LogError(StringFormat("The distance from the opening price %f where the stoploss is located is greater than or equal to the price to trigger the breakeven", this.extra_value_be), FUNCION_ACTUAL); return false; } position_be new_pos; new_pos.breakeven_price = position_type == POSITION_TYPE_BUY ? open_price + val : open_price - val; new_pos.type = position_type; new_pos.price_to_beat = position_type == POSITION_TYPE_BUY ? open_price + (coefficient_rr * diff) : open_price - (coefficient_rr * diff); new_pos.ticket = post_ticket; LogInfo(StringFormat("El precio del nuevo stop loss sera %f, valor actual del atr[%d] = %f", new_pos.breakeven_price, atr_ultra.Index(), val), FUNCION_ACTUAL); AddArrayNoVerification(this.PostionsBe, new_pos, CBREAKEVEN_RESERVE_ARR); return true; } //+------------------------------------------------------------------+ //| CBreakEven class | //+------------------------------------------------------------------+ struct BreakEvenParamsInfo { BreakEvenParams params[]; }; //--- class CBreakEven { private: ulong magic; string symbol; BreakEvenParamsInfo parameters[]; CBreakEvenBase * CreateBreakEven(ENUM_BREAKEVEN_TYPE type); public: CBreakEven(ulong magic_, string symbol_); ~CBreakEven(); CBreakEvenBase* obj; //--- Setters void SetInternalPointer(ENUM_BREAKEVEN_TYPE type); void SetBeByFixedPoints(int points_be_, int extra_points_be_); void SetBeByAtr(int atr_period, int atr_idx_, double atr_multiplier_extra_be_, double atr_multiplier_be_, ENUM_TIMEFRAMES timeframe); void SetBeByAtr(double atr_multiplier_be, double atr_multiplier_extra_be, CAtrUltraOptimized* atr_ptr); void SetBeByRR(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, CAtrUltraOptimized* atr_ptr); void SetBeByRR(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, int idx_atr_, ENUM_TIMEFRAMES tf_atr, int atr_period_); }; //+------------------------------------------------------------------+ //| Contructor | //+------------------------------------------------------------------+ CBreakEven::CBreakEven(ulong magic_, string symbol_) { this.magic = magic_; this.symbol = symbol_; obj = NULL; ArrayResize(parameters, 3); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CBreakEven::~CBreakEven() { //Obj is not deleted since it works with CAccountStatus, without it it cannot do anything } //+------------------------------------------------------------------+ //| Set rr without handle | //+------------------------------------------------------------------+ void CBreakEven::SetBeByRR(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, int idx_atr_, ENUM_TIMEFRAMES tf_atr, int atr_period_) { ArrayResize(parameters[int(BREAKEVEN_TYPE_RR)].params, 6); parameters[BREAKEVEN_TYPE_RR].params[0].double_value = rr_a_put_the_break_even; parameters[BREAKEVEN_TYPE_RR].params[1].integer_value = (int)type_extra; parameters[BREAKEVEN_TYPE_RR].params[2].double_value = atr_multiplier_or_extra_points; parameters[BREAKEVEN_TYPE_RR].params[3].integer_value = idx_atr_; parameters[BREAKEVEN_TYPE_RR].params[4].integer_value = (int)tf_atr; parameters[BREAKEVEN_TYPE_RR].params[5].integer_value = atr_period_; } //+------------------------------------------------------------------+ //| Set rr with handle | //+------------------------------------------------------------------+ void CBreakEven::SetBeByRR(double rr_a_put_the_break_even, ENUM_TYPE_EXTRA_BE_BY_RRR type_extra, double atr_multiplier_or_extra_points, CAtrUltraOptimized* atr_ptr) { ArrayResize(parameters[int(BREAKEVEN_TYPE_RR)].params, 6); parameters[BREAKEVEN_TYPE_RR].params[0].double_value = rr_a_put_the_break_even; parameters[BREAKEVEN_TYPE_RR].params[1].integer_value = (int)type_extra; parameters[BREAKEVEN_TYPE_RR].params[2].double_value = atr_multiplier_or_extra_points; parameters[BREAKEVEN_TYPE_RR].params[3].integer_value = 0; parameters[BREAKEVEN_TYPE_RR].params[4].atr_pointer_value = atr_ptr; parameters[BREAKEVEN_TYPE_RR].params[5].integer_value = POINTER_INSTEAD_OF_PERIOD; } //+------------------------------------------------------------------+ //| Set atr (without handle) | //+------------------------------------------------------------------+ void CBreakEven::SetBeByAtr(int atr_period, int atr_idx_, double atr_multiplier_extra_be_, double atr_multiplier_be_, ENUM_TIMEFRAMES timeframe) { ArrayResize(parameters[int(BREAKEVEN_TYPE_ATR)].params, 5); parameters[BREAKEVEN_TYPE_ATR].params[0].integer_value = atr_idx_; parameters[BREAKEVEN_TYPE_ATR].params[1].double_value = atr_multiplier_be_; parameters[BREAKEVEN_TYPE_ATR].params[2].double_value = atr_multiplier_extra_be_; parameters[BREAKEVEN_TYPE_ATR].params[3].integer_value = int(timeframe); parameters[BREAKEVEN_TYPE_ATR].params[4].integer_value = atr_period; } //+------------------------------------------------------------------+ //| Set atr (with handle) | //+------------------------------------------------------------------+ void CBreakEven::SetBeByAtr(double atr_multiplier_be, double atr_multiplier_extra_be, CAtrUltraOptimized* atr_ptr) { ArrayResize(parameters[int(BREAKEVEN_TYPE_ATR)].params, 5); parameters[BREAKEVEN_TYPE_ATR].params[0].atr_pointer_value = atr_ptr; parameters[BREAKEVEN_TYPE_ATR].params[1].double_value = atr_multiplier_be; parameters[BREAKEVEN_TYPE_ATR].params[2].double_value = atr_multiplier_extra_be; parameters[BREAKEVEN_TYPE_ATR].params[3].integer_value = 0; parameters[BREAKEVEN_TYPE_ATR].params[4].integer_value = POINTER_INSTEAD_OF_PERIOD; } //+------------------------------------------------------------------+ //| Set Fixed Point be | //+------------------------------------------------------------------+ void CBreakEven::SetBeByFixedPoints(int points_be_, int extra_points_be_) { ArrayResize(parameters[int(BREAKEVEN_TYPE_FIXED_POINTS)].params, 2); parameters[BREAKEVEN_TYPE_FIXED_POINTS].params[0].integer_value = points_be_; parameters[BREAKEVEN_TYPE_FIXED_POINTS].params[1].integer_value = extra_points_be_; } //+------------------------------------------------------------------+ //| Dynamically create the correct BreakEven | //+------------------------------------------------------------------+ CBreakEvenBase * CBreakEven::CreateBreakEven(ENUM_BREAKEVEN_TYPE type) { switch(type) { case BREAKEVEN_TYPE_ATR: return new CBreakEvenAtr(this.symbol, this.magic); case BREAKEVEN_TYPE_RR: return new CBreakEvenRR(this.symbol, this.magic); case BREAKEVEN_TYPE_FIXED_POINTS: return new CBreakEvenSimple(this.symbol, this.magic); default: return NULL; } } //+------------------------------------------------------------------+ //| Set Pointer | //+------------------------------------------------------------------+ void CBreakEven::SetInternalPointer(ENUM_BREAKEVEN_TYPE type) { if(CheckPointer(this.obj) == POINTER_DYNAMIC) { delete this.obj; this.obj = NULL; account_status.Remove(obj); } this.obj = CreateBreakEven(type); if(this.obj == NULL) { printf("%s: Critical error | The type %d is invalid.", __FUNCTION__, type); ExpertRemove(); return; } if((int)parameters[type].params.Size() < obj.GetNumParams()) { printf("%s: Error | The parameter array for %s is too small (%I32u elements)", __FUNCTION__, EnumToString(type), parameters[type].params.Size()); delete obj; obj = NULL; account_status.Remove(obj); ExpertRemove(); return; } obj.Set(parameters[type].params); //--- We link the object so that it has access to the account positions account_status.AddItemFast(obj); } //+------------------------------------------------------------------+ #endif //+------------------------------------------------------------------+