add new backup ...

This commit is contained in:
2024-06-01 19:37:54 +03:30
parent 0998ffa2a5
commit 83c000fdd6
142 changed files with 60067 additions and 0 deletions
@@ -0,0 +1,168 @@
//+------------------------------------------------------------------+
//| ExpertMACD.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
#include <Expert\Signal\SignalMACD.mqh>
#include <Expert\Trailing\TrailingNone.mqh>
#include <Expert\Money\MoneyNone.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Inp_Expert_Title ="ExpertMACD";
int Expert_MagicNumber =10981;
bool Expert_EveryTick =false;
//--- inputs for signal
input int Inp_Signal_MACD_PeriodFast =12;
input int Inp_Signal_MACD_PeriodSlow =24;
input int Inp_Signal_MACD_PeriodSignal=9;
input int Inp_Signal_MACD_TakeProfit =50;
input int Inp_Signal_MACD_StopLoss =20;
//+------------------------------------------------------------------+
//| Global expert object |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Initializing expert
if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
{
//--- failed
printf(__FUNCTION__+": error initializing expert");
ExtExpert.Deinit();
return(-1);
}
//--- Creation of signal object
CSignalMACD *signal=new CSignalMACD;
if(signal==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating signal");
ExtExpert.Deinit();
return(-2);
}
//--- Add signal to expert (will be deleted automatically))
if(!ExtExpert.InitSignal(signal))
{
//--- failed
printf(__FUNCTION__+": error initializing signal");
ExtExpert.Deinit();
return(-3);
}
//--- Set signal parameters
signal.PeriodFast(Inp_Signal_MACD_PeriodFast);
signal.PeriodSlow(Inp_Signal_MACD_PeriodSlow);
signal.PeriodSignal(Inp_Signal_MACD_PeriodSignal);
signal.TakeLevel(Inp_Signal_MACD_TakeProfit);
signal.StopLevel(Inp_Signal_MACD_StopLoss);
//--- Check signal parameters
if(!signal.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error signal parameters");
ExtExpert.Deinit();
return(-4);
}
//--- Creation of trailing object
CTrailingNone *trailing=new CTrailingNone;
if(trailing==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating trailing");
ExtExpert.Deinit();
return(-5);
}
//--- Add trailing to expert (will be deleted automatically))
if(!ExtExpert.InitTrailing(trailing))
{
//--- failed
printf(__FUNCTION__+": error initializing trailing");
ExtExpert.Deinit();
return(-6);
}
//--- Set trailing parameters
//--- Check trailing parameters
if(!trailing.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error trailing parameters");
ExtExpert.Deinit();
return(-7);
}
//--- Creation of money object
CMoneyNone *money=new CMoneyNone;
if(money==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating money");
ExtExpert.Deinit();
return(-8);
}
//--- Add money to expert (will be deleted automatically))
if(!ExtExpert.InitMoney(money))
{
//--- failed
printf(__FUNCTION__+": error initializing money");
ExtExpert.Deinit();
return(-9);
}
//--- Set money parameters
//--- Check money parameters
if(!money.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error money parameters");
ExtExpert.Deinit();
return(-10);
}
//--- Tuning of all necessary indicators
if(!ExtExpert.InitIndicators())
{
//--- failed
printf(__FUNCTION__+": error initializing indicators");
ExtExpert.Deinit();
return(-11);
}
//--- succeed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ExtExpert.Deinit();
}
//+------------------------------------------------------------------+
//| Function-event handler "tick" |
//+------------------------------------------------------------------+
void OnTick(void)
{
ExtExpert.OnTick();
}
//+------------------------------------------------------------------+
//| Function-event handler "trade" |
//+------------------------------------------------------------------+
void OnTrade(void)
{
ExtExpert.OnTrade();
}
//+------------------------------------------------------------------+
//| Function-event handler "timer" |
//+------------------------------------------------------------------+
void OnTimer(void)
{
ExtExpert.OnTimer();
}
//+------------------------------------------------------------------+
@@ -0,0 +1,175 @@
//+------------------------------------------------------------------+
//| ExpertMAMA.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
#include <Expert\Signal\SignalMA.mqh>
#include <Expert\Trailing\TrailingMA.mqh>
#include <Expert\Money\MoneyNone.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Inp_Expert_Title ="ExpertMAMA";
int Expert_MagicNumber =12003;
bool Expert_EveryTick =false;
//--- inputs for signal
input int Inp_Signal_MA_Period =12;
input int Inp_Signal_MA_Shift =6;
input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA;
input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE;
//--- inputs for trailing
input int Inp_Trailing_MA_Period =12;
input int Inp_Trailing_MA_Shift =0;
input ENUM_MA_METHOD Inp_Trailing_MA_Method =MODE_SMA;
input ENUM_APPLIED_PRICE Inp_Trailing_MA_Applied=PRICE_CLOSE;
//+------------------------------------------------------------------+
//| Global expert object |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Initializing expert
if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
{
//--- failed
printf(__FUNCTION__+": error initializing expert");
ExtExpert.Deinit();
return(-1);
}
//--- Creation of signal object
CSignalMA *signal=new CSignalMA;
if(signal==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating signal");
ExtExpert.Deinit();
return(-2);
}
//--- Add signal to expert (will be deleted automatically))
if(!ExtExpert.InitSignal(signal))
{
//--- failed
printf(__FUNCTION__+": error initializing signal");
ExtExpert.Deinit();
return(-3);
}
//--- Set signal parameters
signal.PeriodMA(Inp_Signal_MA_Period);
signal.Shift(Inp_Signal_MA_Shift);
signal.Method(Inp_Signal_MA_Method);
signal.Applied(Inp_Signal_MA_Applied);
//--- Check signal parameters
if(!signal.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error signal parameters");
ExtExpert.Deinit();
return(-4);
}
//--- Creation of trailing object
CTrailingMA *trailing=new CTrailingMA;
if(trailing==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating trailing");
ExtExpert.Deinit();
return(-5);
}
//--- Add trailing to expert (will be deleted automatically))
if(!ExtExpert.InitTrailing(trailing))
{
//--- failed
printf(__FUNCTION__+": error initializing trailing");
ExtExpert.Deinit();
return(-6);
}
//--- Set trailing parameters
trailing.Period(Inp_Trailing_MA_Period);
trailing.Shift(Inp_Trailing_MA_Shift);
trailing.Method(Inp_Trailing_MA_Method);
trailing.Applied(Inp_Trailing_MA_Applied);
//--- Check trailing parameters
if(!trailing.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error trailing parameters");
ExtExpert.Deinit();
return(-7);
}
//--- Creation of money object
CMoneyNone *money=new CMoneyNone;
if(money==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating money");
ExtExpert.Deinit();
return(-8);
}
//--- Add money to expert (will be deleted automatically))
if(!ExtExpert.InitMoney(money))
{
//--- failed
printf(__FUNCTION__+": error initializing money");
ExtExpert.Deinit();
return(-9);
}
//--- Set money parameters
//--- Check money parameters
if(!money.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error money parameters");
ExtExpert.Deinit();
return(-10);
}
//--- Tuning of all necessary indicators
if(!ExtExpert.InitIndicators())
{
//--- failed
printf(__FUNCTION__+": error initializing indicators");
ExtExpert.Deinit();
return(-11);
}
//--- succeed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ExtExpert.Deinit();
}
//+------------------------------------------------------------------+
//| Function-event handler "tick" |
//+------------------------------------------------------------------+
void OnTick(void)
{
ExtExpert.OnTick();
}
//+------------------------------------------------------------------+
//| Function-event handler "trade" |
//+------------------------------------------------------------------+
void OnTrade(void)
{
ExtExpert.OnTrade();
}
//+------------------------------------------------------------------+
//| Function-event handler "timer" |
//+------------------------------------------------------------------+
void OnTimer(void)
{
ExtExpert.OnTimer();
}
//+------------------------------------------------------------------+
@@ -0,0 +1,171 @@
//+------------------------------------------------------------------+
//| ExpertMAPSAR.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
#include <Expert\Signal\SignalMA.mqh>
#include <Expert\Trailing\TrailingParabolicSAR.mqh>
#include <Expert\Money\MoneyNone.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Inp_Expert_Title ="ExpertMAPSAR";
int Expert_MagicNumber =14598;
bool Expert_EveryTick =false;
//--- inputs for signal
input int Inp_Signal_MA_Period =12;
input int Inp_Signal_MA_Shift =6;
input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA;
input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE;
//--- inputs for trailing
input double Inp_Trailing_ParabolicSAR_Step =0.02;
input double Inp_Trailing_ParabolicSAR_Maximum=0.2;
//+------------------------------------------------------------------+
//| Global expert object |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Initializing expert
if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
{
//--- failed
printf(__FUNCTION__+": error initializing expert");
ExtExpert.Deinit();
return(-1);
}
//--- Creation of signal object
CSignalMA *signal=new CSignalMA;
if(signal==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating signal");
ExtExpert.Deinit();
return(-2);
}
//--- Add signal to expert (will be deleted automatically))
if(!ExtExpert.InitSignal(signal))
{
//--- failed
printf(__FUNCTION__+": error initializing signal");
ExtExpert.Deinit();
return(-3);
}
//--- Set signal parameters
signal.PeriodMA(Inp_Signal_MA_Period);
signal.Shift(Inp_Signal_MA_Shift);
signal.Method(Inp_Signal_MA_Method);
signal.Applied(Inp_Signal_MA_Applied);
//--- Check signal parameters
if(!signal.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error signal parameters");
ExtExpert.Deinit();
return(-4);
}
//--- Creation of trailing object
CTrailingPSAR *trailing=new CTrailingPSAR;
if(trailing==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating trailing");
ExtExpert.Deinit();
return(-5);
}
//--- Add trailing to expert (will be deleted automatically))
if(!ExtExpert.InitTrailing(trailing))
{
//--- failed
printf(__FUNCTION__+": error initializing trailing");
ExtExpert.Deinit();
return(-6);
}
//--- Set trailing parameters
trailing.Step(Inp_Trailing_ParabolicSAR_Step);
trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum);
//--- Check trailing parameters
if(!trailing.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error trailing parameters");
ExtExpert.Deinit();
return(-7);
}
//--- Creation of money object
CMoneyNone *money=new CMoneyNone;
if(money==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating money");
ExtExpert.Deinit();
return(-8);
}
//--- Add money to expert (will be deleted automatically))
if(!ExtExpert.InitMoney(money))
{
//--- failed
printf(__FUNCTION__+": error initializing money");
ExtExpert.Deinit();
return(-9);
}
//--- Set money parameters
//--- Check money parameters
if(!money.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error money parameters");
ExtExpert.Deinit();
return(-10);
}
//--- Tuning of all necessary indicators
if(!ExtExpert.InitIndicators())
{
//--- failed
printf(__FUNCTION__+": error initializing indicators");
ExtExpert.Deinit();
return(-11);
}
//--- succeed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ExtExpert.Deinit();
}
//+------------------------------------------------------------------+
//| Function-event handler "tick" |
//+------------------------------------------------------------------+
void OnTick(void)
{
ExtExpert.OnTick();
}
//+------------------------------------------------------------------+
//| Function-event handler "trade" |
//+------------------------------------------------------------------+
void OnTrade(void)
{
ExtExpert.OnTrade();
}
//+------------------------------------------------------------------+
//| Function-event handler "timer" |
//+------------------------------------------------------------------+
void OnTimer(void)
{
ExtExpert.OnTimer();
}
//+------------------------------------------------------------------+
@@ -0,0 +1,176 @@
//+------------------------------------------------------------------+
//| ExpertMAPSARSizeOptimized.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
#include <Expert\Signal\SignalMA.mqh>
#include <Expert\Trailing\TrailingParabolicSAR.mqh>
#include <Expert\Money\MoneySizeOptimized.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Inp_Expert_Title ="ExpertMAPSARSizeOptimized";
int Expert_MagicNumber =27893;
bool Expert_EveryTick =false;
//--- inputs for signal
input int Inp_Signal_MA_Period =12;
input int Inp_Signal_MA_Shift =6;
input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA;
input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE;
//--- inputs for trailing
input double Inp_Trailing_ParabolicSAR_Step =0.02;
input double Inp_Trailing_ParabolicSAR_Maximum =0.2;
//--- inputs for money
input double Inp_Money_SizeOptimized_DecreaseFactor=3.0;
input double Inp_Money_SizeOptimized_Percent =10.0;
//+------------------------------------------------------------------+
//| Global expert object |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Initializing expert
if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
{
//--- failed
printf(__FUNCTION__+": error initializing expert");
ExtExpert.Deinit();
return(-1);
}
//--- Creation of signal object
CSignalMA *signal=new CSignalMA;
if(signal==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating signal");
ExtExpert.Deinit();
return(-2);
}
//--- Add signal to expert (will be deleted automatically))
if(!ExtExpert.InitSignal(signal))
{
//--- failed
printf(__FUNCTION__+": error initializing signal");
ExtExpert.Deinit();
return(-3);
}
//--- Set signal parameters
signal.PeriodMA(Inp_Signal_MA_Period);
signal.Shift(Inp_Signal_MA_Shift);
signal.Method(Inp_Signal_MA_Method);
signal.Applied(Inp_Signal_MA_Applied);
//--- Check signal parameters
if(!signal.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error signal parameters");
ExtExpert.Deinit();
return(-4);
}
//--- Creation of trailing object
CTrailingPSAR *trailing=new CTrailingPSAR;
if(trailing==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating trailing");
ExtExpert.Deinit();
return(-5);
}
//--- Add trailing to expert (will be deleted automatically))
if(!ExtExpert.InitTrailing(trailing))
{
//--- failed
printf(__FUNCTION__+": error initializing trailing");
ExtExpert.Deinit();
return(-6);
}
//--- Set trailing parameters
trailing.Step(Inp_Trailing_ParabolicSAR_Step);
trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum);
//--- Check trailing parameters
if(!trailing.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error trailing parameters");
ExtExpert.Deinit();
return(-7);
}
//--- Creation of money object
CMoneySizeOptimized *money=new CMoneySizeOptimized;
if(money==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating money");
ExtExpert.Deinit();
return(-8);
}
//--- Add money to expert (will be deleted automatically))
if(!ExtExpert.InitMoney(money))
{
//--- failed
printf(__FUNCTION__+": error initializing money");
ExtExpert.Deinit();
return(-9);
}
//--- Set money parameters
money.DecreaseFactor(Inp_Money_SizeOptimized_DecreaseFactor);
money.Percent(Inp_Money_SizeOptimized_Percent);
//--- Check money parameters
if(!money.ValidationSettings())
{
//--- failed
printf(__FUNCTION__+": error money parameters");
ExtExpert.Deinit();
return(-10);
}
//--- Tuning of all necessary indicators
if(!ExtExpert.InitIndicators())
{
//--- failed
printf(__FUNCTION__+": error initializing indicators");
ExtExpert.Deinit();
return(-11);
}
//--- succeed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ExtExpert.Deinit();
}
//+------------------------------------------------------------------+
//| Function-event handler "tick" |
//+------------------------------------------------------------------+
void OnTick(void)
{
ExtExpert.OnTick();
}
//+------------------------------------------------------------------+
//| Function-event handler "trade" |
//+------------------------------------------------------------------+
void OnTrade(void)
{
ExtExpert.OnTrade();
}
//+------------------------------------------------------------------+
//| Function-event handler "timer" |
//+------------------------------------------------------------------+
void OnTimer(void)
{
ExtExpert.OnTimer();
}
//+------------------------------------------------------------------+
@@ -0,0 +1,45 @@
//+------------------------------------------------------------------+
//| Controls.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "ControlsDialog.mqh"
//+------------------------------------------------------------------+
//| Global Variables |
//+------------------------------------------------------------------+
CControlsDialog ExtDialog;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create application dialog
if(!ExtDialog.Create(0,"Controls",0,20,20,360,324))
return(INIT_FAILED);
//--- run application
ExtDialog.Run();
//--- succeed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy dialog
ExtDialog.Destroy(reason);
}
//+------------------------------------------------------------------+
//| Expert chart event function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // event ID
const long& lparam, // event parameter of the long type
const double& dparam, // event parameter of the double type
const string& sparam) // event parameter of the string type
{
ExtDialog.ChartEvent(id,lparam,dparam,sparam);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,427 @@
//+------------------------------------------------------------------+
//| ControlsDialog.mqh |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\DatePicker.mqh>
#include <Controls\ListView.mqh>
#include <Controls\ComboBox.mqh>
#include <Controls\SpinEdit.mqh>
#include <Controls\RadioGroup.mqh>
#include <Controls\CheckGroup.mqh>
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT (11) // indent from left (with allowance for border width)
#define INDENT_TOP (11) // indent from top (with allowance for border width)
#define INDENT_RIGHT (11) // indent from right (with allowance for border width)
#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width)
#define CONTROLS_GAP_X (5) // gap by X coordinate
#define CONTROLS_GAP_Y (5) // gap by Y coordinate
//--- for buttons
#define BUTTON_WIDTH (100) // size by X coordinate
#define BUTTON_HEIGHT (20) // size by Y coordinate
//--- for the indication area
#define EDIT_HEIGHT (20) // size by Y coordinate
//--- for group controls
#define GROUP_WIDTH (150) // size by X coordinate
#define LIST_HEIGHT (179) // size by Y coordinate
#define RADIO_HEIGHT (56) // size by Y coordinate
#define CHECK_HEIGHT (93) // size by Y coordinate
//+------------------------------------------------------------------+
//| Class CControlsDialog |
//| Usage: main dialog of the Controls application |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
{
private:
CEdit m_edit; // the display field object
CButton m_button1; // the button object
CButton m_button2; // the button object
CButton m_button3; // the fixed button object
CSpinEdit m_spin_edit; // the up-down object
CDatePicker m_date; // the datepicker object
CListView m_list_view; // the list object
CComboBox m_combo_box; // the dropdown list object
CRadioGroup m_radio_group; // the radio buttons group object
CCheckGroup m_check_group; // the check box group object
public:
CControlsDialog(void);
~CControlsDialog(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
protected:
//--- create dependent controls
bool CreateEdit(void);
bool CreateButton1(void);
bool CreateButton2(void);
bool CreateButton3(void);
bool CreateSpinEdit(void);
bool CreateDate(void);
bool CreateListView(void);
bool CreateComboBox(void);
bool CreateRadioGroup(void);
bool CreateCheckGroup(void);
//--- handlers of the dependent controls events
void OnClickButton1(void);
void OnClickButton2(void);
void OnClickButton3(void);
void OnChangeSpinEdit(void);
void OnChangeDate(void);
void OnChangeListView(void);
void OnChangeComboBox(void);
void OnChangeRadioGroup(void);
void OnChangeCheckGroup(void);
};
//+------------------------------------------------------------------+
//| Event Handling |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CControlsDialog)
ON_EVENT(ON_CLICK,m_button1,OnClickButton1)
ON_EVENT(ON_CLICK,m_button2,OnClickButton2)
ON_EVENT(ON_CLICK,m_button3,OnClickButton3)
ON_EVENT(ON_CHANGE,m_spin_edit,OnChangeSpinEdit)
ON_EVENT(ON_CHANGE,m_date,OnChangeDate)
ON_EVENT(ON_CHANGE,m_list_view,OnChangeListView)
ON_EVENT(ON_CHANGE,m_combo_box,OnChangeComboBox)
ON_EVENT(ON_CHANGE,m_radio_group,OnChangeRadioGroup)
ON_EVENT(ON_CHANGE,m_check_group,OnChangeCheckGroup)
EVENT_MAP_END(CAppDialog)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CControlsDialog::CControlsDialog(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CControlsDialog::~CControlsDialog(void)
{
}
//+------------------------------------------------------------------+
//| Create |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateButton1())
return(false);
if(!CreateButton2())
return(false);
if(!CreateButton3())
return(false);
if(!CreateSpinEdit())
return(false);
if(!CreateListView())
return(false);
if(!CreateDate())
return(false);
if(!CreateRadioGroup())
return(false);
if(!CreateCheckGroup())
return(false);
if(!CreateComboBox())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the display field |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateEdit(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP;
int x2=ClientAreaWidth()-INDENT_RIGHT;
int y2=y1+EDIT_HEIGHT;
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Button1" button |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButton1(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+BUTTON_WIDTH;
int y2=y1+BUTTON_HEIGHT;
//--- create
if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button1.Text("Button1"))
return(false);
if(!Add(m_button1))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Button2" button |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButton2(void)
{
//--- coordinates
int x1=INDENT_LEFT+(BUTTON_WIDTH+CONTROLS_GAP_X);
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+BUTTON_WIDTH;
int y2=y1+BUTTON_HEIGHT;
//--- create
if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button2.Text("Button2"))
return(false);
if(!Add(m_button2))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Button3" fixed button |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButton3(void)
{
//--- coordinates
int x1=INDENT_LEFT+2*(BUTTON_WIDTH+CONTROLS_GAP_X);
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+BUTTON_WIDTH;
int y2=y1+BUTTON_HEIGHT;
//--- create
if(!m_button3.Create(m_chart_id,m_name+"Button3",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button3.Text("Locked"))
return(false);
if(!Add(m_button3))
return(false);
m_button3.Locking(true);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "SpinEdit" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateSpinEdit(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+EDIT_HEIGHT;
//--- create
if(!m_spin_edit.Create(m_chart_id,m_name+"SpinEdit",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_spin_edit))
return(false);
m_spin_edit.MinValue(10);
m_spin_edit.MaxValue(1000);
m_spin_edit.Value(100);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "DatePicker" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateDate(void)
{
//--- coordinates
int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+EDIT_HEIGHT;
//--- create
if(!m_date.Create(m_chart_id,m_name+"Date",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_date))
return(false);
m_date.Value(TimeCurrent());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "ListView" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateListView(void)
{
//--- coordinates
int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(BUTTON_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+2*CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+LIST_HEIGHT-CONTROLS_GAP_Y;
//--- create
if(!m_list_view.Create(m_chart_id,m_name+"ListView",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_list_view))
return(false);
//--- fill out with strings
for(int i=0;i<16;i++)
if(!m_list_view.AddItem("Item "+IntegerToString(i)))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "ComboBox" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateComboBox(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(BUTTON_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+EDIT_HEIGHT;
//--- create
if(!m_combo_box.Create(m_chart_id,m_name+"ComboBox",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_combo_box))
return(false);
//--- fill out with strings
for(int i=0;i<16;i++)
if(!m_combo_box.ItemAdd("Item "+IntegerToString(i)))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "RadioGroup" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateRadioGroup(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(BUTTON_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+RADIO_HEIGHT;
//--- create
if(!m_radio_group.Create(m_chart_id,m_name+"RadioGroup",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_radio_group))
return(false);
//--- fill out with strings
for(int i=0;i<3;i++)
if(!m_radio_group.AddItem("Item "+IntegerToString(i),1<<i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "CheckGroup" element |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateCheckGroup(void)
{
//--- coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(BUTTON_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(EDIT_HEIGHT+CONTROLS_GAP_Y)+
(RADIO_HEIGHT+CONTROLS_GAP_Y);
int x2=x1+GROUP_WIDTH;
int y2=y1+CHECK_HEIGHT;
//--- create
if(!m_check_group.Create(m_chart_id,m_name+"CheckGroup",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_check_group))
return(false);
//--- fill out with strings
for(int i=0;i<5;i++)
if(!m_check_group.AddItem("Item "+IntegerToString(i),1<<i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickButton1(void)
{
m_edit.Text(__FUNCTION__);
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickButton2(void)
{
m_edit.Text(__FUNCTION__);
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnClickButton3(void)
{
if(m_button3.Pressed())
m_edit.Text(__FUNCTION__+"On");
else
m_edit.Text(__FUNCTION__+"Off");
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeSpinEdit()
{
m_edit.Text(__FUNCTION__+" : Value="+IntegerToString(m_spin_edit.Value()));
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeDate(void)
{
m_edit.Text(__FUNCTION__+" \""+TimeToString(m_date.Value(),TIME_DATE)+"\"");
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeListView(void)
{
m_edit.Text(__FUNCTION__+" \""+m_list_view.Select()+"\"");
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeComboBox(void)
{
m_edit.Text(__FUNCTION__+" \""+m_combo_box.Select()+"\"");
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeRadioGroup(void)
{
m_edit.Text(__FUNCTION__+" : Value="+IntegerToString(m_radio_group.Value()));
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CControlsDialog::OnChangeCheckGroup(void)
{
m_edit.Text(__FUNCTION__+" : Value="+IntegerToString(m_check_group.Value()));
}
//+------------------------------------------------------------------+
@@ -0,0 +1,451 @@
//+------------------------------------------------------------------+
//| MACD Sample.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "5.50"
#property description "It is important to make sure that the expert works with a normal"
#property description "chart and the user did not make any mistakes setting input"
#property description "variables (Lots, TakeProfit, TrailingStop) in our case,"
#property description "we check TakeProfit on a chart of more than 2*trend_period bars"
#define MACD_MAGIC 1234502
//---
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>
//---
input double InpLots =0.1; // Lots
input int InpTakeProfit =50; // Take Profit (in pips)
input int InpTrailingStop =30; // Trailing Stop Level (in pips)
input int InpMACDOpenLevel =3; // MACD open level (in pips)
input int InpMACDCloseLevel=2; // MACD close level (in pips)
input int InpMATrendPeriod =26; // MA trend period
//---
int ExtTimeOut=10; // time out in seconds between trade operations
//+------------------------------------------------------------------+
//| MACD Sample expert class |
//+------------------------------------------------------------------+
class CSampleExpert
{
protected:
double m_adjusted_point; // point value adjusted for 3 or 5 points
CTrade m_trade; // trading object
CSymbolInfo m_symbol; // symbol info object
CPositionInfo m_position; // trade position object
CAccountInfo m_account; // account info wrapper
//--- indicators
int m_handle_macd; // MACD indicator handle
int m_handle_ema; // moving average indicator handle
//--- indicator buffers
double m_buff_MACD_main[]; // MACD indicator main buffer
double m_buff_MACD_signal[]; // MACD indicator signal buffer
double m_buff_EMA[]; // EMA indicator buffer
//--- indicator data for processing
double m_macd_current;
double m_macd_previous;
double m_signal_current;
double m_signal_previous;
double m_ema_current;
double m_ema_previous;
//---
double m_macd_open_level;
double m_macd_close_level;
double m_traling_stop;
double m_take_profit;
public:
CSampleExpert(void);
~CSampleExpert(void);
bool Init(void);
void Deinit(void);
bool Processing(void);
protected:
bool InitCheckParameters(const int digits_adjust);
bool InitIndicators(void);
bool LongClosed(void);
bool ShortClosed(void);
bool LongModified(void);
bool ShortModified(void);
bool LongOpened(void);
bool ShortOpened(void);
};
//--- global expert
CSampleExpert ExtExpert;
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSampleExpert::CSampleExpert(void) : m_adjusted_point(0),
m_handle_macd(INVALID_HANDLE),
m_handle_ema(INVALID_HANDLE),
m_macd_current(0),
m_macd_previous(0),
m_signal_current(0),
m_signal_previous(0),
m_ema_current(0),
m_ema_previous(0),
m_macd_open_level(0),
m_macd_close_level(0),
m_traling_stop(0),
m_take_profit(0)
{
ArraySetAsSeries(m_buff_MACD_main,true);
ArraySetAsSeries(m_buff_MACD_signal,true);
ArraySetAsSeries(m_buff_EMA,true);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CSampleExpert::~CSampleExpert(void)
{
}
//+------------------------------------------------------------------+
//| Initialization and checking for input parameters |
//+------------------------------------------------------------------+
bool CSampleExpert::Init(void)
{
//--- initialize common information
m_symbol.Name(Symbol()); // symbol
m_trade.SetExpertMagicNumber(MACD_MAGIC); // magic
m_trade.SetMarginMode();
m_trade.SetTypeFillingBySymbol(Symbol());
//--- tuning for 3 or 5 digits
int digits_adjust=1;
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
digits_adjust=10;
m_adjusted_point=m_symbol.Point()*digits_adjust;
//--- set default deviation for trading in adjusted points
m_macd_open_level =InpMACDOpenLevel*m_adjusted_point;
m_macd_close_level=InpMACDCloseLevel*m_adjusted_point;
m_traling_stop =InpTrailingStop*m_adjusted_point;
m_take_profit =InpTakeProfit*m_adjusted_point;
//--- set default deviation for trading in adjusted points
m_trade.SetDeviationInPoints(3*digits_adjust);
//---
if(!InitCheckParameters(digits_adjust))
return(false);
if(!InitIndicators())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Checking for input parameters |
//+------------------------------------------------------------------+
bool CSampleExpert::InitCheckParameters(const int digits_adjust)
{
//--- initial data checks
if(InpTakeProfit*digits_adjust<m_symbol.StopsLevel())
{
printf("Take Profit must be greater than %d",m_symbol.StopsLevel());
return(false);
}
if(InpTrailingStop*digits_adjust<m_symbol.StopsLevel())
{
printf("Trailing Stop must be greater than %d",m_symbol.StopsLevel());
return(false);
}
//--- check for right lots amount
if(InpLots<m_symbol.LotsMin() || InpLots>m_symbol.LotsMax())
{
printf("Lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
return(false);
}
if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10)
{
printf("Lots amount is not corresponding with lot step %f",m_symbol.LotsStep());
return(false);
}
//--- warning
if(InpTakeProfit<=InpTrailingStop)
printf("Warning: Trailing Stop must be less than Take Profit");
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialization of the indicators |
//+------------------------------------------------------------------+
bool CSampleExpert::InitIndicators(void)
{
//--- create MACD indicator
if(m_handle_macd==INVALID_HANDLE)
if((m_handle_macd=iMACD(NULL,0,12,26,9,PRICE_CLOSE))==INVALID_HANDLE)
{
printf("Error creating MACD indicator");
return(false);
}
//--- create EMA indicator and add it to collection
if(m_handle_ema==INVALID_HANDLE)
if((m_handle_ema=iMA(NULL,0,InpMATrendPeriod,0,MODE_EMA,PRICE_CLOSE))==INVALID_HANDLE)
{
printf("Error creating EMA indicator");
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Check for long position closing |
//+------------------------------------------------------------------+
bool CSampleExpert::LongClosed(void)
{
bool res=false;
//--- should it be closed?
if(m_macd_current>0)
if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous)
if(m_macd_current>m_macd_close_level)
{
//--- close position
if(m_trade.PositionClose(Symbol()))
printf("Long position by %s to be closed",Symbol());
else
printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment());
//--- processed and cannot be modified
res=true;
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| Check for short position closing |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortClosed(void)
{
bool res=false;
//--- should it be closed?
if(m_macd_current<0)
if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous)
if(MathAbs(m_macd_current)>m_macd_close_level)
{
//--- close position
if(m_trade.PositionClose(Symbol()))
printf("Short position by %s to be closed",Symbol());
else
printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment());
//--- processed and cannot be modified
res=true;
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| Check for long position modifying |
//+------------------------------------------------------------------+
bool CSampleExpert::LongModified(void)
{
bool res=false;
//--- check for trailing stop
if(InpTrailingStop>0)
{
if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop)
{
double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits());
double tp=m_position.TakeProfit();
if(m_position.StopLoss()<sl || m_position.StopLoss()==0.0)
{
//--- modify position
if(m_trade.PositionModify(Symbol(),sl,tp))
printf("Long position by %s to be modified",Symbol());
else
{
printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
printf("Modify parameters : SL=%f,TP=%f",sl,tp);
}
//--- modified and must exit from expert
res=true;
}
}
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| Check for short position modifying |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortModified(void)
{
bool res=false;
//--- check for trailing stop
if(InpTrailingStop>0)
{
if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop))
{
double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits());
double tp=m_position.TakeProfit();
if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0)
{
//--- modify position
if(m_trade.PositionModify(Symbol(),sl,tp))
printf("Short position by %s to be modified",Symbol());
else
{
printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
printf("Modify parameters : SL=%f,TP=%f",sl,tp);
}
//--- modified and must exit from expert
res=true;
}
}
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| Check for long position opening |
//+------------------------------------------------------------------+
bool CSampleExpert::LongOpened(void)
{
bool res=false;
//--- check for long position (BUY) possibility
if(m_macd_current<0)
if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous)
if(MathAbs(m_macd_current)>(m_macd_open_level) && m_ema_current>m_ema_previous)
{
double price=m_symbol.Ask();
double tp =m_symbol.Bid()+m_take_profit;
//--- check for free money
if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_BUY,InpLots,price)<0.0)
printf("We have no money. Free Margin = %f",m_account.FreeMargin());
else
{
//--- open position
if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_BUY,InpLots,price,0.0,tp))
printf("Position by %s to be opened",Symbol());
else
{
printf("Error opening BUY position by %s : '%s'",Symbol(),m_trade.ResultComment());
printf("Open parameters : price=%f,TP=%f",price,tp);
}
}
//--- in any case we must exit from expert
res=true;
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| Check for short position opening |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortOpened(void)
{
bool res=false;
//--- check for short position (SELL) possibility
if(m_macd_current>0)
if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous)
if(m_macd_current>(m_macd_open_level) && m_ema_current<m_ema_previous)
{
double price=m_symbol.Bid();
double tp =m_symbol.Ask()-m_take_profit;
//--- check for free money
if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL,InpLots,price)<0.0)
printf("We have no money. Free Margin = %f",m_account.FreeMargin());
else
{
//--- open position
if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_SELL,InpLots,price,0.0,tp))
printf("Position by %s to be opened",Symbol());
else
{
printf("Error opening SELL position by %s : '%s'",Symbol(),m_trade.ResultComment());
printf("Open parameters : price=%f,TP=%f",price,tp);
}
}
//--- in any case we must exit from expert
res=true;
}
//--- result
return(res);
}
//+------------------------------------------------------------------+
//| main function returns true if any position processed |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
{
//--- refresh rates
if(!m_symbol.RefreshRates())
return(false);
//--- refresh indicators
if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
return(false);
if(CopyBuffer(m_handle_macd,0,0,2,m_buff_MACD_main) !=2 ||
CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 ||
CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA) !=2)
return(false);
// m_indicators.Refresh();
//--- to simplify the coding and speed up access
//--- data are put into internal variables
m_macd_current =m_buff_MACD_main[0];
m_macd_previous =m_buff_MACD_main[1];
m_signal_current =m_buff_MACD_signal[0];
m_signal_previous=m_buff_MACD_signal[1];
m_ema_current =m_buff_EMA[0];
m_ema_previous =m_buff_EMA[1];
//--- it is important to enter the market correctly,
//--- but it is more important to exit it correctly...
//--- first check if position exists - try to select it
if(m_position.Select(Symbol()))
{
if(m_position.PositionType()==POSITION_TYPE_BUY)
{
//--- try to close or modify long position
if(LongClosed())
return(true);
if(LongModified())
return(true);
}
else
{
//--- try to close or modify short position
if(ShortClosed())
return(true);
if(ShortModified())
return(true);
}
}
//--- no opened position identified
else
{
//--- check for long position (BUY) possibility
if(LongOpened())
return(true);
//--- check for short position (SELL) possibility
if(ShortOpened())
return(true);
}
//--- exit without position processing
return(false);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- create all necessary objects
if(!ExtExpert.Init())
return(INIT_FAILED);
//--- secceed
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert new tick handling function |
//+------------------------------------------------------------------+
void OnTick(void)
{
static datetime limit_time=0; // last trade processing time + timeout
//--- don't process if timeout
if(TimeCurrent()>=limit_time)
{
//--- check for data
if(Bars(Symbol(),Period())>2*InpMATrendPeriod)
{
//--- change limit time by timeout in seconds if processed
if(ExtExpert.Processing())
limit_time=TimeCurrent()+ExtTimeOut;
}
}
}
//+------------------------------------------------------------------+
@@ -0,0 +1,372 @@
//+------------------------------------------------------------------+
//| Functions.mqh |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
//--- custom function y=f(x,y)
typedef double(*MathFunction)(double,double);
//+------------------------------------------------------------------+
//| math functions |
//+------------------------------------------------------------------+
enum EnMathFunction
{
Peaks=0,
Chomolungma=1,
ClimberDream=2,
Granite=3,
Hedgehog=4,
Hill=5,
Josephine=6,
Screw=7,
DoubleScrew=8,
MultiExtremalScrew=9,
Sink=10,
Skin=11,
Trapfall=12,
};
//+------------------------------------------------------------------+
//| Names of the math functions |
//+------------------------------------------------------------------+
const string ExtFunctionsNames[]=
{
"Peaks",
"Chomolungma",
"Climber Dream",
"Granite",
"Hedgehog",
"Hill",
"Josephine",
"Screw",
"Double Screw",
"Multi Extremal Screw",
"Sinc",
"Skin",
"Trapfall"
};
//+------------------------------------------------------------------+
//| Function Peaks |
//+------------------------------------------------------------------+
double PeaksFunction(double x,double y)
{
double res = 3*MathPow((1-x),2)*MathExp(-x*x-(y+1)*(y+1))-10*(0.2*x-MathPow(x,3)-MathPow(y,5))*MathExp(-x*x-y*y)-1/3*MathExp(-(x+1)*(x+1)-y*y);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Chomolungma |
//+------------------------------------------------------------------+
double ChomolungmaFunction(double x,double y)
{
double a= MathCos(x*x)+MathCos(y*y);
double b= MathPow(MathCos(5*x*y),5);
double c=1.0/MathPow(2,b);
//--- calculate result
double res=a-c;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function ClimberDream |
//+------------------------------------------------------------------+
double ClimberDreamFunction(double x,double y)
{
double a= MathSin(MathSqrt(MathAbs(x - 1.3) + MathAbs(y)));
double b= MathCos(MathSqrt(MathAbs(MathSin(x))) + MathSqrt(MathAbs(MathSin(y))));
double f=a+b;
//--- calculate result
double res=MathPow(f,4);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Granite |
//+------------------------------------------------------------------+
double GraniteFunction(double x,double y)
{
double a= MathPow(MathSin(MathSqrt(MathAbs(x)+MathAbs(y))),2);
double b= MathPow(MathCos(MathSqrt(MathAbs(x)+MathAbs(y))),2);
//--- calculate result
double res=a*b;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Hedgehog |
//+------------------------------------------------------------------+
double HedgehogFunction(double x,double y)
{
double a1=MathSin(MathSqrt(MathAbs(x-2)+MathAbs(y)));
double a2=MathCos(MathSqrt(MathAbs(MathSin(x)))+MathSqrt(MathAbs(MathSin(y))));
//--- calculate result
double res=a1+a2;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Hill |
//+------------------------------------------------------------------+
double HillFunction(double x,double y)
{
//--- calculate result
double res=MathExp(-x*x-y*y);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Josephine |
//+------------------------------------------------------------------+
double JosephineFunction(double x,double y)
{
double a= MathSin(MathPow(MathAbs(x)+MathAbs(y),0.5));
double b= MathCos(MathPow(MathAbs(x),0.5)+MathPow(MathAbs(y),0.5));
//--- calculate function
double res=a+b;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Screw |
//+------------------------------------------------------------------+
double ScrewFunction(double x,double y)
{
double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI);
double b=x*x+y*y;
double f=MathSin(b+a);
//--- calculate result
double res=(f*f);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function DoubleScrew |
//+------------------------------------------------------------------+
double DoubleScrewFunction(double x,double y)
{
double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI);
double b=x*x+y*y;
double res1=MathCos(b/2+a*3);
res1=((res1*res1)/sqrt(b+1)-0.2);
double res2=MathCos(b/2-a*3);
res2=((res2*res2)/sqrt(b+1)-0.2);
double f=fmax(res1,res2);
//--- calculate result
double res=(f>0)?f:0;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function MultiExtremalScrew |
//+------------------------------------------------------------------+
double MultiExtremalScrewFunction(double x,double y)
{
double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI);
double b=x*x+y*y;
double res1=MathCos(b/2+a*3);
res1=((res1*res1)/sqrt(b+1)-0.2);
double res2=MathCos(b/2-a*3);
res2=((res2*res2)/sqrt(b+1)-0.2);
//--- calculate function
double res=fmin(res1,res2);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Sink |
//+------------------------------------------------------------------+
double SinkFunction(double x,double y)
{
static double k=5.0;
static double p=6.0;
//--- calculate result
double res=MathSin(x*x+y*y)+k*MathExp(-p*x*x-p*y*y);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Skin |
//+------------------------------------------------------------------+
double SkinFunction(double x,double y)
{
double a1=2*x*x;
double a2=2*y*y;
double b1=MathCos(a1)-1.1;
b1=b1*b1;
double c1=MathSin(0.5*x)-1.2;
c1=c1*c1;
double d1=MathCos(a2)-1.1;
d1=d1*d1;
double e1=MathSin(0.5*y)-1.2;
e1=e1*e1;
//--- calculate result
double res=b1+c1-d1+e1;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Function Trapfall |
//+------------------------------------------------------------------+
double TrapfallFunction(double x,double y)
{
double a1=MathSqrt(MathAbs(MathSin(x-1.0)));
double b1=MathSqrt(MathAbs(MathSin(y+2.0)));
//--- calculate result
double res=-MathSqrt(MathAbs(MathSin(MathSin(a1+b1))));
//---
return(res);
}
//+------------------------------------------------------------------+
//| GenerateFunctionData |
//+------------------------------------------------------------------+
void GenerateFunctionData(double &data[],int &x_size,int &y_size,double x_min,double x_max,double y_min,double y_max,MathFunction function)
{
double dx = 0.1;
double dy = 0.1;
//---
x_size = (int)((x_max - x_min)/dx) + 1;
y_size = (int)((y_max - y_min)/dy) + 1;
ArrayResize(data,x_size*y_size);
//---
for(int j = 0; j < y_size; j++)
{
for(int i = 0; i < x_size; i++)
{
double x = x_min + i*dx;
double y = y_min + j*dy;
data[j*x_size + i] = function(x,y);
}
}
}
//+------------------------------------------------------------------+
//| GenerateData |
//+------------------------------------------------------------------+
void GenerateData(EnMathFunction function_id,double &data[],int &x_size,int &y_size)
{
//---
switch(function_id)
{
case Peaks:
GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,PeaksFunction);
break;
case Chomolungma:
GenerateFunctionData(data,x_size,y_size,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction);
break;
case ClimberDream:
GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction);
break;
case Granite:
GenerateFunctionData(data,x_size,y_size,-4.0,+4.0,-4.0,+4.0,GraniteFunction);
break;
case Hedgehog:
GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,HedgehogFunction);
break;
case Hill:
GenerateFunctionData(data,x_size,y_size,-1.5,+1.5,-1.5,+1.5,HillFunction);
break;
case Josephine:
GenerateFunctionData(data,x_size,y_size,-200.0,+200.0,-200.0,+200.0,JosephineFunction);
break;
case Screw:
GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,ScrewFunction);
break;
case DoubleScrew:
GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction);
break;
case MultiExtremalScrew:
GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction);
break;
case Sink:
GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,SinkFunction);
break;
case Skin:
GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,SkinFunction);
break;
case Trapfall:
GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,TrapfallFunction);
break;
}
}
//+------------------------------------------------------------------+
//| GenerateFunctionDataFixedSize |
//+------------------------------------------------------------------+
bool GenerateFunctionDataFixedSize(int x_size,int y_size,double &data[],double x_min,double x_max,double y_min,double y_max,MathFunction function)
{
if(x_size<2 || y_size<2)
{
PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size);
return(false);
}
double dx = (x_max - x_min)/(x_size-1);
double dy = (y_max - y_min)/(y_size-1);
ArrayResize(data,x_size*y_size);
//---
for(int j = 0; j < y_size; j++)
{
for(int i = 0; i < x_size; i++)
{
double x = x_min + i*dx;
double y = y_min + j*dy;
data[j*x_size + i] = function(x,y);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| GenerateDataFixedSize |
//+------------------------------------------------------------------+
bool GenerateDataFixedSize(int x_size,int y_size,EnMathFunction function_id,double &data[])
{
if(x_size<2 || y_size<2)
{
PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size);
return(false);
}
bool result=false;
//---
switch(function_id)
{
case Peaks:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,PeaksFunction);
break;
case Chomolungma:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction);
break;
case ClimberDream:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction);
break;
case Granite:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-4.0,+4.0,-4.0,+4.0,GraniteFunction);
break;
case Hedgehog:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,HedgehogFunction);
break;
case Hill:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-1.5,+1.5,-1.5,+1.5,HillFunction);
break;
case Josephine:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-200.0,+200.0,-200.0,+200.0,JosephineFunction);
break;
case Screw:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,ScrewFunction);
break;
case DoubleScrew:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction);
break;
case MultiExtremalScrew:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction);
break;
case Sink:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,SinkFunction);
break;
case Skin:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,SkinFunction);
break;
case Trapfall:
result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,TrapfallFunction);
break;
}
//---
return(result);
}
//+------------------------------------------------------------------+
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,233 @@
//+------------------------------------------------------------------+
//| Moving Averages.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
input double MaximumRisk = 0.02; // Maximum Risk in percentage
input double DecreaseFactor = 3; // Descrease factor
input int MovingPeriod = 12; // Moving Average period
input int MovingShift = 6; // Moving Average shift
//---
int ExtHandle=0;
bool ExtHedging=false;
CTrade ExtTrade;
#define MA_MAGIC 1234501
//+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
{
double price=0.0;
double margin=0.0;
//--- select lot size
if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
return(0.0);
if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
return(0.0);
if(margin<=0.0)
return(0.0);
double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2);
//--- calculate number of losses orders without a break
if(DecreaseFactor>0)
{
//--- select history for access
HistorySelect(0,TimeCurrent());
//---
int orders=HistoryDealsTotal(); // total history deals
int losses=0; // number of losses orders without a break
for(int i=orders-1;i>=0;i--)
{
ulong ticket=HistoryDealGetTicket(i);
if(ticket==0)
{
Print("HistoryDealGetTicket failed, no trade history");
break;
}
//--- check symbol
if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
continue;
//--- check Expert Magic number
if(HistoryDealGetInteger(ticket,DEAL_MAGIC)!=MA_MAGIC)
continue;
//--- check profit
double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
if(profit>0.0)
break;
if(profit<0.0)
losses++;
}
//---
if(losses>1)
lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
}
//--- normalize and check limits
double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
lot=stepvol*NormalizeDouble(lot/stepvol,0);
double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
if(lot<minvol)
lot=minvol;
double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
if(lot>maxvol)
lot=maxvol;
//--- return trading volume
return(lot);
}
//+------------------------------------------------------------------+
//| Check for open position conditions |
//+------------------------------------------------------------------+
void CheckForOpen(void)
{
MqlRates rt[2];
//--- go trading only for first ticks of new bar
if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
{
Print("CopyRates of ",_Symbol," failed, no history");
return;
}
if(rt[1].tick_volume>1)
return;
//--- get current Moving Average
double ma[1];
if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
{
Print("CopyBuffer from iMA failed, no data");
return;
}
//--- check signals
ENUM_ORDER_TYPE signal=WRONG_VALUE;
if(rt[0].open>ma[0] && rt[0].close<ma[0])
signal=ORDER_TYPE_SELL; // sell conditions
else
{
if(rt[0].open<ma[0] && rt[0].close>ma[0])
signal=ORDER_TYPE_BUY; // buy conditions
}
//--- additional checking
if(signal!=WRONG_VALUE)
{
if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
ExtTrade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
0,0);
}
//---
}
//+------------------------------------------------------------------+
//| Check for close position conditions |
//+------------------------------------------------------------------+
void CheckForClose(void)
{
MqlRates rt[2];
//--- go trading only for first ticks of new bar
if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
{
Print("CopyRates of ",_Symbol," failed, no history");
return;
}
if(rt[1].tick_volume>1)
return;
//--- get current Moving Average
double ma[1];
if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
{
Print("CopyBuffer from iMA failed, no data");
return;
}
//--- positions already selected before
bool signal=false;
long type=PositionGetInteger(POSITION_TYPE);
if(type==(long)POSITION_TYPE_BUY && rt[0].open>ma[0] && rt[0].close<ma[0])
signal=true;
if(type==(long)POSITION_TYPE_SELL && rt[0].open<ma[0] && rt[0].close>ma[0])
signal=true;
//--- additional checking
if(signal)
{
if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
ExtTrade.PositionClose(_Symbol,3);
}
//---
}
//+------------------------------------------------------------------+
//| Position select depending on netting or hedging |
//+------------------------------------------------------------------+
bool SelectPosition()
{
bool res=false;
//--- check position in Hedging mode
if(ExtHedging)
{
uint total=PositionsTotal();
for(uint i=0; i<total; i++)
{
string position_symbol=PositionGetSymbol(i);
if(_Symbol==position_symbol && MA_MAGIC==PositionGetInteger(POSITION_MAGIC))
{
res=true;
break;
}
}
}
//--- check position in Netting mode
else
{
if(!PositionSelect(_Symbol))
return(false);
else
return(PositionGetInteger(POSITION_MAGIC)==MA_MAGIC); //---check Magic number
}
//--- result for Hedging mode
return(res);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- prepare trade class to control positions if hedging mode is active
ExtHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
ExtTrade.SetExpertMagicNumber(MA_MAGIC);
ExtTrade.SetMarginMode();
ExtTrade.SetTypeFillingBySymbol(Symbol());
//--- Moving Average indicator
ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
if(ExtHandle==INVALID_HANDLE)
{
printf("Error creating MA indicator");
return(INIT_FAILED);
}
//--- ok
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(void)
{
//---
if(SelectPosition())
CheckForClose();
else
CheckForOpen();
//---
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
@@ -0,0 +1,657 @@
//+------------------------------------------------------------------+
//| BlackCrows WhiteSoldiers CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=120100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check 3 Black Crows
if((Open(3)-Close(3)>AvgBody(1)) && // long black
(Open(2)-Close(2)>AvgBody(1)) &&
(Open(1)-Close(1)>AvgBody(1)) &&
(MidPoint(2)<MidPoint(3)) && // lower midpoints
(MidPoint(1)<MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\n3 Black Crows detected";
ExtDirection="Sell";
return(true);
}
//--- check 3 White Soldiers
if((Close(3)-Open(3)>AvgBody(1)) && // long white
(Close(2)-Open(2)>AvgBody(1)) &&
(Close(1)-Open(1)>AvgBody(1)) &&
(MidPoint(2)>MidPoint(3)) && // higher midpoints
(MidPoint(1)>MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\n3 White Soldiers detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,657 @@
//+------------------------------------------------------------------+
//| BlackCrows WhiteSoldiers MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=120200; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check 3 Black Crows
if((Open(3)-Close(3)>AvgBody(1)) && // long black
(Open(2)-Close(2)>AvgBody(1)) &&
(Open(1)-Close(1)>AvgBody(1)) &&
(MidPoint(2)<MidPoint(3)) && // lower midpoints
(MidPoint(1)<MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\n3 Black Crows detected";
ExtDirection="Sell";
return(true);
}
//--- check 3 White Soldiers
if((Close(3)-Open(3)>AvgBody(1)) && // long white
(Close(2)-Open(2)>AvgBody(1)) &&
(Close(1)-Open(1)>AvgBody(1)) &&
(MidPoint(2)>MidPoint(3)) && // higher midpoints
(MidPoint(1)>MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\n3 White Soldiers detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,657 @@
//+------------------------------------------------------------------+
//| BlackCrows WhiteSoldiers RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=120300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check 3 Black Crows
if((Open(3)-Close(3)>AvgBody(1)) && // long black
(Open(2)-Close(2)>AvgBody(1)) &&
(Open(1)-Close(1)>AvgBody(1)) &&
(MidPoint(2)<MidPoint(3)) && // lower midpoints
(MidPoint(1)<MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\n3 Black Crows detected";
ExtDirection="Sell";
return(true);
}
//--- check 3 White Soldiers
if((Close(3)-Open(3)>AvgBody(1)) && // long white
(Close(2)-Open(2)>AvgBody(1)) &&
(Close(1)-Open(1)>AvgBody(1)) &&
(MidPoint(2)>MidPoint(3)) && // higher midpoints
(MidPoint(1)>MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\n3 White Soldiers detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,661 @@
//+------------------------------------------------------------------+
//| BlackCrows WhiteSoldiers Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=120400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check 3 Black Crows
if((Open(3)-Close(3)>AvgBody(1)) && // long black
(Open(2)-Close(2)>AvgBody(1)) &&
(Open(1)-Close(1)>AvgBody(1)) &&
(MidPoint(2)<MidPoint(3)) && // lower midpoints
(MidPoint(1)<MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\n3 Black Crows detected";
ExtDirection="Sell";
return(true);
}
//--- check 3 White Soldiers
if((Close(3)-Open(3)>AvgBody(1)) && // long white
(Close(2)-Open(2)>AvgBody(1)) &&
(Close(1)-Open(1)>AvgBody(1)) &&
(MidPoint(2)>MidPoint(3)) && // higher midpoints
(MidPoint(1)>MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\n3 White Soldiers detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Engulfing CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=121100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Engulfing
if((Open(2)<Close(2)) && // previous candle is bearish
(Open(1)-Close(1)>AvgBody(1)) && // body of the candle is higher than average value of the body
(Close(1)<Open(2)) && // close price of the bearish candle is lower than open price of the bullish candle
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Engulfing detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Engulfing
if((Open(2)>Close(2)) && // previous candle is bearish
(Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body
(Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Close(2))) // open price of the bullish candle is lower than close price of the bearish
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Engulfing detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Engulfing MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=120600; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Engulfing
if((Open(2)<Close(2)) && // previous candle is bearish
(Open(1)-Close(1)>AvgBody(1)) && // body of the candle is higher than average value of the body
(Close(1)<Open(2)) && // close price of the bearish candle is lower than open price of the bullish candle
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Engulfing detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Engulfing
if((Open(2)>Close(2)) && // previous candle is bearish
(Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body
(Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Close(2))) // open price of the bullish candle is lower than close price of the bearish
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Engulfing detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Engulfing RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=121300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Engulfing
if((Open(2)<Close(2)) && // previous candle is bearish
(Open(1)-Close(1)>AvgBody(1)) && // body of the candle is higher than average value of the body
(Close(1)<Open(2)) && // close price of the bearish candle is lower than open price of the bullish candle
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Engulfing detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Engulfing
if((Open(2)>Close(2)) && // previous candle is bearish
(Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body
(Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Close(2))) // open price of the bullish candle is lower than close price of the bearish
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Engulfing detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,688 @@
//+------------------------------------------------------------------+
//| BullishBearish Engulfing Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow=13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=121400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Engulfing
if((Open(2)<Close(2)) && // previous candle is bearish
(Open(1)-Close(1)>AvgBody(1)) && // body of the candle is higher than average value of the body
(Close(1)<Open(2)) && // close price of the bearish candle is lower than open price of the bullish candle
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Engulfing detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Engulfing
if((Open(2)>Close(2)) && // previous candle is bearish
(Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body
(Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Close(2))) // open price of the bullish candle is lower than close price of the bearish
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Engulfing detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Harami CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=122100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Harami
if((Close(1)<Open(1)) && // last completed bar is bearish (black day)
((Close(2)-Open(2))>AvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white)
(Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle
(Open(1)<Close(2)) && // open price of the bearish candle is lower than close price of the bullish candle
(MidPoint(2)>CloseAvg(2))) // up trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Harami detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Harami
if((Close(1)>Open(1)) && // the last completed bar is bullish (white day)
((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black)
(Close(1)<Open(2)) && // close price of the bullish candle is lower than open price of the bearish candle
(Open(1)>Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle
(MidPoint(2)<CloseAvg(2))) // down trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Harami detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Harami MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=121600; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Harami
if((Close(1)<Open(1)) && // last completed bar is bearish (black day)
((Close(2)-Open(2))>AvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white)
(Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle
(Open(1)<Close(2)) && // open price of the bearish candle is lower than close price of the bullish candle
(MidPoint(2)>CloseAvg(2))) // up trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Harami detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Harami
if((Close(1)>Open(1)) && // the last completed bar is bullish (white day)
((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black)
(Close(1)<Open(2)) && // close price of the bullish candle is lower than open price of the bearish candle
(Open(1)>Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle
(MidPoint(2)<CloseAvg(2))) // down trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Harami detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| BullishBearish Harami RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=121300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Harami
if((Close(1)<Open(1)) && // last completed bar is bearish (black day)
((Close(2)-Open(2))>AvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white)
(Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle
(Open(1)<Close(2)) && // open price of the bearish candle is lower than close price of the bullish candle
(MidPoint(2)>CloseAvg(2))) // up trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Harami detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Harami
if((Close(1)>Open(1)) && // the last completed bar is bullish (white day)
((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black)
(Close(1)<Open(2)) && // close price of the bullish candle is lower than open price of the bearish candle
(Open(1)>Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle
(MidPoint(2)<CloseAvg(2))) // down trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Harami detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,685 @@
//+------------------------------------------------------------------+
//| BullishBearish Harami Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=122400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle =INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish Harami
if((Close(1)<Open(1)) && // last completed bar is bearish (black day)
((Close(2)-Open(2))>AvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white)
(Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle
(Open(1)<Close(2)) && // open price of the bearish candle is lower than close price of the bullish candle
(MidPoint(2)>CloseAvg(2))) // up trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish Harami detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish Harami
if((Close(1)>Open(1)) && // the last completed bar is bullish (white day)
((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black)
(Close(1)<Open(2)) && // close price of the bullish candle is lower than open price of the bearish candle
(Open(1)>Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle
(MidPoint(2)<CloseAvg(2))) // down trend
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish Harami detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,654 @@
//+------------------------------------------------------------------+
//| BullishBearish MeetingLines CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=123100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish MeetingLines
if((Close(2)-Open(2)>AvgBody(1)) && // long white candle
((Open(1)-Close(1))>AvgBody(1)) && // long black candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish MeetingLines detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish MeetingLines
if((Open(2)-Close(2)>AvgBody(1)) && // long black candle
((Close(1)-Open(1))>AvgBody(1)) && // long white candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish MeetingLines detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,652 @@
//+------------------------------------------------------------------+
//| BullishBearish MeetingLines MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=121200; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish MeetingLines
if((Close(2)-Open(2)>AvgBody(1)) && // long white candle
((Open(1)-Close(1))>AvgBody(1)) && // long black candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish MeetingLines detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish MeetingLines
if((Open(2)-Close(2)>AvgBody(1)) && // long black candle
((Close(1)-Open(1))>AvgBody(1)) && // long white candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish MeetingLines detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,653 @@
//+------------------------------------------------------------------+
//| BullishBearish MeetingLines RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot =0.1; // lot
//--- Expert ID
input long InpMagicNumber=122300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Bearish MeetingLines
if((Close(2)-Open(2)>AvgBody(1)) && // long white candle
((Open(1)-Close(1))>AvgBody(1)) && // long black candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nBearish MeetingLines detected";
ExtDirection="Sell";
return(true);
}
//--- check Bullish MeetingLines
if((Open(2)-Close(2)>AvgBody(1)) && // long black candle
((Close(1)-Open(1))>AvgBody(1)) && // long white candle
(MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nBullish MeetingLines detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,662 @@
//+------------------------------------------------------------------+
//| BullishBearish MeetingLines Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=123400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen=0; // Buy/Sell signal
int ExtSignalClose=0; // signal to close a position
string ExtPatternInfo=""; // current pattern information
string ExtDirection=""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed=false; // pattern confirmed
bool ExtCloseByTime=true; // requires closing by time
bool ExtCheckPassed=true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check 3 Black Crows
if((Open(3)-Close(3)>AvgBody(1)) && // long black
(Open(2)-Close(2)>AvgBody(1)) &&
(Open(1)-Close(1)>AvgBody(1)) &&
(MidPoint(2)<MidPoint(3)) && // lower midpoints
(MidPoint(1)<MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\n3 Black Crows detected";
ExtDirection="Sell";
return(true);
}
//--- check 3 White Soldiers
if((Close(3)-Open(3)>AvgBody(1)) && // long white
(Close(2)-Open(2)>AvgBody(1)) &&
(Close(1)-Open(1)>AvgBody(1)) &&
(MidPoint(2)>MidPoint(3)) && // higher midpoints
(MidPoint(1)>MidPoint(2)))
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\n3 White Soldiers detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,682 @@
//+------------------------------------------------------------------+
//| DarkCloud PiercingLine CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=120500; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Dark Cloud Cover
if((Close(2)-Open(2)>AvgBody(1)) && // long body of the white candlestick (long white)
(Close(1)<Close(2)) && // followed by a black candlestick
(Close(1)>Open(2)) && // close within the previous candlestick body (white)
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>High(2))) // open above the previous day's High price (open at new high)
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nDark Cloud Cover detected";
ExtDirection="Sell";
return(true);
}
//--- check Piercing Line
if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white)
(Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black)
(Close(1)>Close(2)) && // close within the body
(Close(1)<Open(2)) && // of the previous candlestick (close inside previous body)
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Low(2))) // open lower than previous Low
return(true);
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nPiercing Line detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,681 @@
//+------------------------------------------------------------------+
//| DarkCloud PiercingLine MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=122600; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Dark Cloud Cover
if((Close(2)-Open(2)>AvgBody(1)) && // long body of the white candlestick (long white)
(Close(1)<Close(2)) && // followed by a black candlestick
(Close(1)>Open(2)) && // close within the previous candlestick body (white)
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>High(2))) // open above the previous day's High price (open at new high)
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nDark Cloud Cover detected";
ExtDirection="Sell";
return(true);
}
//--- check Piercing Line
if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white)
(Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black)
(Close(1)>Close(2)) && // close within the body
(Close(1)<Open(2)) && // of the previous candlestick (close inside previous body)
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Low(2))) // open lower than previous Low
return(true);
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nPiercing Line detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,683 @@
//+------------------------------------------------------------------+
//| DarkCloud PiercingLine RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=120700; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Dark Cloud Cover
if((Close(2)-Open(2)>AvgBody(1)) && // long body of the white candlestick (long white)
(Close(1)<Close(2)) && // followed by a black candlestick
(Close(1)>Open(2)) && // close within the previous candlestick body (white)
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>High(2))) // open above the previous day's High price (open at new high)
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nDark Cloud Cover detected";
ExtDirection="Sell";
return(true);
}
//--- check Piercing Line
if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white)
(Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black)
(Close(1)>Close(2)) && // close within the body
(Close(1)<Open(2)) && // of the previous candlestick (close inside previous body)
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Low(2))) // open lower than previous Low
return(true);
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nPiercing Line detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,687 @@
//+------------------------------------------------------------------+
//| DarkCloud PiercingLine Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=120800; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Dark Cloud Cover
if((Close(2)-Open(2)>AvgBody(1)) && // long body of the white candlestick (long white)
(Close(1)<Close(2)) && // followed by a black candlestick
(Close(1)>Open(2)) && // close within the previous candlestick body (white)
(MidOpenClose(2)>CloseAvg(2)) && // uptrend
(Open(1)>High(2))) // open above the previous day's High price (open at new high)
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nDark Cloud Cover detected";
ExtDirection="Sell";
return(true);
}
//--- check Piercing Line
if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white)
(Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black)
(Close(1)>Close(2)) && // close within the body
(Close(1)<Open(2)) && // of the previous candlestick (close inside previous body)
(MidOpenClose(2)<CloseAvg(2)) && // downtrend
(Open(1)<Low(2))) // open lower than previous Low
return(true);
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nPiercing Line detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,679 @@
//+------------------------------------------------------------------+
//| HangingMan Hammer CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=124100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Hanging man
if((MidPoint(1)>CloseAvg(2)) && // up trend
(MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nHanging Man detected";
ExtDirection="Sell";
return(true);
}
//--- check Hammer
if((MidPoint(1)<CloseAvg(2)) && // down trend
(MathMin(Open(1), Close(1))>(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)<Close(2)) && (Open(1)<Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nHammer detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,679 @@
//+------------------------------------------------------------------+
//| HangingMan Hammer MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=123600; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Hanging man
if((MidPoint(1)>CloseAvg(2)) && // up trend
(MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nHanging Man detected";
ExtDirection="Sell";
return(true);
}
//--- check Hammer
if((MidPoint(1)<CloseAvg(2)) && // down trend
(MathMin(Open(1), Close(1))>(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)<Close(2)) && (Open(1)<Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nHammer detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,677 @@
//+------------------------------------------------------------------+
//| HangingMan Hammer RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=123300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Hanging man
if((MidPoint(1)>CloseAvg(2)) && // up trend
(MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nHanging Man detected";
ExtDirection="Sell";
return(true);
}
//--- check Hammer
if((MidPoint(1)<CloseAvg(2)) && // down trend
(MathMin(Open(1), Close(1))>(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)<Close(2)) && (Open(1)<Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nHammer detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,683 @@
//+------------------------------------------------------------------+
//| HangingMan Hammer Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpMAPeriod =5; // Trend MA period
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=124400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handles
int ExtIndicatorHandle=INVALID_HANDLE;
int ExtTrendMAHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- trend moving average
ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating Moving Average indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Hanging man
if((MidPoint(1)>CloseAvg(2)) && // up trend
(MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nHanging Man detected";
ExtDirection="Sell";
return(true);
}
//--- check Hammer
if((MidPoint(1)<CloseAvg(2)) && // down trend
(MathMin(Open(1), Close(1))>(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3
(Close(1)<Close(2)) && (Open(1)<Open(2))) // body gap
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nHammer detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
//| SMA value at the specified bar |
//+------------------------------------------------------------------+
double CloseAvg(int index)
{
double indicator_values[];
if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,685 @@
//+------------------------------------------------------------------+
//| MorningEvening StarDoji CCI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodCCI =37; // CCI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration =10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage =10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=130100; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Evening Doji
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Open(1)<Close(2)) && // down price gap on the last candlestick
(Close(1)<Close(2))) // last candlestick close lower than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Doji detected";
ExtDirection="Sell";
return(true);
}
//--- check Evening Star
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Close(1)<MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bullish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Star detected";
ExtDirection="Sell";
return(true);
}
//--- check Morning Doji
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Open(1)>Close(2)) && // upward price gap on the last candlestick
(Close(1)>Close(2))) // last candlestick close higher than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Doji detected";
ExtDirection="Buy";
return(true);
}
//--- check Morning Star
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Close(1)>MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Star detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=CCI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<-50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI<-50";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>50))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: CCI>50";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| CCI indicator value at the specified bar |
//+------------------------------------------------------------------+
double CCI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,686 @@
//+------------------------------------------------------------------+
//| MorningEvening StarDoji MFI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodMFI =37; // MFI period
input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=130200; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating MFI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Evening Doji
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Open(1)<Close(2)) && // down price gap on the last candlestick
(Close(1)<Close(2))) // last candlestick close lower than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Doji detected";
ExtDirection="Sell";
return(true);
}
//--- check Evening Star
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Close(1)<MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bullish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Star detected";
ExtDirection="Sell";
return(true);
}
//--- check Morning Doji
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Open(1)>Close(2)) && // upward price gap on the last candlestick
(Close(1)>Close(2))) // last candlestick close higher than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Doji detected";
ExtDirection="Buy";
return(true);
}
//--- check Morning Star
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Close(1)>MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Star detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=MFI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: MFI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| MFI indicator value at the specified bar |
//+------------------------------------------------------------------+
double MFI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,686 @@
//+------------------------------------------------------------------+
//| MorningEvening StarDoji RSI.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpPeriodRSI =37; // RSI period
input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=130300; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating CCI indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Evening Doji
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Open(1)<Close(2)) && // down price gap on the last candlestick
(Close(1)<Close(2))) // last candlestick close lower than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Doji detected";
ExtDirection="Sell";
return(true);
}
//--- check Evening Star
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Close(1)<MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bullish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Star detected";
ExtDirection="Sell";
return(true);
}
//--- check Morning Doji
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Open(1)>Close(2)) && // upward price gap on the last candlestick
(Close(1)>Close(2))) // last candlestick close higher than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Doji detected";
ExtDirection="Buy";
return(true);
}
//--- check Morning Star
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Close(1)>MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Star detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=RSI(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<40))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI<40";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>60))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: RSI>60";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30)))
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70)))
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| RSI indicator value at the specified bar |
//+------------------------------------------------------------------+
double RSI(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
@@ -0,0 +1,691 @@
//+------------------------------------------------------------------+
//| MorningEvening StarDoji Stoch.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"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#define SIGNAL_BUY 1 // Buy signal
#define SIGNAL_NOT 0 // no trading signal
#define SIGNAL_SELL -1 // Sell signal
#define CLOSE_LONG 2 // signal to close Long
#define CLOSE_SHORT -2 // signal to close Short
//--- Input parameters
input int InpAverBodyPeriod=12; // period for calculating average candlestick size
input int InpStochK =47; // period %K
input int InpStochD =9; // period %D
input int InpStochSlow =13; // smoothing period %K
input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type
input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type
//--- trade parameters
input uint InpDuration=10; // position holding time in bars
input uint InpSL =200; // Stop Loss in points
input uint InpTP =200; // Take Profit in points
input uint InpSlippage=10; // slippage in points
//--- money management parameters
input double InpLot=0.1; // lot
//--- Expert ID
input long InpMagicNumber=130400; // Magic Number
//--- global variables
int ExtAvgBodyPeriod; // average candlestick calculation period
int ExtSignalOpen =0; // Buy/Sell signal
int ExtSignalClose =0; // signal to close a position
string ExtPatternInfo =""; // current pattern information
string ExtDirection =""; // position opening direction
bool ExtPatternDetected=false; // pattern detected
bool ExtConfirmed =false; // pattern confirmed
bool ExtCloseByTime =true; // requires closing by time
bool ExtCheckPassed =true; // status checking error
//--- indicator handle
int ExtIndicatorHandle=INVALID_HANDLE;
//--- service objects
CTrade ExtTrade;
CSymbolInfo ExtSymbolInfo;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("InpSL=", InpSL);
Print("InpTP=", InpTP);
//--- set parameters for trading operations
ExtTrade.SetDeviationInPoints(InpSlippage); // slippage
ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID
ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level
ExtAvgBodyPeriod=InpAverBodyPeriod;
//--- indicator initialization
ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied);
if(ExtIndicatorHandle==INVALID_HANDLE)
{
Print("Error creating iStochastic indicator");
return(INIT_FAILED);
}
//--- OK
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- release indicator handle
IndicatorRelease(ExtIndicatorHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- save the next bar start time; all checks at bar opening only
static datetime next_bar_open=0;
//--- Phase 1 - check the emergence of a new bar and update the status
if(TimeCurrent()>=next_bar_open)
{
//--- get the current state of environment on the new bar
// namely, set the values of global variables:
// ExtPatternDetected - pattern detection
// ExtConfirmed - pattern confirmation
// ExtSignalOpen - signal to open
// ExtSignalClose - signal to close
// ExtPatternInfo - current pattern information
if(CheckState())
{
//--- set the new bar opening time
next_bar_open=TimeCurrent();
next_bar_open-=next_bar_open%PeriodSeconds(_Period);
next_bar_open+=PeriodSeconds(_Period);
//--- report the emergence of a new bar only once within a bar
if(ExtPatternDetected && ExtConfirmed)
Print(ExtPatternInfo);
}
else
{
//--- error getting the status, retry on the next tick
return;
}
}
//--- Phase 2 - if there is a signal and no position in this direction
if(ExtSignalOpen && !PositionExist(ExtSignalOpen))
{
Print("\r\nSignal to open position ", ExtDirection);
PositionOpen();
if(PositionExist(ExtSignalOpen))
ExtSignalOpen=SIGNAL_NOT;
}
//--- Phase 3 - close if there is a signal to close
if(ExtSignalClose && PositionExist(ExtSignalClose))
{
Print("\r\nSignal to close position ", ExtDirection);
CloseBySignal(ExtSignalClose);
if(!PositionExist(ExtSignalClose))
ExtSignalClose=SIGNAL_NOT;
}
//--- Phase 4 - close upon expiration
if(ExtCloseByTime && PositionExpiredByTimeExist())
{
CloseByTime();
ExtCloseByTime=PositionExpiredByTimeExist();
}
}
//+------------------------------------------------------------------+
//| Get the current environment and check for a pattern |
//+------------------------------------------------------------------+
bool CheckState()
{
//--- check if there is a pattern
if(!CheckPattern())
{
Print("Error, failed to check pattern");
return(false);
}
//--- check for confirmation
if(!CheckConfirmation())
{
Print("Error, failed to check pattern confirmation");
return(false);
}
//--- if there is no confirmation, cancel the signal
if(!ExtConfirmed)
ExtSignalOpen=SIGNAL_NOT;
//--- check if there is a signal to close a position
if(!CheckCloseSignal())
{
Print("Error, failed to check the closing signal");
return(false);
}
//--- if positions are to be closed after certain holding time in bars
if(InpDuration)
ExtCloseByTime=true; // set flag to close upon expiration
//--- all checks done
return(true);
}
//+------------------------------------------------------------------+
//| Open a position in the direction of the signal |
//+------------------------------------------------------------------+
bool PositionOpen()
{
ExtSymbolInfo.Refresh();
ExtSymbolInfo.RefreshRates();
double price=0;
//--- Stop Loss and Take Profit are not set by default
double stoploss=0.0;
double takeprofit=0.0;
int digits=ExtSymbolInfo.Digits();
double point=ExtSymbolInfo.Point();
double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid();
//--- uptrend
if(ExtSignalOpen==SIGNAL_BUY)
{
price=NormalizeDouble(ExtSymbolInfo.Ask(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price-spread, digits);
}
else
stoploss = NormalizeDouble(price-InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price+spread, digits);
}
else
takeprofit = NormalizeDouble(price+InpTP*point, digits);
}
if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d",
Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError());
return(false);
}
}
//--- downtrend
if(ExtSignalOpen==SIGNAL_SELL)
{
price=NormalizeDouble(ExtSymbolInfo.Bid(), digits);
//--- if Stop Loss is set
if(InpSL>0)
{
if(spread>=InpSL*point)
{
PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point);
stoploss = NormalizeDouble(price+spread, digits);
}
else
stoploss = NormalizeDouble(price+InpSL*point, digits);
}
//--- if Take Profit is set
if(InpTP>0)
{
if(spread>=InpTP*point)
{
PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point);
takeprofit = NormalizeDouble(price-spread, digits);
}
else
takeprofit = NormalizeDouble(price-InpTP*point, digits);
}
if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit))
{
PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d",
Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError());
ExtTrade.PrintResult();
Print(" ");
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Close a position based on the specified signal |
//+------------------------------------------------------------------+
void CloseBySignal(int type_close)
{
//--- if there is no signal to close, return successful completion
if(type_close==SIGNAL_NOT)
return;
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalClose)==0)
return;
//--- closing direction
long type;
switch(type_close)
{
case CLOSE_SHORT:
type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
type=POSITION_TYPE_BUY;
break;
default:
Print("Error! Signal to close not detected");
return;
}
//--- check all positions and close ours based on the signal
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
if(PositionGetInteger(POSITION_TYPE)==type)
{
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close positions upon holding time expiration in bars |
//+------------------------------------------------------------------+
void CloseByTime()
{
//--- if there are no positions opened by our EA
if(PositionExist(ExtSignalOpen)==0)
return;
//--- check all positions and close ours based on the holding time in bars
int positions=PositionsTotal();
for(int i=positions-1; i>=0; i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket!=0)
{
//--- get the name of the symbol and the position id (magic)
string symbol=PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
if(BarsHold(open_time)>=(int)InpDuration)
{
Print("\r\nTime to close position #", ticket);
ExtTrade.PositionClose(ticket, InpSlippage);
ExtTrade.PrintResult();
Print(" ");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions |
//+------------------------------------------------------------------+
bool PositionExist(int signal_direction)
{
bool check_type=(signal_direction!=SIGNAL_NOT);
//--- what positions to search
ENUM_POSITION_TYPE search_type=WRONG_VALUE;
if(check_type)
switch(signal_direction)
{
case SIGNAL_BUY:
search_type=POSITION_TYPE_BUY;
break;
case SIGNAL_SELL:
search_type=POSITION_TYPE_SELL;
break;
case CLOSE_LONG:
search_type=POSITION_TYPE_BUY;
break;
case CLOSE_SHORT:
search_type=POSITION_TYPE_SELL;
break;
default:
//--- entry direction is not specified; nothing to search
return(false);
}
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- if the position type does not match, move on to the next one
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(check_type && (type!=search_type))
continue;
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- yes, this is the right position, stop the search
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Returns true if there are open positions with expired time |
//+------------------------------------------------------------------+
bool PositionExpiredByTimeExist()
{
//--- go through the list of all positions
int positions=PositionsTotal();
for(int i=0; i<positions; i++)
{
if(PositionGetTicket(i)!=0)
{
//--- get the name of the symbol and the expert id (magic number)
string symbol =PositionGetString(POSITION_SYMBOL);
long magic =PositionGetInteger(POSITION_MAGIC);
//--- if they correspond to our values
if(symbol==Symbol() && magic==InpMagicNumber)
{
//--- position opening time
datetime open_time=(datetime)PositionGetInteger(POSITION_TIME);
//--- check position holding time in bars
int check=BarsHold(open_time);
//--- id the value is -1, the check completed with an error
if(check==-1 || (BarsHold(open_time)>=(int)InpDuration))
return(true);
}
}
}
//--- open position not found
return(false);
}
//+------------------------------------------------------------------+
//| Checks position closing time in bars |
//+------------------------------------------------------------------+
int BarsHold(datetime open_time)
{
//--- first run a basic simple check
if(TimeCurrent()-open_time<PeriodSeconds(_Period))
{
//--- opening time is inside the current bar
return(0);
}
//---
MqlRates bars[];
if(CopyRates(_Symbol, _Period, open_time, TimeCurrent(), bars)==-1)
{
Print("Error. CopyRates() failed, error = ", GetLastError());
return(-1);
}
//--- check position holding time in bars
return(ArraySize(bars));
}
//+------------------------------------------------------------------+
//| Returns the open price of the specified bar |
//+------------------------------------------------------------------+
double Open(int index)
{
double val=iOpen(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the close price of the specified bar |
//+------------------------------------------------------------------+
double Close(int index)
{
double val=iClose(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the low price of the specified bar |
//+------------------------------------------------------------------+
double Low(int index)
{
double val=iLow(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the high price of the specified bar |
//+------------------------------------------------------------------+
double High(int index)
{
double val=iHigh(_Symbol, _Period, index);
//--- if the current check state was successful and an error was received
if(ExtCheckPassed && val==0)
ExtCheckPassed=false; // switch the status to failed
return(val);
}
//+------------------------------------------------------------------+
//| Returns the middle body price for the specified bar |
//+------------------------------------------------------------------+
double MidPoint(int index)
{
return(High(index)+Low(index))/2.;
}
//+------------------------------------------------------------------+
//| Returns the middle price of the range for the specified bar |
//+------------------------------------------------------------------+
double MidOpenClose(int index)
{
return((Open(index)+Close(index))/2.);
}
//+------------------------------------------------------------------+
//| Returns the average candlestick body size for the specified bar |
//+------------------------------------------------------------------+
double AvgBody(int index)
{
double sum=0;
for(int i=index; i<index+ExtAvgBodyPeriod; i++)
{
sum+=MathAbs(Open(i)-Close(i));
}
return(sum/ExtAvgBodyPeriod);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful pattern check |
//+------------------------------------------------------------------+
bool CheckPattern()
{
ExtPatternDetected=false;
//--- check if there is a pattern
ExtSignalOpen=SIGNAL_NOT;
ExtPatternInfo="\r\nPattern not detected";
ExtDirection="";
//--- check Evening Doji
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Open(1)<Close(2)) && // down price gap on the last candlestick
(Close(1)<Close(2))) // last candlestick close lower than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Doji detected";
ExtDirection="Sell";
return(true);
}
//--- check Evening Star
if((Close(3)-Open(3)>AvgBody(1)) && // bullish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)>Close(3)) && // second candlestick close is higher than first candlestick close
(Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open
(Close(1)<MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bullish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_SELL;
ExtPatternInfo="\r\nEvening Star detected";
ExtDirection="Sell";
return(true);
}
//--- check Morning Doji
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.1) && // second candlestick body is doji (less than one tenth of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Open(1)>Close(2)) && // upward price gap on the last candlestick
(Close(1)>Close(2))) // last candlestick close higher than second candlestick close
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Doji detected";
ExtDirection="Buy";
return(true);
}
//--- check Morning Star
if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average
(MathAbs(Close(2)-Open(2))<AvgBody(1)*0.5) && // second candlestick body is short (less than a half of the average candle body)
(Close(2)<Close(3)) && // second candlestick close is lower than first candlestick close
(Open(2)<Open(3)) && // second candlestick open is lower than first candlestick open
(Close(1)>MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one
{
ExtPatternDetected=true;
ExtSignalOpen=SIGNAL_BUY;
ExtPatternInfo="\r\nMorning Star detected";
ExtDirection="Buy";
return(true);
}
//--- result of checking
return(ExtCheckPassed);
}
//+------------------------------------------------------------------+
//| Returns true in case of successful confirmation check |
//+------------------------------------------------------------------+
bool CheckConfirmation()
{
ExtConfirmed=false;
//--- if there is no pattern, do not search for confirmation
if(!ExtPatternDetected)
return(true);
//--- get the value of the stochastic indicator to confirm the signal
double signal=StochSignal(1);
if(signal==EMPTY_VALUE)
{
//--- failed to get indicator value, check failed
return(false);
}
//--- check the Buy signal
if(ExtSignalOpen==SIGNAL_BUY && (signal<30))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal<30";
}
//--- check the Sell signal
if(ExtSignalOpen==SIGNAL_SELL && (signal>70))
{
ExtConfirmed=true;
ExtPatternInfo+="\r\n Confirmed: StochSignal>70";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Check if there is a signal to close |
//+------------------------------------------------------------------+
bool CheckCloseSignal()
{
ExtSignalClose=false;
//--- if there is a signal to enter the market, do not check the signal to close
if(ExtSignalOpen!=SIGNAL_NOT)
return(true);
//--- check if there is a signal to close a long position
if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards
((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards
{
//--- there is a signal to close a long position
ExtSignalClose=CLOSE_LONG;
ExtDirection="Long";
}
//--- check if there is a signal to close a short position
if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards
((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards
{
//--- there is a signal to close a short position
ExtSignalClose=CLOSE_SHORT;
ExtDirection="Short";
}
//--- successful completion of the check
return(true);
}
//+------------------------------------------------------------------+
//| Stochastic indicator value at the specified bar |
//+------------------------------------------------------------------+
double StochSignal(int index)
{
double indicator_values[];
if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0)
{
//--- if the copying fails, report the error code
PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError());
return(EMPTY_VALUE);
}
return(indicator_values[0]);
}
//+------------------------------------------------------------------+
File diff suppressed because it is too large Load Diff
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More