12 KiB
Execution Pipeline — DualEA System
Complete trade execution flow from signal to position
Pipeline Overview
OnTick/OnTimer
↓
[1. Early Safety & Filters] ← circuit breaker, memory guard, news filter (PaperEA); risk/spread/session/news/etc (LiveEA)
↓ PASS
[2. Strategy Selection] ← selector scoring (PaperEA) or external orchestration (LiveEA)
↓ SELECTED
[3. Signal Generation] ← PaperEA: indicator signal generator registry; LiveEA: strategy bridge is available but not called from OnTick
↓ SIGNAL
[4. 8-Stage Gates] ← GateManager (PaperEA) / LiveEA early + risk4 gates
↓ PASS
[5. Policy & Insights Gating] ← LiveEA: per-slice policy + insights gating + exploration; PaperEA: minimal policy load + min_conf gate
↓ PASS
[6. Trade Execution] ← TradeManager.ExecuteOrder() (both EAs)
↓ SUCCESS
[7. Post-Execution] ← KB logging, features export, telemetry, learning
Stage 1: Signal Generation
Entry Points:
OnTick(): Real-time tick processingOnTimer(): Used today for maintenance and reload polling (PaperEA); LiveEA uses a timer for insights auto-reload polling
PaperEA_v2 Signal Generation (actual):
- Strategy selection chooses from a 23-strategy list (e.g.,
ADXStrategy,RSIStrategy,MACDStrategy,IchimokuStrategy, etc.). - Signal generation is executed through
Include/StrategySignalGenerators.mqhviaGenerateSignalFromStrategy(). - Output is a
TradingSignal(fromInclude/GateManager.mqh) withprice,sl,tp,volume, andconfidenceseeded.
LiveEA Signal Generation (actual):
LiveEA.mq5provides the gating and execution pipeline but does not call the strategy bridge fromOnTick().- Strategy generation exists as
LiveEA_StrategyBridge.mqh(21 defaultIStrategyimplementations) and can be used by an external orchestrator or future wiring.
Signal Structure:
strategy_name,direction(1=Buy, -1=Sell)confidence(0.0-1.0),entry_price,stop_loss,take_profit,lot_sizereason(human-readable),timestamp- Strategy-specific indicator values
Stage 2: Early Phase Validation
Quick rejection before expensive gate processing.
Checks:
- Circuit breakers / risk limits
- News blackout (Common Files CSV
DualEA\news_blackouts.csv) - Session/trading hours caps (where enabled)
- Spread and margin checks (LiveEA)
NoConstraintsMode:
- PaperEA default is
trueand bypasses many constraints, but circuit breaker + memory guard remain enforced. - LiveEA default is
false; whentrue, many gates become shadow/diagnostic only (it logs but does not block on early gates).
Stage 3: 8-Stage Gate Processing
Progressive filtering through configurable gates.
Important reality check: In Include/GateManager.mqh, several gates are currently implemented as simplified/deterministic checks (for repeatable Strategy Tester runs), not a full production-grade market simulation.
Gate 1: Signal Rinse
- Purpose: Basic validation
- Checks:
confidence ≥ G1_MinConfidence,strength ≥ G1_MinStrength
Gate 2: Market Soap
- Purpose: Market context
- Checks: ATR within
[G2_MinVolatility, G2_MaxVolatility], portfolio correlation ≤G2_MaxCorrelation, regime tradeable
Gate 3: Strategy Scrub
- Purpose: Strategy-specific validation
- Checks: History bars ≥
G3_MinHistoryBars, strategy.ValidateSignal()
Gate 4: Risk Wash
- Purpose: Risk validation
- Checks: Risk/trade ≤
G4_MaxRiskPct, portfolio risk ≤G4_MaxPortfolioRisk, RR ≥G4_MinRiskReward
Gate 5: Performance Wax
- Purpose: Backtest performance
- Checks: Backtest WR ≥
G5_MinBacktestWinRate, trades ≥G5_MinBacktestTrades, R ≥G5_MinBacktestRMultiple
Gate 6: ML Polish
- Purpose: ML confidence
- Checks: ML confidence ≥
G6_MinMLConfidence, ML available ifG6_RequireMLAvailable
Gate 7: Live Clean
- Purpose: Live market conditions
- Checks: Spread, market open, liquidity
Gate 8: Final Verify
- Purpose: Pre-execution validation
- Checks: Broker constraints (min/max lots), duplicate signals
Learning Integration: Each gate decision recorded via LearningBridge for threshold optimization.
Stage 4: Strategy Selection
StrategySelector Scoring (PaperEA)
score = (winRate × W1) + (normRMultiple × W2) + (normSharpe × W3) + (normTrades × W4)
if(SelectorUseRecency) score ×= recencyDecay^daysSinceLastTrade
Weights (actual PaperEA inputs): SelW_PF, SelW_Exp, SelW_WR, SelW_DD with optional recency overlay.
Insights Gating
Load insights.json slice for strategy|symbol|timeframe:
- No slice found: Enter exploration mode if enabled
- Slice exists: Check
winRate ≥ InsightsMinWinRate,totalTrades ≥ InsightsMinTotalTrades,avgR ≥ InsightsMinAvgR
Exploration Mode
Triggered when: No insights slice exists
Caps (current defaults in code):
- Daily:
ExploreMaxPerSlicePerDay(default 100) - Weekly:
ExploreMaxPerSlice(default 100)
Counters: Persist in explore_counts.csv and explore_counts_day.csv
NoConstraintsMode: Bypasses insights gating and exploration caps entirely.
Stage 5: Policy Application
Policy Loading
LiveEA (actual):
- Loads
DualEA\policy.jsonfrom Common Files. - Parses per-slice fields including
p_win, and optional scaling keyssl_scale,tp_scale,trail_scale. - Applies a slice lookup order:
- Exact
strategy+symbol+timeframe - Aggregate
strategy+symbolwithtimeframe=-1 - Aggregate
strategywithsymbol="*"andtimeframe=-1
- Exact
PaperEA_v2 (actual):
- Loads
DualEA\policy.jsonfrom Common Files and treats the policy as “loaded” if it can find the stringmin_confidence. g_policy_min_confdefaults to0.5.- Per-slice parsing/scaling is not currently wired in PaperEA’s
Policy_Load(). - HTTP polling exists (see
PolicyServerUrl,PolicyHttpPollPercent) but still only checks formin_confidence.
Policy Gating Logic
if policy.slices == 0:
if FallbackWhenNoPolicy && (FallbackDemoOnly→demo OR !FallbackDemoOnly):
→ FALLBACK: neutral scaling, bypass insights/exploration
else:
→ BLOCK
if slice missing:
if FallbackWhenSliceMissing && (demo check as above):
→ FALLBACK: neutral scaling
else:
→ BLOCK
if slice.probability < policy.min_confidence:
→ BLOCK
else:
→ PASS: Apply scaling
Policy Scaling
LiveEA (actual):
- Adjusts SL/TP distance from entry using
sl_scale/tp_scale. - Adjusts trailing distance using
trail_scale.
PaperEA_v2 (current):
- Policy gating is applied as a minimum confidence check (and the scaling path is currently neutral/placeholder in
ApplyPolicyGating()).
Stage 6: Risk Management
Position Sizing
Base Sizing:
pipRisk = |entry - SL| / Point / 10
riskAmount = Balance × (G4_MaxRiskPct / 100)
lots = riskAmount / (pipRisk × tickValue)
lots = NormalizeLots(lots) // Broker constraints
Correlation Adjustment (LiveEA with PositionManager):
avgCorr = CorrelationManager.GetAverageCorrelation(symbol)
dampening = 1.0 - (avgCorr × 0.5)
adjustedLots = lots × dampening
adjustedLots = max(adjustedLots, max(lots × PM_CorrMinMult, PM_CorrMinLots))
Circuit Breakers
- Daily Loss: Block if daily PnL <
-MaxDailyLossPct - Drawdown: Block if drawdown from peak >
MaxDrawdownPct - Consecutive Losses: Block after
MaxConsecutiveLosseslosses - Cooldown: After breaker trips, wait
CircuitCooldownSecseconds
Stage 7: Trade Execution
TradeManager.Execute()
PaperEA_v2 (actual): Places real MT5 orders on demo accounts via CTradeManager::ExecuteOrder().
LiveEA (actual): Places real MT5 orders via CTradeManager::ExecuteOrder().
- Market orders: Immediate execution
- Pending orders: BuyStop, SellStop, BuyLimit, SellLimit
- SL/TP normalization to broker tick size
- Volume normalization (min/max/step)
Trailing Stops: Initialized if TrailEnabled=true
- Fixed-points:
TrailActivationPoints,TrailDistancePoints,TrailStepPoints - ATR-based:
TrailATRMultiplier × ATRfor distance
Stage 8: Post-Execution
Knowledge Base Logging
knowledge_base.csv:
timestamp,symbol,type,entry_price,stop_loss,take_profit,close_price,profit,strategy_id
knowledge_base_events.csv:
timestamp,strategy,retcode,deal,order
Features Export
features.csv (long format):
timestamp,symbol,timeframe,strategy,direction,confidence,...,indicator_1,indicator_2,...
- 50+ features per trade
- Automatic ~100MB rotation (rename to
*.bak); no compression is performed in MQL5
Telemetry & Logging
Telemetry Events:
gate_decision: Pass/block with reason, latencytrade_execution: Order placement, retcodepolicy_load,insights_rebuild,threshold_adjustrisk4_*: Risk gate events (spread, margin, drawdown)pm_*: PositionManager events (correlation sizing, scale-ins)p5_*: Selector events (refresh, rescore, tune)
UnifiedTradeLogger: Daily JSON logs with full lifecycle
{
"timestamp": "2025-01-15T10:30:00Z",
"strategy": "ADXStrategy",
"symbol": "EURUSD",
"timeframe": 60,
"direction": 1,
"entry": 1.0850,
"sl": 1.0800,
"tp": 1.0950,
"lots": 0.10,
"gates": ["signal_rinse:pass", "market_soap:pass", ...],
"policy": {"confidence": 0.75, "sl_mult": 1.0, "tp_mult": 1.2},
"outcome": "closed",
"profit": 15.50,
"r_multiple": 1.2
}
Learning System Update
LearningBridge: Records CSignalDecision with:
- All 8 gate decisions (pass/fail, reason, latency)
- Final outcome (executed, blocked, reason)
- Trade result (if executed): profit, R-multiple, duration
GateLearningSystem: Updates gate thresholds
- Hybrid learning: immediate (5% rate) + batch (every 20 trades)
- Target success rate per gate configurable
- Adjusts thresholds to optimize pass rate vs trade quality
Live Trading Flow (LiveEA)
Differences from PaperEA_v2 (as wired today):
- Insights auto-reload loop: LiveEA requests rebuild by creating
DualEA\insights.reloadand waits forDualEA\insights.ready. - Per-slice policy scaling: LiveEA parses per-slice policy entries and applies SL/TP/trailing scaling.
- Risk gates: LiveEA includes spread/session/margin/consecutive-loss gating in the EA itself.
Safety Features:
- Shadow mode possible (log decisions, don't execute)
- Policy fallback with demo-only restriction
- Multiple circuit breakers
- One-execution-per-slice-per-minute de-dup (Phase 6 - planned)
Error Handling
Broker Errors
Retcode Handling:
TRADE_RETCODE_DONE: Success → proceed to post-executionTRADE_RETCODE_REQUOTE: Retry with new price (max 3 attempts)TRADE_RETCODE_REJECT: Log + telemetry, don't retryTRADE_RETCODE_NO_MONEY: Trip circuit breaker, halt trading- Other errors: Log, telemetry, optional cooldown
File I/O Errors
KB Write Failures:
- Retry with exponential backoff (3 attempts)
- Create directory if missing
- Log to Journal on persistent failure
- Continue execution (non-fatal)
Policy/Insights Load Failures:
- Use last-known-good cached version
- Log warning + telemetry event
- Fallback to neutral scaling if allowed
- Reload attempt on next timer cycle
Learning System Failures
- Non-fatal: Log errors, continue trading
- Disable learning if consecutive failures > 5
- Telemetry event for monitoring
Performance Characteristics
Latency Targets
- Signal → Gate entry: <5ms
- 8-stage gates: <50ms total (target <10ms per gate)
- Policy/insights lookup: <2ms (in-memory cache)
- KB write: <10ms (non-blocking preferred)
- Telemetry emit: <1ms
- Total pipeline: <100ms (OnTick → OrderSend)
Memory Footprint
- Strategies (21): ~500KB
- Gate Manager: ~100KB
- Policy cache: ~50KB
- Insights cache: ~200KB
- Telemetry buffer: ~500KB
- Total: ~1.5MB per EA instance
File I/O
- KB writes: Append-only, buffered every 10 trades
- Features export: Buffered every 50 trades
- Telemetry flush: Every 5 minutes or 1000 events
- Policy/insights reload: On timer (every 60 minutes) or .reload trigger
See Also:
- Configuration-Reference.md - All input parameters
- Observability-Guide.md - Telemetry and monitoring
- Policy-Exploration-Guide.md - Policy fallback and exploration details