π Toss Auto-Trading Bot Dev Journal β Full Index (Entry 23 of 23)
- Phase 0 β Project Foundation
- Phase 0-1 β Currency Bug Fix
- Phase 1 β Config & Retry Logic
- Phase 1-2 β Config & Retry Follow-up
- Phase 1-3 β Introducing pytest
- Phase 1-4 β Log Rotation
- Phase 2-1 β Strategy Class Design
- Phase 2-2 β Multi-Symbol Monitoring
- Phase 3-1 β Data Persistence Design
- Phase 3-2 β DB Module Implementation
- Phase 3-3 β DB Integration
- Phase 2-3 β Strategy Plugin Interface
- Phase 4 β Backtest Engine
- Phase 4 β Candle API Pagination
- Phase 5 β Read-Only Dashboard
- Phase 5-2 β Telegram Control Logic
- Phase 5-2 β Telegram Control Logic (Part 2)
- Phase 6 β Scheduler Watchdog
- Phase 7 β Order Limit Guard
- Phase 7-2 β Loss Limit Auto-Pause
- Phase 7-3 β Dual-Channel Notifications
- Phase 7-4 β Security Diagnostics
- Phase 7-5 β Take-Profit/Stop-Loss Cycle Complete (this entry)
β¬ οΈ Previous: Phase 7-4 β Security Diagnostics Module Β· Next entry not published yet.
π‘ Phase 7-5 at a glance
- Goal: Pull per-symbol buy targets and take-profit/stop-loss ratios into config and run a full virtual trade cycle under DRY_RUN.
- Key decision: Split notifier.py into its own module with severity-based dual-channel dispatch.
- Verification: All 136 pytest cases pass; security_check.py runs a non-destructive audit of tokens, account link, and the 5-layer safety brake.
This round, the Toss auto-trading bot finally got a real trade cycle. Running under DRY_RUN doesn’t mean cutting corners β once take-profit/stop-loss logic is fully wired, flipping to live trading later is just a config flag away. For context, Toss Securities (ν μ€μ¦κΆ) is a Korean brokerage, and this bot talks to its official trading API.
Toss auto-trading bot: take-profit/stop-loss cycle structure
Previously the bot just watched a target price and stopped after a single buy signal. Now it runs a full cycle:
config.TARGET_STRATEGIESdefines per-symbol buy target, quantity,take_profit_pct(default +5%),stop_loss_pct(default -3%)strategy.create_strategy()dynamically builds the right strategy object from that config dict- Virtual buy β position opened β return calculated β virtual sell triggered (with alert + DB write to
trades) once take-profit or stop-loss is hit
Say a virtual buy on Samsung Electronics (005930) fills at β©70,000 β hitting β©73,500 (+5%) triggers a take-profit sell, and β©67,900 (-3%) triggers a stop-loss sell. Symbols without these ratios configured still fall back to the old single-shot watch behavior, so backward compatibility holds.
Dual-channel alerts β notifier.py
Alert logic used to be scattered across auto_trader.py. It’s now fully isolated:
Severity routing: INFO goes to Telegram + DB only. WARNING/ERROR/CRITICAL go to both Telegram and email (SMTP).
The part I cared about most was making failures best-effort. During testing I actually hit this:
smtplib.SMTPServerDisconnected: please run connect() first
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded
None of that should ever take down the watch loop, so notifier.py wraps every send in try/except and just logs the failure. It also hooks into risk_control.py β once cumulative loss crosses MAX_CUMULATIVE_LOSS_PCT, monitoring auto-pauses and an emergency alert fires on both channels.
Security & permission audit β security_check.py
Before going live, this script bundles the checklist into one run:
- Verifies
.envexists and is listed in.gitignore, so credentials never get committed - Confirms the 5-layer safety brake:
DRY_RUN=True,TARGET_BUY_PRICE=1 KRW,MAX_ORDER_QUANTITY_PER_TRADE=10 shares,MAX_CUMULATIVE_LOSS_PCT=10%, and a hard block on the order-placement API - Non-destructively checks OAuth2 token issuance (
POST /api-v1/oauth2/token), account serial linkage, and quote API access (GET /api-v1/quote/{symbol}) without placing any real orders
The take-profit/stop-loss cycle is implemented by defining per-symbol target price and ratios in config.TARGET_STRATEGIES, then having strategy.create_strategy() dynamically build a strategy object that safely runs the full buy-to-sell cycle under DRY_RUN.
136 pytest cases, all green
Between the new take-profit/stop-loss cycle tests, notifier.py’s severity-routing tests, and security_check.py’s audit tests, the suite now sits at 136 passing cases. The trickiest one deliberately forced an SMTP outage to confirm the watch loop survives it β and it did. The fixture/parametrize patterns came straight out of the official pytest docs.
What’s next
The last thing before going live is a small-scale test with real account linkage β that’ll be the next entry.
FAQ
Q1. Does take-profit/stop-loss actually run in DRY_RUN mode?
Yes β no real orders go out, but the virtual buy/sell, return calculation, and DB logging all run exactly like the live path.
Q2. When do alerts go to email instead of just Telegram?
Only at WARNING severity and above. INFO-level events stay on Telegram + DB.
Q3. Does security_check.py touch the live account?
No β it’s a non-destructive audit that only reads token/permission/safety-brake state.
Q4. Can take-profit/stop-loss ratios differ per symbol?
Yes, each symbol in TARGET_STRATEGIES can have its own take_profit_pct and stop_loss_pct.
Pingback: ν μ€μ¦κΆ μλλ§€λ§€ λ΄ μ΅μ μμ μ¬μ΄ν΄ μμ± | ν μ€ μλλ§€λ§€ κ°λ°κΈ° #23 - TS ννΈ: μ£Όμ μλλ§€λ§€ μ°κ΅¬μ