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.