Files
mt5-quant-lib/Orders/CalculatePositionData.mqh
T
2025-07-11 16:30:06 +02:00

176 lines
6.7 KiB
Plaintext

#include <MyLibs/Utils/MarketDataUtils.mqh>
#include <MyLibs/Utils/TimeZones.mqh>
#include <MyLibs/Utils/AtrHandleManager.mqh>
#include <Trade/Trade.mqh>
class CalculatePositionData : public CObject {
protected:
CTrade trade;
CPositionInfo position;
MarketDataUtils mdu;
AtrHandleManager atr_manager;
bool check_lots(double& lots, string symbol);
bool normalise_price(double price, double& normalizedPrice, string symbol);
public:
double calculate_stoploss(string symbol, double price, int order_side, string mode_sl, double sl_var, ENUM_TIMEFRAMES atr_tf);
double calculate_take_profit(string symbol, double price, double stoploss, int order_side, string mode_tp, double tp_var, ENUM_TIMEFRAMES atr_tf);
double calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var);
double calculate_trading_cost(string symbol, ulong ticket);
};
//+------------------------------------------------------------------+
double CalculatePositionData::calculate_stoploss(string symbol, double price, int order_side, string mode_sl, double sl_var, ENUM_TIMEFRAMES atr_tf) {
double sl = 0;
if (mode_sl == "NO_STOPLOSS") return 0;
if (mode_sl == "SL_FIXED_PIPS") {
double adj_point = mdu.adjusted_point(symbol);
sl = (order_side == 1) ? price - sl_var * adj_point : price + sl_var * adj_point;
if (!normalise_price(sl, sl, symbol)) return 0;
}
if (mode_sl == "SL_FIXED_PERCENT") {
sl = (order_side == 1) ? price - (sl_var * price / 100.0) : price + (sl_var * price / 100.0);
if (!normalise_price(sl, sl, symbol)) return 0;
}
if (mode_sl == "SL_ATR_MULTIPLE") {
double atr = atr_manager.get_atr_value(symbol, atr_tf, 14);
if (atr == EMPTY_VALUE) return 0;
sl = (order_side == 1) ? price - atr * sl_var : price + atr * sl_var;
if (!normalise_price(sl, sl, symbol)) return 0;
}
if (mode_sl == "SL_SPECIFIED_VALUE") {
double adj_point = mdu.adjusted_point(symbol);
double limit_sl = (order_side == 1) ? price - 10 * adj_point : price + 10 * adj_point;
sl = (order_side == 1) ? fmax(sl_var, limit_sl) : fmin(sl_var, limit_sl);
if (!normalise_price(sl, sl, symbol)) return 0;
}
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_tf) {
double tp = 0;
if (mode_tp == "NO_TAKE_PROFIT") return 0;
if (mode_tp == "TP_FIXED_PIPS") {
double adj_point = mdu.adjusted_point(symbol);
tp = (order_side == 1) ? price + tp_var * adj_point : price - tp_var * adj_point;
if (!normalise_price(tp, tp, symbol)) return 0;
}
if (mode_tp == "TP_FIXED_PERCENT") {
tp = (order_side == 1) ? price + tp_var * price / 100.0 : price - tp_var * price / 100.0;
if (!normalise_price(tp, tp, symbol)) return 0;
}
if (mode_tp == "TP_ATR_MULTIPLE") {
double atr = atr_manager.get_atr_value(symbol, atr_tf, 14);
if (atr == EMPTY_VALUE) return 0;
tp = (order_side == 1) ? price + atr * tp_var : price - atr * tp_var;
if (!normalise_price(tp, tp, symbol)) return 0;
}
if (mode_tp == "TP_SL_MULTIPLE") {
double sl_size = (order_side == 1) ? price - stoploss : stoploss - price;
tp = (order_side == 1) ? price + tp_var * sl_size : price - tp_var * sl_size;
if (!normalise_price(tp, tp, symbol)) return 0;
}
if (mode_tp == "TP_SPECIFIED_VALUE") {
double adj_point = mdu.adjusted_point(symbol);
double limit_tp = (order_side == 1) ? price + 10 * adj_point : price - 10 * adj_point;
tp = (order_side == 1) ? fmin(tp_var, limit_tp) : fmax(tp_var, limit_tp);
if (!normalise_price(tp, tp, symbol)) return 0;
}
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.0;
if (mode_lot == "LOT_MODE_FIXED") {
lots = lot_var;
}
if (mode_lot == "LOT_MODE_PCT_RISK") {
double money_per_step = (sl_distance / tick_size) * tick_value * volume_step;
lots = MathFloor(risk_money / money_per_step) * volume_step;
}
if (mode_lot == "LOT_MODE_PCT_ACCOUNT") {
double money_per_step = (price / tick_size) * tick_value * volume_step;
lots = MathFloor(risk_money / money_per_step) * volume_step;
}
if (!check_lots(lots, symbol)) return 0;
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 (lots < min) {
lots = min;
return true;
}
if (lots > max) {
Print("Lot size exceeds max for ", symbol);
return false;
}
lots = (int)MathFloor(lots / step) * step;
return true;
}
//+------------------------------------------------------------------+
bool CalculatePositionData::normalise_price(double price, double& normalizedPrice, string symbol) {
double tick_size;
if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tick_size)) {
Print("Failed to get tick size for ", symbol);
return false;
}
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
normalizedPrice = NormalizeDouble(MathRound(price / tick_size) * tick_size, digits);
return true;
}
//+------------------------------------------------------------------+
// double CalculatePositionData::calculate_trading_cost(string symbol, ulong ticket) {
// position.SelectByTicket(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 lots = PositionGetDouble(POSITION_VOLUME);
// return -1.0 * ((commission + swap) / tick_value * tick_size / lots);
// }