94 lines
4.5 KiB
MQL5
94 lines
4.5 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| WarriorExpert.mqh |
| |||
//| AnimateDread |
| |||
//| |
| |||
//| CExpert WITH A SESSION-AWARE BAR CLOCK. One override, Refresh(). |
| |||
//| |
| |||
//| WHAT THE STDLIB DOES. With EveryTick = false, CExpert::Refresh() |
| |||
//| lets Processing() run only on ticks TimeframesFlags() marks as a |
| |||
//| new bar of the chart period, and for D1 that is the first tick of |
| |||
//| each calendar day - whatever hour it arrives at. The tick is then |
| |||
//| CONSUMED: m_last_tick_time moves to it, and every later tick that |
| |||
//| day compares against it and reads as "same day, no new bar". |
| |||
//| |
| |||
//| WHY THAT FAILS ON A CFD. An index CFD quotes a tick at 00:00 (or |
| |||
//| 01:00 across the DST seam) while its trading session is still |
| |||
//| shut, so the one evaluation the day gets lands on a tick the |
| |||
//| broker will not fill. Measured on SP500 D1 2012-2026: 1,647 of |
| |||
//| 3,887 daily entries declined at the gate - "SP500 has no open |
| |||
//| trading session at 2012.01.04 00:00" - and every exit attempted at |
| |||
//| 01:00 failed with [Market closed] and was retried a day later. |
| |||
//| NAS100 lost 189 the same way. The signal was right; the clock was |
| |||
//| reading it during the maintenance hour. |
| |||
//| |
| |||
//| THE FIX. A new-bar tick that arrives while the session is shut is |
| |||
//| NOT consumed: m_last_tick_time stays where it was, so the next |
| |||
//| tick still compares as a new bar, and the first tick INSIDE a |
| |||
//| session is the one that gets processed. The signals read bar 1 - |
| |||
//| the closed bar - through StartIndex() either way, so what is |
| |||
//| evaluated is identical; only the minute it is acted on moves, |
| |||
//| from the maintenance hour to the open. Every-tick mode is left |
| |||
//| exactly as the stdlib has it. |
| |||
//+------------------------------------------------------------------+
| |||
#ifndef WARRIOR_EXPERT_MQH
| |||
#define WARRIOR_EXPERT_MQH
| |||
| |||
#include <Expert\Expert.mqh>
| |||
#include "..\System\TradeChecks.mqh"
| |||
| |||
class CWarriorExpert : public CExpert
| |||
{
| |||
protected:
| |||
int m_deferred; // new-bar ticks held back because the session was shut
| |||
int m_deferredBars; // ...and how many distinct bars that was
| |||
datetime m_deferredBar; // the bar being held back, so it is counted once
| |||
| |||
public:
| |||
CWarriorExpert(void) : m_deferred(0), m_deferredBars(0), m_deferredBar(0) {}
| |||
~CWarriorExpert(void) {}
| |||
virtual void Deinit(void) override;
| |||
| |||
protected:
| |||
virtual bool Refresh(void) override;
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
bool CWarriorExpert::Refresh(void)
| |||
{
| |||
//--- Every-tick mode: nothing to defer, the stdlib is right as it is.
| |||
if(m_period_flags == WRONG_VALUE || m_period_flags == 0)
| |||
return CExpert::Refresh();
| |||
if(!m_symbol.RefreshRates())
| |||
return false;
| |||
MqlDateTime time;
| |||
TimeToStruct(m_symbol.Time(), time);
| |||
if((m_period_flags & TimeframesFlags(time)) == 0)
| |||
return false; // same bar as the last one processed
| |||
//--- A new bar - but is the market open to act on it? If not, leave m_last_tick_time alone so
| |||
//--- this bar is still "new" on the next tick, and say nothing per tick: the count is reported
| |||
//--- once at deinit, the way the vote reports its gates.
| |||
string why = "";
| |||
if(!TCMarketIsOpen(m_symbol.Name(), m_symbol.Time(), why))
| |||
{
| |||
m_deferred++;
| |||
const datetime bar = iTime(m_symbol.Name(), m_period, 0);
| |||
if(bar != m_deferredBar)
| |||
{
| |||
m_deferredBar = bar;
| |||
m_deferredBars++;
| |||
}
| |||
return false;
| |||
}
| |||
m_last_tick_time = time;
| |||
m_indicators.Refresh();
| |||
return true;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
void CWarriorExpert::Deinit(void)
| |||
{
| |||
if(m_deferredBars > 0)
| |||
PrintFormat("CWarriorExpert: BAR CLOCK - %d bar(s) opened with the session shut and were"
| |||
" processed at the first tick inside a session instead (%d closed ticks skipped).",
| |||
m_deferredBars, m_deferred);
| |||
CExpert::Deinit();
| |||
}
| |||
#endif // WARRIOR_EXPERT_MQH
|