243 行
23 KiB
MQL5
243 行
23 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TrailingBySAR_02.mq5 |
|
|
//| Copyright 2024, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
|
|
#define SAR_DATA_INDEX 1 // бар, с которого получаем данные Parabolic SAR
|
|
|
|
#include <Trade\Trade.mqh> // заменим торговые функции методами Стандартной Библиотеки
|
|
|
|
//--- input parameters
|
|
input ENUM_TIMEFRAMES InpTimeframeSAR = PERIOD_CURRENT; // Parabolic SAR Timeframe
|
|
input double InpStepSAR = 0.02; // Parabolic SAR Step
|
|
input double InpMaximumSAR = 0.2; // Parabolic SAR Maximum
|
|
input ulong InpMagic = 123; // Magic Number
|
|
|
|
//--- global variables
|
|
int ExtHandleSAR=INVALID_HANDLE; // хэндл Parabolic SAR
|
|
double ExtStepSAR=0; // шаг Parabolic SAR
|
|
double ExtMaximumSAR=0; // максимум Parabolic SAR
|
|
CTrade ExtTrade; // экземпляр класса торговых операций
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- устанавливаем в объект торгового класса магический номер
|
|
ExtTrade.SetExpertMagicNumber(InpMagic);
|
|
|
|
//--- устанавливаем параметры Parabolic SAR в допустимых пределах
|
|
ExtStepSAR =(InpStepSAR<0.0001 ? 0.0001 : InpStepSAR);
|
|
ExtMaximumSAR=(InpMaximumSAR<0.0001 ? 0.0001 : InpMaximumSAR);
|
|
|
|
//--- при ошибке создания индикатора выводим сообщение в журнал и выходим с ошибкой из OnInit
|
|
ExtHandleSAR =iSAR(Symbol(), InpTimeframeSAR, ExtStepSAR, ExtMaximumSAR);
|
|
if(ExtHandleSAR==INVALID_HANDLE)
|
|
{
|
|
PrintFormat("Failed to create iSAR(%s, %s, %.3f, %.2f) handle. Error %d",
|
|
Symbol(), TimeframeDescription(InpTimeframeSAR), ExtStepSAR, ExtMaximumSAR, GetLastError());
|
|
return(INIT_FAILED);
|
|
}
|
|
//--- успешно
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//--- если не новый бар - уходим из обработчика
|
|
if(!IsNewBar())
|
|
return;
|
|
|
|
if(MQLInfoInteger(MQL_TESTER))
|
|
{
|
|
//--- получаем данные Parabolic SAR с баров 1 и 2
|
|
double sar1=GetSARData(SAR_DATA_INDEX);
|
|
double sar2=GetSARData(SAR_DATA_INDEX+1);
|
|
|
|
//--- если структура цен заполнена и данные от Parabolic SAR получены
|
|
MqlTick tick={};
|
|
if(SymbolInfoTick(Symbol(), tick) && sar1!=EMPTY_VALUE && sar2!=EMPTY_VALUE)
|
|
{
|
|
//--- если Parabolic SAR на баре 1 ниже цены Bid, а на баре 2 выше - открываем длинную позицию
|
|
if(sar1<tick.bid && sar2>tick.bid)
|
|
ExtTrade.Buy(0.1);
|
|
//--- если Parabolic SAR на баре 1 выше цены Ask, а на баре 2 ниже - открываем короткую позицию
|
|
if(sar1>tick.ask && sar2<tick.ask)
|
|
ExtTrade.Sell(0.1);
|
|
}
|
|
}
|
|
|
|
//--- тралим стопы позиций по Parabolic SAR
|
|
TrailingStopBySAR(InpMagic);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| TradeTransaction function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTradeTransaction(const MqlTradeTransaction& trans,
|
|
const MqlTradeRequest& request,
|
|
const MqlTradeResult& result)
|
|
{
|
|
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
|
|
TrailingStopBySAR(InpMagic);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает описание таймфрейма |
|
|
//+------------------------------------------------------------------+
|
|
string TimeframeDescription(const ENUM_TIMEFRAMES timeframe)
|
|
{
|
|
return(StringSubstr(EnumToString(timeframe==PERIOD_CURRENT ? Period() : timeframe), 7));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает время открытия бара по индексу таймсерии |
|
|
//+------------------------------------------------------------------+
|
|
datetime TimeOpenBar(const int index)
|
|
{
|
|
datetime array[1];
|
|
ResetLastError();
|
|
if(CopyTime(NULL, PERIOD_CURRENT, index, 1, array)!=1)
|
|
{
|
|
PrintFormat("%s: CopyTime() failed. Error %d", __FUNCTION__, GetLastError());
|
|
return 0;
|
|
}
|
|
return array[0];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает флаг открытия нового бара таймсерии |
|
|
//+------------------------------------------------------------------+
|
|
bool IsNewBar(void)
|
|
{
|
|
static datetime time_prev=0;
|
|
datetime bar_open_time=TimeOpenBar(0);
|
|
if(bar_open_time==0)
|
|
return false;
|
|
if(bar_open_time!=time_prev)
|
|
{
|
|
time_prev=bar_open_time;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает данные Parabolic SAR с указанного индекса таймсерии |
|
|
//+------------------------------------------------------------------+
|
|
double GetSARData(const int index)
|
|
{
|
|
double array[1];
|
|
ResetLastError();
|
|
if(CopyBuffer(ExtHandleSAR, 0, index, 1, array)!=1)
|
|
{
|
|
PrintFormat("%s: CopyBuffer() failed. Error %d", __FUNCTION__, GetLastError());
|
|
return EMPTY_VALUE;
|
|
}
|
|
return array[0];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает размер StopLevel в пунктах |
|
|
//+------------------------------------------------------------------+
|
|
int StopLevel(const int spread_multiplier)
|
|
{
|
|
int spread =(int)SymbolInfoInteger(Symbol(), SYMBOL_SPREAD);
|
|
int stop_level=(int)SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
|
|
return(stop_level==0 ? spread * spread_multiplier : stop_level);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Универсальная функция трейлинга стопа по значению цены StopLoss |
|
|
//+------------------------------------------------------------------+
|
|
void TrailingStopByValue(const double value_sl, const long magic=-1, const int trailing_step_pt=0, const int trailing_start_pt=0)
|
|
{
|
|
//--- структура цен
|
|
MqlTick tick={};
|
|
//--- в цикле по общему количеству открытых позиций
|
|
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((magic!=-1 && pos_magic!=magic) || pos_symbol!=Symbol())
|
|
continue;
|
|
|
|
//--- если цены получить не удалось - идём далее
|
|
if(!SymbolInfoTick(Symbol(), tick))
|
|
continue;
|
|
|
|
//--- получаем тип позиции, цену её открытия и уровень 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 подходят - модифицируем стоп позиции
|
|
if(CheckCriterion(pos_type, pos_open, pos_sl, value_sl, trailing_step_pt, trailing_start_pt, tick))
|
|
ExtTrade.PositionModify(pos_ticket, value_sl, PositionGetDouble(POSITION_TP));
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//|Проверяет критерии модификации StopLoss позициии и возвращает флаг|
|
|
//+------------------------------------------------------------------+
|
|
bool CheckCriterion(ENUM_POSITION_TYPE pos_type, double pos_open, double pos_sl, double value_sl,
|
|
int trailing_step_pt, int trailing_start_pt, MqlTick &tick)
|
|
{
|
|
//--- если стоп позиции и уровень стопа для модификации равны - возвращаем false
|
|
if(NormalizeDouble(pos_sl-value_sl, Digits())==0)
|
|
return false;
|
|
|
|
double trailing_step = trailing_step_pt*Point(); // переводим шаг трала в цену
|
|
double stop_level = StopLevel(2)*Point(); // переводим уровень StopLevel символа в цену
|
|
int pos_profit_pt = 0; // прибыль позиции в пунктах
|
|
|
|
//--- в зависимости от типа позиции проверяем условия для модицикации StopLoss
|
|
switch(pos_type)
|
|
{
|
|
//--- длинная позиция
|
|
case POSITION_TYPE_BUY :
|
|
pos_profit_pt=int((tick.bid-pos_open)/Point()); // рассчитываем прибыль позиции в пунктах
|
|
if(tick.bid-stop_level>value_sl // если цена и отложенный от неё уровень StopLevel выше уровня StopLoss (соблюдена дистанция по StopLevel)
|
|
&& pos_sl+trailing_step<value_sl // если уровень StopLoss выше, чем шаг трала, отложенный от текущего StopLoss позиции
|
|
&& (trailing_start_pt==0 || pos_profit_pt>trailing_start_pt) // если тралим при любой прибыли или прибыль позиции в пунктах больше значения начала трейлинга - возвращаем true
|
|
)
|
|
return true;
|
|
break;
|
|
//--- короткая позиция
|
|
case POSITION_TYPE_SELL :
|
|
pos_profit_pt=int((pos_open-tick.ask)/Point()); // рассчитываем прибыль позиции в пунктах
|
|
if(tick.ask+stop_level<value_sl // если цена и отложенный от неё уровень StopLevel ниже уровня StopLoss (соблюдена дистанция по StopLevel)
|
|
&& (pos_sl-trailing_step>value_sl || pos_sl==0) // если уровень StopLoss ниже, чем шаг трала, отложенный от текущего StopLoss позиции или у позиции ещё не установлен StopLoss
|
|
&& (trailing_start_pt==0 || pos_profit_pt>trailing_start_pt) // если тралим при любой прибыли или прибыль позиции в пунктах больше значения начала трейлинга - возвращаем true
|
|
)
|
|
return true;
|
|
break;
|
|
//--- по умолчанию вернём false
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Функция трейлинга StopLoss по индикатору Parabolic SAR |
|
|
//+------------------------------------------------------------------+
|
|
void TrailingStopBySAR(const long magic=-1, const int trailing_step_pt=0, const int trailing_start_pt=0)
|
|
{
|
|
//--- получаем значение Parabolic SAR с первого бара таймсерии
|
|
double sar=GetSARData(SAR_DATA_INDEX);
|
|
|
|
//--- если данные получить не удалось - уходим
|
|
if(sar==EMPTY_VALUE)
|
|
return;
|
|
|
|
//--- вызываем универсальную функцию трала с указанием цены StopLoss, полученной от Parabolic SAR
|
|
TrailingStopByValue(sar, magic, trailing_step_pt, trailing_start_pt);
|
|
}
|
|
//+------------------------------------------------------------------+
|