refactor(provider): TET Phase3老接口内部委托Fetcher——①四老方法(get_price/get_closes_panel/get_index_stocks/get_fundamentals_df)旧体删除,改调同款Fetcher(与_ex两张皮,strict契约自此对老接口生效:非法frequency/fq/count/日期/空列表→ValueError,查询失败raise;Phase2副本对照4/4语义等值已验issue#19)②qfq因子二次读库归一:_build_qfq_factor/_apply_qfq_batch拆为_read_qfq_rows+_qfq_factor_from_rows与_read_qfq_events+_apply_qfq_events(IO/纯计算),因子读全挪进extract_data,transform零IO③all_weather四处get_fundamentals_df(choice)补空守卫(空候选集=调用方业务态)④3个宽松断言回归测试改strict(1m频率/空stocks/空symbols);938绿 [vps]
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
Mac 本地 TDD: sqlite tmp_path + tmp parquet fixture,零 VPS 依赖,零网络。
|
||||
覆盖:
|
||||
- ``jq_to_dbbardata`` / ``dbbardata_to_jq`` / ``_jq_to_bs_code`` 代码转换
|
||||
- ``_build_qfq_factor`` 复权因子构造(asof)
|
||||
- ``_build_qfq_factor`` 复权因子构造(asof;Phase 3 拆为 _read_qfq_rows IO + _qfq_factor_from_rows 纯计算)
|
||||
- ``get_price`` dbbardata('d') raw + fq='qfq' 前复权 + panel=False 长表
|
||||
- ``get_index_stocks`` constituent_unified 并集(治偏差,无 date 时点)
|
||||
- ``get_fundamentals_df`` pe/pb/ps/pcf←valuation_baostock + 市值←static akshare + 三表委托 LocalParquetProvider
|
||||
@@ -21,11 +21,17 @@ from sanguo_portfolio.providers.local_unified_provider import (
|
||||
jq_to_dbbardata,
|
||||
dbbardata_to_jq,
|
||||
_jq_to_bs_code,
|
||||
_build_qfq_factor,
|
||||
_read_qfq_rows,
|
||||
_qfq_factor_from_rows,
|
||||
LocalUnifiedProvider,
|
||||
)
|
||||
|
||||
|
||||
def _build_qfq_factor(bs_code, conn, dates):
|
||||
"""Phase 3 拆分后的组合形式(IO 读 + 纯计算),保留原测试调用形状。"""
|
||||
return _qfq_factor_from_rows(_read_qfq_rows(bs_code, conn), dates)
|
||||
|
||||
|
||||
# ======================== Task 0: 代码转换 ========================
|
||||
class TestCodeFormat:
|
||||
def test_jq_to_dbbardata_sh(self):
|
||||
@@ -242,16 +248,16 @@ class TestGetPrice:
|
||||
assert abs(df.iloc[0]["high_limit"] - expected) < 1e-6
|
||||
|
||||
def test_minute_frequency_returns_empty(self, unified_provider):
|
||||
# 1m 频率无数据 → 返空 DataFrame
|
||||
df = unified_provider.get_price(
|
||||
"600519.XSHG",
|
||||
end_date="2024-06-20",
|
||||
frequency="1m",
|
||||
count=1,
|
||||
panel=False,
|
||||
)
|
||||
assert isinstance(df, pd.DataFrame)
|
||||
assert df.empty
|
||||
# Phase 3(2026-08-17)起老接口=Fetcher strict 契约:
|
||||
# 1m 频率 → ValueError fail-fast(老实现静默返空表;15m 走 get_closes_panel)
|
||||
with pytest.raises(ValueError, match="frequency"):
|
||||
unified_provider.get_price(
|
||||
"600519.XSHG",
|
||||
end_date="2024-06-20",
|
||||
frequency="1m",
|
||||
count=1,
|
||||
panel=False,
|
||||
)
|
||||
|
||||
def test_multi_stocks_panel_false(self, tmp_path):
|
||||
# 多股 panel=False → 长表含 code 列区分
|
||||
@@ -469,10 +475,12 @@ class TestGetFundamentals:
|
||||
assert col in df.columns, f"missing col: {col}"
|
||||
|
||||
def test_empty_stocks_returns_empty(self, tmp_path):
|
||||
# Phase 3(2026-08-17)起老接口=Fetcher strict 契约:
|
||||
# 空 stocks → ValueError(老实现返空表);空候选集由调用方守卫(if not choice)
|
||||
db = _make_fundamentals_fixture(tmp_path)
|
||||
p = LocalUnifiedProvider({"db_path": str(db), "data_dir": str(tmp_path)})
|
||||
df = p.get_fundamentals_df([], date="2024-09-30")
|
||||
assert df.empty
|
||||
with pytest.raises(ValueError, match="stocks"):
|
||||
p.get_fundamentals_df([], date="2024-09-30")
|
||||
|
||||
|
||||
# ======================== Task 3b: get_fundamentals_df fields= 按需短路 + 并发 ========================
|
||||
|
||||
@@ -183,10 +183,10 @@ class TestDateRangeAndInterval:
|
||||
# ======================== 4. 空 symbols + dedup ========================
|
||||
class TestEmptyAndDedup:
|
||||
def test_empty_symbols_returns_empty_dataframe(self, batch_provider):
|
||||
df = batch_provider.get_closes_panel([], start="2024-06-18", end="2024-06-20")
|
||||
assert isinstance(df, pd.DataFrame)
|
||||
assert df.empty
|
||||
assert list(df.columns) == []
|
||||
# Phase 3(2026-08-17)起老接口=Fetcher strict 契约:
|
||||
# 空 symbols → ValueError(老实现返空骨架);空候选集由调用方守卫(if not stocks)
|
||||
with pytest.raises(ValueError, match="symbols"):
|
||||
batch_provider.get_closes_panel([], start="2024-06-18", end="2024-06-20")
|
||||
|
||||
def test_duplicate_rows_deduped_keep_last(self, tmp_path):
|
||||
# 同 (symbol, datetime) 两行 close 不同 → dedup keep last
|
||||
|
||||
Reference in New Issue
Block a user