Article-16991-MQL5-Post-Fac.../Trailings.mqh
2026-03-24 13:45:14 +07:00

932 行
101 KiB
MQL5

//+------------------------------------------------------------------+
//| Trailings.mqh |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Класс простого трала StopLoss позиций |
//+------------------------------------------------------------------+
class CSimpleTrailing : public CObject
{
private:
//--- проверяет критерии модификации StopLoss позициии и возвращает флаг
bool CheckCriterion(ENUM_POSITION_TYPE pos_type, double pos_open, double pos_sl, double value_sl, MqlTick &tick);
//--- модифицирует StopLoss позиции по её тикету
bool ModifySL(const ulong ticket, const double stop_loss);
//--- возвращает размер StopLevel в пунктах
int StopLevel(void);
protected:
string m_symbol; // торговый символ
long m_magic; // идентификатор эксперта
double m_point; // Point символа
int m_digits; // Digits символа
int m_offset; // дистанция стопа от цены
int m_trail_start; // прибыль в пунктах для запуска трала
uint m_trail_step; // шаг трала
uint m_spread_mlt; // множитель спреда для возврата значения StopLevel
bool m_active; // флаг активности трала
//--- рассчитывает и возвращает уровень StopLoss выбранной позиции
virtual double GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick);
public:
//--- установка параметров трала
void SetSymbol(const string symbol)
{
this.m_symbol = (symbol==NULL || symbol=="" ? ::Symbol() : symbol);
this.m_point =::SymbolInfoDouble(this.m_symbol, SYMBOL_POINT);
this.m_digits = (int)::SymbolInfoInteger(this.m_symbol, SYMBOL_DIGITS);
}
void SetMagicNumber(const long magic) { this.m_magic = magic; }
void SetStopLossOffset(const int offset) { this.m_offset = offset; }
void SetTrailingStart(const int start) { this.m_trail_start = start; }
void SetTrailingStep(const uint step) { this.m_trail_step = step; }
void SetSpreadMultiplier(const uint value) { this.m_spread_mlt = value; }
void SetActive(const bool flag) { this.m_active = flag; }
//--- возврат параметров трала
string Symbol(void) const { return this.m_symbol; }
long MagicNumber(void) const { return this.m_magic; }
int StopLossOffset(void) const { return this.m_offset; }
int TrailingStart(void) const { return this.m_trail_start; }
uint TrailingStep(void) const { return this.m_trail_step; }
uint SpreadMultiplier(void) const { return this.m_spread_mlt; }
bool IsActive(void) const { return this.m_active; }
//--- запуск трала с отступом StopLoss от цены
bool Run(void);
bool Run(const ulong pos_ticket);
//--- конструкторы
CSimpleTrailing() : m_symbol(::Symbol()), m_point(::Point()), m_digits(::Digits()),
m_magic(-1), m_trail_start(0), m_trail_step(0), m_offset(0), m_spread_mlt(2) {}
CSimpleTrailing(const string symbol, const long magic,
const int trailing_start, const uint trailing_step, const int offset);
//--- деструктор
~CSimpleTrailing() {}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CSimpleTrailing::CSimpleTrailing(const string symbol, const long magic,
const int trail_start, const uint trail_step, const int offset) : m_spread_mlt(2)
{
this.SetSymbol(symbol);
this.m_magic = magic;
this.m_trail_start= trail_start;
this.m_trail_step = trail_step;
this.m_offset = offset;
}
//+------------------------------------------------------------------+
//| Рассчитывает и возвращает уровень StopLoss выбранной позиции |
//+------------------------------------------------------------------+
double CSimpleTrailing::GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick)
{
//--- в зависимости от типа позиции рассчитываем и возвращаем уровень StopLoss
switch(pos_type)
{
case POSITION_TYPE_BUY : return(tick.bid - this.m_offset * this.m_point);
case POSITION_TYPE_SELL : return(tick.ask + this.m_offset * this.m_point);
default : return 0;
}
}
//+------------------------------------------------------------------+
//|Проверяет критерии модификации StopLoss позициии и возвращает флаг|
//+------------------------------------------------------------------+
bool CSimpleTrailing::CheckCriterion(ENUM_POSITION_TYPE pos_type, double pos_open, double pos_sl, double value_sl, MqlTick &tick)
{
//--- если стоп позиции и уровень стопа для модификации равны, или передан нулевой StopLoss - возвращаем false
if(::NormalizeDouble(pos_sl - value_sl, this.m_digits) == 0 || value_sl==0)
return false;
//--- переменные трала
double trailing_step = this.m_trail_step * this.m_point; // переводим шаг трала в цену
double stop_level = this.StopLevel() * this.m_point; // переводим StopLevel символа в цену
int pos_profit_pt = 0; // прибыль позиции в пунктах
//--- в зависимости от типа позиции проверяем условия для модицикации StopLoss
switch(pos_type)
{
//--- длинная позиция
case POSITION_TYPE_BUY :
pos_profit_pt = int((tick.bid - pos_open) / this.m_point); // рассчитываем прибыль позиции в пунктах
if(tick.bid - stop_level > value_sl // если уровень StopLoss ниже цены с отложенным вниз от неё уровнем StopLevel (соблюдена дистанция по StopLevel)
&& pos_sl + trailing_step < value_sl // если уровень StopLoss выше, чем шаг трала, отложенный вверх от текущего StopLoss позиции
&& (this.m_trail_start == 0 || pos_profit_pt > this.m_trail_start) // если тралим при любой прибыли, или прибыль позиции в пунктах больше значения начала трейлинга - возвращаем true
)
return true;
break;
//--- короткая позиция
case POSITION_TYPE_SELL :
pos_profit_pt = int((pos_open - tick.ask) / this.m_point); // рассчитываем прибыль позиции в пунктах
if(tick.ask + stop_level < value_sl // если уровень StopLoss выше цены с отложенным вверх от неё уровнем StopLevel (соблюдена дистанция по StopLevel)
&& (pos_sl - trailing_step > value_sl || pos_sl == 0) // если уровень StopLoss ниже, чем шаг трала, отложенный вниз от текущего StopLoss позиции, или у позиции ещё не установлен StopLoss
&& (this.m_trail_start == 0 || pos_profit_pt > this.m_trail_start) // если тралим при любой прибыли, или прибыль позиции в пунктах больше значения начала трейлинга - возвращаем true
)
return true;
break;
//--- по умолчанию вернём false
default:
break;
}
//--- условия не подошли - возвращаем false
return false;
}
//+------------------------------------------------------------------+
//| Модифицирует StopLoss позиции по тикету |
//+------------------------------------------------------------------+
bool CSimpleTrailing::ModifySL(const ulong ticket, const double stop_loss)
{
//--- если взведён флаг остановки эксперта - сообщаем об этом в журнал и возвращаем false
if(::IsStopped())
{
Print("The Expert Advisor is stopped, trading is disabled");
return false;
}
//--- если позицию не удалось выбрать по тикету - сообщаем об этом в журнал и возвращаем false
::ResetLastError();
if(!::PositionSelectByTicket(ticket))
{
::PrintFormat("%s: Failed to select position by ticket number %I64u. Error %d", __FUNCTION__, ticket, ::GetLastError());
return false;
}
//--- объявляем структуры торгового запроса и результата запроса
MqlTradeRequest request= {};
MqlTradeResult result = {};
//--- заполняем структуру запроса
request.action = TRADE_ACTION_SLTP;
request.symbol = ::PositionGetString(POSITION_SYMBOL);
request.magic = ::PositionGetInteger(POSITION_MAGIC);
request.tp = ::PositionGetDouble(POSITION_TP);
request.position = ticket;
request.sl = ::NormalizeDouble(stop_loss, this.m_digits);
//--- если торговую операцию отправить не удалось - сообщаем об этом в журнал и возвращаем false
if(!::OrderSend(request, result))
{
PrintFormat("%s: OrderSend() failed to modify position #%I64u. Error %d",__FUNCTION__, ticket, ::GetLastError());
return false;
}
//--- успешно отправлен запрос на изменение StopLoss позиции
return true;
}
//+------------------------------------------------------------------+
//| Возвращает размер StopLevel в пунктах |
//+------------------------------------------------------------------+
int CSimpleTrailing::StopLevel(void)
{
int spread = (int)::SymbolInfoInteger(this.m_symbol, SYMBOL_SPREAD);
int stop_level = (int)::SymbolInfoInteger(this.m_symbol, SYMBOL_TRADE_STOPS_LEVEL);
return int(stop_level == 0 ? spread * this.m_spread_mlt : stop_level);
}
//+------------------------------------------------------------------+
//| Запускает простой трейлинг с отступом StopLoss от цены |
//+------------------------------------------------------------------+
bool CSimpleTrailing::Run(void)
{
//--- если отключен - уходим
if(!this.m_active)
return false;
//--- переменные трала
bool res = true; // результат модификации всех позиций
//--- проверка корректности данных по символу
if(this.m_point==0)
{
//--- попробуем ещё раз получить данные
::ResetLastError();
this.SetSymbol(this.m_symbol);
if(this.m_point==0)
{
::PrintFormat("%s: Correct data was not received for the %s symbol. Error %d",__FUNCTION__, this.m_symbol, ::GetLastError());
return false;
}
}
//--- в цикле по общему количеству открытых позиций
int total =::PositionsTotal();
for(int i = total - 1; i >= 0; i--)
{
//--- получаем тикет очередной позиции
ulong pos_ticket =::PositionGetTicket(i);
if(pos_ticket == 0)
continue;
//--- получаем символ и магик позиции
string pos_symbol = ::PositionGetString(POSITION_SYMBOL);
long pos_magic = ::PositionGetInteger(POSITION_MAGIC);
//--- если позиция не соответствует фильтру по символу и магику - уходим
if((this.m_magic != -1 && pos_magic != this.m_magic) || (pos_symbol != this.m_symbol))
continue;
res &=this.Run(pos_ticket);
}
//--- по окончании цикла возвращаем результат модификации каждой подходящей по фильтру "символ/магик" позиции
return res;
}
//+------------------------------------------------------------------+
//| Запускает простой трейлинг с отступом StopLoss от цены |
//+------------------------------------------------------------------+
bool CSimpleTrailing::Run(const ulong pos_ticket)
{
//--- если трейлинг отключен, или невалидный тикет - уходим
if(!this.m_active || pos_ticket==0)
return false;
//--- переменные трала
MqlTick tick = {}; // структура цен
//--- проверка корректности данных по символу
::ResetLastError();
if(this.m_point==0)
{
//--- попробуем ещё раз получить данные
this.SetSymbol(this.m_symbol);
if(this.m_point==0)
{
::PrintFormat("%s: Correct data was not received for the %s symbol. Error %d",__FUNCTION__, this.m_symbol, ::GetLastError());
return false;
}
}
//--- выбираем позицию по тикету
if(!::PositionSelectByTicket(pos_ticket))
{
::PrintFormat("%s: PositionSelectByTicket(%I64u) failed. Error %d",__FUNCTION__, pos_ticket, ::GetLastError());
return false;
}
//--- если цены получить не удалось - возвращаем false
if(!::SymbolInfoTick(this.m_symbol, tick))
return false;
//--- получаем тип позиции, цену её открытия и уровень StopLoss
ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)::PositionGetInteger(POSITION_TYPE);
double pos_open =::PositionGetDouble(POSITION_PRICE_OPEN);
double pos_sl =::PositionGetDouble(POSITION_SL);
//--- получаем рассчитанный уровень StopLoss
double value_sl = this.GetStopLossValue(pos_type, tick);
//--- если условия для модификации StopLoss подходят - возвращаем результат модифицикации стопа позиции
if(this.CheckCriterion(pos_type, pos_open, pos_sl, value_sl, tick))
return(this.ModifySL(pos_ticket, value_sl));
//--- условия для модификации не подходят
return false;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Базовый класс тралов по индикаторам |
//+------------------------------------------------------------------+
class CTrailingByInd : public CSimpleTrailing
{
protected:
ENUM_TIMEFRAMES m_timeframe; // таймфрейм индикатора
int m_handle; // хэндл индикатора
uint m_data_index; // бар данных индикатора
string m_timeframe_descr; // описание таймфрейма
//--- возвращает данные индикатора
double GetDataInd(void) const { return this.GetDataInd(this.m_data_index); }
//--- рассчитывает и возвращает уровень StopLoss выбранной позиции
virtual double GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick);
public:
//--- установка параметров
void SetTimeframe(const ENUM_TIMEFRAMES timeframe)
{
this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);
this.m_timeframe_descr=::StringSubstr(::EnumToString(this.m_timeframe), 7);
}
void SetDataIndex(const uint index) { this.m_data_index=index; }
//--- возврат параметров
ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; }
uint DataIndex(void) const { return this.m_data_index; }
string TimeframeDescription(void) const { return this.m_timeframe_descr; }
//--- возвращает данные индикатора с указанного индекса таймсерии
double GetDataInd(const int index) const;
//--- конструкторы
CTrailingByInd(void) : CSimpleTrailing(::Symbol(), -1, 0, 0, 0), m_timeframe(::Period()),
m_handle(INVALID_HANDLE), m_data_index(1), m_timeframe_descr(::StringSubstr(::EnumToString(::Period()), 7)) {}
CTrailingByInd(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic, const int trail_start, const uint trail_step, const int trail_offset) :
CSimpleTrailing(symbol, magic, trail_start, trail_step, trail_offset), m_data_index(1), m_handle(INVALID_HANDLE)
{
this.SetTimeframe(timeframe);
}
//--- деструктор
~CTrailingByInd(void)
{
if(this.m_handle!=INVALID_HANDLE)
{
::IndicatorRelease(this.m_handle);
this.m_handle=INVALID_HANDLE;
}
}
};
//+------------------------------------------------------------------+
//| Возвращает данные индикатора с указанного индекса таймсерии |
//+------------------------------------------------------------------+
double CTrailingByInd::GetDataInd(const int index) const
{
//--- если хендл невалидный - сообщаем об этом и возвращаем "пустое значение"
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("%s: Error. Invalid handle",__FUNCTION__);
return EMPTY_VALUE;
}
//--- получаем значение буфера индикатора по указанному индексу
double array[1];
::ResetLastError();
if(::CopyBuffer(this.m_handle, 0, index, 1, array)!=1)
{
::PrintFormat("%s: CopyBuffer() failed. Error %d", __FUNCTION__, ::GetLastError());
return EMPTY_VALUE;
}
//--- возвращаем полученное значение
return array[0];
}
//+------------------------------------------------------------------+
//| Рассчитывает и возвращает уровень StopLoss выбранной позиции |
//+------------------------------------------------------------------+
double CTrailingByInd::GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick)
{
//--- получаем значение индикатора как уровень для StopLoss
double data=this.GetDataInd();
//--- в зависимости от типа позиции рассчитываем и возвращаем уровень StopLoss
switch(pos_type)
{
case POSITION_TYPE_BUY : return(data!=EMPTY_VALUE ? data - this.m_offset * this.m_point : tick.bid);
case POSITION_TYPE_SELL : return(data!=EMPTY_VALUE ? data + this.m_offset * this.m_point : tick.ask);
default : return 0;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Parabolic SAR |
//+------------------------------------------------------------------+
class CTrailingBySAR : public CTrailingByInd
{
private:
double m_sar_step; // параметр Step Parabolic SAR
double m_sar_max; // параметр Maximum Parabolic SAR
public:
//--- установка параметров Parabolic SAR
void SetSARStep(const double step) { this.m_sar_step=(step<0.0001 ? 0.0001 : step); }
void SetSARMaximum(const double max) { this.m_sar_max =(max <0.0001 ? 0.0001 : max); }
//--- возврат параметров Parabolic SAR
double SARStep(void) const { return this.m_sar_step; }
double SARMaximum(void) const { return this.m_sar_max; }
//--- создаёт индикатор Parabolic SAR, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const double sar_step, const double sar_maximum);
//--- конструкторы
CTrailingBySAR() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 0.02, 0.2);
}
CTrailingBySAR(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const double sar_step, const double sar_maximum,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingBySAR(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingBySAR::CTrailingBySAR(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const double sar_step, const double sar_maximum,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, sar_step, sar_maximum);
}
//+------------------------------------------------------------------+
//| создаёт индикатор Parabolic SAR, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingBySAR::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const double sar_step, const double sar_maximum)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetSARStep(sar_step);
this.SetSARMaximum(sar_maximum);
::ResetLastError();
this.m_handle=::iSAR(this.m_symbol, this.m_timeframe, this.m_sar_step, this.m_sar_max);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iSAR(%s, %s, %.3f, %.2f) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_sar_step, this.m_sar_max, ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Adaptive Moving Average |
//+------------------------------------------------------------------+
class CTrailingByAMA : public CTrailingByInd
{
private:
int m_period; // параметр Period AMA
int m_fast_ema; // параметр Fast EMA Period
int m_slow_ema; // параметр Slow EMA Period
int m_shift; // параметр Shift AMA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price AMA
public:
//--- установка параметров AMA
void SetPeriod(const uint period) { this.m_period=int(period<1 ? 9 : period); }
void SetFastEMAPeriod(const uint period) { this.m_fast_ema=int(period<1 ? 2 : period); }
void SetSlowEMAPeriod(const uint period) { this.m_slow_ema=int(period<1 ? 30 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров AMA
int Period(void) const { return this.m_period; }
int FastEMAPeriod(void) const { return this.m_fast_ema; }
int SlowEMAPeriod(void) const { return this.m_slow_ema; }
int Shift(void) const { return this.m_shift; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор AMA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe,
const int period, const int fast_ema, const int slow_ema, const int shift, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByAMA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 9, 2, 30, 0, PRICE_CLOSE);
}
CTrailingByAMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int fast_ema, const int slow_ema, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByAMA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByAMA::CTrailingByAMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int fast_ema, const int slow_ema, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period, fast_ema, slow_ema, shift, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор AMA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByAMA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe,
const int period, const int fast_ema, const int slow_ema, const int shift, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriod(period);
this.SetFastEMAPeriod(fast_ema);
this.SetSlowEMAPeriod(slow_ema);
this.SetShift(shift);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iAMA(this.m_symbol, this.m_timeframe, this.m_period, this.m_fast_ema, this.m_slow_ema, this.m_shift, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iAMA(%s, %s, %d, %d, %d, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_period, this.m_fast_ema, this.m_slow_ema,
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Double Exponential Moving Average|
//+------------------------------------------------------------------+
class CTrailingByDEMA : public CTrailingByInd
{
private:
int m_period; // параметр Period DEMA
int m_shift; // параметр Shift DEMA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price DEMA
public:
//--- установка параметров DEMA
void SetPeriod(const uint period) { this.m_period=int(period<1 ? 14 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров DEMA
int Period(void) const { return this.m_period; }
int Shift(void) const { return this.m_shift; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор DEMA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByDEMA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 14, 0, PRICE_CLOSE);
}
CTrailingByDEMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByDEMA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByDEMA::CTrailingByDEMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period, shift, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор DEMA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByDEMA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriod(period);
this.SetShift(shift);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iDEMA(this.m_symbol, this.m_timeframe, this.m_period, this.m_shift, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iDEMA(%s, %s, %d, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_period,
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Fractal Adaptive Moving Average |
//+------------------------------------------------------------------+
class CTrailingByFRAMA : public CTrailingByInd
{
private:
int m_period; // параметр Period FRAMA
int m_shift; // параметр Shift DEMA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price FRAMA
public:
//--- установка параметров FRAMA
void SetPeriod(const uint period) { this.m_period=int(period<3 ? 14 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров FRAMA
int Period(void) const { return this.m_period; }
int Shift(void) const { return this.m_shift; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор FRAMA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByFRAMA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 14, 0, PRICE_CLOSE);
}
CTrailingByFRAMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByFRAMA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByFRAMA::CTrailingByFRAMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period, shift, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор FRAMA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByFRAMA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriod(period);
this.SetShift(shift);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iFrAMA(this.m_symbol, this.m_timeframe, this.m_period, this.m_shift, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iFrAMA(%s, %s, %d, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_period,
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Moving Average |
//+------------------------------------------------------------------+
class CTrailingByMA : public CTrailingByInd
{
private:
int m_period; // параметр Period MA
int m_shift; // параметр Shift MA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price MA
ENUM_MA_METHOD m_method; // параметр Method MA
public:
//--- установка параметров MA
void SetPeriod(const uint period) { this.m_period=int(period<1 ? 10 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetMethod(const ENUM_MA_METHOD method) { this.m_method=method; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров MA
int Period(void) const { return this.m_period; }
int Shift(void) const { return this.m_shift; }
ENUM_MA_METHOD Method(void) const { return this.m_method; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор MA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift,
const ENUM_MA_METHOD method, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByMA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 10, 0, MODE_SMA, PRICE_CLOSE);
}
CTrailingByMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_MA_METHOD method, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByMA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByMA::CTrailingByMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_MA_METHOD method, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period, shift, method, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор MA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByMA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift,
const ENUM_MA_METHOD method, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriod(period);
this.SetShift(shift);
this.SetMethod(method);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iMA(this.m_symbol, this.m_timeframe, this.m_period, this.m_shift, this.m_method, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iMA(%s, %s, %d, %s, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_period,
::StringSubstr(::EnumToString(this.m_method),5),
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Triple Exponential Moving Average|
//+------------------------------------------------------------------+
class CTrailingByTEMA : public CTrailingByInd
{
private:
int m_period; // параметр Period TEMA
int m_shift; // параметр Shift TEMA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price TEMA
public:
//--- установка параметров TEMA
void SetPeriod(const uint period) { this.m_period=int(period<1 ? 14 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров TEMA
int Period(void) const { return this.m_period; }
int Shift(void) const { return this.m_shift; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор TEMA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByTEMA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 14, 0, PRICE_CLOSE);
}
CTrailingByTEMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByTEMA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByTEMA::CTrailingByTEMA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period, shift, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор TEMA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByTEMA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int shift, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriod(period);
this.SetShift(shift);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iTEMA(this.m_symbol, this.m_timeframe, this.m_period, this.m_shift, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iTEMA(%s, %s, %d, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_period,
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала StopLoss позиций по Variable Index Dynamyc Average |
//+------------------------------------------------------------------+
class CTrailingByVIDYA : public CTrailingByInd
{
private:
int m_cmo_period; // параметр CMO Period VIDYA
int m_ema_period; // параметр EMA Period VIDYA
int m_shift; // параметр Shift VIDYA
ENUM_APPLIED_PRICE m_price; // параметр Applied Price VIDYA
public:
//--- установка параметров VIDYA
void SetPeriodCMO(const uint period) { this.m_cmo_period=int(period<1 ? 9 : period); }
void SetPeriodEMA(const uint period) { this.m_ema_period=int(period<1? 12 : period); }
void SetShift(const int shift) { this.m_shift = shift; }
void SetPrice(const ENUM_APPLIED_PRICE price) { this.m_price = price; }
//--- возврат параметров VIDYA
int PeriodCMO(void) const { return this.m_cmo_period; }
int Shift(void) const { return this.m_shift; }
ENUM_APPLIED_PRICE Price(void) const { return this.m_price; }
//--- создаёт индикатор VIDYA, возвращает результат
bool Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe,
const int period_cmo, const int period_ema,
const int shift, const ENUM_APPLIED_PRICE price);
//--- конструкторы
CTrailingByVIDYA() : CTrailingByInd(::Symbol(), ::Period(), -1, 0, 0, 0)
{
this.Initialize(this.m_symbol, this.m_timeframe, 9, 12, 0, PRICE_CLOSE);
}
CTrailingByVIDYA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period_cmo, const int period_ema, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset);
//--- деструктор
~CTrailingByVIDYA(){}
};
//+------------------------------------------------------------------+
//| Параметрический конструктор |
//+------------------------------------------------------------------+
CTrailingByVIDYA::CTrailingByVIDYA(const string symbol, const ENUM_TIMEFRAMES timeframe, const long magic,
const int period_cmo, const int period_ema, const int shift, const ENUM_APPLIED_PRICE price,
const int trail_start, const uint trail_step, const int trail_offset) :
CTrailingByInd(symbol, timeframe, magic, trail_start, trail_step, trail_offset)
{
this.Initialize(symbol, timeframe, period_cmo, period_ema, shift, price);
}
//+------------------------------------------------------------------+
//| создаёт индикатор VIDYA, возвращает результат |
//+------------------------------------------------------------------+
bool CTrailingByVIDYA::Initialize(const string symbol, const ENUM_TIMEFRAMES timeframe,
const int period_cmo, const int period_ema,
const int shift, const ENUM_APPLIED_PRICE price)
{
this.SetSymbol(symbol);
this.SetTimeframe(timeframe);
this.SetPeriodCMO(period_cmo);
this.SetPeriodEMA(period_ema);
this.SetShift(shift);
this.SetPrice(price);
::ResetLastError();
this.m_handle=::iVIDyA(this.m_symbol, this.m_timeframe, this.m_cmo_period, this.m_ema_period, this.m_shift, this.m_price);
if(this.m_handle==INVALID_HANDLE)
{
::PrintFormat("Failed to create iVIDyA(%s, %s, %d, %d, %s) handle. Error %d",
this.m_symbol, this.TimeframeDescription(), this.m_cmo_period, this.m_ema_period,
::StringSubstr(::EnumToString(this.m_price),6), ::GetLastError());
}
return(this.m_handle!=INVALID_HANDLE);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс трала по указанному значению |
//+------------------------------------------------------------------+
class CTrailingByValue : public CSimpleTrailing
{
protected:
double m_value_sl_long; // значение уровня StopLoss длинных позиций
double m_value_sl_short; // значение уровня StopLoss коротких позиций
//--- рассчитывает и возвращает уровень StopLoss выбранной позиции
virtual double GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick);
public:
//--- возвращает уровень StopLoss (2) длинных, (2) коротких позиций
double StopLossValueLong(void) const { return this.m_value_sl_long; }
double StopLossValueShort(void) const { return this.m_value_sl_short; }
//--- запуск трала с указанным отступом StopLoss от цены
bool Run(const double value_sl_long, double value_sl_short);
bool Run(const ulong pos_ticket, const double value_sl_long, double value_sl_short);
//--- конструкторы
CTrailingByValue(void) : CSimpleTrailing(::Symbol(), -1, 0, 0, 0), m_value_sl_long(0), m_value_sl_short(0) {}
CTrailingByValue(const string symbol, const long magic, const int trail_start, const uint trail_step, const int trail_offset) :
CSimpleTrailing(symbol, magic, trail_start, trail_step, trail_offset), m_value_sl_long(0), m_value_sl_short(0) {}
//--- деструктор
~CTrailingByValue(void){}
};
//+------------------------------------------------------------------+
//| Рассчитывает и возвращает уровень StopLoss выбранной позиции |
//+------------------------------------------------------------------+
double CTrailingByValue::GetStopLossValue(ENUM_POSITION_TYPE pos_type, MqlTick &tick)
{
//--- в зависимости от типа позиции рассчитываем и возвращаем уровень StopLoss
switch(pos_type)
{
case POSITION_TYPE_BUY : return(this.m_value_sl_long - this.m_offset * this.m_point);
case POSITION_TYPE_SELL : return(this.m_value_sl_short + this.m_offset * this.m_point);
default : return 0;
}
}
//+------------------------------------------------------------------+
//| Запуск трала с указанным отступом StopLoss от цены |
//+------------------------------------------------------------------+
bool CTrailingByValue::Run(const double value_sl_long, double value_sl_short)
{
this.m_value_sl_long =value_sl_long;
this.m_value_sl_short=value_sl_short;
return CSimpleTrailing::Run();
}
//+------------------------------------------------------------------+
//| Запуск трала с указанным отступом StopLoss от цены |
//+------------------------------------------------------------------+
bool CTrailingByValue::Run(const ulong pos_ticket,const double value_sl_long,double value_sl_short)
{
this.m_value_sl_long =value_sl_long;
this.m_value_sl_short=value_sl_short;
return CSimpleTrailing::Run(pos_ticket);
}
//+------------------------------------------------------------------+