Skip to content

My Portfolio — Implementation

How It Works

  1. User uploads screenshot(s) via the My Portfolio page
  2. portfolio/parser.py:parse_screenshots() encodes images as base64 and calls Gemini 2.5 Flash with a structured extraction prompt
  3. Returns JSON with summary, kr_holdings, us_holdings keys and _tokens metadata
  4. save_snapshot() persists PortfolioSnapshot + PortfolioHolding rows; each upload is a new timestamped snapshot

Korean Name → Ticker Mapping

KR_NAME_TO_TICKER in portfolio/parser.py is a static lookup table mapping Korean stock names (as shown in the M-STOCK app) to KRX 6-digit codes. If a name is not in the table, ticker is stored as None on the PortfolioHolding row.

Token Tracking

tokens_input, tokens_output, tokens_total stored on PortfolioSnapshot from usage_metadata in the Gemini response. Exposed via GET /portfolio/token-usage endpoint.

System Overlap Tab

Cross-references PortfolioHolding.ticker values against load_predictions() — shows 1d ML direction + confidence alongside each holding position.

Gotchas

  • ANTHROPIC_API_KEY is required — the upload button is disabled with an error message if the key is absent. The rest of the portfolio page still works (viewing past snapshots).
  • Each upload is a new snapshot — there is no upsert/replace logic. Old snapshots are preserved.
  • ticker=None holdings appear in the UI but have no ML prediction or sentiment data to show.
  • Supported formats: JPEG, PNG, WebP. Large images are sent as-is (base64 encoded).