Warrior_EA/Expert/WarriorExpert.mqh
AnimateDread 47a5ef338b Refactor Warrior EA: Integrate custom signal modules, enhance voting mechanism, and improve management features
- 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.
2026-09-13 14:32:40 -04:00

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