BaoStock
Overview
BaoStock is a free, open-source securities data platform for China A-shares. It provides historical quotes, financial indicators, macroeconomic data, and industry classification through a unified Python API, returning pandas DataFrames.
Key advantages: Free, stable, long history (since 1990), no rate limits or credits required.
Quick Start
Installation
pip install baostock
Basic Usage Pattern
import baostock as bs
import pandas as pd
# 1. Login (required)
lg = bs.login()
# 2. Query data
rs = bs.query_history_k_data_plus(
"sh.600000",
"date,code,open,high,low,close,volume,amount",
start_date="2024-01-01",
end_date="2024-12-31",
frequency="d",
adjustflag="3",
)
# 3. Collect results (pandas 2.0+ compatible)
rows = []
while (rs.error_code == "0") and rs.next():
rows.append(rs.get_row_data())
df = pd.DataFrame(rows, columns=rs.fields)
# 4. Logout
bs.logout()
Stock Code Format
BaoStock uses exchange.code format (note the dot separator):
| Exchange | Prefix | Example | |----------|--------|---------| | Shanghai (SSE) | sh. | sh.600000 (SPDB) | | Shenzhen (SZSE) | sz. | sz.000001 (Ping An Bank) |
Parameter Conventions
- Date:
YYYY-MM-DD(e.g.,2024-12-31) - Stock code:
sh.600000,sz.000001 - Return format: Iterate via
rs.next()+rs.get_row_data(), assemble into DataFrame - All return values are strings: Must manually
pd.to_numeric()for numeric columns
Complete API Reference
I. Market Data
1. Historical K-line: query_history_k_data_plus()
The most important API — supports daily/weekly/monthly/minute bars with adjustment.
rs = bs.query_history_k_data_plus(
code="sh.600000", # Stock code
fields="date,code,...", # Return fields (comma-separated)
start_date="2024-01-01",# Start date, default 2015-01-01
end_date="2024-12-31", # End date, default latest trading day
frequency="d", # Frequency
adjustflag="3", # Adjustment type
)
frequency values:
| Value | Frequency | Notes | |-------|-----------|-------| | "d" | Daily | Default | | "w" | Weekly | | | "m" | Monthly | | | "5" | 5-minute | Index does not support minute bars | | "15" | 15-minute | | | "30" | 30-minute | | | "60" | 60-minute | |
adjustflag values:
| Value | Meaning | Method | |-------|---------|--------| | "3" | Unadjusted | Default | | "1" | Backward adjusted | Percentage change method | | "2" | Forward adjusted | Percentage change method |
Note: BaoStock uses the "percentage change adjustment method", which differs from other platforms (e.g., Tongdaxin).
Daily/Weekly/Monthly fields:
| Field | Description | Type | |-------|-------------|------| | date | Trading date | str | | code | Stock code | str | | open | Open price | str→float | | high | High price | str→float | | low | Low price | str→float | | close | Close price | str→float | | preclose | Previous close | str→float | | volume | Volume (shares) | str→float | | amount | Amount (CNY) | str→float | | adjustflag | Adjustment flag | str | | turn | Turnover rate (%) | str→float, empty string when suspended | | tradestatus | Trading status | str, "1"=normal, "0"=suspended | | pctChg | Price change (%) | str→float | | peTTM | PE ratio (TTM) | str→float | | pbMRQ | PB ratio (MRQ) | str→float | | psTTM | PS ratio (TTM) | str→float | | pcfNcfTTM | PCF ratio (TTM) | str→float | | isST | Is ST stock | str, "1"=yes, "0"=no |
Minute bar fields:
| Field | Description | |-------|-------------| | date | Date | | time | Time (format YYYYMMDDHHmmssSSS) | | code | Stock code | | open | Open price | | high | High price | | low | Low price | | close | Close price | | volume | Volume | | amount | Amount | | adjustflag | Adjustment flag |
Minute bars do not include index data or valuation metrics (peTTM, etc.).
2. Index K-line
Uses the same query_history_k_data_plus() API with index codes:
| Index | Code | |-------|------| | SSE Composite | sh.000001 | | SZSE Component | sz.399001 | | CSI 300 | sh.000300 | | CSI 500 | sh.000905 | | ChiNext Index | sz.399006 |
Index does not support minute bars, only daily/weekly/monthly.
3. All Securities on Date: query_all_stock()
rs = bs.query_all_stock(day="2024-12-31")
# Returns: code, tradeStatus columns
II. Basic Information
4. Stock Basic Info: query_stock_basic()
rs = bs.query_stock_basic(code="sh.600000") # Single stock
rs = bs.query_stock_basic() # All stocks
Returns: code, code_name, ipoDate, outDate, type (1=stock, 2=index, 3=other, 4=convertible bond, 5=ETF), status (1=listed, 0=delisted)
5. Industry Classification: query_stock_industry()
rs = bs.query_stock_industry(date="2024-12-31") # Specific date
rs = bs.query_stock_industry() # Latest
Returns: updateDate, code, code_name, industry, industryClassification
Uses CSRC industry classification standard.
6. SSE 50 Constituents: query_sz50_stocks()
rs = bs.query_sz50_stocks(date="2024-12-31")
Returns: updateDate, code, code_name
7. CSI 300 Constituents: query_hs300_stocks()
rs = bs.query_hs300_stocks(date="2024-12-31")
8. CSI 500 Constituents: query_zz500_stocks()
rs = bs.query_zz500_stocks(date="2024-12-31")
III. Dividends & Adjustment
9. Dividend Information: query_dividend_data()
rs = bs.query_dividend_data(
code="sh.600000",
year="2024",
yearType="report", # "report"=announcement year, "operate"=ex-dividend year
)
Returns:
| Field | Description | |-------|-------------| | dividPreNoticeDate | Pre-notice date | | dividAgmPumDate | AGM announcement date | | dividPlanAnnounceDate | Plan announcement date | | dividPlanDate | Implementation announcement date | | dividRegistDate | Record date | | dividOperateDate | Ex-dividend date | | dividPayDate | Payment date | | dividStockMarketDate | Stock listing date | | dividCashPsBeforeTax | Cash dividend per share (before tax) | | dividCashPsAfterTax | Cash dividend per share (after tax) | | dividStocksPs | Stock dividend per share | | dividCashStock | Dividend & transfer info | | dividReserveToStockPs | Reserve to stock per share |
10. Adjustment Factor: query_adjust_factor()
rs = bs.query_adjust_factor(
code="sh.600000",
start_date="2015-01-01",
end_date="2024-12-31",
)
Returns: code, dividOperateDate, foreAdjustFactor, backAdjustFactor, adjustFactor
IV. Quarterly Financial Data
All quarterly APIs share the same parameters:
rs = bs.query_xxx_data(code="sh.600000", year=2024, quarter=2)
code: Stock codeyear: Fiscal year (int)quarter: Quarter (1/2/3/4)
11. Profitability: query_profit_data()
Returns:
| Field | Description | |-------|-------------| | code | Stock code | | pubDate | Publication date | | statDate | Statistics end date | | roeAvg | ROE (average, %) | | npMargin | Net profit margin (%) | | gpMargin | Gross profit margin (%) | | netProfit | Net profit (CNY) | | epsTTM | Earnings per share | | MBRevenue | Main business revenue (CNY) | | totalShare | Total shares | | liqaShare | Tradable shares |
12. Operating Efficiency: query_operation_data()
Returns: NRTurnRatio (receivables turnover), NRTurnDays, INVTurnRatio (inventory turnover), INVTurnDays, CATurnRatio (current asset turnover), AssetTurnRatio (total asset turnover)
13. Growth: query_growth_data()
Returns: YOYEquity (equity YoY), YOYAsset (asset YoY), YOYNI (net income YoY), YOYEPSBasic (basic EPS YoY), YOYPNI (net income attributable to pare