update to my MQL5 Libs

This commit is contained in:
Matt Corcoran
2025-07-07 15:43:17 +02:00
parent 10c1d86a0c
commit e9fc8ada0d
10 changed files with 885 additions and 575 deletions
+187
View File
@@ -0,0 +1,187 @@
class AdjustPosition {
public:
void set_breakeven_sl(string symbol, int runner_magic_no, double buffer_points = 5);
void set_breakeven_sl_if_tp_crossed(string symbol, int runner_magic_no, double buffer_points = 5);
void set_fixed_sl(string symbol, int runner_magic_no, double fixed_sl_price);
void set_trailing_sl(string symbol, int runner_magic_no, double sl_offset_points = 5);
private:
void set_breakeven_sl_for_ticket(string symbol, ulong ticket, long order_type, double entry_price, double current_sl, double current_tp,
int digits, double buffer_price, bool remove_tp);
};
// ---------------------------------------------------------
void AdjustPosition::set_breakeven_sl(string symbol, int runner_magic_no, double buffer_points) {
int digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double buffer_price = buffer_points * _Point;
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (!PositionSelectByTicket(ticket)) continue;
if (PositionGetString(POSITION_SYMBOL) != symbol) continue;
if ((int) PositionGetInteger(POSITION_MAGIC) != runner_magic_no) continue;
long order_type = PositionGetInteger(POSITION_TYPE);
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
set_breakeven_sl_for_ticket(symbol, ticket, order_type, entry, sl, tp, digits, buffer_price, false);
}
}
// ---------------------------------------------------------
/**
* Check runner trades for virtual take-profit hits and set SL to breakeven if crossed.
*
* Runner trades are assumed to be opened with no TP and a special comment in the format: "runner_tp:1.10500".
* This method parses that comment to determine the virtual TP, and if price has crossed it, moves SL to breakeven ± buffer.
*
* param symbol: Trading symbol to check positions for
* param runner_magic_no: Magic number assigned to runner trades
* param buffer_points: Buffer to add/subtract from entry price when setting SL (in points, converted internally)
*/
void AdjustPosition::set_breakeven_sl_if_tp_crossed(string symbol, int runner_magic_no, double buffer_points) {
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); // Current ask price (for sell comparisons)
double bid = SymbolInfoDouble(symbol, SYMBOL_BID); // Current bid price (for buy comparisons)
int digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS); // Symbol's decimal precision
double buffer_price = buffer_points * _Point; // Convert buffer from points to price
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i); // Get the position ticket
if (!PositionSelectByTicket(ticket)) continue; // Select the position
if (PositionGetString(POSITION_SYMBOL) != symbol) continue; // Only process positions for this symbol
if ((int) PositionGetInteger(POSITION_MAGIC) != runner_magic_no) continue; // Ensure it matches runner magic
// --- Get position details ---
long order_type = PositionGetInteger(POSITION_TYPE); // POSITION_TYPE_BUY or POSITION_TYPE_SELL
double entry = PositionGetDouble(POSITION_PRICE_OPEN); // Entry price of the trade
double sl = PositionGetDouble(POSITION_SL); // Current stop loss
double tp = PositionGetDouble(POSITION_TP); // Should be 0 for runners
string comment = PositionGetString(POSITION_COMMENT); // Read comment to check for virtual TP
// --- Parse virtual TP from comment ---
// Format expected: "runner_tp:1.10500"
double virtual_tp = 0.0;
if (StringFind(comment, "runner_tp:") == 0) {
string tp_str = StringSubstr(comment, StringLen("runner_tp:")); // Extract number part
virtual_tp = StringToDouble(tp_str); // Convert to double
}
// Skip if no virtual TP was found or invalid
if (virtual_tp <= 0.0) continue;
// Warn if a TP is still set (runner should not have one)
if (tp > 0.0) {
PrintFormat("Warning: Runner trade on %s (ticket %d) has a non-zero TP: %.5f (should be 0)", symbol, ticket, tp);
}
// --- Check if price has hit virtual TP ---
bool tp_hit = false;
if (order_type == POSITION_TYPE_BUY && bid >= virtual_tp) // For buys, bid must be ≥ virtual TP
tp_hit = true;
if (order_type == POSITION_TYPE_SELL && ask <= virtual_tp) // For sells, ask must be ≤ virtual TP
tp_hit = true;
if (!tp_hit) continue;
// --- Set breakeven SL if TP was hit ---
// Move SL to entry ± buffer. Leave TP unchanged (but should be 0.0 at init for runners)
set_breakeven_sl_for_ticket(symbol, ticket, order_type, entry, sl, tp, digits, buffer_price, true);
}
}
// ---------------------------------------------------------
void AdjustPosition::set_breakeven_sl_for_ticket(string symbol, ulong ticket, long order_type, double entry_price, double current_sl,
double current_tp, int digits, double buffer_price, bool remove_tp) {
double breakeven_sl = (order_type == POSITION_TYPE_BUY) ? entry_price + buffer_price : entry_price - buffer_price;
if ((order_type == POSITION_TYPE_BUY && current_sl >= breakeven_sl) || (order_type == POSITION_TYPE_SELL && current_sl <= breakeven_sl))
return;
MqlTradeRequest request = {};
MqlTradeResult result;
request.action = TRADE_ACTION_SLTP;
request.symbol = symbol;
request.position = ticket;
request.sl = NormalizeDouble(breakeven_sl, digits);
request.tp = remove_tp ? 0.0 : current_tp;
request.magic = (int) PositionGetInteger(POSITION_MAGIC);
if (!OrderSend(request, result)) {
Print("Failed to adjust runner: ", symbol, ". Error: ", result.retcode);
} else if (remove_tp) {
Print("Runner upgraded to trailing: SL at breakeven, TP removed for ", symbol);
}
}
// ---------------------------------------------------------
void AdjustPosition::set_fixed_sl(string symbol, int runner_magic_no, double fixed_sl_price) {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (!PositionSelectByTicket(ticket)) continue;
if (PositionGetString(POSITION_SYMBOL) != symbol) continue;
if ((int) PositionGetInteger(POSITION_MAGIC) != runner_magic_no) continue;
double current_sl = PositionGetDouble(POSITION_SL);
double current_tp = PositionGetDouble(POSITION_TP);
if (current_sl == fixed_sl_price) continue;
MqlTradeRequest request = {};
MqlTradeResult result;
request.action = TRADE_ACTION_SLTP;
request.symbol = symbol;
request.position = ticket;
request.sl = fixed_sl_price;
request.tp = current_tp;
request.magic = runner_magic_no;
if (!OrderSend(request, result)) {
Print("Failed to set fixed SL for runner on ", symbol, ". Error: ", result.retcode);
}
}
}
// ---------------------------------------------------------
void AdjustPosition::set_trailing_sl(string symbol, int runner_magic_no, double sl_offset_points) {
int digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double price = 0;
double sl = 0;
double offset = sl_offset_points * _Point;
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (!PositionSelectByTicket(ticket)) continue;
if (PositionGetString(POSITION_SYMBOL) != symbol) continue;
if ((int) PositionGetInteger(POSITION_MAGIC) != runner_magic_no) continue;
long type = PositionGetInteger(POSITION_TYPE);
double current_sl = PositionGetDouble(POSITION_SL);
double current_tp = PositionGetDouble(POSITION_TP);
price = (type == POSITION_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK);
sl = (type == POSITION_TYPE_BUY) ? price - offset : price + offset;
if ((type == POSITION_TYPE_BUY && sl <= current_sl) || (type == POSITION_TYPE_SELL && sl >= current_sl)) continue;
MqlTradeRequest request = {};
MqlTradeResult result;
request.action = TRADE_ACTION_SLTP;
request.symbol = symbol;
request.position = ticket;
request.sl = NormalizeDouble(sl, digits);
request.tp = current_tp;
request.magic = runner_magic_no;
if (!OrderSend(request, result)) {
Print("Failed to update trailing SL for runner on ", symbol, ". Error: ", result.retcode);
}
}
}
+75 -46
View File
@@ -1,9 +1,8 @@
#include <Trade/Trade.mqh>
#include <MyLibs/Utils/TimeZones.mqh>
#include <MyLibs/Utils/MarketDataUtils.mqh> #include <MyLibs/Utils/MarketDataUtils.mqh>
#include <MyLibs/Utils/TimeZones.mqh>
#include <Trade/Trade.mqh>
class CalculatePositionData : public CObject { class CalculatePositionData : public CObject {
protected: protected:
CTrade trade; CTrade trade;
CPositionInfo position; CPositionInfo position;
@@ -13,14 +12,15 @@ class CalculatePositionData : public CObject{
bool normalise_price(double price, double& normalizedPrice, string symbol); bool normalise_price(double price, double& normalizedPrice, string symbol);
public: public:
double calculate_stoploss(string symbol, double price, int order_side, string _sl_mode, double sl_var, ENUM_TIMEFRAMES atr_period); 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_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_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var);
double calculate_trading_cost(string symbol, ulong position_ticket); 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){ 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 // order_side int must be 1 for BUY or 2 for
double sl = 0; double sl = 0;
@@ -40,27 +40,34 @@ double CalculatePositionData::calculate_stoploss(string symbol, double price, in
if (order_side == 1) { if (order_side == 1) {
sl = price - sl_var * adj_point; sl = price - sl_var * adj_point;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
sl = price + sl_var * adj_point; sl = price + sl_var * adj_point;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
} }
if (mode_sl == "SL_FIXED_PERCENT") { if (mode_sl == "SL_FIXED_PERCENT") {
if (order_side == 1) { if (order_side == 1) {
sl = (-1.0 * sl_var * price / 100.00) + price; sl = (-1.0 * sl_var * price / 100.00) + price;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
sl = sl_var * price / 100.00 + price; sl = sl_var * price / 100.00 + price;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
} }
if (mode_sl == "SL_ATR_MULTIPLE") { if (mode_sl == "SL_ATR_MULTIPLE") {
int _atr_handle = iATR(symbol, atr_period, 14); int _atr_handle = iATR(symbol, atr_period, 14);
double atr[]; double atr[];
ArraySetAsSeries(atr, true); ArraySetAsSeries(atr, true);
@@ -68,45 +75,51 @@ double CalculatePositionData::calculate_stoploss(string symbol, double price, in
if (order_side == 1) { if (order_side == 1) {
sl = price - (atr[0] * sl_var); sl = price - (atr[0] * sl_var);
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
sl = price + (atr[0] * sl_var); sl = price + (atr[0] * sl_var);
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
} }
if (mode_sl == "SL_SPECIFIED_VALUE") { if (mode_sl == "SL_SPECIFIED_VALUE") {
double adj_point = mdu.adjusted_point(symbol); double adj_point = mdu.adjusted_point(symbol);
if (order_side == 1) { if (order_side == 1) {
double pip_50_sl = price - 10 * adj_point; double pip_50_sl = price - 10 * adj_point;
if (sl_var >= pip_50_sl) { if (sl_var >= pip_50_sl) {
sl = pip_50_sl; sl = pip_50_sl;
} } else
else sl = sl_var; sl = sl_var;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
double pip_50_sl = price + 10 * adj_point; double pip_50_sl = price + 10 * adj_point;
if (sl_var <= pip_50_sl) { if (sl_var <= pip_50_sl) {
sl = pip_50_sl; sl = pip_50_sl;
} } else
else sl = sl_var; sl = sl_var;
sl = sl = sl_var; sl = sl = sl_var;
if(!normalise_price(sl,sl,symbol)){return false;} if (!normalise_price(sl, sl, symbol)) {
return false;
}
} }
} }
return sl; 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){ 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 // order_side int must be 1 for BUY or 2 for SELL
double tp = 0; double tp = 0;
@@ -116,31 +129,37 @@ double CalculatePositionData::calculate_take_profit(string symbol, double price,
} }
if (mode_tp == "TP_FIXED_PIPS") { if (mode_tp == "TP_FIXED_PIPS") {
double adj_point = mdu.adjusted_point(symbol); double adj_point = mdu.adjusted_point(symbol);
if (order_side == 1) { if (order_side == 1) {
tp = price + _tp_var * adj_point; tp = price + _tp_var * adj_point;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
tp = price - _tp_var * adj_point; tp = price - _tp_var * adj_point;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
} }
if (mode_tp == "TP_FIXED_PERCENT") { if (mode_tp == "TP_FIXED_PERCENT") {
if (order_side == 1) { if (order_side == 1) {
tp = _tp_var * price / 100.00 + price; tp = _tp_var * price / 100.00 + price;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
tp = (-1 * _tp_var * price / 100.00) + price; tp = (-1 * _tp_var * price / 100.00) + price;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
} }
if (mode_tp == "TP_ATR_MULTIPLE") { if (mode_tp == "TP_ATR_MULTIPLE") {
int _atr_handle = iATR(symbol, atr_period, 14); int _atr_handle = iATR(symbol, atr_period, 14);
double atr[]; double atr[];
ArraySetAsSeries(atr, true); ArraySetAsSeries(atr, true);
@@ -148,11 +167,15 @@ double CalculatePositionData::calculate_take_profit(string symbol, double price,
if (order_side == 1) { if (order_side == 1) {
tp = price + (atr[0] * _tp_var); tp = price + (atr[0] * _tp_var);
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
tp = price - (atr[0] * _tp_var); tp = price - (atr[0] * _tp_var);
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
} }
@@ -160,17 +183,20 @@ double CalculatePositionData::calculate_take_profit(string symbol, double price,
if (order_side == 1) { if (order_side == 1) {
double sl_size = price - stoploss; double sl_size = price - stoploss;
tp = price + (_tp_var * sl_size); tp = price + (_tp_var * sl_size);
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
double sl_size = stoploss - price; double sl_size = stoploss - price;
tp = price - (_tp_var * sl_size); tp = price - (_tp_var * sl_size);
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
} }
if (mode_tp == "TP_SPECIFIED_VALUE") { if (mode_tp == "TP_SPECIFIED_VALUE") {
if (_tp_var != 0) { if (_tp_var != 0) {
double adj_point = mdu.adjusted_point(symbol); double adj_point = mdu.adjusted_point(symbol);
@@ -178,34 +204,37 @@ double CalculatePositionData::calculate_take_profit(string symbol, double price,
double pip_limit = price + 10 * adj_point; double pip_limit = price + 10 * adj_point;
if (_tp_var <= pip_limit) { if (_tp_var <= pip_limit) {
tp = pip_limit; tp = pip_limit;
} } else
else tp = _tp_var; tp = _tp_var;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
if (order_side == 2) { if (order_side == 2) {
double pip_limit = price - 10 * adj_point; double pip_limit = price - 10 * adj_point;
if (_tp_var >= pip_limit) { if (_tp_var >= pip_limit) {
tp = pip_limit; tp = pip_limit;
} } else
else tp = _tp_var; tp = _tp_var;
tp = tp = _tp_var; tp = tp = _tp_var;
if(!normalise_price(tp,tp,symbol)){return false;} if (!normalise_price(tp, tp, symbol)) {
return false;
}
} }
} }
} }
return tp; return tp;
} }
double CalculatePositionData::calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var) { double CalculatePositionData::calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var) {
double lots = 0; double lots = 0;
double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
double account_value = fmin(fmin(AccountInfoDouble(ACCOUNT_EQUITY),AccountInfoDouble(ACCOUNT_BALANCE)),AccountInfoDouble(ACCOUNT_MARGIN_FREE)); double account_value =
fmin(fmin(AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE)), AccountInfoDouble(ACCOUNT_MARGIN_FREE));
double risk_money = account_value * lot_var / 100; double risk_money = account_value * lot_var / 100;
if (mode_lot == "LOT_MODE_FIXED") { if (mode_lot == "LOT_MODE_FIXED") {
@@ -222,12 +251,13 @@ double CalculatePositionData::calculate_lots(string symbol, double sl_distance,
lots = MathFloor(risk_money / money_lot_step) * volume_step; lots = MathFloor(risk_money / money_lot_step) * volume_step;
} }
if(!check_lots(lots, symbol)){return false;} if (!check_lots(lots, symbol)) {
return false;
}
return lots; return lots;
} }
bool CalculatePositionData::check_lots(double& lots, string symbol) { bool CalculatePositionData::check_lots(double& lots, string symbol) {
double min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); double max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
@@ -259,7 +289,6 @@ bool CalculatePositionData::normalise_price(double price, double &normalizedPric
} }
double CalculatePositionData::calculate_trading_cost(string symbol, ulong position_ticket) { double CalculatePositionData::calculate_trading_cost(string symbol, ulong position_ticket) {
position.SelectByTicket(position_ticket); position.SelectByTicket(position_ticket);
double swap = PositionGetDouble(POSITION_SWAP); double swap = PositionGetDouble(POSITION_SWAP);
+111 -75
View File
@@ -1,35 +1,44 @@
#include <Trade/Trade.mqh>
#include <MyLibs/Orders/CalculatePositionData.mqh> #include <MyLibs/Orders/CalculatePositionData.mqh>
#include <Trade/Trade.mqh>
class EntryOrders { class EntryOrders {
protected: protected:
CTrade trade; CTrade trade;
CalculatePositionData calc; CalculatePositionData calc;
double stop_loss;
double take_profit;
int total_open_buy_orders;
int total_open_sell_orders;
double current_price;
int count_open_positions(string symbol, int order_side, long magic_number);
public: public:
bool open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,string _tp_mode, double tp_var, string _lot_mode, double lot_var, long magic_number); int count_open_positions(string symbol, int order_side, long _magic_number);
bool open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, long magic_number);
bool open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation,ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, long magic_number); bool open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode,
bool open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation,ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var,string _lot_mode, double lot_var, long magic_number); double tp_var, string _lot_mode, double lot_var, long _magic_number);
bool open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode,
double tp_var, string _lot_mode, double lot_var, long _magic_number);
bool open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period,
string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
long _magic_number);
bool open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period,
string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
long _magic_number);
bool open_runner_buy_order_with_virtual_tp(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,
string _tp_mode, double tp_var, string _lot_mode, double lot_var, long _magic_number);
bool open_runner_sell_order_with_virtual_tp(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,
string _tp_mode, double tp_var, string _lot_mode, double lot_var, long _magic_number);
}; };
int EntryOrders::count_open_positions(string symbol, int order_side, long _magic_number) {
int EntryOrders::count_open_positions(string symbol, int order_side, long magic_number) {
int count = 0; int count = 0;
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i); ulong ticket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
PositionGetInteger(POSITION_MAGIC) == magic_number) { int type = (int) PositionGetInteger(POSITION_TYPE);
if ((order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ||
(order_side == 2 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)) { // Count: order_side == 0 (both sides), order_side == 1 (longs only), order_side == 2 (shorts only)
if (order_side == 0 || (order_side == 1 && type == POSITION_TYPE_BUY) || (order_side == 2 && type == POSITION_TYPE_SELL)) {
count++; count++;
} }
} }
@@ -37,76 +46,103 @@ int EntryOrders::count_open_positions(string symbol, int order_side, long magic_
return count; return count;
} }
bool EntryOrders::open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, bool EntryOrders::open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,
double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, long _magic_number) {
long magic_number) { if (!condition) return false;
if (condition) {
current_price = SymbolInfoDouble(symbol, SYMBOL_ASK); double current_price = SymbolInfoDouble(symbol, SYMBOL_ASK);
total_open_buy_orders = count_open_positions(symbol, 1, magic_number); if (count_open_positions(symbol, 1, _magic_number) > 0) return false;
if (total_open_buy_orders == 0) {
stop_loss = calc.calculate_stoploss(symbol, current_price, 1, _sl_mode, sl_var, atr_period); double stop_loss = calc.calculate_stoploss(symbol, current_price, 1, _sl_mode, sl_var, atr_period);
take_profit = calc.calculate_take_profit(symbol, current_price, stop_loss, 1, _tp_mode, tp_var, atr_period); double take_profit = calc.calculate_take_profit(symbol, current_price, stop_loss, 1, _tp_mode, tp_var, atr_period);
double sl_distance = current_price - stop_loss; double sl_distance = current_price - stop_loss;
double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var); double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(magic_number);
string comment = "Magic Number: " + IntegerToString(magic_number); trade.SetExpertMagicNumber(_magic_number);
trade.PositionOpen(symbol, ORDER_TYPE_BUY, lots, current_price, stop_loss, take_profit, comment); string comment = "Magic Number: " + IntegerToString(_magic_number);
} return trade.PositionOpen(symbol, ORDER_TYPE_BUY, lots, current_price, stop_loss, take_profit, comment);
}
return true;
} }
bool EntryOrders::open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, bool EntryOrders::open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,
double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, long _magic_number) {
long magic_number) { if (!condition) return false;
if (condition) {
current_price = SymbolInfoDouble(symbol, SYMBOL_BID); double current_price = SymbolInfoDouble(symbol, SYMBOL_BID);
total_open_sell_orders = count_open_positions(symbol, 2, magic_number); if (count_open_positions(symbol, 2, _magic_number) > 0) return false;
if (total_open_sell_orders == 0) {
stop_loss = calc.calculate_stoploss(symbol, current_price, 2, _sl_mode, sl_var, atr_period); double stop_loss = calc.calculate_stoploss(symbol, current_price, 2, _sl_mode, sl_var, atr_period);
take_profit = calc.calculate_take_profit(symbol, current_price, stop_loss, 2, _tp_mode, tp_var, atr_period); double take_profit = calc.calculate_take_profit(symbol, current_price, stop_loss, 2, _tp_mode, tp_var, atr_period);
double sl_distance = stop_loss - current_price; double sl_distance = stop_loss - current_price;
double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var); double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(magic_number);
string comment = "Magic Number: " + IntegerToString(magic_number); trade.SetExpertMagicNumber(_magic_number);
trade.PositionOpen(symbol, ORDER_TYPE_SELL, lots, current_price, stop_loss, take_profit, comment); string comment = "Magic Number: " + IntegerToString(_magic_number);
} return trade.PositionOpen(symbol, ORDER_TYPE_SELL, lots, current_price, stop_loss, take_profit, comment);
}
return true;
} }
bool EntryOrders::open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation, bool EntryOrders::open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period,
ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
double tp_var, string _lot_mode, double lot_var, long magic_number) { long _magic_number) {
if (condition) { if (!condition) return false;
total_open_buy_orders = count_open_positions(symbol, 1, magic_number); if (count_open_positions(symbol, 1, _magic_number) > 0) return false;
if (total_open_buy_orders == 0) {
stop_loss = calc.calculate_stoploss(symbol, entry_price, 1, _sl_mode, sl_var, atr_period); double stop_loss = calc.calculate_stoploss(symbol, entry_price, 1, _sl_mode, sl_var, atr_period);
take_profit = calc.calculate_take_profit(symbol, entry_price, stop_loss, 1, _tp_mode, tp_var, atr_period); double take_profit = calc.calculate_take_profit(symbol, entry_price, stop_loss, 1, _tp_mode, tp_var, atr_period);
double sl_distance = entry_price - stop_loss; double sl_distance = entry_price - stop_loss;
double lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var); double lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(magic_number);
string comment = "Magic Number: " + IntegerToString(magic_number); trade.SetExpertMagicNumber(_magic_number);
trade.BuyStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment); string comment = "Magic Number: " + IntegerToString(_magic_number);
} return trade.BuyStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
}
return true;
} }
bool EntryOrders::open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation, bool EntryOrders::open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period,
ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
double tp_var, string _lot_mode, double lot_var, long magic_number) { long _magic_number) {
if (condition) { if (!condition) return false;
total_open_sell_orders = count_open_positions(symbol, 2, magic_number); if (count_open_positions(symbol, 2, _magic_number) > 0) return false;
if (total_open_sell_orders == 0) {
stop_loss = calc.calculate_stoploss(symbol, entry_price, 2, _sl_mode, sl_var, atr_period); double stop_loss = calc.calculate_stoploss(symbol, entry_price, 2, _sl_mode, sl_var, atr_period);
take_profit = calc.calculate_take_profit(symbol, entry_price, stop_loss, 2, _tp_mode, tp_var, atr_period); double take_profit = calc.calculate_take_profit(symbol, entry_price, stop_loss, 2, _tp_mode, tp_var, atr_period);
double sl_distance = stop_loss - entry_price; double sl_distance = stop_loss - entry_price;
double lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var); double lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(magic_number);
string comment = "Magic Number: " + IntegerToString(magic_number); trade.SetExpertMagicNumber(_magic_number);
trade.SellStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment); string comment = "Magic Number: " + IntegerToString(_magic_number);
return trade.SellStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
} }
bool EntryOrders::open_runner_buy_order_with_virtual_tp(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode,
double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
long _magic_number) {
if (!condition) return false;
double current_price = SymbolInfoDouble(symbol, SYMBOL_ASK);
if (count_open_positions(symbol, 1, _magic_number) > 0) return false;
double stop_loss = calc.calculate_stoploss(symbol, current_price, 1, _sl_mode, sl_var, atr_period);
double virtual_tp = calc.calculate_take_profit(symbol, current_price, stop_loss, 1, _tp_mode, tp_var, atr_period);
double sl_distance = current_price - stop_loss;
double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(_magic_number);
string comment = StringFormat("runner_tp:%.5f", virtual_tp);
return trade.PositionOpen(symbol, ORDER_TYPE_BUY, lots, current_price, stop_loss, 0.0, comment);
} }
return true;
bool EntryOrders::open_runner_sell_order_with_virtual_tp(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode,
double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,
long _magic_number) {
if (!condition) return false;
double current_price = SymbolInfoDouble(symbol, SYMBOL_BID);
if (count_open_positions(symbol, 2, _magic_number) > 0) return false;
double stop_loss = calc.calculate_stoploss(symbol, current_price, 2, _sl_mode, sl_var, atr_period);
double virtual_tp = calc.calculate_take_profit(symbol, current_price, stop_loss, 2, _tp_mode, tp_var, atr_period);
double sl_distance = stop_loss - current_price;
double lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
trade.SetExpertMagicNumber(_magic_number);
string comment = StringFormat("runner_tp:%.5f", virtual_tp);
return trade.PositionOpen(symbol, ORDER_TYPE_SELL, lots, current_price, stop_loss, 0.0, comment);
} }
+25 -41
View File
@@ -1,34 +1,31 @@
#include <Trade/Trade.mqh>
#include <MyLibs/Utils/TimeZones.mqh>
#include <MyLibs/Orders/CalculatePositionData.mqh> #include <MyLibs/Orders/CalculatePositionData.mqh>
#include <MyLibs/Utils/TimeZones.mqh>
#include <Trade/Trade.mqh>
class ExitOrders { class ExitOrders {
protected: protected:
CTrade trade; CTrade trade;
TimeZones tz; TimeZones tz;
CalculatePositionData cpd; CalculatePositionData calc;
ulong posTicket; ulong posTicket;
long position_open_time; long position_open_time;
long first_allowed_close_time; long first_allowed_close_time;
public: public:
bool close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,long magic_number); bool close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long _magic_number);
bool close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,long magic_number); bool close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long _magic_number);
bool daily_timed_exit(string symbol, datetime exit_time, int delay_days, long magic_number); bool daily_timed_exit(string symbol, datetime exit_time, int delay_days, long _magic_number);
bool daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, string cw_tzone, int delay_days, long magic_number); bool daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, string cw_tzone, int delay_days,
bool first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long magic_number); long _magic_number);
bool first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long _magic_number);
}; };
bool ExitOrders::close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long _magic_number) {
bool ExitOrders::close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,
long magic_number) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
posTicket = PositionGetTicket(i); posTicket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1; int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
@@ -41,14 +38,11 @@ bool ExitOrders::close_buy_orders(string symbol, bool condition, int close_bars,
return true; return true;
} }
bool ExitOrders::close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long _magic_number) {
bool ExitOrders::close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,
long magic_number) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
posTicket = PositionGetTicket(i); posTicket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1; int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
@@ -61,9 +55,7 @@ bool ExitOrders::close_sell_orders(string symbol, bool condition, int close_bars
return true; return true;
} }
bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_days, long _magic_number) {
bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_days, long magic_number) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
posTicket = PositionGetTicket(i); posTicket = PositionGetTicket(i);
position_open_time = PositionGetInteger(POSITION_TIME); position_open_time = PositionGetInteger(POSITION_TIME);
@@ -72,7 +64,7 @@ bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_d
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1)); first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
if (TimeCurrent() > first_allowed_close_time && TimeCurrent() >= exit_time) { if (TimeCurrent() > first_allowed_close_time && TimeCurrent() >= exit_time) {
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
trade.PositionClose(posTicket); trade.PositionClose(posTicket);
} }
} }
@@ -81,10 +73,8 @@ bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_d
return true; return true;
} }
bool ExitOrders::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, string cw_tzone, int delay_days,
bool ExitOrders::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, long _magic_number) {
string cw_tzone, int delay_days, long magic_number) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
posTicket = PositionGetTicket(i); posTicket = PositionGetTicket(i);
position_open_time = PositionGetInteger(POSITION_TIME); position_open_time = PositionGetInteger(POSITION_TIME);
@@ -95,14 +85,12 @@ bool ExitOrders::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_ba
if (TimeCurrent() > first_allowed_close_time) { if (TimeCurrent() > first_allowed_close_time) {
datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker"); datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker");
if (TimeCurrent() >= broker_close_time && if (TimeCurrent() >= broker_close_time && PositionGetString(POSITION_SYMBOL) == symbol &&
PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
PositionGetInteger(POSITION_MAGIC) == magic_number) {
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN); double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID); double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID);
double bar_close = iClose(_Symbol, close_bar_period, 1); // shift 1 because 0 is live candle double bar_close = iClose(_Symbol, close_bar_period, 1); // shift 1 because 0 is live candle
double trading_cost = cpd.calculate_trading_cost(symbol, posTicket); double trading_cost = calc.calculate_trading_cost(symbol, posTicket);
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
bar_close > (position_open_price + spread + trading_cost)) { bar_close > (position_open_price + spread + trading_cost)) {
@@ -120,9 +108,7 @@ bool ExitOrders::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_ba
return true; return true;
} }
bool ExitOrders::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long _magic_number) {
bool ExitOrders::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long magic_number) {
position_open_time = PositionGetInteger(POSITION_TIME); position_open_time = PositionGetInteger(POSITION_TIME);
first_allowed_close_time = position_open_time + PeriodSeconds(close_bar_period); first_allowed_close_time = position_open_time + PeriodSeconds(close_bar_period);
@@ -130,19 +116,17 @@ bool ExitOrders::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES clos
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
posTicket = PositionGetTicket(i); posTicket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN); double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID); double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID);
double bar_close = iClose(_Symbol, close_bar_period, 1); double bar_close = iClose(_Symbol, close_bar_period, 1);
double trading_cost = cpd.calculate_trading_cost(symbol, posTicket); double trading_cost = calc.calculate_trading_cost(symbol, posTicket);
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && bar_close > (position_open_price + spread + trading_cost)) {
bar_close > (position_open_price + spread + trading_cost)) {
trade.PositionClose(posTicket); trade.PositionClose(posTicket);
} }
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && bar_close < (position_open_price - spread - trading_cost)) {
bar_close < (position_open_price - spread - trading_cost)) {
trade.PositionClose(posTicket); trade.PositionClose(posTicket);
} }
} }
+2 -8
View File
@@ -2,7 +2,6 @@
#include <Trade/PositionInfo.mqh> #include <Trade/PositionInfo.mqh>
class OrderTracker { class OrderTracker {
protected: protected:
COrderInfo m_order; COrderInfo m_order;
CPositionInfo m_position; CPositionInfo m_position;
@@ -19,9 +18,7 @@ int OrderTracker::count_open_positions(string symbol, int order_side, long magic
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i); ulong ticket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
PositionGetInteger(POSITION_MAGIC) == magic_number) {
if (order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
count++; count++;
} }
@@ -35,15 +32,13 @@ int OrderTracker::count_open_positions(string symbol, int order_side, long magic
return count; return count;
} }
int OrderTracker::count_all_positions(string symbol, long magic_number) { int OrderTracker::count_all_positions(string symbol, long magic_number) {
int count = 0; int count = 0;
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i); ulong ticket = PositionGetTicket(i);
if (PositionGetString(POSITION_SYMBOL) == symbol && if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
PositionGetInteger(POSITION_MAGIC) == magic_number) {
count++; count++;
} }
} }
@@ -51,7 +46,6 @@ int OrderTracker::count_all_positions(string symbol, long magic_number) {
return count; return count;
} }
int OrderTracker::count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic) { int OrderTracker::count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic) {
int count = 0; int count = 0;
+4 -18
View File
@@ -1,7 +1,6 @@
#include <Trade/Trade.mqh> #include <Trade/Trade.mqh>
class TrailingLogic { class TrailingLogic {
protected: protected:
CTrade trade; CTrade trade;
@@ -10,11 +9,9 @@ class TrailingLogic {
void nnfx_trailing_stop(string symbol, double sl_var, double tp_var, double atr_value, ulong magic_number); void nnfx_trailing_stop(string symbol, double sl_var, double tp_var, double atr_value, ulong magic_number);
}; };
void TrailingLogic::break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer) { void TrailingLogic::break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT); double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits); double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits);
@@ -29,9 +26,7 @@ void TrailingLogic::break_even_stop(string symbol, ulong magic_number, int be_tr
double position_tp = PositionGetDouble(POSITION_TP); double position_tp = PositionGetDouble(POSITION_TP);
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE); ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
if (position_type == POSITION_TYPE_BUY && if (position_type == POSITION_TYPE_BUY && bid > position_open_price + be_trigger_points * symbol_point) {
bid > position_open_price + be_trigger_points * symbol_point) {
double sl = NormalizeDouble(position_open_price + be_puffer * symbol_point, symbol_digits); double sl = NormalizeDouble(position_open_price + be_puffer * symbol_point, symbol_digits);
if (sl > position_sl) { if (sl > position_sl) {
trade.PositionModify(ticket, sl, position_tp); trade.PositionModify(ticket, sl, position_tp);
@@ -39,9 +34,7 @@ void TrailingLogic::break_even_stop(string symbol, ulong magic_number, int be_tr
} }
} }
if (position_type == POSITION_TYPE_SELL && if (position_type == POSITION_TYPE_SELL && ask < position_open_price - be_trigger_points * symbol_point) {
ask < position_open_price - be_trigger_points * symbol_point) {
double sl = NormalizeDouble(position_open_price - be_puffer * symbol_point, symbol_digits); double sl = NormalizeDouble(position_open_price - be_puffer * symbol_point, symbol_digits);
if (sl < position_sl) { if (sl < position_sl) {
trade.PositionModify(ticket, sl, position_tp); trade.PositionModify(ticket, sl, position_tp);
@@ -54,14 +47,11 @@ void TrailingLogic::break_even_stop(string symbol, ulong magic_number, int be_tr
} }
} }
void TrailingLogic::nnfx_trailing_stop(string symbol, double sl_var, double tp_var, double atr_value, ulong magic_number) { void TrailingLogic::nnfx_trailing_stop(string symbol, double sl_var, double tp_var, double atr_value, ulong magic_number) {
for (int i = PositionsTotal() - 1; i >= 0; i--) { for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i); ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) { if (PositionSelectByTicket(ticket)) {
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) { if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT); double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits); double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits);
@@ -72,18 +62,14 @@ void TrailingLogic::nnfx_trailing_stop(string symbol, double sl_var, double tp_v
double position_tp = PositionGetDouble(POSITION_TP); double position_tp = PositionGetDouble(POSITION_TP);
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE); ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
if (position_type == POSITION_TYPE_BUY && if (position_type == POSITION_TYPE_BUY && bid > position_open_price + (atr_value * tp_var)) {
bid > position_open_price + (atr_value * tp_var)) {
double sl = NormalizeDouble(bid - (atr_value * sl_var), symbol_digits); double sl = NormalizeDouble(bid - (atr_value * sl_var), symbol_digits);
if (sl > (position_sl + (atr_value * 0.5))) { if (sl > (position_sl + (atr_value * 0.5))) {
trade.PositionModify(ticket, sl, position_tp); trade.PositionModify(ticket, sl, position_tp);
} }
} }
if (position_type == POSITION_TYPE_SELL && if (position_type == POSITION_TYPE_SELL && ask < position_open_price - (atr_value * tp_var)) {
ask < position_open_price - (atr_value * tp_var)) {
double sl = NormalizeDouble(ask + (atr_value * sl_var), symbol_digits); double sl = NormalizeDouble(ask + (atr_value * sl_var), symbol_digits);
if (sl < (position_sl + (atr_value * 0.5))) { if (sl < (position_sl + (atr_value * 0.5))) {
trade.PositionModify(ticket, sl, position_tp); trade.PositionModify(ticket, sl, position_tp);
+6 -12
View File
@@ -1,4 +1,3 @@
class EntryState { class EntryState {
public: public:
int last_trigger_bar_long; int last_trigger_bar_long;
@@ -28,10 +27,8 @@ public:
} }
void update_baseline_cross(int curr_bar, double price, double baseline, double prev_price, double prev_baseline) { void update_baseline_cross(int curr_bar, double price, double baseline, double prev_price, double prev_baseline) {
if (prev_price < prev_baseline && price > baseline) if (prev_price < prev_baseline && price > baseline) last_bl_cross_long = curr_bar;
last_bl_cross_long = curr_bar; if (prev_price > prev_baseline && price < baseline) last_bl_cross_short = curr_bar;
if (prev_price > prev_baseline && price < baseline)
last_bl_cross_short = curr_bar;
} }
void update_entry(bool is_long, int curr_bar) { void update_entry(bool is_long, int curr_bar) {
@@ -40,15 +37,12 @@ public:
else else
last_entry_short = curr_bar; last_entry_short = curr_bar;
} }
int get_last_trigger(bool is_long) { int get_last_trigger(bool is_long) {
return is_long ? last_trigger_bar_long : last_trigger_bar_short; return is_long ? last_trigger_bar_long : last_trigger_bar_short;
} }
int get_last_cross(bool is_long) { int get_last_cross(bool is_long) {
return is_long ? last_bl_cross_long : last_bl_cross_short; return is_long ? last_bl_cross_long : last_bl_cross_short;
} }
int get_last_entry(bool is_long) { int get_last_entry(bool is_long) {
return is_long ? last_entry_long : last_entry_short; return is_long ? last_entry_long : last_entry_short;
} }
@@ -73,9 +67,8 @@ bool is_recent(int signal_bar, int curr_bar, int lookback) {
} }
// Utility: build current entry condition context // Utility: build current entry condition context
EntryContext build_entry_context(bool is_long, double price, double baseline, double atr, EntryContext build_entry_context(bool is_long, double price, double baseline, double atr, int last_cross, int last_entry, bool trigger,
int last_cross, int last_entry, bool confirm, bool volume, bool recent) {
bool trigger, bool confirm, bool volume, bool recent) {
EntryContext ctx; EntryContext ctx;
ctx.trigger = trigger; ctx.trigger = trigger;
ctx.confirm = confirm; ctx.confirm = confirm;
@@ -100,7 +93,8 @@ public:
return (curr_bar - ctx.last_cross <= 2) && ctx.confirm && ctx.volume && ctx.base_ok && ctx.far; return (curr_bar - ctx.last_cross <= 2) && ctx.confirm && ctx.volume && ctx.base_ok && ctx.far;
} }
bool is_baseline_cross_entry(const EntryContext &ctx, double prev_price, double prev_baseline,double price, double baseline, bool is_long){ bool is_baseline_cross_entry(const EntryContext& ctx, double prev_price, double prev_baseline, double price, double baseline,
bool is_long) {
bool crossed = is_long ? (prev_price < prev_baseline && price > baseline) : (prev_price > prev_baseline && price < baseline); bool crossed = is_long ? (prev_price < prev_baseline && price > baseline) : (prev_price > prev_baseline && price < baseline);
return crossed && ctx.confirm && ctx.volume && ctx.near; return crossed && ctx.confirm && ctx.volume && ctx.near;
} }
+8 -4
View File
@@ -42,17 +42,21 @@ double MarketDataUtils::get_latest_buffer_value(int handle) {
return 0.0; return 0.0;
} }
// Retrieves a historical buffer value at specified shift // shift = 0 refers to the live candle (still forming)
// shift = 1 is the most recently closed candle
// shift = 2 is the one before that, etc.
double MarketDataUtils::get_buffer_value(int handle, int shift) { double MarketDataUtils::get_buffer_value(int handle, int shift) {
double val[]; double val[];
ArraySetAsSeries(val, true); ArraySetAsSeries(val, true);
if (CopyBuffer(handle, 0, shift, 1, val) == 1) if (CopyBuffer(handle, 0, shift, 1, val) == 1 && val[0] != EMPTY_VALUE)
return val[0]; // Historical value at given shift return val[0];
return 0.0; return EMPTY_VALUE;
} }
// Adjusts the point value for symbol to account for fractional pips (e.g., 5-digit brokers) // Adjusts the point value for symbol to account for fractional pips (e.g., 5-digit brokers)
double MarketDataUtils::adjusted_point(string symbol) { double MarketDataUtils::adjusted_point(string symbol) {
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
+96
View File
@@ -0,0 +1,96 @@
// File: MyLibs/Utils/AtrBands.mqh
class AtrBands {
protected:
string symbol;
int atr_period;
ENUM_TIMEFRAMES timeframe;
string prefix;
color upper_color;
color lower_color;
color mid_color;
int line_width;
bool plot_bands;
int atr_handle;
public:
AtrBands(string _symbol, int _atr_period = 14, ENUM_TIMEFRAMES _timeframe = PERIOD_CURRENT,
color _upper = clrDodgerBlue, color _lower = clrDodgerBlue, color _mid = clrDodgerBlue,
int _width = 1, bool plot = true);
double upper_band(double baseline, int shift = 1, double mult = 1.0);
double lower_band(double baseline, int shift = 1, double mult = 1.0);
double middle_band(double baseline, int shift = 1);
protected:
double get_atr(int shift);
void draw_line(string name, int shift, double price, color clr);
};
// Constructor
AtrBands::AtrBands(string _symbol, int _atr_period, ENUM_TIMEFRAMES _timeframe,
color _upper, color _lower, color _mid, int _width, bool plot) {
symbol = _symbol;
atr_period = _atr_period;
timeframe = _timeframe;
prefix = "ATRBand";
upper_color = _upper;
lower_color = _lower;
mid_color = _mid;
line_width = _width;
plot_bands = plot;
atr_handle = iATR(symbol, timeframe, atr_period);
if (atr_handle == INVALID_HANDLE) {
Print("Failed to create ATR handle for symbol: ", symbol);
}
}
// Public methods
double AtrBands::upper_band(double baseline, int shift, double mult) {
double atr = get_atr(shift);
double upper = baseline + atr * mult;
if (plot_bands) draw_line(prefix + "_Upper_" + symbol, shift, upper, upper_color);
return upper;
}
double AtrBands::lower_band(double baseline, int shift, double mult) {
double atr = get_atr(shift);
double lower = baseline - atr * mult;
if (plot_bands) draw_line(prefix + "_Lower_" + symbol, shift, lower, lower_color);
return lower;
}
double AtrBands::middle_band(double baseline, int shift) {
if (plot_bands) draw_line(prefix + "_Mid_" + symbol, shift, baseline, mid_color);
return baseline;
}
// Internal: Get ATR value from buffer
double AtrBands::get_atr(int shift) {
if (atr_handle == INVALID_HANDLE) return 0;
double buf[];
ArraySetAsSeries(buf, true);
if (CopyBuffer(atr_handle, 0, shift, 1, buf) == 1 && buf[0] != EMPTY_VALUE)
return buf[0];
return 0;
}
// Internal: Draw line for a given price at a bar
void AtrBands::draw_line(string name, int shift, double price, color clr) {
datetime time0 = iTime(symbol, timeframe, shift);
datetime time1 = time0 + PeriodSeconds(timeframe);
if (ObjectFind(0, name) < 0) {
ObjectCreate(0, name, OBJ_TREND, 0, time0, price, time1, price);
} else {
ObjectMove(0, name, 0, time0, price);
ObjectMove(0, name, 1, time1, price);
}
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_WIDTH, line_width);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
}