新增独立 xiaobai-datahub 服务(SQLite WAL、Tushare 盘后发布、/v1 契约和管理后台),不改现站页面与数据链路。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from datahub.normalize import (
|
|
AMOUNT_THOUSAND_YUAN,
|
|
AMOUNT_WAN_YUAN,
|
|
VOLUME_LOT,
|
|
apply_qfq,
|
|
normalize_auction,
|
|
normalize_daily,
|
|
normalize_index_daily,
|
|
normalize_moneyflow,
|
|
normalize_valuation,
|
|
review_daily_to_canonical,
|
|
)
|
|
from tests.fixtures import RAW
|
|
|
|
|
|
class NormalizeTests(unittest.TestCase):
|
|
def test_daily_matches_architecture_and_review_native_conversion(self) -> None:
|
|
raw = RAW["daily"][0]
|
|
hub = normalize_daily(raw, adj_factor=1.1)
|
|
# review stores Tushare native units; canonical = review * factor
|
|
review_native = dict(raw)
|
|
converted = review_daily_to_canonical(review_native)
|
|
self.assertEqual(hub["amount"], converted["amount"])
|
|
self.assertEqual(hub["amount"], raw["amount"] * AMOUNT_THOUSAND_YUAN)
|
|
self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)
|
|
self.assertEqual(hub["close"], 10.2)
|
|
self.assertEqual(hub["adj_factor"], 1.1)
|
|
self.assertEqual(hub["ts_code"], "600000.SH")
|
|
|
|
def test_moneyflow_wan_to_yuan(self) -> None:
|
|
raw = RAW["moneyflow"][0]
|
|
hub = normalize_moneyflow(raw)
|
|
self.assertEqual(hub["net_mf_amount"], raw["net_mf_amount"] * AMOUNT_WAN_YUAN)
|
|
self.assertEqual(hub["buy_lg_amount"], 30 * AMOUNT_WAN_YUAN)
|
|
|
|
def test_valuation_mv_wan_to_yuan(self) -> None:
|
|
raw = RAW["daily_basic"][0]
|
|
hub = normalize_valuation(raw)
|
|
self.assertEqual(hub["total_mv"], 1000 * AMOUNT_WAN_YUAN)
|
|
self.assertEqual(hub["circ_mv"], 800 * AMOUNT_WAN_YUAN)
|
|
|
|
def test_index_daily_amount_thousand_yuan(self) -> None:
|
|
raw = RAW["index_daily"][0]
|
|
hub = normalize_index_daily(raw)
|
|
self.assertEqual(hub["amount"], raw["amount"] * AMOUNT_THOUSAND_YUAN)
|
|
self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)
|
|
|
|
def test_auction_amount_already_yuan(self) -> None:
|
|
raw = RAW["stk_auction"][0]
|
|
hub = normalize_auction(raw)
|
|
self.assertEqual(hub["amount"], raw["amount"])
|
|
self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)
|
|
|
|
def test_field_diff_against_review_native_is_explained(self) -> None:
|
|
"""Golden: every non-zero diff vs review-native daily is a documented unit factor."""
|
|
raw = RAW["daily"][0]
|
|
hub = normalize_daily(raw)
|
|
diffs = {}
|
|
for key in ("open", "high", "low", "close", "pct_chg"):
|
|
if hub[key] != raw[key]:
|
|
diffs[key] = (raw[key], hub[key])
|
|
self.assertEqual(diffs, {})
|
|
self.assertNotEqual(hub["amount"], raw["amount"])
|
|
self.assertEqual(hub["amount"] / raw["amount"], AMOUNT_THOUSAND_YUAN)
|
|
self.assertEqual(hub["volume"] / raw["vol"], VOLUME_LOT)
|
|
|
|
def test_qfq_formula(self) -> None:
|
|
self.assertEqual(apply_qfq(10.0, 1.1, 2.2), 5.0)
|
|
none_price = apply_qfq(None, 1.1, 2.2)
|
|
self.assertIsNone(none_price)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|