Introduction
pykrx is the easiest way to get Korean stock market data in Python. No API key needed, no account required — just install and start pulling data.
This guide covers 10 real-world examples from basic price data to advanced screening.
Setup
pip install pykrx pandas
from pykrx import stock
import pandas as pd
from datetime import datetime, timedelta
# Helper: today's date
TODAY = datetime.now().strftime("%Y%m%d")
MONTH_AGO = (datetime.now() - timedelta(days=30)).strftime("%Y%m%d")
YEAR_AGO = (datetime.now() - timedelta(days=365)).strftime("%Y%m%d")
Example 1: Get Stock Price History
from pykrx import stock
# Samsung Electronics (005930)
df = stock.get_market_ohlcv_by_date("20240101", "20241231", "005930")
df.columns = ["Open", "High", "Low", "Close", "Volume"]
print(df.tail())
Example 2: Get All KOSPI Tickers
from pykrx import stock
kospi = stock.get_market_ticker_list(market="KOSPI")
kosdaq = stock.get_market_ticker_list(market="KOSDAQ")
print(f"KOSPI stocks: {len(kospi)}")
print(f"KOSDAQ stocks: {len(kosdaq)}")
# Get company name
name = stock.get_market_ticker_name("005930")
print(f"005930 = {name}") # 삼성전자
Example 3: Market Cap Rankings
from pykrx import stock
# Top 10 KOSPI by market cap
df = stock.get_market_cap_by_ticker(TODAY, market="KOSPI")
top10 = df.sort_values("시가총액", ascending=False).head(10)
for ticker, row in top10.iterrows():
name = stock.get_market_ticker_name(ticker)
market_cap_trillion = row["시가총액"] / 1e12
print(f"{name}: {market_cap_trillion:.1f}T KRW")
Example 4: Fundamental Data (PER, PBR, Dividend)
from pykrx import stock
# Get fundamentals for all KOSPI stocks
df = stock.get_market_fundamental_by_ticker(TODAY, market="KOSPI")
# Find undervalued stocks (low PER, low PBR)
undervalued = df[
(df["PER"] > 0) & (df["PER"] < 10) &
(df["PBR"] > 0) & (df["PBR"] < 1.0)
].copy()
undervalued["name"] = [stock.get_market_ticker_name(t) for t in undervalued.index]
print(undervalued[["name", "PER", "PBR", "DIV"]].sort_values("PER").head(10))
Example 5: KOSPI Index Data
from pykrx import stock
# Get KOSPI index history
# "1001" = KOSPI, "2001" = KOSDAQ
kospi_index = stock.get_index_ohlcv_by_date("20240101", "20241231", "1001")
print(kospi_index.tail())
# Year high/low
print(f"2024 KOSPI High: {kospi_index['고가'].max():,}")
print(f"2024 KOSPI Low: {kospi_index['저가'].min():,}")
Example 6: Foreign Investor Trading Data
from pykrx import stock
# Foreign net buying/selling for Samsung
df = stock.get_market_trading_volume_by_date(
"20240101", "20241231", "005930"
)
print(df.tail())
# Days with heavy foreign buying
foreign_buying = df[df["외국인"] > 1000000]
print(f"Heavy foreign buying days: {len(foreign_buying)}")
Example 7: Sector Performance
from pykrx import stock
# Get sector (theme) data
# Major KOSPI sector tickers
sectors = {
"1001": "KOSPI",
"1028": "KOSPI200",
"2001": "KOSDAQ",
"1163": "KOSPI IT",
"1150": "KOSPI Finance"
}
for code, name in sectors.items():
df = stock.get_index_ohlcv_by_date(MONTH_AGO, TODAY, code)
if not df.empty:
start = df["종가"].iloc[0]
end = df["종가"].iloc[-1]
change = (end - start) / start * 100
print(f"{name}: {change:+.2f}%")
Example 8: Volume Surge Detector
from pykrx import stock
import pandas as pd
def find_volume_surges(market="KOSPI", multiplier=3.0):
"""Find stocks with volume 3x above their 20-day average"""
tickers = stock.get_market_ticker_list(market=market)
surges = []
for ticker in tickers[:50]: # Limit for demo
try:
df = stock.get_market_ohlcv_by_date(MONTH_AGO, TODAY, ticker)
if len(df) < 20:
continue
avg_vol = df["거래량"].iloc[:-1].mean()
today_vol = df["거래량"].iloc[-1]
if today_vol > avg_vol * multiplier:
name = stock.get_market_ticker_name(ticker)
surges.append({
"ticker": ticker,
"name": name,
"volume_ratio": today_vol / avg_vol,
"close": df["종가"].iloc[-1]
})
except:
continue
return sorted(surges, key=lambda x: x["volume_ratio"], reverse=True)
surges = find_volume_surges()
for s in surges[:5]:
print(f"{s['name']}: {s['volume_ratio']:.1f}x average volume")
Example 9: Simple Backtesting
from pykrx import stock
import pandas as pd
def backtest_moving_average(ticker, short=5, long=20):
"""Simple moving average crossover backtest"""
df = stock.get_market_ohlcv_by_date("20230101", "20241231", ticker)
df.columns = ["Open", "High", "Low", "Close", "Volume"]
df[f"MA{short}"] = df["Close"].rolling(short).mean()
df[f"MA{long}"] = df["Close"].rolling(long).mean()
# Signal: 1 = buy, -1 = sell
df["signal"] = 0
df.loc[df[f"MA{short}"] > df[f"MA{long}"], "signal"] = 1
df.loc[df[f"MA{short}"] < df[f"MA{long}"], "signal"] = -1
# Returns
df["returns"] = df["Close"].pct_change()
df["strategy"] = df["signal"].shift(1) * df["returns"]
total_return = (1 + df["strategy"].dropna()).prod() - 1
buy_hold = (df["Close"].iloc[-1] - df["Close"].iloc[0]) / df["Close"].iloc[0]
print(f"Strategy return: {total_return:.2%}")
print(f"Buy & hold return: {buy_hold:.2%}")
return df
result = backtest_moving_average("005930")
Example 10: Export to Excel
from pykrx import stock
import pandas as pd
# Get data for multiple stocks
watchlist = {
"005930": "Samsung Electronics",
"000660": "SK Hynix",
"373220": "LG Energy Solution",
"005380": "Hyundai Motor",
"035420": "NAVER"
}
with pd.ExcelWriter("korean_stocks.xlsx") as writer:
for ticker, name in watchlist.items():
df = stock.get_market_ohlcv_by_date("20240101", "20241231", ticker)
df.columns = ["Open", "High", "Low", "Close", "Volume"]
df.to_excel(writer, sheet_name=name[:30])
print(f"Saved {name}")
print("Excel file created: korean_stocks.xlsx")
Common Mistakes
| Mistake | Fix |
|---|---|
Date with dashes "2024-01-01" | Remove dashes: "20240101" |
| Using company name as ticker | Use 6-digit number: "005930" |
| Calling too frequently | Add time.sleep(0.5) between calls |
| Empty result on weekends | KRX is closed Sat/Sun |
Key Takeaways
- pykrx is free and requires no API key
- Date format is always
YYYYMMDD - Column names default to Korean — rename for easier use
- Add delays between multiple API calls to avoid rate limiting
- For real-time data and trading, use KIS API instead