- Replaced standard library signal modules with custom implementations to allow for named patterns and improved voting. - Added new input parameters for module weights, allowing for optimization of individual signal contributions. - Enhanced the management of trades with new options for breakeven and management cut. - Introduced a mechanism for dynamic ranking of signal weights based on historical performance. - Improved initialization logic to ensure proper registration of filters and handling of trading conditions. - Added detailed logging for trading permissions and account status during initialization.
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
|