One-Click Sell Condition UI on the Holdings Dashboard | Toss Auto-Trading Dev Journal #7-8

🌐 ν•œκ΅­μ–΄λ‘œ 보기

πŸ’‘ Phase 7-8 at a glance

  • Goal: Let a user set a sell target directly from the holdings table, with independent BUY/SELL/BOTH conditions per symbol
  • Key decision: A FastAPI Form API (backed by python-multipart) writes straight to strategy_configs, and a new stock_names cache table powers a “Samsung Electronics (005930)”-style display
  • Verification: Live API token diagnostics passed, 130/130 pytest cases green

One-click sell condition setup is finally live on my Toss Securities dashboard as of Phase 7-8. My dashboard used to show a wall of ticker codes I had to look up every time, and setting a sell condition meant editing the code by hand.

Holdings Visualization & One-Click Sell Condition UI

Holdings pulled via toss_portfolio.fetch_holdings now render at the top of the dashboard β€” quantity, average price, current price, unrealized P&L, and return rate β€” each row with an inline form to set a sell target on the spot.

@app.post("/api/strategies")
async def create_strategy(
    symbol: str = Form(...),
    side: str = Form(...),  # BUY / SELL / BOTH
    target_price: float = Form(...),
):
    save_strategy_config(symbol, side, target_price)
    return RedirectResponse("/", status_code=303)
Forgot to install the form dependency first and hit RuntimeError: Form data requires "python-multipart" to be installed. Fixed with pip install python-multipart.

In a mock account, if Samsung Electronics (005930) is held at an average price of β‚©71,000 for 10 shares, entering a target of β‚©78,000 writes to strategy_configs instantly and monitoring starts right away.

Independent Buy/Sell Conditions & Stock-Name Display

The old setup only supported a single buy condition. I split it into a side column with three values: BUY, SELL, and BOTH β€” so a symbol you already hold can be watched for SELL only, a new symbol for BUY only, or both at once.

The stock_names Cache Table

Every API response now caches its stock name into a stock_names table, and a single get_display_name() helper standardizes the label across the whole dashboard.

def get_display_name(code: str) -> str:
    name = get_cached_stock_name(code)
    return f"{name} ({code})" if name else code

No more raw codes like “005930” β€” it now reads “Samsung Electronics (005930)” everywhere, same for SK Hynix (000660).

Dry-Run Buy/Sell Cycle, Dual-Channel Alerts & Security Diagnostics

With DRY_RUN = True, hitting a target price now runs a full dry-run cycle β€” buy β†’ track return β†’ take-profit/stop-loss sell β€” and logs it to the trades table, so I can validate strategy logic without placing real orders.

Alerts got redundant too: anything WARNING or above now goes out over both Telegram and email (SMTP) via a reworked notifier.py. security_check.py non-destructively checks .env Git protection, the five safety-brake states, and OAuth2 token connectivity in one report.

Finally, start_all_daemons.bat / stop_all_daemons.bat now bring up all four daemons β€” auto_trader, bot_server, scheduler, dashboard β€” with a single click on Windows boot.

Verification: 130 pytest Cases

Live API token diagnostics passed, and all 130 pytest cases β€” including the new python-multipart form handling β€” passed as well. Since this phase touched UI, DB, alerts, and security all at once, the regression suite mattered more than usual.

Wrap-Up

The one-click sell condition goal is basically done for this phase. Next up: adding a stop-loss ratio slider to the same UI.

πŸ‘‰ See the full series index at the top of this post

Leave a Comment

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

Scroll to Top