| name | baostock |
| description | Free China A-share data platform — supports K-line, financial data, and industry classification queries with no registration required. |
| homepage | https://www.baostock.com |
BaoStock (Free China A-Share Data Platform)
BaoStock is a free, open-source data platform for China A-share securities. No registration or API key is required, and it returns pandas.DataFrame.
Installation
pip install baostock --upgrade
Verify the installation:
python3 -c "import baostock as bs; lg = bs.login(); print(lg.error_msg); bs.logout()"
Expected output: login success!.
Basic Usage
Each session must begin with bs.login() and end with bs.logout():
import baostock as bs
import pandas as pd
lg = bs.login()
bs.logout()
Use .get_data() to retrieve the DataFrame from query results:
rs = bs.query_all_stock()
df = rs.get_data()
Core API
1. query_all_stock — Get All Securities List
Retrieves all stock/index codes for a specified trading day.
rs = bs.query_all_stock(day="2024-01-02")
df = rs.get_data()
- day — Date string
YYYY-MM-DD (default: today). Returns an empty DataFrame on non-trading days.
2. query_history_k_data_plus — K-Line Data
Retrieves historical K-line data (OHLCV + indicators).
rs = bs.query_history_k_data_plus(
"sh.601398",
"date,code,open,high,low,close,volume,amount,pctChg",
start_date="2024-01-01",
end_date="2024-06-30",
frequency="d",
adjustflag="3"
)
df = rs.get_data()
Parameters:
- code — Stock code, format
sh.600000 or sz.000001
- fields — Comma-separated field names (see below)
- start_date / end_date —
YYYY-MM-DD format
- frequency —
d (daily), w (weekly), m (monthly), 5/15/30/60 (minute). Indices have no minute-level data.
- adjustflag —
1 (forward adjustment), 2 (backward adjustment), 3 (no adjustment, default)
Available fields for daily data:
date (date), code (securities code), open (open price), high (high price), low (low price), close (close price), preclose (previous close price), volume (volume), amount (turnover), adjustflag (adjustment flag), turn (turnover rate), tradestatus (trading status), pctChg (percent change), peTTM (trailing P/E ratio), pbMRQ (P/B ratio), psTTM (trailing P/S ratio), pcfNcfTTM (trailing P/CF ratio), isST (is ST stock)
Available fields for minute data:
date (date), time (time), code (securities code), open (open price), high (high price), low (low price), close (close price), volume (volume), amount (turnover), adjustflag (adjustment flag)
3. query_trade_dates — Trading Calendar
rs = bs.query_trade_dates(start_date="2024-01-01", end_date="2024-12-31")
df = rs.get_data()
4. query_stock_industry — Industry Classification
rs = bs.query_stock_industry()
df = rs.get_data()
5. query_stock_basic — Stock Basic Information
rs = bs.query_stock_basic(code="sh.601398")
df = rs.get_data()
- type —
1 stock, 2 index, 3 other
- status —
1 listed, 0 delisted
6. query_dividend_data — Dividend Information
rs = bs.query_dividend_data(code="sh.601398", year="2023", yearType="report")
df = rs.get_data()
- yearType —
report (reporting period) or operate (implementation period)
7. Financial Data (Quarterly)
Profitability
rs = bs.query_profit_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
Operational Efficiency
rs = bs.query_operation_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
Growth Capability
rs = bs.query_growth_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
Solvency
rs = bs.query_balance_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
Cash Flow
rs = bs.query_cash_flow_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
DuPont Analysis
rs = bs.query_dupont_data(code="sh.601398", year=2023, quarter=4)
df = rs.get_data()
8. Index Data
Index Constituent Stocks
rs = bs.query_hs300_stocks()
df = rs.get_data()
rs = bs.query_sz50_stocks()
df = rs.get_data()
rs = bs.query_zz500_stocks()
df = rs.get_data()
Full Example: Download Daily K-Line Data and Save as CSV
import baostock as bs
import pandas as pd
bs.login()
rs = bs.query_history_k_data_plus(
"sh.600519",
"date,code,open,high,low,close,volume,amount,pctChg,peTTM",
start_date="2024-01-01",
end_date="2024-12-31",
frequency="d",
adjustflag="2"
)
df = rs.get_data()
df.to_csv("kweichow_moutai_2024.csv", index=False)
print(df.head())
bs.logout()
Stock Code Format
- Shanghai:
sh.600000, sh.601398
- Shenzhen:
sz.000001, sz.300750
- Beijing:
bj.430047
- Indices:
sh.000001 (SSE Composite Index), sh.000300 (CSI 300)
Usage Tips
- No registration or API key required — just call
bs.login() to get started.
- Sessions may time out after prolonged inactivity — simply call
bs.login() again.
- Not thread-safe — for parallel downloads, use
multiprocessing (multi-process), not threading (multi-thread).
- Data coverage: A-shares from 1990 to present.
- Financial data is provided quarterly, with approximately a 2-month delay after the reporting period ends.
- Documentation: http://baostock.com/baostock/index.php/Python_API%E6%96%87%E6%A1%A3
Advanced Examples
Batch Download Data for Multiple Stocks
import baostock as bs
import pandas as pd
bs.login()
stock_list = ["sh.600519", "sh.601398", "sz.000001", "sz.300750", "sh.601318"]
all_data = []
for code in stock_list:
rs = bs.query_history_k_data_plus(
code,
"date,code,open,high,low,close,volume,amount,pctChg,turn,peTTM,pbMRQ",
start_date="2024-01-01",
end_date="2024-06-30",
frequency="d",
adjustflag="1"
)
df = rs.get_data()
all_data.append(df)
print(f"Downloaded {code}, {len(df)} records")
combined = pd.concat(all_data, ignore_index=True)
combined.to_csv("multi_stock_baostock.csv", index=False)
print(f"Total merged records: {len(combined)}")
bs.logout()
Get Full Market Stock List and Filter
import baostock as bs
import pandas as pd
bs.login()
rs = bs.query_all_stock(day="2024-06-28")
df = rs.get_data()
stocks = df[df["tradeStatus"] == "1"]
sh_stocks = stocks[stocks["code"].str.startswith("sh.6")]
print(f"Shanghai A-shares: {len(sh_stocks)} stocks")
sz_main = stocks[stocks["code"].str.startswith("sz.00")]
print(f"Shenzhen main board: {len(sz_main)} stocks")
gem = stocks[stocks["code"].str.startswith("sz.30")]
print(f"ChiNext board: {len(gem)} stocks")
bs.logout()
Calculate Technical Indicators
import baostock as bs
import pandas as pd
import numpy as np
bs.login()
rs = bs.query_history_k_data_plus(
"sz.000001",
"date,close,volume",
start_date="2024-01-01",
end_date="2024-12-31",
frequency="d",
adjustflag="1"
)
df = rs.get_data()
df["close"] = df["close"].astype(float)
df["volume"] = df["volume"].astype(float)
df["MA5"] = df["close"].rolling(5).mean()
df["MA10"] = df["close"].rolling(10).mean()
df["MA20"] = df["close"].rolling(20).mean()
ema12 = df["close"].ewm(span=12, adjust=False).mean()
ema26 = df["close"].ewm(span=26, adjust=False).mean()
df["DIF"] = ema12 - ema26
df["DEA"] = df["DIF"].ewm(span=9, adjust=False).mean()
df["MACD"] = 2 * (df["DIF"] - df["DEA"])
df["VOL_MA5"] = df["volume"].rolling(5).mean()
df[] = df[].rolling().mean()
df[] =
df.loc[(df[] > df[]) & (df[].shift() <= df[].shift()), ] =
df.loc[(df[] < df[]) & (df[].shift() >= df[].shift()), ] = -
golden_cross = df[df[] == ]
death_cross = df[df[] == -]
()
(, golden_cross[].tolist())
bs.logout()
Get CSI 300 Constituent Stocks and Download Data
import baostock as bs
import pandas as pd
bs.login()
rs = bs.query_hs300_stocks()
hs300 = rs.get_data()
print(f"CSI 300 has {len(hs300)} constituent stocks")
for _, row in hs300.head(10).iterrows():
code = row["code"]
name = row["code_name"]
rs = bs.query_history_k_data_plus(
code,
"date,code,close,pctChg,turn",
start_date="2024-06-01",
end_date="2024-06-30",
frequency="d",
adjustflag="1"
)
df = rs.get_data()
print(f"{name}({code}): {len(df)} records")
bs.logout()
Get Financial Data and Analyze
import baostock as bs
import pandas as pd
bs.login()
bank_codes = ["sh.601398", "sh.601939", "sh.601288", "sh.600036", "sh.601166"]
profit_data = []
for code in bank_codes:
rs = bs.query_profit_data(code=code, year=2023, quarter=4)
df = rs.get_data()
if not df.empty:
profit_data.append(df.iloc[0])
profit_df = pd.DataFrame(profit_data)
print(profit_df[["code", "roeAvg", "npMargin", "gpMargin"]])
growth_data = []
for code in bank_codes:
rs = bs.query_growth_data(code=code, year=2023, quarter=4)
df = rs.get_data()
if not df.empty:
growth_data.append(df.iloc[0])
growth_df = pd.DataFrame(growth_data)
print(growth_df[["code", "YOYEquity", "YOYAsset", "YOYNI"]])
bs.logout()
Full Example: Simple Backtesting Framework
import baostock as bs
import pandas as pd
import numpy as np
bs.login()
rs = bs.query_history_k_data_plus(
"sz.000001",
"date,open,high,low,close,volume",
start_date="2023-01-01",
end_date="2023-12-31",
frequency="d",
adjustflag="1"
)
df = rs.get_data()
for col in ["open", "high", "low", "close", "volume"]:
df[col] = df[col].astype(float)
df["MA5"] = df["close"].rolling(5).mean()
df["MA20"] = df["close"].rolling(20).mean()
initial_cash = 100000
cash = initial_cash
shares = 0
trades = []
for i in range(20, len(df)):
if df["MA5"].iloc[i] > df["MA20"].iloc[i] and df["MA5"].iloc[i-1] <= df["MA20"].iloc[i-1]:
if cash > :
buy_price = df[].iloc[i]
shares = (cash / buy_price / ) *
cost = shares * buy_price
cash -= cost
trades.append({: df[].iloc[i], : ,
: buy_price, : shares, : cash})
df[].iloc[i] < df[].iloc[i] df[].iloc[i-] >= df[].iloc[i-]:
shares > :
sell_price = df[].iloc[i]
cash += shares * sell_price
trades.append({: df[].iloc[i], : ,
: sell_price, : shares, : cash})
shares =
final_value = cash + shares * df[].iloc[-]
total_return = (final_value - initial_cash) / initial_cash *
()
()
()
()
t trades:
()
bs.logout()
社区与支持
由 大佬量化 (Boss Quant) 维护 — 量化交易教学与策略研发团队。
微信客服: bossquant1 · Bilibili · 搜索 大佬量化 on 微信公众号 / Bilibili / 抖音