#property library #include #include #include class CalculatePositionData : public CObject{ protected: CTrade trade; TimeZones tz; CPositionInfo position; MyFunctions mf; bool check_lots(double &lots, string symbol); bool normalise_price(double price, double &normalizedPrice, string symbol); // double adjusted_point(string symbol); public: double calculate_stoploss(string symbol, double price, int order_side, string _sl_mode, double sl_var, ENUM_TIMEFRAMES atr_period); double calculate_take_profit(string symbol, double price, double stoploss, int order_side, string mode_tp, double tp_var, ENUM_TIMEFRAMES atr_period); double calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var); double calculate_trading_cost(string symbol, ulong position_ticket); }; double CalculatePositionData::calculate_stoploss(string symbol, double price, int order_side, string mode_sl, double sl_var, ENUM_TIMEFRAMES atr_period){ // order_side int must be 1 for BUY or 2 for double sl=0; if(mode_sl=="NO_STOPLOSS"){ sl=0; } if(mode_sl=="SL_BREAKEVEN"){ // https://www.youtube.com/watch?v=idPulZ3_iR0 Alert("Not implemented yet yet"); } if(mode_sl=="SL_FIXED_PIPS"){ // pips/poins = https://www.mql5.com/en/forum/187757 double adj_point = mf.adjusted_point(symbol); if(order_side == 1){ sl = price - sl_var * adj_point; if(!normalise_price(sl,sl,symbol)){return false;} } if(order_side == 2){ sl = price + sl_var * adj_point; if(!normalise_price(sl,sl,symbol)){return false;} } } if(mode_sl=="SL_FIXED_PERCENT"){ if(order_side == 1){ sl = (-1.0 * sl_var * price / 100.00) + price; if(!normalise_price(sl,sl,symbol)){return false;} } if(order_side == 2){ sl = sl_var * price / 100.00 + price; if(!normalise_price(sl,sl,symbol)){return false;} } } if(mode_sl=="SL_ATR_MULTIPLE"){ int atr_handle = iATR(symbol,atr_period,14); double atr[]; ArraySetAsSeries(atr,true); CopyBuffer(atr_handle,MAIN_LINE,1,1,atr); if(order_side == 1){ sl = price - (atr[0] * sl_var); if(!normalise_price(sl,sl,symbol)){return false;} } if(order_side == 2){ sl = price + (atr[0] * sl_var); if(!normalise_price(sl,sl,symbol)){return false;} } } if(mode_sl=="SL_SPECIFIED_VALUE"){ double adj_point = mf.adjusted_point(symbol); if(order_side == 1){ double pip_50_sl = price - 10 * adj_point; if(sl_var >= pip_50_sl){ sl = pip_50_sl; } else sl = sl_var; if(!normalise_price(sl,sl,symbol)){return false;} } if(order_side == 2){ double pip_50_sl = price + 10 * adj_point; if(sl_var <= pip_50_sl){ sl = pip_50_sl; } else sl = sl_var; sl = sl = sl_var; if(!normalise_price(sl,sl,symbol)){return false;} } } return sl; } double CalculatePositionData::calculate_take_profit(string symbol, double price, double stoploss, int order_side, string mode_tp, double _tp_var, ENUM_TIMEFRAMES atr_period){ // order_side int must be 1 for BUY or 2 for SELL double tp=0; if(mode_tp=="NO_TAKE_PROFIT"){ tp=0; } if(mode_tp=="TP_FIXED_PIPS"){ double adj_point = mf.adjusted_point(symbol); if(order_side == 1){ tp = price + _tp_var * adj_point; if(!normalise_price(tp,tp,symbol)){return false;} } if(order_side == 2){ tp = price - _tp_var * adj_point; if(!normalise_price(tp,tp,symbol)){return false;} } } if(mode_tp=="TP_FIXED_PERCENT"){ if(order_side == 1){ tp = _tp_var * price / 100.00 + price; if(!normalise_price(tp,tp,symbol)){return false;} } if(order_side == 2){ tp = (-1 * _tp_var * price / 100.00) + price; if(!normalise_price(tp,tp,symbol)){return false;} } } if(mode_tp=="TP_ATR_MULTIPLE"){ int atr_handle = iATR(symbol,atr_period,14); double atr[]; ArraySetAsSeries(atr,true); CopyBuffer(atr_handle,MAIN_LINE,1,1,atr); if(order_side == 1){ tp = price + (atr[0] * _tp_var); if(!normalise_price(tp,tp,symbol)){return false;} } if(order_side == 2){ tp = price - (atr[0] * _tp_var); if(!normalise_price(tp,tp,symbol)){return false;} } } if(mode_tp=="TP_SL_MULTIPLE"){ if(order_side == 1){ double sl_size = price - stoploss; tp = price + (_tp_var * sl_size); if(!normalise_price(tp,tp,symbol)){return false;} } if(order_side == 2){ double sl_size = stoploss - price; tp = price - (_tp_var * sl_size); if(!normalise_price(tp,tp,symbol)){return false;} } } if(mode_tp=="TP_SPECIFIED_VALUE"){ if(_tp_var!=0){ double adj_point = mf.adjusted_point(symbol); if(order_side == 1){ double pip_limit = price + 10 * adj_point; if(_tp_var <= pip_limit){ tp = pip_limit; } else tp = _tp_var; if(!normalise_price(tp,tp,symbol)){return false;} } if(order_side == 2){ double pip_limit = price - 10 * adj_point; if(_tp_var >= pip_limit){ tp = pip_limit; } else tp = _tp_var; tp = tp = _tp_var; if(!normalise_price(tp,tp,symbol)){return false;} } } } return tp; } double CalculatePositionData::calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var){ double lots = 0; double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double account_value = fmin(fmin(AccountInfoDouble(ACCOUNT_EQUITY),AccountInfoDouble(ACCOUNT_BALANCE)),AccountInfoDouble(ACCOUNT_MARGIN_FREE)); double risk_money = account_value * lot_var / 100; if(mode_lot=="LOT_MODE_FIXED"){ lots = lot_var; } if(mode_lot=="LOT_MODE_PCT_RISK"){ double money_lot_step = (sl_distance / tick_size) * tick_value * volume_step; lots = MathFloor(risk_money/money_lot_step) * volume_step; } if(mode_lot=="LOT_MODE_PCT_ACCOUNT"){ double money_lot_step = (price / tick_size) * tick_value * volume_step; lots = MathFloor(risk_money/money_lot_step) * volume_step; } if(!check_lots(lots, symbol)){return false;} return lots; } bool CalculatePositionData::check_lots(double &lots, string symbol){ double min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); if(lotsmax){ Print("Lot size greater than maximum allowed volume. lots:",lots,"max:",max); return false; } lots = (int)MathFloor(lots/step) * step; return true; } bool CalculatePositionData::normalise_price(double price, double &normalizedPrice, string symbol){ double tickSize; if(!SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE,tickSize)){ Print("Failed to get tick size"); return false; } int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); normalizedPrice = NormalizeDouble(MathRound(price/tickSize)*tickSize, symbol_digits); return true; } double CalculatePositionData::calculate_trading_cost(string symbol, ulong position_ticket){ position.SelectByTicket(position_ticket); double swap = PositionGetDouble(POSITION_SWAP); double commission = PositionGetDouble(POSITION_COMMISSION); double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double lots = PositionGetDouble(POSITION_VOLUME); double trading_cost = -1 * ((commission + swap) / tick_value * tick_size / lots); return trading_cost; }