π νκ΅μ΄λ‘ 보기 β νκ΅μ΄ λ²μ
π Toss Auto-Trading Dev Journal Series (Phase 7-4 / entry #22 of 22)
- #0 Foundation setup (Phase 0)
- #0-1 Currency bug fix (Phase 0-1)
- #3 Config separation & retry logic (Phase 1)
- #4 Config/retry follow-up (Phase 1-2)
- #5 Introducing pytest (Phase 1-3)
- #6 Log rotation (Phase 1-4)
- #7 Strategy class design (Phase 2-1)
- #8 Multi-symbol monitoring (Phase 2-2)
- #9 Data persistence design (Phase 3-1)
- #10 DB module implementation (Phase 3-2)
- #11 DB integration (Phase 3-3)
- #12 Strategy plugin interface (Phase 2-3)
- #13 Backtest engine (Phase 4)
- #14 Candle API pagination (Phase 4)
- #15 Read-only dashboard (Phase 5)
- #16 Telegram control logic (Phase 5)
- #17 Telegram control logic, revisited (Phase 5)
- #18 Scheduler watchdog (Phase 6)
- #19 Order limit guard (Phase 7)
- #20 Loss-limit auto-pause (Phase 7)
- #21 Dual-channel notification, first pass (Phase 7-3)
β Previous: #21 Dual-channel notification, first pass | Next: not yet published
π‘ Phase 7-4 Summary
- Goal: Non-destructively verify API permissions and security posture before live runs, and remove the single point of failure in alerting
- Key decision: Verify the five safety brakes at runtime via a diagnostic script rather than trusting config values
- Validation: Successful diagnostics against the live Toss Securities Open API, 140/140 pytest cases passing
This post walks through building auto-trading security diagnostics for the Toss trading bot, plus finishing off dual-channel alerts. For readers unfamiliar with the setup: Toss Securities is a Korean brokerage, and this bot trades through its Open API using Korean won. Every deploy used to come with the same nagging worry β did a stray commit expose the .env file, or did one of the safety switches get flipped off without anyone noticing. This time, that checklist became a script.
Why Auto-Trading Security Diagnostics, Now
Safety mechanisms like DRY_RUN, a capped target price, and an order quantity ceiling had lived scattered across the codebase. The gap was between “the safeguard exists in code” and “it’s actually active right now” β a value could get changed right before a deploy and slip through unnoticed. That gap is exactly what auto-trading security diagnostics was built to close.
security_check.py β Non-Destructive Diagnostics
Environment Variable and Git Exposure Check
The script first checks whether a .env file exists and whether it’s registered in .gitignore. Without both, everything else is moot.
def check_env_git_safety():
issues = []
if not os.path.exists(".env"):
issues.append("WARNING: .env file not found")
with open(".gitignore", "r") as f:
gitignore_content = f.read()
if ".env" not in gitignore_content:
issues.append("CRITICAL: .env is not listed in .gitignore")
return issues
Verifying the Five Safety Brakes
DRY_RUN = True(simulation mode)TARGET_BUY_PRICE = 1(an unfillable target price)MAX_ORDER_QUANTITY_PER_TRADE(per-order quantity cap, e.g. 10 shares in this mock example)MAX_CUMULATIVE_LOSS_PCT(cumulative loss threshold, e.g. 10% in this mock example)- The actual
requests.postorder call is regex-checked to confirm it’s still commented out
The point isn’t whether the configured value looks right β it’s whether the system is actually in that state right now. The shift was toward checking live state instead of trusting config.
Non-Destructive API Token and Permission Check
The script confirms OAuth2 token issuance, account linkage (mock example: an account holding Samsung Electronics, 005930), and quote-lookup permissions β all without placing a real order β then prints a pass/fail report to the console.
notifier.py β Finishing Dual-Channel Alerts
Alert logic used to be baked directly into auto_trader.py. Splitting it into its own module solved two problems at once.
Best-Effort Exception Handling
def send_alert(level, message):
try:
send_telegram(message)
except Exception as e:
log_error(f"Telegram failed: {e}")
if level in ("WARNING", "ERROR", "CRITICAL"):
try:
send_email(message)
except Exception as e:
log_error(f"SMTP failed: {e}")
# The monitoring engine must never stop, even if alerting fails
Even if both Telegram and SMTP fail, the monitoring engine and background scheduler are guaranteed to keep running β that guarantee is now enforced in code, not just intended.
Tiered Dual Delivery
INFO goes to Telegram and the database log only; WARNING, ERROR, and CRITICAL go to both Telegram and email. This removes the single point of failure of relying on Telegram alone during an outage.
Integration with risk_control.py
When cumulative loss crosses the threshold (10% in this mock example), monitoring auto-pauses and an emergency alert fires through both email and Telegram simultaneously.
Validation: Live API Diagnostics + 140 pytest Cases
The auto-trading security diagnostics script ran successfully against the live Toss Securities Open API, and all 140 pytest unit tests passed. Watching that number climb over the series has been satisfying.
What’s Next
With auto-trading security diagnostics and dual-channel alerts in place, the next step is a longer-run stability test in the mock trading environment.