How I Built an Automated Korean Stock Trading Bot (KIS API + Python)

Background I’ve been actively trading Korean stocks on the KOSPI and KOSDAQ for years. After spending too many hours watching charts, I decided to automate part of my trading strategy using the KIS API. This post shares what I built, what worked, and what I learned — including mistakes. The Strategy My bot focuses on momentum scalping on KOSPI stocks: Screen for stocks with high volume breakouts in the first 30 minutes Enter positions with defined risk (1-2% of account per trade) Exit on target profit or stop loss Maximum 3 concurrent positions System Architecture GitHub Actions (scheduler) ↓ Python Script ↓ ↓ ↓ KIS API pykrx Telegram Bot (trading) (data) (alerts) Core Components 1. Market Scanner from pykrx import stock import pandas as pd def scan_breakouts(min_volume_ratio=2.0): """Find stocks with unusual volume""" today = stock.get_market_ticker_list(market="KOSPI") breakouts = [] for ticker in today[:100]: # Limit for demo try: df = stock.get_market_ohlcv_by_date( prev_date, today_date, ticker ) if len(df) < 20: continue avg_volume = df["거래량"].mean() current_volume = df["거래량"].iloc[-1] if current_volume > avg_volume * min_volume_ratio: breakouts.append({ "ticker": ticker, "volume_ratio": current_volume / avg_volume }) except: continue return sorted(breakouts, key=lambda x: x["volume_ratio"], reverse=True) 2. Order Execution (KIS API) def place_market_order(ticker, quantity, order_type="buy", token=None): url = "https://openapi.koreainvestment.com:9443/uapi/domestic-stock/v1/trading/order-cash" tr_id = "TTTC0802U" if order_type == "buy" else "TTTC0801U" headers = { "authorization": f"Bearer {token}", "appkey": APP_KEY, "appsecret": APP_SECRET, "tr_id": tr_id } body = { "CANO": ACCOUNT_NO, "ACNT_PRDT_CD": "01", "PDNO": ticker, "ORD_DVSN": "01", # Market order "ORD_QTY": str(quantity), "ORD_UNPR": "0" } res = requests.post(url, headers=headers, json=body) return res.json() Key Lessons Learned What Worked Automating the scanning phase saved significant time Telegram alerts for signals I review manually before execution Strict position sizing rules enforced by code What Did Not Work Fully automated execution without human review (too many false signals) Running during the first 5 minutes of market open (too volatile) Ignoring market regime (bot designed for trending markets struggled in choppy conditions) Risk Management Rules Never risk more than 2% of account per trade Maximum 3 concurrent positions Hard daily loss limit of 5% — bot stops automatically No trading during major news events Current Status The bot currently runs in semi-automated mode: it scans and sends signals via Telegram, but I manually approve each trade before execution. This hybrid approach has been more profitable than either full automation or pure manual trading.

June 10, 2026 · 2 min · Phillip