Toss Auto-Trading Dev Journal series (Post 3 of 3)
- Phase 0 — Building the Foundation
- Phase 0-1 — Fixing the Currency Display Bug
- Phase 1 — Config Refactor and Retry Unification (this post)
Previous: Phase 0-1 — Currency Display Bug / Next: added after publish
I’m building a small automated trading bot on top of Toss Securities’ brokerage API (a Korean stock brokerage). Phase 0 got the basic system running, Phase 0-1 fixed a currency display bug. Now it’s Phase 1 — hardening the config and error-handling layer. Two items down today.
The Problem: Scattered Config and Duplicated Retry Code
Stock symbols, polling intervals, and target prices were hardcoded across multiple files. Changing one value meant editing four or five files. The retry and timeout handling logic had the same problem — the same code copy-pasted in each file that made an API call.
Task 1: Centralizing Config in config.py
I created a new config.py holding TARGET_STOCKS, TARGET_SYMBOL, ORDER_QUANTITY, MONITOR_INTERVAL, ERROR_BACKOFF_INTERVAL, MAX_CONSECUTIVE_ERRORS, and DEFAULT_TIMEOUT. get_price.py, auto_trader.py, and toss_common.py now reference it instead of hardcoded values.
Importantly, the safety switches — DRY_RUN=True and TARGET_BUY_PRICE=1 — stayed untouched during the refactor. A three-layer safety brake is a rule I don’t bend even mid-refactor. Running python get_price.py confirmed prices for a placeholder stock (Samsung Electronics, 005930 — used here purely as a stand-in, not a real position) came through correctly.
Task 2: Unifying Retry and Backoff Logic
I added a retry_on_network_error() decorator in toss_common.py. It only retries on timeouts or network errors, with the count and interval pulled from config.py. I applied it to get_access_token, get_account_sequence, get_current_prices, fetch_holdings, and fetch_holdings_raw.
One deliberate exception: get_current_price() inside auto_trader.py doesn’t get the decorator. The monitoring loop itself already behaves like a retry mechanism, so stacking the decorator on top would double up the retries. Instead I split it into two layers — an immediate retry as the first line of defense, and the monitoring loop’s longer backoff as the second.
Unifying retry logic into a single decorator centralizes network-error handling in one place, making it easier to maintain and avoiding redundant retries with the monitoring loop.
I forced a timeout via mocking to confirm the decorator retries exactly the configured number of times, then falls back to a safe default.
The Scare: A Regression, and the Recovery
While working on the retry decorator, I broke something. The KRW/USD currency-splitting feature I’d fixed in toss_portfolio.py just a couple days earlier had quietly disappeared. Digging into it, the cause was simple: I’d started this session’s edits from an outdated local file instead of the latest one, and stitched new code onto the wrong base.
I caught it early because the person testing the bot shared their actual output — everything showing in KRW only — before it went any further. After restoring the fix, I re-verified it by running the function directly against mock test data. I also put a guardrail in place: before swapping in any file, run Select-String (or grep) first to confirm the key function names actually still exist in it.
What’s Next
Two items remain in Phase 1: log rotation with RotatingFileHandler, and introducing pytest for unit tests. Today’s regression scare turned out to be a pretty concrete argument for why pytest matters. The next post will probably pick up right there.
Pingback: Best-Effort SQLite Logging for a Trading Bot | Toss Dev #3-2 - Orbit - Space & ETF Investing
Pingback: Monitoring Multiple Tickers at Once | Toss Dev #2-2 - Orbit - Space & ETF Investing
Pingback: Managing Log Files with RotatingFileHandler | Toss Dev #1-4 - Orbit - Space & ETF Investing
Pingback: Patching Up My Retry Logic Follow-Up | Toss Dev #1-2 - Orbit - Space & ETF Investing
Pingback: Wiring the Trading Engine Into SQLite Logging | Toss Auto-Trading Dev Journal #11 (Phase 3-3) - Orbit - Space & ETF Investing
Pingback: Plugin Interface for Trading Strategies | Toss Auto-Trading Dev Journal #12 (Phase 2-3) - Orbit - Space & ETF Investing
Pingback: Backtesting on Just a Price List | Toss Auto-Trading Dev Journal #13 (Phase 4) - Orbit - Space & ETF Investing
Pingback: Candle API Pagination for Historical Backtesting | Toss Auto-Trading Dev Journal #14 - Orbit - Space & ETF Investing
Pingback: Wiring Up python-telegram-bot Command Handlers | Toss Auto-Trading Dev Journal #16 - Orbit - Space & ETF Investing