Skip to content

feat(enrichment): automatic trade context enrichment MVP - #12

Open
omerElezra wants to merge 8 commits into
mainfrom
feat/trade-context-enrichment
Open

feat(enrichment): automatic trade context enrichment MVP#12
omerElezra wants to merge 8 commits into
mainfrom
feat/trade-context-enrichment

Conversation

@omerElezra

Copy link
Copy Markdown
Owner

What

Automatic Trade Context Enrichment: given a completed trade's raw broker data, compute the essential objective post-trade metrics and store them separately from executions.

  • Domain serviceenrichTradeContext(trade, provider) in frontend/lib/domain/enrichment.ts (pure, provider injected, unit-testable):
    • Basic result: gross/net P&L, P&L %, holding period, Win/Loss/Breakeven
    • Risk/Reward: planned risk & reward per share, planned R:R, actual R — all null when the stop is missing or invalid
    • Stock context at entry: above MA20/50/200, MA alignment, distance from MAs, 5/20/60d returns, avg volume 20d, entry-day & relative volume, ATR14 + ATR%
    • Market context at entry: SPY + QQQ bias, combined market bias, marketSupportiveForTrade (long↔bullish, short↔bearish)
    • Trade journey: high/low during trade, MFE/MAE ($/%/R), exit efficiency
    • Data quality: missingInputs, missingMarketData, assumptions, warnings
  • Provider interfaceDailyBarProvider with a default adapter over the existing Yahoo/Polygon getCandles dispatch; another source can be plugged in without touching the domain logic.
  • Storage — new trade_context_enrichment table (migration 009, applied to Supabase): JSONB payload keyed by (symbol, entry_time) like trade_journal; raw broker data stays untouched.
  • APIPOST /api/v1/trades/[tradeId]/enrichment computes from the grouped trade + journal plan (stop/target) and upserts; GET returns the stored row. Closed trades only.
  • UI — "Trade Context" card on the trade detail page with a Compute/Recompute button; missing data renders as / UNKNOWN badges.
  • Tests — first unit-test infra in the repo: vitest (npm test), 19 tests covering long/short P&L, R/R, missing-stop behavior, MA alignment, market bias, MFE/MAE, and exit efficiency via a fake bar provider.

Design rules

No recommendations, no predictions, no invented data — anything not derivable from inputs is null/UNKNOWN and reported in dataQuality. Indicators use daily closes strictly before the entry day; MFE/MAE come from daily highs/lows (recorded as assumptions).

Reviewer notes

  • Verified end-to-end on localhost: computed + persisted enrichment for a real SOFI trade; GET returns the stored row.
  • On the Intel/VPN network Yahoo rate-limits candle fetches, so stock/market sections degrade to UNKNOWN with a missingMarketData note suggesting POLYGON_API_KEY; broker-derived metrics compute regardless.
  • planned_stop_loss/planned_target_price are not in IBKR data — they come from the journal when filled in; R metrics are null otherwise.
  • Enrichment gross P&L is (avgExit − avgEntry) × qty minus commission per spec, which can differ slightly from the group's broker realized_pnl-based netPnl.

🤖 Generated with Claude Code

Given a completed trade's broker data, compute objective post-trade
metrics and store them separately from raw executions:

- lib/domain/enrichment.ts: pure enrichTradeContext(trade, provider) —
  basic result, planned R/R + actual R, stock technicals at entry
  (MA20/50/200, returns, volume, ATR14), SPY+QQQ market bias, MFE/MAE
  journey with exit efficiency, and a dataQuality section (missing
  inputs, missing market data, assumptions, warnings). Never invents
  data: null/UNKNOWN when inputs or candles are unavailable.
- DailyBarProvider interface with a default adapter over the existing
  Yahoo/Polygon getCandles dispatch (lib/marketdata/daily-provider.ts).
- trade_context_enrichment table (migration 009, JSONB payload keyed by
  symbol+entry_time like trade_journal) + upsert/fetch queries.
- GET/POST /api/v1/trades/[tradeId]/enrichment: POST computes from the
  grouped trade + journal plan (stop/target) and upserts; closed trades
  only.
- Trade detail page: "Trade Context" card with Compute/Recompute button
  rendering all sections, with — / UNKNOWN for missing data.
- First unit-test infra in the repo: vitest (npm test), 19 tests
  covering long/short P&L, R/R, missing-stop behavior, MA alignment,
  market bias, MFE/MAE and exit efficiency via a fake bar provider.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
