Analytics
Strategy Insights & Signal Attribution
Last updated April 20, 2026
After every backtest, Norena automatically computes eight analytics modules that go beyond simple PnL — measuring why the strategy performed the way it did. This includes which conditions actually drove signals, how often each condition was true, which ones could be removed without hurting performance, and a complete autopsy of how the strategy navigated different market regimes.
Overview
The analytics system is built on two core data structures that the backtest engine accumulates during simulation:
| Data structure | Contents | Used by |
|---|---|---|
EvalLog[] | One entry per bar where a trade signal was evaluated. Contains the full ConditionRow[] array at trigger time — label, value, rule, result for every condition evaluated before the trade call. | Trigger Stats, Signal Attribution, Condition Truth Rate, Condition Removal Impact, Strategy Autopsy |
SignalEvent[] | One entry per trade placed. Contains entry/exit prices, bars held, MFE (max favorable excursion), MAE (max adverse excursion), and regime state at signal time. | Strategy Behavior, Signal Quality, Trade Distribution, Regime Analysis, Strategy DNA |
All analytics modules are computed in the browser after the simulation loop completes. There is no server round-trip — the entire analytics pipeline runs client-side from the collected EvalLogs and SignalEvents.
Condition Evaluation Logs
Every time a trade signal fires, the engine records the exact state of every condition that was evaluated during that tick, in order. This produces a ConditionRowfor each evaluation:
| Field | Example | Description |
|---|---|---|
label | "RSI(14)" | Human-readable name of the condition |
value | "28.4" | Runtime value of the indicator or expression at trigger time |
rule | "RSI(14) < 30" | The full comparison rule string |
result | true | Whether the condition evaluated to true or false |
type | "leaf" | "group" | "ctx" | Whether this is an atomic condition, a compound AND/OR group, or a context-only display row |
These rows are what appear in the Trade Detail Modal when you click a trade in the Positions tab. They also form the input to all condition-level analytics.
In live mode, the same condition rows are written to the TRADE_TRIGGER log entry, stored in detail_json.conditions. The Trade Detail Modal reads directly from this log.
Trigger Statistics
The Trigger Stats module answers: when did signals fire, and how often? It computes:
- Total signals: number of buy + sell signals across the simulation
- Signal frequency: average bars between signals
- Signals by hour of day: a heatmap of when signals tend to concentrate
- Signals by day of week: which days generated the most activity
- Signals by market regime: how many fired in trending vs. ranging conditions
This is useful for identifying strategies that are over-trading (too many signals), strategies that are concentrated in specific time windows, and potential data-snooping if signals cluster suspiciously in one period.
Signal Attribution
Signal Attribution answers: which conditions actually caused this signal to fire?It processes the ConditionRow[] arrays from all EvalLogs and builds a table of every unique condition label that appears in the dataset, along with:
- How many times the condition appeared in a signal's evaluation log
- How many times the condition was true when a signal fired
- The condition's truth rate at signal time (see below)
- The percentage of all signals this condition was present in
This makes it possible to see, for example, that RSI < 30 was present in 87% of buy signals but was only true 34% of the time when evaluated — meaning it was a genuine filter, not just always true noise.
Condition Truth Rate
The truth rate of a condition is the fraction of times it evaluated totrue across all its appearances in the condition log:
truth_rate = appearances_where_result_is_true / total_appearances
Truth rate tells you how selective a condition is. Interpreting it:
| Truth rate | Interpretation |
|---|---|
| ~50% | Condition is roughly random — may not be adding signal value |
| Very low (5–15%) | Condition is highly selective — it only allows through rare market states |
| Very high (85–100%) | Condition is almost always true — likely not filtering anything meaningful |
| 0% | Condition never fires. Branch body is dead code. Remove it. |
| 100% | Condition is always true. It is not filtering signals at all. Remove it. |
A useful condition typically has a truth rate between 10% and 50% — selective enough to filter noise but not so rare that it almost never contributes.
Contributor Percentages
The contributor percentage for a condition answers: what fraction of all executed trades had this condition present in the trigger evaluation?
contributor_pct = trades_where_condition_appeared / total_trades × 100
A condition with a 100% contributor percentage was evaluated in every single trade. A condition with a 40% contributor percentage was only evaluated in less than half of trades — likely because it lives inside an else-branch or an AND group that short-circuits.
Combined with truth rate, contributor percentage helps identify which conditions are actually driving your strategy's behavior vs. which are passive passengers in the logic.
Condition Removal Impact
The Condition Removal Impact module asks a counterfactual question for each condition: if this condition were always true (removed from the filter), how would the strategy's total return change?
For each condition, the module re-simulates the trade sequence with that condition removed (i.e., treated as always true), computes the resulting total return, and reports the delta versus the actual return. A condition is useful if removing it makes performance worse — i.e., it is filtering out bad trades.
| Impact result | Interpretation |
|---|---|
| Removing condition worsens return | The condition is doing useful work — it is filtering out losing trades. |
| Removing condition improves return | The condition may be filtering out winning trades. Consider loosening or removing it. |
| Removing condition has no effect | The condition is redundant — it either always true, never fires, or is overridden by another condition in the AND group. |
Strategy Autopsy
Strategy Autopsy is the most comprehensive module. It performs a post-mortem on the entire simulation, identifying:
- Best and worst trades: the top and bottom trades by PnL percentage
- Best and worst periods: rolling windows with the highest and lowest strategy performance
- Win streak and loss streak: longest consecutive winning and losing sequences
- Exit analysis: breakdown of how positions were closed (TP hit, SL hit, time exit, manual)
- Condition correlation with outcomes: which conditions appeared disproportionately in winning vs. losing trades
- Drawdown anatomy: the maximum drawdown period — when it started, when it recovered, and what was happening to conditions during it
The autopsy is displayed as a scrollable report at the bottom of the backtest analytics panel. It is recomputed after every backtest run.
Signal Quality — MFE / MAE
MFE (Maximum Favorable Excursion) is the highest unrealized profit that occurred during a trade — i.e., how far into profit the position went before it closed.MAE (Maximum Adverse Excursion) is the worst unrealized loss during a trade — i.e., how deep the position went negative before closing.
The Signal Quality module classifies each trade as:
| Classification | Criteria | What it means |
|---|---|---|
| Good signal WIN | MFE significantly exceeded final PnL | The trade was in profit and was exited well — take profit was effective |
| Bad signal LOSS | MAE was large relative to final PnL | The trade went deeply negative — stop loss may be too wide or missing |
| Neutral signal NEUTRAL | MFE and MAE were both small | The trade didn't move much in either direction — low conviction signal |
A healthy signal quality distribution shows more "Good" signals than "Bad" ones. A high proportion of "Bad" signals suggests the strategy's entries are correct but exits are letting losses run too far.
Regime Analysis
The Regime Analysis module tags each trade with the market regime that was active at entry time, then breaks down win rate and average return by regime. Market regime is determined by two indicators computed independently of strategy code:
| Indicator | Classification |
|---|---|
| EMA50 vs EMA200 | Price above EMA200 = bullish trend; below = bearish trend; EMA50/200 close together = ranging |
| ATR percentile | Current ATR vs. its own moving average: above threshold = high volatility regime; below = low volatility regime |
This produces a grid of results: how did the strategy perform in uptrend + high volatility? In downtrend + low volatility? In ranging + high volatility? These breakdowns reveal whether the strategy has a structural edge in specific market conditions or relies on a single regime that may not persist.
Strategy DNA
Strategy DNA is a compact visual fingerprint of the strategy's behavior across the entire backtest. It encodes:
- Trade frequency over time (how active the strategy was in each period)
- Win/loss coloring by time period
- Drawdown depth over time
- Condition engagement rate (how often conditions were actually evaluated vs. short-circuited)
The DNA visualization makes it immediately obvious when a strategy's performance is concentrated in one short window (a potential data overfitting signal) vs. distributed evenly over time (a more robust strategy).
How to Use These Insights
The analytics system is designed to help you ask better questions, not to automatically optimize strategies. Here is a practical workflow:
- Start with Strategy Behavior — look at total return, win rate, drawdown, and Sharpe ratio to get a baseline view.
- Check Signal Quality — if you have many "Bad" signals, your exits may be the problem rather than your entries. Consider tightening the stop loss.
- Review Condition Truth Rates — conditions with 90%+ truth rate are not filtering. Conditions with 0% truth rate are dead code. Both should be removed or reconsidered.
- Use Condition Removal Impact — find conditions that have negligible or negative impact, and consider simplifying the strategy by removing them.
- Check Regime Analysis — if the strategy only performs in one regime (e.g. bull market), consider whether that regime is likely to persist.
- Review Strategy DNA — if most profits came from one narrow window, be skeptical of the overall performance number.
- Run Autopsy on losing periods — look at what conditions were doing during the worst drawdown period. This often reveals structural weaknesses.