Skip to content

Fix History tab £0 recovered: work around T212 pagination dropping orders#63

Open
ko5tas wants to merge 1 commit into
mainfrom
fix/history-recovered-zero
Open

Fix History tab £0 recovered: work around T212 pagination dropping orders#63
ko5tas wants to merge 1 commit into
mainfrom
fix/history-recovered-zero

Conversation

@ko5tas

@ko5tas ko5tas commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Per-ticker reconciliation works around a Trading212 API bug where the unfiltered /equity/history/orders endpoint silently drops orders in certain time windows for some accounts. The same orders ARE returned when queried with ?ticker=X. After the unfiltered fetch, t2 now identifies "closed-position candidates" (tickers with BUYs but no SELLs/divs and not in current open positions) and fetches each per-ticker to fill the gap.
  • Cache durability fixes for systemd installations: cacheDir() now honors \$CACHE_DIRECTORY (set by systemd CacheDirectory=t2) first, and skips \$HOME=/nonexistent (the placeholder for system users) so the cache lands somewhere actually writable. Without this, t2 silently writes orders.json to the working directory (/), every restart re-fetches ~1,100 orders from T212, and ~4 minutes of warmup is required before any history is visible.
  • Optional backup_dir config field mirrors the cache to a second location after each successful save. Pointed at a Dropbox/OneDrive/rclone-synced folder, this keeps an off-machine archive of trading history (T212 may eventually purge old records, and the pagination bug above can drop them sooner). On startup, if the primary cache is missing but the backup exists, t2 rehydrates from it.
  • Footer surface: Last updated now also shows orders/dividends cache freshness timestamps and a backup ✓ indicator when backup_dir is set, so cache state is visible without reading logs.
  • Gap detection log: warns when consecutive orders in the unfiltered stream are >30 days apart, surfacing future T212 regressions immediately.

Evidence

For the user's specific bug, the History tab went from:

Before After
AMD £0.00 / -100% £124.64 / +24.64%
SHOP £0.00 / -100% £102.49 / +2.49%
PLTR £0.00 / -100% £100.55 / +0.55%
Total Recovered £553.51 £881.19 (+£327.68 of previously-missing money)
Total Performance -53.87% -26.57%

Direct API verification (per-ticker query): T212 has 3 SELL orders for SHOP, 2 for PLTR, 1 for AMD that are absent from the unfiltered paginated stream but present when queried with ?ticker=X.

The unfiltered stream has 7 detected gaps in the user's history, the largest being 112 days (Sep 5 – Dec 26, 2025).

Test plan

  • Local end-to-end test with empty cache: full pagination + reconciliation runs in ~3 min, History tab shows correct values for all 12 closed positions
  • Warm-start test: 0 new orders (cache is current) and reconcile: no closed-position candidates need filling log on second start
  • backup_dir test: cache mirrored to second directory, footer shows backup ✓
  • Rehydrate-from-backup test: wipe primary cache, restart, log confirms rehydrated 491 orders from backup_dir
  • Gap-detection log fires for all 3 actual gaps (52d, 53d, 112d)
  • go build ./..., go vet ./..., go test ./... all clean
  • Deploy to DietPi: add CacheDirectory=t2 and StateDirectory=t2 to /usr/lib/systemd/system/t2.service, set backup_dir in /etc/t2/config.yaml to a Dropbox-synced folder, restart, confirm History tab fixed

🤖 Generated with Claude Code

…ders

Trading212's unfiltered /equity/history/orders endpoint silently drops
orders in certain time windows for some accounts (verified gap up to 112
days for this account). The same orders ARE returned when queried with
?ticker=X, so the workaround is a per-ticker reconciliation pass.

Changes:
- Per-ticker reconciliation: after the unfiltered fetch builds the
  returns map, identify closed-position candidates (BUYs in cache, no
  SELLs/divs, not in current open positions) and fetch each via
  ?ticker=X to fill the gap. Cost is bounded by the number of
  mismatched closed positions, typically a handful.
- Gap detection log: warn when consecutive orders in the unfiltered
  stream are >30 days apart, so future T212 regressions surface
  immediately.
- cacheDir(): honor systemd's $CACHE_DIRECTORY env var first, and
  skip $HOME=/nonexistent (the placeholder for system users) so the
  cache lands somewhere actually writable when t2 runs as a service.
- Optional backup_dir config field: mirror orders.json/dividends.json
  to a second location after each successful save (typically a
  Dropbox/OneDrive/rclone-synced folder). On startup, if the primary
  cache is missing but the backup exists, t2 rehydrates from it.
  Useful because T212 may eventually purge older records and a
  pagination bug can drop them sooner.
- Footer surface: show orders/dividends cache freshness timestamps
  and a "backup ✓" indicator next to "Last updated" so cache state
  is visible without reading logs.
- README: document CacheDirectory=t2 / StateDirectory=t2 systemd
  directives and the new backup_dir option.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant