140 lines
4.2 KiB
MQL5
140 lines
4.2 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| TrailingStop.mqh |
|
||
|
//| Copyright 2022, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#include "MqlTradeSync.mqh"
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Base class for trailing on specific distance in points |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class TrailingStop
|
||
|
{
|
||
|
const ulong ticket; // position to manage
|
||
|
const string symbol; // symbol of the position
|
||
|
const double point; // price point for the symbol
|
||
|
const uint distance; // stop loss in points (for default trailing method)
|
||
|
const uint step; // sensitivity in points (1+)
|
||
|
|
||
|
protected:
|
||
|
double level;
|
||
|
bool ok;
|
||
|
|
||
|
virtual double detectLevel() // override this method in descendants
|
||
|
{
|
||
|
return DBL_MAX; // default distance trailing is enabled
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
TrailingStop(const ulong t, const uint d, const uint s = 1) :
|
||
|
ticket(t), distance(d), step(fmax(s, 1)),
|
||
|
symbol(PositionSelectByTicket(t) ? PositionGetString(POSITION_SYMBOL) : NULL),
|
||
|
point(SymbolInfoDouble(symbol, SYMBOL_POINT))
|
||
|
{
|
||
|
if(symbol == NULL)
|
||
|
{
|
||
|
WARNING("Position not found: " + (string)t);
|
||
|
ok = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ok = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool isOK() const
|
||
|
{
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
double getLevel() const
|
||
|
{
|
||
|
return level;
|
||
|
}
|
||
|
|
||
|
virtual bool trail()
|
||
|
{
|
||
|
if(!PositionSelectByTicket(ticket))
|
||
|
{
|
||
|
ok = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// get prices required for calculations
|
||
|
const double current = PositionGetDouble(POSITION_PRICE_CURRENT);
|
||
|
const double sl = PositionGetDouble(POSITION_SL);
|
||
|
const double tp = PositionGetDouble(POSITION_TP);
|
||
|
|
||
|
// POSITION_TYPE_BUY = 0 (false)
|
||
|
// POSITION_TYPE_SELL = 1 (true)
|
||
|
const bool sell = (bool)PositionGetInteger(POSITION_TYPE);
|
||
|
TU::TradeDirection dir(sell);
|
||
|
|
||
|
level = detectLevel();
|
||
|
if(level == 0) return true; // can't trail - caller should remove SL if they want
|
||
|
if(level == DBL_MAX) level = dir.negative(current, point * distance);
|
||
|
level = TU::NormalizePrice(level, symbol);
|
||
|
|
||
|
if(!dir.better(current, level))
|
||
|
{
|
||
|
return true; // can't change SL to profitable side
|
||
|
}
|
||
|
|
||
|
if(sl == 0)
|
||
|
{
|
||
|
PrintFormat("Initial SL: %f", level);
|
||
|
move(level, tp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(dir.better(level, sl) && fabs(level - sl) >= point * step)
|
||
|
{
|
||
|
PrintFormat("SL: %f -> %f", sl, level);
|
||
|
move(level, tp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true; // has position
|
||
|
}
|
||
|
|
||
|
bool move(const double sl, const double tp)
|
||
|
{
|
||
|
MqlTradeRequestSync request;
|
||
|
request.position = ticket;
|
||
|
if(request.adjust(sl, tp) && request.completed())
|
||
|
{
|
||
|
Print("OK Trailing: ", TU::StringOf(sl));
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Derived class for trailing by Moving Average |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class TrailingStopByMA: public TrailingStop
|
||
|
{
|
||
|
int handle;
|
||
|
public:
|
||
|
TrailingStopByMA(const ulong t, const int period,
|
||
|
const int offset = 1,
|
||
|
const ENUM_MA_METHOD method = MODE_SMA,
|
||
|
const ENUM_APPLIED_PRICE type = PRICE_CLOSE): TrailingStop(t, 0, 1)
|
||
|
{
|
||
|
handle = iMA(_Symbol, PERIOD_CURRENT, period, offset, method, type);
|
||
|
}
|
||
|
virtual double detectLevel() override
|
||
|
{
|
||
|
double array[1];
|
||
|
ResetLastError();
|
||
|
if(CopyBuffer(handle, 0, 0, 1, array) != 1)
|
||
|
{
|
||
|
Print("CopyBuffer error: ", _LastError);
|
||
|
return 0;
|
||
|
}
|
||
|
return array[0];
|
||
|
}
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|