update to my MQL5 Libs
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+175
-146
@@ -1,274 +1,303 @@
|
||||
#include <Trade/Trade.mqh>
|
||||
#include <MyLibs/Utils/TimeZones.mqh>
|
||||
#include <MyLibs/Utils/MarketDataUtils.mqh>
|
||||
#include <MyLibs/Utils/TimeZones.mqh>
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
class CalculatePositionData : public CObject{
|
||||
|
||||
protected:
|
||||
CTrade trade;
|
||||
CPositionInfo position;
|
||||
MarketDataUtils mdu;
|
||||
class CalculatePositionData : public CObject {
|
||||
protected:
|
||||
CTrade trade;
|
||||
CPositionInfo position;
|
||||
MarketDataUtils mdu;
|
||||
|
||||
bool check_lots(double &lots, string symbol);
|
||||
bool normalise_price(double price, double &normalizedPrice, string symbol);
|
||||
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 _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);
|
||||
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 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;
|
||||
double sl = 0;
|
||||
|
||||
if(mode_sl=="NO_STOPLOSS"){
|
||||
sl=0;
|
||||
if (mode_sl == "NO_STOPLOSS") {
|
||||
sl = 0;
|
||||
}
|
||||
|
||||
if(mode_sl=="SL_BREAKEVEN"){
|
||||
if (mode_sl == "SL_BREAKEVEN") {
|
||||
// https://www.youtube.com/watch?v=idPulZ3_iR0
|
||||
Alert("Not implemented yet yet");
|
||||
}
|
||||
|
||||
if(mode_sl=="SL_FIXED_PIPS"){
|
||||
if (mode_sl == "SL_FIXED_PIPS") {
|
||||
// pips/poins = https://www.mql5.com/en/forum/187757
|
||||
double adj_point = mdu.adjusted_point(symbol);
|
||||
|
||||
if(order_side == 1){
|
||||
sl = price - sl_var * adj_point;
|
||||
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||
|
||||
if (order_side == 1) {
|
||||
sl = price - sl_var * adj_point;
|
||||
if (!normalise_price(sl, sl, symbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(order_side == 2){
|
||||
if (order_side == 2) {
|
||||
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(order_side == 1){
|
||||
sl = (-1.0 * sl_var * price / 100.00) + price;
|
||||
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){
|
||||
if (order_side == 2) {
|
||||
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"){
|
||||
|
||||
int _atr_handle = iATR(symbol,atr_period,14);
|
||||
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;}
|
||||
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){
|
||||
if (order_side == 2) {
|
||||
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);
|
||||
|
||||
if(order_side == 1){
|
||||
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;
|
||||
|
||||
double pip_50_sl = price - 10 * adj_point;
|
||||
if(sl_var >= pip_50_sl){
|
||||
sl = pip_50_sl;
|
||||
if (!normalise_price(sl, sl, symbol)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
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;}
|
||||
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){
|
||||
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;
|
||||
double tp = 0;
|
||||
|
||||
if(mode_tp=="NO_TAKE_PROFIT"){
|
||||
tp=0;
|
||||
if (mode_tp == "NO_TAKE_PROFIT") {
|
||||
tp = 0;
|
||||
}
|
||||
|
||||
if(mode_tp=="TP_FIXED_PIPS"){
|
||||
|
||||
if (mode_tp == "TP_FIXED_PIPS") {
|
||||
double adj_point = mdu.adjusted_point(symbol);
|
||||
if(order_side == 1){
|
||||
tp = price + _tp_var * adj_point;
|
||||
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||
if (order_side == 1) {
|
||||
tp = price + _tp_var * adj_point;
|
||||
if (!normalise_price(tp, tp, symbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(order_side == 2){
|
||||
if (order_side == 2) {
|
||||
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(order_side == 1){
|
||||
tp = _tp_var * price / 100.00 + price;
|
||||
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){
|
||||
if (order_side == 2) {
|
||||
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"){
|
||||
|
||||
int _atr_handle = iATR(symbol,atr_period,14);
|
||||
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);
|
||||
ArraySetAsSeries(atr, true);
|
||||
CopyBuffer(_atr_handle, MAIN_LINE, 1, 1, atr);
|
||||
|
||||
if(order_side == 1){
|
||||
if (order_side == 1) {
|
||||
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);
|
||||
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||
if (!normalise_price(tp, tp, symbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mode_tp=="TP_SL_MULTIPLE"){
|
||||
if(order_side == 1){
|
||||
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 (!normalise_price(tp, tp, symbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(order_side == 2){
|
||||
if (order_side == 2) {
|
||||
double sl_size = stoploss - price;
|
||||
tp = price - (_tp_var * sl_size);
|
||||
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||
tp = price - (_tp_var * sl_size);
|
||||
if (!normalise_price(tp, tp, symbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mode_tp=="TP_SPECIFIED_VALUE"){
|
||||
|
||||
if(_tp_var!=0){
|
||||
if (mode_tp == "TP_SPECIFIED_VALUE") {
|
||||
if (_tp_var != 0) {
|
||||
double adj_point = mdu.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 (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;
|
||||
if (!normalise_price(tp, tp, symbol)) {
|
||||
return false;
|
||||
}
|
||||
else tp = _tp_var;
|
||||
}
|
||||
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;}
|
||||
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 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_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 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;
|
||||
|
||||
if(mode_lot=="LOT_MODE_FIXED"){
|
||||
if (mode_lot == "LOT_MODE_FIXED") {
|
||||
lots = lot_var;
|
||||
}
|
||||
|
||||
if(mode_lot=="LOT_MODE_PCT_RISK"){
|
||||
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;
|
||||
lots = MathFloor(risk_money / money_lot_step) * volume_step;
|
||||
}
|
||||
|
||||
if(mode_lot=="LOT_MODE_PCT_ACCOUNT"){
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
bool CalculatePositionData::check_lots(double &lots, string symbol){
|
||||
|
||||
double min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
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){
|
||||
if (lots < min) {
|
||||
Print("Lot size will be set to minimum allowed volume");
|
||||
lots = min;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(lots>max){
|
||||
Print("Lot size greater than maximum allowed volume. lots:",lots,"max:",max);
|
||||
if (lots > max) {
|
||||
Print("Lot size greater than maximum allowed volume. lots:", lots, "max:", max);
|
||||
return false;
|
||||
}
|
||||
|
||||
lots = (int)MathFloor(lots/step) * step;
|
||||
lots = (int) MathFloor(lots / step) * step;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CalculatePositionData::normalise_price(double price, double &normalizedPrice, string symbol){
|
||||
bool CalculatePositionData::normalise_price(double price, double& normalizedPrice, string symbol) {
|
||||
double tickSize;
|
||||
if(!SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE,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);
|
||||
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){
|
||||
double CalculatePositionData::calculate_trading_cost(string symbol, ulong position_ticket) {
|
||||
position.SelectByTicket(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);
|
||||
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;
|
||||
return trading_cost;
|
||||
}
|
||||
+130
-94
@@ -1,112 +1,148 @@
|
||||
#include <Trade/Trade.mqh>
|
||||
#include <MyLibs/Orders/CalculatePositionData.mqh>
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
class EntryOrders {
|
||||
|
||||
protected:
|
||||
CTrade trade;
|
||||
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);
|
||||
CTrade trade;
|
||||
CalculatePositionData calc;
|
||||
|
||||
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);
|
||||
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);
|
||||
int count_open_positions(string symbol, int order_side, long _magic_number);
|
||||
|
||||
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);
|
||||
|
||||
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 count = 0;
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
|
||||
int type = (int) PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
int EntryOrders::count_open_positions(string symbol, int order_side, long magic_number) {
|
||||
int count = 0;
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
if ((order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ||
|
||||
(order_side == 2 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool EntryOrders::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) {
|
||||
if (condition) {
|
||||
current_price = SymbolInfoDouble(symbol, SYMBOL_ASK);
|
||||
total_open_buy_orders = count_open_positions(symbol, 1, magic_number);
|
||||
if (total_open_buy_orders == 0) {
|
||||
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 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 = "Magic Number: " + IntegerToString(magic_number);
|
||||
trade.PositionOpen(symbol, ORDER_TYPE_BUY, lots, current_price, stop_loss, take_profit, comment);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
bool EntryOrders::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) {
|
||||
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 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 lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
|
||||
|
||||
trade.SetExpertMagicNumber(_magic_number);
|
||||
string comment = "Magic Number: " + IntegerToString(_magic_number);
|
||||
return trade.PositionOpen(symbol, ORDER_TYPE_BUY, lots, current_price, stop_loss, take_profit, comment);
|
||||
}
|
||||
|
||||
bool EntryOrders::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) {
|
||||
if (condition) {
|
||||
current_price = SymbolInfoDouble(symbol, SYMBOL_BID);
|
||||
total_open_sell_orders = count_open_positions(symbol, 2, magic_number);
|
||||
if (total_open_sell_orders == 0) {
|
||||
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 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 = "Magic Number: " + IntegerToString(magic_number);
|
||||
trade.PositionOpen(symbol, ORDER_TYPE_SELL, 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, 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 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 lots = calc.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
|
||||
|
||||
trade.SetExpertMagicNumber(_magic_number);
|
||||
string comment = "Magic Number: " + IntegerToString(_magic_number);
|
||||
return trade.PositionOpen(symbol, ORDER_TYPE_SELL, lots, current_price, stop_loss, take_profit, comment);
|
||||
}
|
||||
|
||||
bool EntryOrders::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) {
|
||||
if (condition) {
|
||||
total_open_buy_orders = count_open_positions(symbol, 1, magic_number);
|
||||
if (total_open_buy_orders == 0) {
|
||||
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 sl_distance = entry_price - stop_loss;
|
||||
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.BuyStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
bool EntryOrders::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) {
|
||||
if (!condition) return false;
|
||||
if (count_open_positions(symbol, 1, _magic_number) > 0) return false;
|
||||
|
||||
double stop_loss = calc.calculate_stoploss(symbol, entry_price, 1, _sl_mode, sl_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 lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
|
||||
|
||||
trade.SetExpertMagicNumber(_magic_number);
|
||||
string comment = "Magic Number: " + IntegerToString(_magic_number);
|
||||
return trade.BuyStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
|
||||
}
|
||||
|
||||
bool EntryOrders::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) {
|
||||
if (condition) {
|
||||
total_open_sell_orders = count_open_positions(symbol, 2, magic_number);
|
||||
if (total_open_sell_orders == 0) {
|
||||
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 sl_distance = stop_loss - entry_price;
|
||||
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.SellStop(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, 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;
|
||||
if (count_open_positions(symbol, 2, _magic_number) > 0) return false;
|
||||
|
||||
double stop_loss = calc.calculate_stoploss(symbol, entry_price, 2, _sl_mode, sl_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 lots = calc.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
|
||||
|
||||
trade.SetExpertMagicNumber(_magic_number);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+98
-114
@@ -1,153 +1,137 @@
|
||||
#include <Trade/Trade.mqh>
|
||||
#include <MyLibs/Utils/TimeZones.mqh>
|
||||
#include <MyLibs/Orders/CalculatePositionData.mqh>
|
||||
#include <MyLibs/Utils/TimeZones.mqh>
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
class ExitOrders {
|
||||
|
||||
protected:
|
||||
CTrade trade;
|
||||
TimeZones tz;
|
||||
CalculatePositionData cpd;
|
||||
CTrade trade;
|
||||
TimeZones tz;
|
||||
CalculatePositionData calc;
|
||||
|
||||
ulong posTicket;
|
||||
long position_open_time;
|
||||
long first_allowed_close_time;
|
||||
ulong posTicket;
|
||||
long position_open_time;
|
||||
long first_allowed_close_time;
|
||||
|
||||
public:
|
||||
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 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 first_profitable_close_exit(string symbol, 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 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 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) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
|
||||
bool ExitOrders::close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,
|
||||
long 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;
|
||||
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
||||
if (condition || (close_bars > 0 && time_difference >= close_bars)) {
|
||||
trade.PositionClose(posTicket);
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
||||
if (condition || (close_bars > 0 && time_difference >= close_bars)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
|
||||
bool ExitOrders::close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period,
|
||||
long 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;
|
||||
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
int time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
||||
if (condition || (close_bars > 0 && time_difference >= close_bars)) {
|
||||
trade.PositionClose(posTicket);
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
||||
if (condition || (close_bars > 0 && time_difference >= close_bars)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_days, long _magic_number) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
|
||||
bool ExitOrders::daily_timed_exit(string symbol, datetime exit_time, int delay_days, long magic_number) {
|
||||
if ((int) position_open_time > 0) {
|
||||
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
|
||||
if ((int)position_open_time > 0) {
|
||||
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||
|
||||
if (TimeCurrent() > first_allowed_close_time && TimeCurrent() >= exit_time) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
trade.PositionClose(posTicket);
|
||||
if (TimeCurrent() > first_allowed_close_time && TimeCurrent() >= exit_time) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
long _magic_number) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
|
||||
bool ExitOrders::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time,
|
||||
string cw_tzone, int delay_days, long magic_number) {
|
||||
if ((int) position_open_time > 0) {
|
||||
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
if (TimeCurrent() > first_allowed_close_time) {
|
||||
datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker");
|
||||
|
||||
if ((int)position_open_time > 0) {
|
||||
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||
if (TimeCurrent() >= broker_close_time && PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == _magic_number) {
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
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 trading_cost = calc.calculate_trading_cost(symbol, posTicket);
|
||||
|
||||
if (TimeCurrent() > first_allowed_close_time) {
|
||||
datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker");
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
|
||||
bar_close > (position_open_price + spread + trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
|
||||
if (TimeCurrent() >= broker_close_time &&
|
||||
PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
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 trading_cost = cpd.calculate_trading_cost(symbol, posTicket);
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
|
||||
bar_close > (position_open_price + spread + trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
|
||||
bar_close < (position_open_price - spread - trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
|
||||
bar_close < (position_open_price - spread - trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExitOrders::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long _magic_number) {
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
first_allowed_close_time = position_open_time + PeriodSeconds(close_bar_period);
|
||||
|
||||
bool ExitOrders::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long magic_number) {
|
||||
if ((int) position_open_time > 0 && TimeCurrent() > first_allowed_close_time) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
|
||||
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||
first_allowed_close_time = position_open_time + PeriodSeconds(close_bar_period);
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == _magic_number) {
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID);
|
||||
double bar_close = iClose(_Symbol, close_bar_period, 1);
|
||||
double trading_cost = calc.calculate_trading_cost(symbol, posTicket);
|
||||
|
||||
if ((int)position_open_time > 0 && TimeCurrent() > first_allowed_close_time) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
posTicket = PositionGetTicket(i);
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && bar_close > (position_open_price + spread + trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double spread = SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID);
|
||||
double bar_close = iClose(_Symbol, close_bar_period, 1);
|
||||
double trading_cost = cpd.calculate_trading_cost(symbol, posTicket);
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
|
||||
bar_close > (position_open_price + spread + trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && bar_close < (position_open_price - spread - trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
|
||||
bar_close < (position_open_price - spread - trading_cost)) {
|
||||
trade.PositionClose(posTicket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
+36
-42
@@ -2,68 +2,62 @@
|
||||
#include <Trade/PositionInfo.mqh>
|
||||
|
||||
class OrderTracker {
|
||||
|
||||
protected:
|
||||
COrderInfo m_order;
|
||||
CPositionInfo m_position;
|
||||
COrderInfo m_order;
|
||||
CPositionInfo m_position;
|
||||
|
||||
public:
|
||||
int count_open_positions(string symbol, int order_side, long magic_number);
|
||||
int count_all_positions(string symbol, long magic_number);
|
||||
int count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic);
|
||||
int count_open_positions(string symbol, int order_side, long magic_number);
|
||||
int count_all_positions(string symbol, long magic_number);
|
||||
int count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic);
|
||||
};
|
||||
|
||||
int OrderTracker::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--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
if (order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (order_side == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
||||
count++;
|
||||
}
|
||||
if (order_side == 2 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (order_side == 2 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int OrderTracker::count_all_positions(string symbol, long magic_number) {
|
||||
int count = 0;
|
||||
int count = 0;
|
||||
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int OrderTracker::count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic) {
|
||||
int count = 0;
|
||||
int count = 0;
|
||||
|
||||
for (int i = OrdersTotal() - 1; i >= 0; i--) {
|
||||
if (m_order.SelectByIndex(i)) {
|
||||
if (OrderGetInteger(ORDER_MAGIC) == magic && OrderGetString(ORDER_SYMBOL) == symbol) {
|
||||
if (m_order.OrderType() == order_type) {
|
||||
count++;
|
||||
for (int i = OrdersTotal() - 1; i >= 0; i--) {
|
||||
if (m_order.SelectByIndex(i)) {
|
||||
if (OrderGetInteger(ORDER_MAGIC) == magic && OrderGetString(ORDER_SYMBOL) == symbol) {
|
||||
if (m_order.OrderType() == order_type) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,21 +1,21 @@
|
||||
class StopLogic {
|
||||
public:
|
||||
double sl_specified_value_switch(string sl_mode, double inp_sl_var, double value);
|
||||
double tp_specified_value_switch(string tp_mode, double inp_tp_var, double value);
|
||||
double sl_specified_value_switch(string sl_mode, double inp_sl_var, double value);
|
||||
double tp_specified_value_switch(string tp_mode, double inp_tp_var, double value);
|
||||
};
|
||||
|
||||
double StopLogic::sl_specified_value_switch(string sl_mode, double inp_sl_var, double value) {
|
||||
if (sl_mode == "SL_SPECIFIED_VALUE") {
|
||||
return value;
|
||||
} else {
|
||||
return inp_sl_var;
|
||||
}
|
||||
if (sl_mode == "SL_SPECIFIED_VALUE") {
|
||||
return value;
|
||||
} else {
|
||||
return inp_sl_var;
|
||||
}
|
||||
}
|
||||
|
||||
double StopLogic::tp_specified_value_switch(string tp_mode, double inp_tp_var, double value) {
|
||||
if (tp_mode == "SL_SPECIFIED_VALUE") {
|
||||
return value;
|
||||
} else {
|
||||
return inp_tp_var;
|
||||
}
|
||||
if (tp_mode == "SL_SPECIFIED_VALUE") {
|
||||
return value;
|
||||
} else {
|
||||
return inp_tp_var;
|
||||
}
|
||||
}
|
||||
|
||||
+64
-78
@@ -1,95 +1,81 @@
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
class TrailingLogic {
|
||||
|
||||
protected:
|
||||
CTrade trade;
|
||||
CTrade trade;
|
||||
|
||||
public:
|
||||
void break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer);
|
||||
void nnfx_trailing_stop(string symbol, double sl_var, double tp_var, double atr_value, ulong magic_number);
|
||||
void break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer);
|
||||
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) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
|
||||
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits);
|
||||
double bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), symbol_digits);
|
||||
|
||||
if (be_trigger_points != 0) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionSelectByTicket(ticket)) {
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double position_volume = PositionGetDouble(POSITION_VOLUME);
|
||||
double position_sl = PositionGetDouble(POSITION_SL);
|
||||
double position_tp = PositionGetDouble(POSITION_TP);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
if (position_type == POSITION_TYPE_BUY &&
|
||||
bid > position_open_price + be_trigger_points * symbol_point) {
|
||||
|
||||
double sl = NormalizeDouble(position_open_price + be_puffer * symbol_point, symbol_digits);
|
||||
if (sl > position_sl) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
Print("-----------------------------------Stop moved to break even");
|
||||
}
|
||||
}
|
||||
|
||||
if (position_type == POSITION_TYPE_SELL &&
|
||||
ask < position_open_price - be_trigger_points * symbol_point) {
|
||||
|
||||
double sl = NormalizeDouble(position_open_price - be_puffer * symbol_point, symbol_digits);
|
||||
if (sl < position_sl) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
Print("-----------------------------------Stop moved to break even");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionSelectByTicket(ticket)) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
|
||||
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits);
|
||||
double bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), symbol_digits);
|
||||
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double position_sl = PositionGetDouble(POSITION_SL);
|
||||
double position_tp = PositionGetDouble(POSITION_TP);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if (be_trigger_points != 0) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionSelectByTicket(ticket)) {
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double position_volume = PositionGetDouble(POSITION_VOLUME);
|
||||
double position_sl = PositionGetDouble(POSITION_SL);
|
||||
double position_tp = PositionGetDouble(POSITION_TP);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
if (position_type == POSITION_TYPE_BUY &&
|
||||
bid > position_open_price + (atr_value * tp_var)) {
|
||||
if (position_type == POSITION_TYPE_BUY && bid > position_open_price + be_trigger_points * symbol_point) {
|
||||
double sl = NormalizeDouble(position_open_price + be_puffer * symbol_point, symbol_digits);
|
||||
if (sl > position_sl) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
Print("-----------------------------------Stop moved to break even");
|
||||
}
|
||||
}
|
||||
|
||||
double sl = NormalizeDouble(bid - (atr_value * sl_var), symbol_digits);
|
||||
if (sl > (position_sl + (atr_value * 0.5))) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
}
|
||||
if (position_type == POSITION_TYPE_SELL && ask < position_open_price - be_trigger_points * symbol_point) {
|
||||
double sl = NormalizeDouble(position_open_price - be_puffer * symbol_point, symbol_digits);
|
||||
if (sl < position_sl) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
Print("-----------------------------------Stop moved to break even");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (position_type == POSITION_TYPE_SELL &&
|
||||
ask < position_open_price - (atr_value * tp_var)) {
|
||||
|
||||
double sl = NormalizeDouble(ask + (atr_value * sl_var), symbol_digits);
|
||||
if (sl < (position_sl + (atr_value * 0.5))) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (PositionSelectByTicket(ticket)) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number) {
|
||||
int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), symbol_digits);
|
||||
double bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), symbol_digits);
|
||||
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double position_sl = PositionGetDouble(POSITION_SL);
|
||||
double position_tp = PositionGetDouble(POSITION_TP);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
if (position_type == POSITION_TYPE_BUY && bid > position_open_price + (atr_value * tp_var)) {
|
||||
double sl = NormalizeDouble(bid - (atr_value * sl_var), symbol_digits);
|
||||
if (sl > (position_sl + (atr_value * 0.5))) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
}
|
||||
}
|
||||
|
||||
if (position_type == POSITION_TYPE_SELL && ask < position_open_price - (atr_value * tp_var)) {
|
||||
double sl = NormalizeDouble(ask + (atr_value * sl_var), symbol_digits);
|
||||
if (sl < (position_sl + (atr_value * 0.5))) {
|
||||
trade.PositionModify(ticket, sl, position_tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,111 +1,105 @@
|
||||
|
||||
class EntryState {
|
||||
public:
|
||||
int last_trigger_bar_long;
|
||||
int last_trigger_bar_short;
|
||||
int last_bl_cross_long;
|
||||
int last_bl_cross_short;
|
||||
int last_entry_long;
|
||||
int last_entry_short;
|
||||
public:
|
||||
int last_trigger_bar_long;
|
||||
int last_trigger_bar_short;
|
||||
int last_bl_cross_long;
|
||||
int last_bl_cross_short;
|
||||
int last_entry_long;
|
||||
int last_entry_short;
|
||||
|
||||
// Constructor
|
||||
EntryState() {
|
||||
reset();
|
||||
}
|
||||
// Constructor
|
||||
EntryState() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
last_trigger_bar_long = -1000;
|
||||
last_trigger_bar_short = -1000;
|
||||
last_bl_cross_long = -1000;
|
||||
last_bl_cross_short = -1000;
|
||||
last_entry_long = -1000;
|
||||
last_entry_short = -1000;
|
||||
}
|
||||
void reset() {
|
||||
last_trigger_bar_long = -1000;
|
||||
last_trigger_bar_short = -1000;
|
||||
last_bl_cross_long = -1000;
|
||||
last_bl_cross_short = -1000;
|
||||
last_entry_long = -1000;
|
||||
last_entry_short = -1000;
|
||||
}
|
||||
|
||||
void update_trigger(bool trig_long, bool trig_short, int curr_bar) {
|
||||
if (trig_long) last_trigger_bar_long = curr_bar;
|
||||
if (trig_short) last_trigger_bar_short = curr_bar;
|
||||
}
|
||||
void update_trigger(bool trig_long, bool trig_short, int curr_bar) {
|
||||
if (trig_long) last_trigger_bar_long = curr_bar;
|
||||
if (trig_short) last_trigger_bar_short = curr_bar;
|
||||
}
|
||||
|
||||
void update_baseline_cross(int curr_bar, double price, double baseline, double prev_price, double prev_baseline) {
|
||||
if (prev_price < prev_baseline && price > baseline)
|
||||
last_bl_cross_long = curr_bar;
|
||||
if (prev_price > prev_baseline && price < baseline)
|
||||
last_bl_cross_short = curr_bar;
|
||||
}
|
||||
void update_baseline_cross(int curr_bar, double price, double baseline, double prev_price, double prev_baseline) {
|
||||
if (prev_price < prev_baseline && price > baseline) last_bl_cross_long = curr_bar;
|
||||
if (prev_price > prev_baseline && price < baseline) last_bl_cross_short = curr_bar;
|
||||
}
|
||||
|
||||
void update_entry(bool is_long, int curr_bar) {
|
||||
if (is_long)
|
||||
last_entry_long = curr_bar;
|
||||
else
|
||||
last_entry_short = curr_bar;
|
||||
}
|
||||
|
||||
int get_last_trigger(bool is_long) {
|
||||
return is_long ? last_trigger_bar_long : last_trigger_bar_short;
|
||||
}
|
||||
|
||||
int get_last_cross(bool is_long) {
|
||||
return is_long ? last_bl_cross_long : last_bl_cross_short;
|
||||
}
|
||||
|
||||
int get_last_entry(bool is_long) {
|
||||
return is_long ? last_entry_long : last_entry_short;
|
||||
}
|
||||
void update_entry(bool is_long, int curr_bar) {
|
||||
if (is_long)
|
||||
last_entry_long = curr_bar;
|
||||
else
|
||||
last_entry_short = curr_bar;
|
||||
}
|
||||
int get_last_trigger(bool is_long) {
|
||||
return is_long ? last_trigger_bar_long : last_trigger_bar_short;
|
||||
}
|
||||
int get_last_cross(bool is_long) {
|
||||
return is_long ? last_bl_cross_long : last_bl_cross_short;
|
||||
}
|
||||
int get_last_entry(bool is_long) {
|
||||
return is_long ? last_entry_long : last_entry_short;
|
||||
}
|
||||
};
|
||||
|
||||
// Snapshot of conditions for a potential entry signal
|
||||
struct EntryContext {
|
||||
bool trigger;
|
||||
bool confirm;
|
||||
bool volume;
|
||||
bool recent;
|
||||
bool base_ok;
|
||||
bool near;
|
||||
bool far;
|
||||
int last_entry;
|
||||
int last_cross;
|
||||
bool trigger;
|
||||
bool confirm;
|
||||
bool volume;
|
||||
bool recent;
|
||||
bool base_ok;
|
||||
bool near;
|
||||
bool far;
|
||||
int last_entry;
|
||||
int last_cross;
|
||||
};
|
||||
|
||||
// Utility: check if signal occurred recently
|
||||
bool is_recent(int signal_bar, int curr_bar, int lookback) {
|
||||
return (curr_bar - signal_bar) < lookback;
|
||||
return (curr_bar - signal_bar) < lookback;
|
||||
}
|
||||
|
||||
// Utility: build current entry condition context
|
||||
EntryContext build_entry_context(bool is_long, double price, double baseline, double atr,
|
||||
int last_cross, int last_entry,
|
||||
bool trigger, bool confirm, bool volume, bool recent) {
|
||||
EntryContext ctx;
|
||||
ctx.trigger = trigger;
|
||||
ctx.confirm = confirm;
|
||||
ctx.volume = volume;
|
||||
ctx.recent = recent;
|
||||
ctx.base_ok = is_long ? (price > baseline) : (price < baseline);
|
||||
ctx.near = MathAbs(price - baseline) <= atr;
|
||||
ctx.far = MathAbs(price - baseline) > atr;
|
||||
ctx.last_entry = last_entry;
|
||||
ctx.last_cross = last_cross;
|
||||
return ctx;
|
||||
EntryContext build_entry_context(bool is_long, double price, double baseline, double atr, int last_cross, int last_entry, bool trigger,
|
||||
bool confirm, bool volume, bool recent) {
|
||||
EntryContext ctx;
|
||||
ctx.trigger = trigger;
|
||||
ctx.confirm = confirm;
|
||||
ctx.volume = volume;
|
||||
ctx.recent = recent;
|
||||
ctx.base_ok = is_long ? (price > baseline) : (price < baseline);
|
||||
ctx.near = MathAbs(price - baseline) <= atr;
|
||||
ctx.far = MathAbs(price - baseline) > atr;
|
||||
ctx.last_entry = last_entry;
|
||||
ctx.last_cross = last_cross;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Class wrapper for entry logic
|
||||
class EntryLogic {
|
||||
public:
|
||||
bool is_standard_entry(const EntryContext &ctx) {
|
||||
return ctx.trigger && ctx.confirm && ctx.volume && ctx.recent && ctx.base_ok && ctx.near;
|
||||
}
|
||||
public:
|
||||
bool is_standard_entry(const EntryContext& ctx) {
|
||||
return ctx.trigger && ctx.confirm && ctx.volume && ctx.recent && ctx.base_ok && ctx.near;
|
||||
}
|
||||
|
||||
bool is_pullback_entry(const EntryContext &ctx, int curr_bar) {
|
||||
return (curr_bar - ctx.last_cross <= 2) && ctx.confirm && ctx.volume && ctx.base_ok && ctx.far;
|
||||
}
|
||||
bool is_pullback_entry(const EntryContext& ctx, int curr_bar) {
|
||||
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 crossed = is_long ? (prev_price < prev_baseline && price > baseline): (prev_price > prev_baseline && price < baseline);
|
||||
return crossed && ctx.confirm && ctx.volume && ctx.near;
|
||||
}
|
||||
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);
|
||||
return crossed && ctx.confirm && ctx.volume && ctx.near;
|
||||
}
|
||||
|
||||
bool is_continuation_entry(const EntryContext &ctx, int curr_bar, int look_back) {
|
||||
return (curr_bar - ctx.last_entry <= look_back) && ctx.last_entry > ctx.last_cross && ctx.trigger && ctx.confirm && ctx.base_ok;
|
||||
}
|
||||
bool is_continuation_entry(const EntryContext& ctx, int curr_bar, int look_back) {
|
||||
return (curr_bar - ctx.last_entry <= look_back) && ctx.last_entry > ctx.last_cross && ctx.trigger && ctx.confirm && ctx.base_ok;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,17 +42,21 @@ double MarketDataUtils::get_latest_buffer_value(int handle) {
|
||||
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 val[];
|
||||
ArraySetAsSeries(val, true);
|
||||
|
||||
if (CopyBuffer(handle, 0, shift, 1, val) == 1)
|
||||
return val[0]; // Historical value at given shift
|
||||
double val[];
|
||||
ArraySetAsSeries(val, true);
|
||||
|
||||
return 0.0;
|
||||
if (CopyBuffer(handle, 0, shift, 1, val) == 1 && val[0] != EMPTY_VALUE)
|
||||
return val[0];
|
||||
|
||||
return EMPTY_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// Adjusts the point value for symbol to account for fractional pips (e.g., 5-digit brokers)
|
||||
double MarketDataUtils::adjusted_point(string symbol) {
|
||||
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user