412 lines
33 KiB
MQL5
412 lines
33 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TrendTrader.mq5 |
|
|
//| Sergey Lebedev |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2019, Sergey Lebedev"
|
|
#property link "https://www.mql5.com/ru/users/c-4"
|
|
#property version "1.0"
|
|
#include "Strategy\Strategy.mqh"
|
|
#include "Strategy\Indicators.mqh"
|
|
#include "Strategy\Trailings\TrailingClassic.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| TrendTrader based on Unified Expert Engine (aka UXE)
|
|
//| Latest verion is https://www.mql5.com/ru/articles/2653
|
|
//| Should be copied to MQL5\Insclude\UXE |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Enums
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_TREND_DIR // Trend Direction
|
|
{
|
|
DIR_DN = 0, // Dir DN
|
|
DIR_UP = 1 // Dir UP
|
|
};
|
|
|
|
enum ENUM_TREND_STATE // Trend State
|
|
{
|
|
STATE_DEAD = 0,
|
|
STATE_JUNG = 1,
|
|
STATE_OLDA = 2,
|
|
STATE_BEAT = 3,
|
|
STATE_FLAT = 4
|
|
};
|
|
|
|
enum ENUM_EXEC_TYPE // Executiuon Type
|
|
{
|
|
ByTimerEvent = 1, // By Timer
|
|
ByTickEvent = 2 // By Ticks
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Inputs
|
|
//+------------------------------------------------------------------+
|
|
sinput string Parameters = "========= Main Parameters =========";
|
|
input ENUM_TREND_DIR TrendDir = DIR_UP; // TrendDir: UP/DN
|
|
input ENUM_TIMEFRAMES MainTF = PERIOD_M1; // Timeframe
|
|
input ENUM_TREND_STATE InitState = STATE_DEAD; // Trend Initial State
|
|
//+-------------------------------------------------+
|
|
sinput string MM_Parameters = "========= Money Managment Parameters =========";
|
|
input ENUM_MM_TYPE AmountMode=MM_PERCENT_DEPO; // MM Type
|
|
input double MMVal=25; // MM Value
|
|
//+-------------------------------------------------+
|
|
sinput string Ind_Params = "========= Indicators Values =========";
|
|
input int PeriiodRSI =14; // Rsi Periiod
|
|
input int PeriiodATR =7; // ATR Periiod
|
|
//+-------------------------------------------------+
|
|
sinput string Open_Events = "========= Open Events =========";
|
|
input bool Open_RSIH1_AT = true; // Open position on RSIH1 в OVX-zone of Corrention
|
|
input bool Open_RSIH4_AT = true; // Open position on RSIH4 в OVX-zone of Corrention
|
|
//+-------------------------------------------------+
|
|
sinput string Close_Events = "========= Close Events =========";
|
|
input bool Close_RSIH4_TRN = true; // Close позицию при RSIH4 в OVX-zone Trend
|
|
input bool Close_RSID1_TRN = true; // Close position при RSID1 в OVX-zone Trend
|
|
//+-------------------------------------------------+
|
|
sinput string Technicals = "========= Technical Parameters =========";
|
|
input ENUM_EXEC_TYPE ExecMode = ByTimerEvent; // Способ активации
|
|
input int TimerSec = 2; // Секунды для таймера
|
|
input double SLonATR = 2.62; // SL on ATR coef
|
|
input bool UseTLS = true; // Use trailing Stop
|
|
sinput bool DebugLog = true; // Extended(Debug) logging
|
|
//+------------------------------------------------------------------+
|
|
//| Стратегия CImpulse |
|
|
//+------------------------------------------------------------------+
|
|
class CTrendTrader : public CStrategy
|
|
{
|
|
private:
|
|
double m_percent; // Deposit persent to open new position
|
|
double m_Amount, m_Taget; // m_Amount - amount to open new position, m_Taget - target for SL/TP
|
|
int h_RSIH1, h_RSIH4, h_RSID1, h_SLATR; // Handles
|
|
CLog* m_log; // Логирование
|
|
bool m_Signal; // Signal to Open/Close
|
|
string m_SgnTag; // Signal Tag (for Comments and Debuggin)
|
|
double m_InitATR4SL; // Initial ATR value for SL
|
|
bool m_ResBool;
|
|
protected:
|
|
virtual void InitBuy(const MarketEvent &event);
|
|
virtual void InitSell(const MarketEvent &event);
|
|
virtual void SupportBuy(const MarketEvent &event,CPosition *pos);
|
|
virtual void SupportSell(const MarketEvent &event,CPosition *pos);
|
|
virtual void SupportPendingBuy(const MarketEvent &event,CPendingOrder *order);
|
|
virtual void SupportPendingSell(const MarketEvent &event,CPendingOrder* order);
|
|
virtual bool OnInit(void);
|
|
public:
|
|
double GetPercent(void);
|
|
void SetPercent(double percent);
|
|
CUnIndicator RSIH1, RSIH4, RSID1, SLATR;
|
|
};
|
|
|
|
|
|
bool CTrendTrader::OnInit(void)
|
|
{
|
|
// Configure Log Manager
|
|
m_log=CLog::GetLog();
|
|
if (DebugLog) m_log.TerminalPriority(MESSAGE_INFO);
|
|
m_ResBool = false;
|
|
|
|
//Configure Signals
|
|
if (ExecMode == ByTimerEvent)
|
|
{
|
|
EventSetTimer(TimerSec); // 1 = 1 sec
|
|
CMessage *msg=new CMessage(MESSAGE_INFO,__FUNCTION__,"Timer is set for "+ TimerSec + " sec!");
|
|
m_log.AddMessage(msg);
|
|
}
|
|
|
|
if (Open_RSIH1_AT)
|
|
{
|
|
RSIH1.SetParameter(PeriiodRSI);
|
|
RSIH1.SetParameter(PRICE_CLOSE);
|
|
h_RSIH1 = RSIH1.Create(Symbol(), PERIOD_H1, IND_RSI);
|
|
if(h_RSIH1 == INVALID_HANDLE)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,"Error-1: RSI-H1 is not created!");
|
|
m_log.AddMessage(msg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (Open_RSIH4_AT || Close_RSIH4_TRN)
|
|
{
|
|
RSIH4.SetParameter(PeriiodRSI);
|
|
RSIH4.SetParameter(PRICE_CLOSE);
|
|
h_RSIH4 = RSIH4.Create(Symbol(), PERIOD_H4, IND_RSI);
|
|
if(h_RSIH4 == INVALID_HANDLE)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,"Error-2: RSI-H4 is not created!");
|
|
m_log.AddMessage(msg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (Close_RSID1_TRN)
|
|
{
|
|
RSID1.SetParameter(PeriiodRSI);
|
|
RSID1.SetParameter(PRICE_CLOSE);
|
|
h_RSID1 = RSID1.Create(Symbol(), PERIOD_H4, IND_RSI);
|
|
if(h_RSID1 == INVALID_HANDLE)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,"Error-3: RSI-D1 is not created!");
|
|
m_log.AddMessage(msg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Configure MM
|
|
MM.SetMMType(AmountMode);
|
|
if (AmountMode==MM_FIX_LOT) MM.SetLotFixed(MMVal);
|
|
if (AmountMode==MM_PERCENT_DEPO) { m_percent = MMVal/100; MM.SetPercent(m_percent); }
|
|
|
|
// Configure SL
|
|
SLATR.SetParameter(PeriiodATR);
|
|
SLATR.SetParameter(PRICE_CLOSE);
|
|
h_SLATR = SLATR.Create(Symbol(), PERIOD_H4, IND_ATR);
|
|
if(h_SLATR == INVALID_HANDLE)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,"Error-4: ATR-H4 is not created!");
|
|
m_log.AddMessage(msg);
|
|
return false;
|
|
}
|
|
|
|
// COnfigure Trade States for Just2Trade broker
|
|
TradeState(TRADE_BUY_AND_SELL);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Set Buy orders |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::InitBuy(const MarketEvent &event)
|
|
{
|
|
if(!IsTrackEvents(event))return;
|
|
if(PositionsTotal(POSITION_TYPE_BUY, ExpertSymbol(), ExpertMagic()) > 0)
|
|
return;
|
|
|
|
m_Signal = false;
|
|
if(TrendDir == DIR_UP)
|
|
{
|
|
if (Open_RSIH1_AT & RSIH1[0]<30) {m_Signal= true;m_SgnTag="RSIH1_AT";}
|
|
if (Open_RSIH4_AT & RSIH4[0]<30) {m_Signal= true;m_SgnTag="RSIH4_AT";}
|
|
|
|
if (m_Signal)
|
|
{
|
|
if (AmountMode==MM_FIX_LOT) m_Amount = MM.GetLotFixed();
|
|
if (AmountMode==MM_PERCENT_DEPO) m_Amount = MM.GetLotByPercentDepo();
|
|
Trade.Buy(m_Amount, ExpertSymbol(), m_SgnTag);
|
|
CMessage *msg=new CMessage(MESSAGE_INFO,__FUNCTION__,"Open BUY(" + DoubleToString(WS.Bid(),WS.Digits()) + ") Signal based on " + m_SgnTag);
|
|
m_log.AddMessage(msg);
|
|
m_InitATR4SL= SLATR[0];
|
|
}
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Set Sell orders |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::InitSell(const MarketEvent &event)
|
|
{
|
|
if(!IsTrackEvents(event))return;
|
|
if(PositionsTotal(POSITION_TYPE_SELL, ExpertSymbol(), ExpertMagic()) > 0)
|
|
return;
|
|
|
|
m_Signal = false;
|
|
if(TrendDir == DIR_DN )
|
|
{
|
|
if (Open_RSIH1_AT & RSIH1[0]>70) {m_Signal= true;m_SgnTag="RSIH1_AT";}
|
|
if (Open_RSIH4_AT & RSIH4[0]>70) {m_Signal= true;m_SgnTag="RSIH4_AT";}
|
|
|
|
if (m_Signal)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_INFO,__FUNCTION__,"Open SELL(" + DoubleToString(WS.Bid(),WS.Digits()) + ") Signal based on " + m_SgnTag);
|
|
m_log.AddMessage(msg);
|
|
if (AmountMode==MM_FIX_LOT) m_Amount = MM.GetLotFixed();
|
|
if (AmountMode==MM_PERCENT_DEPO) m_Amount = MM.GetLotByPercentDepo();
|
|
Trade.Sell(m_Amount, ExpertSymbol(), m_SgnTag);
|
|
m_InitATR4SL= SLATR[0];
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Support BUY |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::SupportBuy(const MarketEvent &event,CPosition *pos)
|
|
{
|
|
if(!IsTrackEvents(event))return;
|
|
|
|
m_Signal = false;
|
|
if (Close_RSIH4_TRN & RSIH4[0]>70) {m_Signal= true;m_SgnTag="RSIH4_TRN";}
|
|
if (Close_RSID1_TRN & RSID1[0]>70) {m_Signal= true;m_SgnTag="RSID1_TRN";}
|
|
|
|
if(m_Signal)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_INFO,__FUNCTION__,"Close BUY(" + DoubleToString(WS.Bid(),WS.Digits()) + ") Signal based on " + m_SgnTag);
|
|
m_log.AddMessage(msg);
|
|
pos.CloseAtMarket(m_SgnTag);
|
|
}
|
|
// SL
|
|
if (pos.StopLossValue()==0)
|
|
{
|
|
m_Taget = WS.Bid() - m_InitATR4SL*SLonATR;
|
|
CPosition *pos=ActivePositions.At(0);
|
|
if (CheckPointer(pos)) pos.StopLossValue(m_Taget);
|
|
CMessage *msg2=new CMessage(MESSAGE_INFO,__FUNCTION__,"SL for BUY is set on "+ DoubleToString(m_Taget,WS.Digits())
|
|
+ " based on ATR "+ DoubleToString(m_InitATR4SL,4)+ " and Price "+ DoubleToString(WS.Bid(),WS.Digits()));
|
|
m_log.AddMessage(msg2);
|
|
}
|
|
// Activate/change TLS if UseTLS is True and profit is reached
|
|
if (UseTLS)
|
|
{
|
|
m_Taget = m_InitATR4SL*SLonATR*WS.ContractSize();
|
|
if (pos.Profit() < m_Taget) return; // Not enougth profit for TLS, still using initial SL
|
|
CMessage *msg3=new CMessage(MESSAGE_INFO,__FUNCTION__,"Position Profit "+ DoubleToString(pos.Profit(),2)
|
|
+ " on Price "+ DoubleToString(WS.Bid(),WS.Digits())+ " reached Level1 "+ DoubleToString(m_Taget,2));
|
|
m_log.AddMessage(msg3);
|
|
if(pos.Trailing == NULL)
|
|
{
|
|
CTrailingClassic* trailing = new CTrailingClassic();
|
|
trailing.SetPosition(pos);
|
|
trailing.SetDiffExtremum(m_InitATR4SL*SLonATR);
|
|
trailing.SetStepModify(m_InitATR4SL*SLonATR/4);
|
|
pos.Trailing = trailing;
|
|
}
|
|
m_ResBool= pos.Trailing.Modify();
|
|
if (m_ResBool)
|
|
{
|
|
CMessage *msg4=new CMessage(MESSAGE_INFO,__FUNCTION__,"TLS for BUY position is set on "+ DoubleToString(pos.StopLossValue(),WS.Digits()));
|
|
m_log.AddMessage(msg4);
|
|
}
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Support SELL |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::SupportSell(const MarketEvent &event,CPosition *pos)
|
|
{
|
|
if(!IsTrackEvents(event))return;
|
|
|
|
m_Signal = false;
|
|
if (Close_RSIH4_TRN & RSIH4[0]<30) {m_Signal= true;m_SgnTag="RSIH4_TRN";}
|
|
if (Close_RSID1_TRN & RSID1[0]<30) {m_Signal= true;m_SgnTag="RSID1_TRN";}
|
|
|
|
if(m_Signal)
|
|
{
|
|
CMessage *msg=new CMessage(MESSAGE_INFO,__FUNCTION__,"Close SELL(" + DoubleToString(WS.Ask(),WS.Digits()) + ") Signal based on " + m_SgnTag);
|
|
m_log.AddMessage(msg);
|
|
pos.CloseAtMarket(m_SgnTag);
|
|
}
|
|
// Set SL
|
|
if (pos.StopLossValue()==0)
|
|
{
|
|
m_Taget = WS.Ask() + m_InitATR4SL*SLonATR;
|
|
CPosition *pos=ActivePositions.At(0);
|
|
if (CheckPointer(pos)) pos.StopLossValue(m_Taget);
|
|
CMessage *msg2=new CMessage(MESSAGE_INFO,__FUNCTION__,"SL for SELL is set on "+ DoubleToString(m_Taget,WS.Digits())
|
|
+ " based on ATR "+ DoubleToString(m_InitATR4SL,4)+ " and Price "+ DoubleToString(WS.Ask(),WS.Digits()));
|
|
m_log.AddMessage(msg2);
|
|
}
|
|
// Activate/change TLS if UseTLS is True and profit is reached
|
|
if (UseTLS)
|
|
{
|
|
m_Taget = m_InitATR4SL*SLonATR*WS.ContractSize();
|
|
if (pos.Profit() < m_Taget) return; // Not enougth profit for TLS, still using initial SL
|
|
CMessage *msg3=new CMessage(MESSAGE_INFO,__FUNCTION__,"Position Profit "+ DoubleToString(pos.Profit(),2)
|
|
+ " at Price "+ DoubleToString(WS.Ask(),WS.Digits()) +" reached Level1 "+ DoubleToString(m_Taget,2));
|
|
m_log.AddMessage(msg3);
|
|
if(pos.Trailing == NULL)
|
|
{
|
|
CTrailingClassic* trailing = new CTrailingClassic();
|
|
trailing.SetPosition(pos);
|
|
trailing.SetDiffExtremum(m_InitATR4SL*SLonATR);
|
|
trailing.SetStepModify(m_InitATR4SL*SLonATR/4);
|
|
pos.Trailing = trailing;
|
|
}
|
|
m_ResBool=pos.Trailing.Modify();
|
|
if (m_ResBool)
|
|
{
|
|
CMessage *msg4=new CMessage(MESSAGE_INFO,__FUNCTION__,"TLS for SELL position is set on "+ DoubleToString(pos.StopLossValue(),WS.Digits()));
|
|
m_log.AddMessage(msg4);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Работа с отложенными ордерами BuyStop для открытия длинной |
|
|
//| позиции |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::SupportPendingBuy(const MarketEvent &event,CPendingOrder *order)
|
|
{
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Работа с отложенными ордерами SellStop для открытия короткой |
|
|
//| позиции |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::SupportPendingSell(const MarketEvent &event,CPendingOrder* order)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает процент средств для открытия позиции |
|
|
//+------------------------------------------------------------------+
|
|
double CTrendTrader::GetPercent(void)
|
|
{
|
|
return m_percent;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает процент средств для открытия позиции |
|
|
//+------------------------------------------------------------------+
|
|
void CTrendTrader::SetPercent(double percent)
|
|
{
|
|
m_percent = percent;
|
|
MM.SetPercent(m_percent);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
CTrendTrader* TrnTrader = new CTrendTrader();
|
|
TrnTrader.ExpertMagic(140578);
|
|
TrnTrader.ExpertName("TrendTrader 1.0");
|
|
TrnTrader.Timeframe(PERIOD_H1);
|
|
TrnTrader.ExpertSymbol(Symbol());
|
|
Manager.AddStrategy(TrnTrader);
|
|
return(INIT_SUCCEEDED);
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
if (ExecMode == ByTickEvent) Manager.OnTick();
|
|
}
|
|
|
|
void OnTimer()
|
|
{
|
|
if (ExecMode == ByTimerEvent) Manager.OnTimer();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ChartEvent function |
|
|
//+------------------------------------------------------------------+
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
Manager.OnChartEvent(id, lparam, dparam, sparam);
|
|
ChartRedraw(0);
|
|
}
|
|
|
|
|