Build a Korean Stock Screener with pykrx (Python Tutorial)

What We’re Building A Python-based Korean stock screener that: Pulls data from KRX via pykrx Filters stocks by multiple criteria (PER, PBR, volume) Exports results to CSV Can be automated with GitHub Actions Setup pip install pykrx pandas Complete Screener Code from pykrx import stock import pandas as pd from datetime import datetime, timedelta class KoreanStockScreener: def __init__(self, market="KOSPI"): self.market = market self.today = datetime.now().strftime("%Y%m%d") def get_all_data(self): fundamentals = stock.get_market_fundamental_by_ticker( self.today, market=self.market ) market_cap = stock.get_market_cap_by_ticker( self.today, market=self.market ) df = pd.concat([fundamentals, market_cap[["시가총액", "거래량"]]], axis=1) df["name"] = [stock.get_market_ticker_name(t) for t in df.index] return df def screen(self, max_per=15, max_pbr=1.5, min_div=2.0, min_volume=100000): df = self.get_all_data() filtered = df[ (df["PER"] > 0) & (df["PER"] < max_per) & (df["PBR"] > 0) & (df["PBR"] < max_pbr) & (df["DIV"] > min_div) & (df["거래량"] > min_volume) ] return filtered[["name", "PER", "PBR", "DIV", "시가총액", "거래량"]] def export(self, df, filename="screener_results.csv"): df.to_csv(filename, encoding="utf-8-sig") print(f"Saved {len(df)} stocks to {filename}") # Run screener screener = KoreanStockScreener(market="KOSPI") results = screener.screen(max_per=12, max_pbr=1.2, min_div=3.0) print(results.head(20)) screener.export(results) Automating with GitHub Actions Create .github/workflows/screener.yml: ...

June 18, 2026 · 2 min · Phillip

Automate Korean Stock Alerts with GitHub Actions

Overview In this guide, we’ll build a free automated stock alert system that: Runs every day at market open (9 AM KST) Screens Korean stocks using pykrx Sends alerts via Telegram Requires zero server infrastructure (GitHub Actions is free) Prerequisites GitHub account Telegram account Basic Python knowledge Step 1: Create a Telegram Bot Open Telegram and search for @BotFather Send /newbot command Choose a name and username for your bot Save the API token you receive Step 2: Get Your Chat ID Send a message to your new bot Visit: https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates Find your chat_id in the response Step 3: Create the Alert Script # alert.py import requests from pykrx import stock from datetime import datetime import os TELEGRAM_TOKEN = os.environ["TELEGRAM_TOKEN"] TELEGRAM_CHAT_ID = os.environ["TELEGRAM_CHAT_ID"] def send_telegram(message): url = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage" payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "HTML"} requests.post(url, json=payload) def get_top_movers(): today = datetime.now().strftime("%Y%m%d") df = stock.get_market_ohlcv_by_ticker(today, market="KOSPI") df["change_pct"] = (df["종가"] - df["시가"]) / df["시가"] * 100 top_gainers = df.nlargest(5, "change_pct") return top_gainers def main(): movers = get_top_movers() message = "<b>Korean Market Alert - Top Movers Today</b>\n\n" for ticker, row in movers.iterrows(): name = stock.get_market_ticker_name(ticker) message += f"{name} ({ticker}): +{row['change_pct']:.1f}%\n" send_telegram(message) if __name__ == "__main__": main() Step 4: GitHub Actions Workflow Create .github/workflows/alert.yml: ...

June 17, 2026 · 2 min · Phillip

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