{% load humanize %}{% if error %} {% else %}{% with r=results %}

{{ r.headline }}

{% if r.trend_note %}

{{ r.trend_note }}

{% endif %}

{{ r.horizon }}-trading-day forecasts made on each of {{ r.origins }} trading days, to . Prices to the close of .

Over this period the price moved {{ r.period_change }}. It was higher {{ r.horizon }} day{{ r.horizon|pluralize }} later after {{ r.up_origins }} of the {{ r.origins }} forecasts.

Hansen's SPA test of whether any model beats naive: p = {{ r.spa_p_value }}.

Leaderboard

{% for row in r.rows %} {% endfor %}
Model Mean error vs naive CRPS vs naive Interval score vs naive Days won Direction right In {{ r.level }}% interval p-value
{{ row.name }} {{ row.family }}{% if row.best and r.rivals > 1 %} ยท best model{% endif %} {{ row.mae }} {{ row.change.text }} {{ row.crps.text }} {{ row.interval.text }} {{ row.win_rate }}{% if row.ties %}{{ row.ties }}{% endif %} {{ row.direction }} {{ row.coverage }} {{ row.p_value }}{% if row.significant %}*{% endif %}
Mean error
Average gap between forecast and actual close at the horizon, measured on log prices, so it reads as a percentage at any price level.
vs naive
Mean error relative to the naive forecast. Negative is better.
CRPS vs naive
Scores the whole forecast distribution, not just its centre. Relative to naive; negative is better.
Interval score vs naive
Rewards a narrow {{ r.level }}% interval and charges heavily for a close outside it. Relative to naive; negative is better.
Days won
Share of the {{ r.origins }} forecasts where the model was closer than naive. Days it forecast exactly what naive did are ties, counted below the share.
Direction right
How often the forecast moved the same way as the price did. Always predicting a rise would have scored {{ r.always_up }}.
In {{ r.level }}% interval
How often the actual close landed inside the model's {{ r.level }}% interval. Close to {{ r.level }}% is well calibrated.
p-value
Diebold-Mariano test against naive, allowing for overlapping forecasts and adjusted for testing {{ r.rivals|apnumber }} model{{ r.rivals|pluralize }} (Holm). An asterisk marks p below {{ r.significance }}.

Up and down markets

Error relative to naive, split by whether the close was above or below its {{ r.trend_days }}-day average on the day of the forecast. An edge that only shows up on one side may just be a bet on the trend.

{% for row in r.trend.rows %} {% for cell in row.cells %}{% endfor %} {% endfor %}
Model Uptrend
{{ r.trend.days.0 }} days
Downtrend
{{ r.trend.days.1 }} days
{{ row.name }}{{ cell.text }}

Forecasts

{% if r.rivals > 1 %}
Compare with naive
{% for row in r.rows %}{% if row.key != 'naive' %} {% endif %}{% endfor %}
{% endif %} {% if r.chart.future.dates %}

The next {{ r.horizon }} trading day{{ r.horizon|pluralize }}

Recent closes, then each model's forecast from the latest close. The band is the selected model's {{ r.level }}% interval. {% if not r.calendar_known %}This exchange's holiday calendar isn't known, so future dates skip weekends only.{% endif %}

Show the data
{% endif %}

Running total against naive

Each day adds how much closer the model's {{ r.horizon }}-day forecast was than naive's, in percentage points of error. The line rises while the model is winning and falls while it is losing, so a steady climb is a lasting edge and a jump is one lucky stretch.

Show the data
{{ r.chart|json_script:"chart-data" }} {% endwith %}{% endif %}