Back to articles
DocumentationSource: backend/agents/notes/score_and_trade_diagnostics_20260428.md

AUTHOR: Tony Mudau

Score Always 0 - Full Diagnostic (2026-04-28)

What is happening in your current cycle

Your cycle is not failing because "market is not moving". It is failing because the technical direction gate is failing first.

For each symbol in the cycle:

  • status=filtered
  • rejection_reason=no_direction (or prefilter spread reject for some symbols/cycles)
  • technical_response.direction=null
  • technical_response.confidence=0.0
  • proposal_candidate=null
  • combined_score=0.0

That means no valid directional setup survived the quality gate, so score stays zero by design.

The score pipeline (in order)

The pipeline is sequential. If a symbol fails early, later score stages do not matter.

  1. Fast prefilter

    • Checks instant spread and market "aliveness"
    • Can reject with:
      • spread_too_wide_prefilter
      • dead_market_prefilter
  2. Precheck build (precheck.score in [0..1])
    Inputs:

    • spread_ratio
    • volatility_20 (20-bar avg range / price)
    • liquidity_20 (20-bar avg tick volume)
    • liquidity_reliability (how trustworthy tick-volume is)
    • symbol/session market baseline (vol_mean, vol_std, liq_mean, liq_std, p20/p80 bands)
    • reject telemetry (symbol_session_reject_rate, session_reject_rate)
  3. Hard quality gate
    Can reject with:

    • no_direction <- your current main reason
    • low_confidence (effective confidence below gate after adjustments)
    • mean_reversion_blocked
    • low_volatility_compression
    • invalid_sl_tp_from_technical
    • expected_value_negative
    • proposal validator rejection (from validate_entry_proposal)
    • news_conflicts_with_technical (if strong opposing macro bias)
  4. Proposal creation (only if quality passes)
    Proposal requires:

    • direction in {buy, sell}
    • valid entry/stop_loss/take_profit
    • EV gate pass
    • confidence floor pass after MTF/reversal/EV blending
    • MTF is now soft-penalized rather than hard-rejected:
      • mtf_alignment_penalty = max(0, 0.6 - mtf_alignment_score)
      • confidence_adjusted = confidence_raw - mtf_alignment_penalty * 0.3
  5. Combined score (combined_score in [0..1])
    If proposal exists, score is:

    • 0.36 * technical_confidence (or effective confidence)
    • 0.17 * blend_conf (market/macro confidence blend)
    • 0.13 * precheck_score
    • 0.18 * mtf_alignment_score
    • 0.16 * ev_component (from win-rate + RR)
    • + news_filter (small bonus/penalty if confident macro aligns/conflicts)
  6. Hard score floor

    • Dynamic floor from _adaptive_combined_score_floor
    • Typical bounded range: 0.52 .. 0.68
    • Reject reason: low_score if combined_score < floor

Why your score is specifically 0 now

In the quoted cycle, technical engine outputs signal_state=no_qualifying_setup and direction=null for all symbols.

When that happens:

  • quality gate sets rejection_reason=no_direction
  • symbol exits before proposal/scoring path
  • proposal_candidate remains null
  • combined_score remains default 0.0

This is consistent with your logs where indicators are present, but rule conditions for a BUY/SELL setup are not simultaneously satisfied.

All score inputs (complete list)

A) Prefilter inputs

  • tick:
    • bid, ask, spread
    • spread_ratio_fast = spread / ask_or_bid
  • quick bars:
    • M15 quick OHLC (n=30)
    • H1 quick OHLC (n=40)
  • adaptive limits:
    • spread_cap
    • spread_hard_reject
    • alive_floor
    • alive_hard_reject
  • telemetry adaptation:
    • symbol_session_reject_rate
    • symbol_session_samples
    • session_reject_rate
    • session_samples

B) Precheck score inputs

  • spread_ratio
  • volatility_20
  • liquidity_20
  • liquidity_reliability
  • market baseline stats:
    • vol_mean, vol_std, vol_p20, vol_p80
    • liq_mean, liq_std, liq_p20, liq_p80
  • derived:
    • vol_z, liq_z
    • band and z-score adjustments

C) Technical quality inputs

  • from technical signal:
    • direction
    • confidence
    • strategy_mode
    • volatility_regime.regime
    • entry, stop_loss, take_profit
    • pattern_win_rate
    • signal_state
  • MTF and reversal:
    • MTF alignment score/hint
    • late reversal guard output
  • EV/risk:
    • risk_reward_ratio
    • ev_gate_allows_entry(...)
    • symbol profile thresholds (ev_min_per_r, entry_min_rr, entry_max_deviation_pct)

D) Market/news inputs used in combined score

  • market_confidence
  • macro_confidence
  • news_bias
  • news_confidence
  • (only as filter/modifier, not standalone entry trigger)

E) Final score floor inputs

  • session_label (off_hours, asia, etc.)
  • precheck_score
  • technical_signal.strategy_mode
  • technical_signal.volatility_regime.regime
  • symbol profile (ev_min_per_r)
  • telemetry reject rates/samples (symbol + session)

Conditions required to place a trade (full checklist)

A trade is only sent when all of these are true:

  1. Symbol passes prefilter (spread and alive checks)
  2. Technical returns direction buy or sell (not null)
  3. Technical confidence >= 0.65 at quality gate
  4. Strategy mode not blocked (mean_reversion blocked here)
  5. Volatility regime not compression
  6. SL/TP valid and entry proposal validation passes
  7. EV gate passes (win_rate + RR + profile threshold)
  8. Macro conflict hard filter does not reject (when high-confidence opposing news)
  9. Combined score >= adaptive floor
  10. LLM adjustment + portfolio filter + risk shaping keep proposal alive
  11. Final execution confidence guard: proposal confidence >= 0.65
  12. Adaptation gates pass:
    • symbol not paused
    • pattern not in cooldown
    • session confidence floor met
  13. Duplicate-position guard passes
  14. Execution guard passes at send time:
    • no stale bars
    • no excessive slippage vs entry
    • no excessive spread
    • no volatility spike
    • optional technical-agreement guard
  15. MT5 order retcode success (10009) for actual open/pending placement

If any condition fails, you get proposal=None, skipped execution, or a rejected symbol.

What to log each cycle for fast root-cause diagnosis

Per symbol:

  • status, rejection_reason, rejection_detail
  • precheck.score, spread_ratio, volatility_20, liquidity_20, liquidity_reliability
  • prefilter_limits.*
  • technical: signal_state, direction, confidence, strategy_mode, volatility_regime
  • pattern_win_rate, computed risk_reward, EV decision
  • mtf_alignment.score/hint, reversal guard result
  • combined_score, combined_score_floor
  • telemetry: reject rates + samples

Per selected symbol / execution:

  • proposal before/after LLM
  • proposal after portfolio + risk agents
  • adaptation gate decision (paused/cooldown/min_confidence)
  • duplicate guard output
  • execution guard output (allowed, reason, detail)
  • execution result (retcode, order, deal, status)

About the "richer cycle with proposal/execution"

I could not find a trade-selected/executed cycle in current local decision history (decisions_20260427.txt and decisions_20260428.txt are no-trade cycles), and local trade_history is empty in this environment.

So for deeper proposal/execution diagnostics, run one cycle that reaches:

  • status=trade_selected
  • non-null proposal
  • non-null execution_result or scheduled_trade

Then re-run this analysis on that cycle payload and the guard/event logs.

Bottom line for your current issue

Directional and MTF logic has since been softened: imperfect MTF alignment now downgrades confidence instead of automatically killing the setup.
Movement alone is still insufficient; the strategy still requires direction + confidence + EV + multi-stage guard pass.