Fixing the Vanishing Overseas Stock Value Bug | Toss Dev #0-1

Toss Auto-Trading Dev Journal Series (Current: #0-1 / 2 posts total)

  • Phase 0 — Foundation
  • Phase 0-1 — Currency bug fix (this post)

Previous: [Phase 0] Five Files, One Bot

A few days into running the portfolio dashboard, I noticed something off. The per-holding list correctly showed overseas positions (dummy tickers “SpaceX” and SOXL) in dollars — but the top-line summary stats (total purchase amount, market value, total P&L) didn’t reflect any of it. Individual rows were right, the totals were wrong. That mismatch is always a bad sign.

The cause: a hardcoded currency key

I went back to the raw API response via toss_test.py. Fields like totalPurchaseAmount, marketValue.amount, profitLoss.amount, and dailyProfitLoss.amount all came back split by currency, as {"krw": ..., "usd": ...}. But my summary logic only read .get("krw") — the USD side was being silently discarded. I also found a second landmine: every one of these amounts comes back as a string, not a number (e.g. "1687167"). Skipping the cast would’ve caused a different bug down the line.

Worth noting: profitLoss.rate and dailyProfitLoss.rate only come back as a single blended percentage, with no currency split.

I chose separate currency totals over FX conversion

Two options were on the table:

  • Option A: show KRW and USD totals separately, no conversion
  • Option B: pull in an FX rate and show one blended total

Option B looks more “finished,” but any FX error would make a number that’s supposed to be precise — my actual asset total — less accurate, not more. It also meant a lot more scope. I went with A: showing the real numbers without distortion mattered more than a single combined figure.

def extract_amounts_by_currency(amount_dict: dict) -> dict:
    """Walk whatever currency keys the response actually contains, casting safely"""
    result = {}
    for currency, value in amount_dict.items():
        try:
            result[currency] = float(value)
        except (TypeError, ValueError):
            result[currency] = 0.0
    return result

Instead of hardcoding currency keys, this walks whatever’s actually in the response — so if a third currency shows up later, nothing needs to change. The dashboard now prints separate [KRW] and [USD] blocks, and the USD block disappears automatically for accounts with no overseas holdings.

Then the real mess started

After the fix, running the script produced… nothing. No error, no output, just back to the prompt. Turned out the entire if __name__ == "__main__": entry point block had vanished somewhere while I was moving code around.

I restored it and ran again — this time, NameError: name 'logger' is not defined. The top-of-file imports and a few helper functions (safe_int, get_display_width) had gone missing along with it. Patching piece by piece had left the file in a half-broken state.

That’s when I stopped trying to patch fragments and rebuilt the whole file as one complete unit instead. Partial patches feel faster in the moment, but tracking down what silently went missing costs a lot more time than just doing it properly once.

The result

After the full rebuild, KRW and USD totals both came out correctly.

💰 [KRW] Total Purchase: ₩1,687,167
💵 [USD] Total Purchase: $1,716.08

Exactly what I was expecting to see.

What this connects to next

The “partial patches fragment your code” lesson here lines up with the retry/backoff consolidation work planned for Phase 1. Consolidating scattered logic into one place is starting to feel less optional.

11 thoughts on “Fixing the Vanishing Overseas Stock Value Bug | Toss Dev #0-1”

  1. Pingback: [Toss Auto-Trading Dev Journal #4] Centralizing Config, Unifying Retry Logic, and a Regression Scare - Orbit - Space & ETF Investing

  2. Pingback: [Toss Auto-Trading Dev Journal #5] Adding pytest: Turning a Regression Scare Into a Safety Net - Orbit - Space & ETF Investing

  3. Pingback: [Toss Auto-Trading Dev Journal #6] Taming Infinite Log Growth — Wrapping Up Phase 1 - Orbit - Space & ETF Investing

  4. Pingback: [Toss Auto-Trading Dev Journal #8] From One Symbol to Many - Orbit - Space & ETF Investing

  5. Pingback: [Toss Auto-Trading Dev Journal #10] Building the SQLite Persistence Module - Orbit - Space & ETF Investing

  6. Pingback: Designing a SQLite Schema for Trade Persistence | Toss Dev #3-1 - Orbit - Space & ETF Investing

  7. Pingback: Abstracting Strategy Classes for Cleaner Trading Logic | Toss Dev #2-1 - Orbit - Space & ETF Investing

  8. Pingback: Wiring the Trading Engine Into SQLite Logging | Toss Auto-Trading Dev Journal #11 (Phase 3-3) - Orbit - Space & ETF Investing

  9. Pingback: Plugin Interface for Trading Strategies | Toss Auto-Trading Dev Journal #12 (Phase 2-3) - Orbit - Space & ETF Investing

  10. Pingback: Backtesting on Just a Price List | Toss Auto-Trading Dev Journal #13 (Phase 4) - Orbit - Space & ETF Investing

  11. Pingback: Candle API Pagination for Historical Backtesting | Toss Auto-Trading Dev Journal #14 - Orbit - Space & ETF Investing

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top