trade-ops-journal Ready Ready Preview, Comment Jul 20, 2026 2:05pm

- Stock context now uses MA20/50/150 (user trades the daily timeframe;
  MA150 is the long-trend reference) — alignment, above/distance fields
  renamed accordingly; schema_version bumped to 2.
- Market context gains VIX at entry: last close before the entry day,
  5d change, and a LOW/NORMAL/ELEVATED/EXTREME regime (<15/<20/<30/30+).
  VIX is display-only context — market bias stays SPY+QQQ.
- ^VIX daily bars come from Cboe's free history CSV (new
  lib/marketdata/cboe-vix.ts): Yahoo blocks datacenter IPs and Polygon
  gates indices behind a paid plan (free tier returns 403). Polygon
  ticker mapping for ^-prefixed indices (I:VIX) added anyway for keys
  with an indices plan.
- Card renders the new MA150 labels and VIX level/regime/5d change,
  tolerating v1 rows (missing fields render as dashes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Redesign the trade journal to only ask for subjective inputs and derive
the rest from measured data. Auto-suggested values are flagged with an
"auto" chip and stay fully editable; a user edit drops the flag.

- Market Read section pre-fills from the trade's enrichment: recent
  trend (MA alignment), volume vs trend (relative volume thresholds
  2.5x/1.1x/0.9x), MA relation chips (above/below MA20 & MA150, plus
  "Overextended" when >7% from MA20). Prefill runs once, only into
  empty fields, and never overwrites saved journal values.
- Risk amount ($) auto-computes live as |entry - stop| x qty while the
  stop is typed; manual override wins permanently.
- Exit reason suggests "Hit Stop"/"Hit Target" when the actual exit
  landed within 1.5% of (or beyond) the planned level.
- Candle pattern, open gaps and support/res/fib move into a collapsed
  "More (optional)" section (auto-opens when they hold saved values).
- Footer shows how many fields are auto-filled pending review; saving
  still requires an explicit click so suggestions are never persisted
  unseen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
oelezra and others added 4 commits July 20, 2026 16:53
…itable scoring rules

New /entry-check page that forces a deliberate pre-entry decision:
- computePreEntryContext reuses the enrichment section calculators as-of any
  timestamp (empty = live "now" check, past = retrospective practice incl.
  a "what happened after" 5/10/20d forward outcome with stop/target first-hit)
- transparent rule-based score: user-editable scoring_rules (AND of typed
  predicates over a curated fact catalog, no black box), 7 seeded defaults,
  fired/skipped breakdown always shown; unified Entry confirmation question
  (confirmation vs anticipation/FOMO) shared with the journal
- trade_plans table (migration 010): full check saved with frozen score
  breakdown, status planned/entered/skipped/expired, editable in place via
  full-form loading (each plan is a single row, PATCH recomputes the score)
- copy-paste AI coach prompt built from the full context/checklist/score/
  outcome, with clipboard fallback modal; lazy return-since-plan chip
- shared journal form controls + Hebrew hover-help extracted for reuse

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ver help

- trade journal form now uses the extracted form-controls/journal-presets;
  "Entry reason" unified with entry-check into the Entry confirmation
  question (discipline dimension only — setups stay in Technical setup,
  incl. new MA Support Bounce / Fibonacci Retracement / Bouncing on MA150);
  sections renamed to match entry-check (Setup & Plan, Chart Details)
- Hebrew hover explanations on every question, option chip and section, on
  the Trade Context card metrics and on the dashboard/analytics KPI cards
- notes and custom-value inputs auto-detect Hebrew (dir="auto")

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parses scripts/migrations/*.sql and fails when code and schema drift:
columns read/written must exist, migrated-but-untouched columns are flagged
as redundant unless whitelisted, upsert conflict keys need a matching UNIQUE
constraint, the scoring_rules seed must parse, pass validateRule and stay
identical to DEFAULT_RULES, and migration numbering must be gapless.
CLAUDE.md documents the repo-root-mounted test command and requires running
the suite for any DB-touching change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verified with knip + manual grep:
- delete the orphaned /api/v1/metrics/performance endpoint and
  lib/domain/performance.ts (no client callers — FastAPI-port leftover),
  their types (PerformanceReport, HoldingTimeStats), the unused kpi-row
  component, the unused autoInterval helper and the unused SSR supabase
  client; drop unused @radix-ui/react-separator and react-tooltip deps
- unexport symbols only used inside their own module

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(entry-check): pre-entry check page with saved trade plans and editable scoring rules
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.

2 participants