Skip to content

fix(priceforecast): bucket local hours, not UTC - #1166

Merged
frahlg merged 2 commits into
masterfrom
fix/priceforecast-local-hours
Sep 8, 2026
Merged

frahlg merged 2 commits into
masterfrom
fix/priceforecast-local-hours

Conversation

@frahlg

@frahlg frahlg commented Sep 8, 2026

Copy link
Copy Markdown
Member

Accepted text proposal

Issue or Discussion: #1161

Maintainer comment that accepted this scope: issue #1161.

What changed

Price-forecast hour-of-week and month buckets now use the Europe/Stockholm civil clock (CET/CEST) instead of UTC. Fit and Predict share that conversion, so the same instant still maps to the same bucket regardless of the time.Time location.

The baked Nordic prior is a local-hour shape (morning 07–09, evening 17–20). UTC indexing put CEST evening peaks two hours late: 19:00 CEST is 17:00 UTC.

Package comments no longer claim that Predict downweights by MAE/counts; those fields remain diagnostics. go/internal/prices/prices.go is untouched (#1044 and #1051).

Why

Overnight fill after the day-ahead cutoff used the wrong diurnal shape for Nordic sites. A SE3 19:00 CEST peak must land in the evening prior bucket, not the UTC-17 bucket.

Boundaries and safety

Out of scope: harvest/tariff in prices, MPC VAT blend, using MAE/counts as a confidence weight. Missing tzdata cannot silently fall back to UTC — the package embeds time/tzdata.

Verification

  • cd go && go test ./internal/priceforecast -count=1 -timeout 60s
  • New regression: SE3 19:00 CEST is Wednesday hour 19 (not UTC 17) and Predict(19:00 CEST) exceeds Predict(21:00 CEST).

Checklist

  • The diff implements one accepted scope and does not add follow-on work.
  • I checked open pull requests that touch the same files.
  • Tests cover the changed behaviour and its failure path.
  • A human reviewed every changed web/UI view in a browser, or no UI changed.
  • A Changeset is included, or the change is exempt.
  • Every commit has a DCO sign-off.

Closes #1161


Note

Medium Risk
Changes how forecasted spot prices are shaped for MPC horizons beyond day-ahead; wrong timing directly affected Nordic arbitrage planning, but the change corrects intentional local-hour semantics rather than introducing new behavior.

Overview
Fixes #1161 by indexing price-forecast hour-of-week and month buckets on the Europe/Stockholm civil clock instead of UTC, so fit and predict both align with the baked Nordic prior (evening 17–20 local). Under UTC, a 19:00 CEST peak was bucketed like 17:00, shifting evening shape 1–2 hours late for overnight MPC fill before day-ahead prices land.

The package embeds time/tzdata so stripped hosts and tests do not silently fall back to UTC. Package docs now describe Counts/MAE as refit diagnostics rather than MPC confidence weights. Tests use Stockholm local times and add a regression that 19:00 CEST maps to the Wednesday 19 bucket and beats 21:00 local.

Reviewed by Cursor Bugbot for commit 344ea12. Bugbot is set up for automated code reviews on this repo. Configure here.

Hour-of-week and month indexing used t.UTC(), so the baked Nordic
evening peak (17–20 local) landed 1–2 hours late in CET/CEST. Fit and
Predict now share the Europe/Stockholm civil clock.

Closes #1161

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_1657673c-828a-4950-a363-089ce904e52f)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-08T09:29:02.064539Z fcd1804 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcd1804fc8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// The baked prior is a Nordic local-hour shape; UTC indexing put CEST
// evening peaks two hours late (19:00 CEST = 17:00 UTC). Stockholm is
// CET/CEST, matching SE1–SE4 / DK / NO / DE.
var bucketTZ = mustLoadTZ("Europe/Stockholm")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Select the bucket timezone from the configured zone

When cfg.Price.Zone is outside CET/CEST, this global Stockholm clock misaligns the baked prior with that market's civil hours. For example, a fresh or sparsely trained PT model treats 16:00 Portuguese winter time as Stockholm 17:00 and therefore starts the evening peak an hour early; Finland and the Baltic zones are shifted in the opposite direction. These are supported price zones, main.go passes the configured zone directly to NewService, and the forecast is wired into the MPC, so the bucket location should be derived from ZoneModel.Zone rather than fixed to Stockholm.

Useful? React with 👍 / 👎.

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f6be74be-31c0-4f15-8b90-2dbbdcdbd940)

@frahlg
frahlg merged commit 9d7bb6a into master Sep 8, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(priceforecast): bucket local hours, not UTC

1 participant