feat: enrich daily bar schema with valuation/status fields + VWAP
Batch download now pulls baostock's preclose, turn, pctChg, tradestatus, isST, and peTTM/pbMRQ/psTTM/pcfNcfTTM on top of OHLCV+amount, plus a derived daily VWAP (amount/volume). VWAP is raw-price scale and not comparable with adjusted OHLC under qfq/hfq — documented in the schema. Richer fields live only in the batch path (download_daily_batch -> download_universe); single-symbol download_daily keeps the legacy 8-column schema that test_downloader.py pins. Also flags intraday/L1-L2 microstructure data as a future phase in the README roadmap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+27
-6
@@ -9,8 +9,27 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Map the adjust argument to baostock's adjustflag codes.
|
||||
_BAOSTOCK_ADJUST = {"qfq": "2", "hfq": "1", "": "3", "none": "3"}
|
||||
_BAOSTOCK_FIELDS = "date,open,high,low,close,volume,amount"
|
||||
_OHLCV = ["open", "high", "low", "close", "volume", "amount"]
|
||||
|
||||
# Richer field set requested by the batch downloader. On top of OHLCV+amount we
|
||||
# pull baostock's preclose, turnover rate, daily % change, trade/ST status, and
|
||||
# the four valuation ratios, then derive a daily VWAP (amount / volume).
|
||||
_BATCH_FIELDS = (
|
||||
"date,open,high,low,close,preclose,volume,amount,turn,pctChg,"
|
||||
"tradestatus,isST,peTTM,pbMRQ,psTTM,pcfNcfTTM"
|
||||
)
|
||||
# Every batch field except ``date`` is numeric (flags included: 0/1 strings).
|
||||
_BATCH_NUMERIC = [
|
||||
"open", "high", "low", "close", "preclose", "volume", "amount",
|
||||
"turn", "pctChg", "tradestatus", "isST",
|
||||
"peTTM", "pbMRQ", "psTTM", "pcfNcfTTM",
|
||||
]
|
||||
# Output column order; ``vwap`` is derived (inserted right after ``amount``).
|
||||
_BATCH_COLUMNS = [
|
||||
"symbol", "date",
|
||||
"open", "high", "low", "close", "preclose", "volume", "amount", "vwap",
|
||||
"turn", "pctChg", "tradestatus", "isST",
|
||||
"peTTM", "pbMRQ", "psTTM", "pcfNcfTTM",
|
||||
]
|
||||
|
||||
|
||||
class _SessionLost(Exception):
|
||||
@@ -163,7 +182,7 @@ def download_daily_batch(
|
||||
"""One baostock query; returns df, or None (no data), or raises _SessionLost."""
|
||||
code = f"{symbol[:2]}.{symbol[2:]}"
|
||||
rs = bs.query_history_k_data_plus(
|
||||
code=code, fields=_BAOSTOCK_FIELDS,
|
||||
code=code, fields=_BATCH_FIELDS,
|
||||
start_date=start, end_date=end, frequency="d", adjustflag=flag,
|
||||
)
|
||||
if rs.error_code != "0":
|
||||
@@ -176,12 +195,14 @@ def download_daily_batch(
|
||||
rows.append(rs.get_row_data())
|
||||
if not rows:
|
||||
return None
|
||||
df = pd.DataFrame(rows, columns=["date", *_OHLCV])
|
||||
df = pd.DataFrame(rows, columns=["date", *_BATCH_NUMERIC])
|
||||
# Suspended-trading days come back as empty strings; coerce to NaN
|
||||
# rather than crashing the whole symbol.
|
||||
df[_OHLCV] = df[_OHLCV].apply(pd.to_numeric, errors="coerce")
|
||||
df[_BATCH_NUMERIC] = df[_BATCH_NUMERIC].apply(pd.to_numeric, errors="coerce")
|
||||
# Daily VWAP = turnover (yuan) / shares; NaN when no volume (suspended).
|
||||
df["vwap"] = (df["amount"] / df["volume"]).where(df["volume"] > 0)
|
||||
df["symbol"] = symbol
|
||||
return df[["symbol", "date", *_OHLCV]]
|
||||
return df[_BATCH_COLUMNS]
|
||||
|
||||
bs.login()
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user