diff --git a/tests/fixtures/real_sh688001.day b/tests/fixtures/real_sh688001.day new file mode 100644 index 0000000..adaf522 Binary files /dev/null and b/tests/fixtures/real_sh688001.day differ diff --git a/tests/fixtures/real_sz000001.day b/tests/fixtures/real_sz000001.day new file mode 100644 index 0000000..53b778f Binary files /dev/null and b/tests/fixtures/real_sz000001.day differ diff --git a/tests/fixtures/real_sz000001.lc5 b/tests/fixtures/real_sz000001.lc5 new file mode 100644 index 0000000..e6e4889 Binary files /dev/null and b/tests/fixtures/real_sz000001.lc5 differ diff --git a/tests/test_reader.py b/tests/test_reader.py index 03d326c..b188635 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -65,6 +65,55 @@ def test_missing_file_raises(self, tdx_reader): tdx_reader.read_daily_data(0, 'sz999999') +@pytest.fixture +def real_tdx_reader(tmp_path): + """真实文件切片(dd bs=32 count=3 自实际 vipdoc,2026-07-07)—— + 防合成 fixture 与解析器共享同一格式误解""" + for market, sub, src, dst in [ + ('sz', 'lday', 'real_sz000001.day', 'sz000001.day'), + ('sh', 'lday', 'real_sh688001.day', 'sh688001.day'), + ('sz', 'fzline', 'real_sz000001.lc5', 'sz000001.lc5'), + ]: + d = tmp_path / 'vipdoc' / market / sub + d.mkdir(parents=True, exist_ok=True) + shutil.copy(FIXTURES / src, d / dst) + return TdxDataReader(tdx_path=str(tmp_path)) + + +class TestRealFileSlices: + """断言值为真实文件的观测值(历史数据永不变化,天然稳定)""" + + def test_sz000001_1991_head(self, real_tdx_reader): + df = real_tdx_reader.read_daily_data(0, 'sz000001') + assert list(df.index.strftime('%Y-%m-%d')) == ['1991-04-03', '1991-04-04', '1991-04-05'] + assert df.iloc[0]['close'] == pytest.approx(49.00, abs=1e-9) + assert df.iloc[1]['close'] == pytest.approx(48.76, abs=1e-9) + assert df.iloc[0]['amount'] == 5000.0 + assert df.iloc[0]['volume'] == 1.0 + + def test_sh688001_2019_head_via_fallback(self, real_tdx_reader): + """688001 华兴源创(科创板第一股)上市首日起 3 条,走 raw 回退路径""" + df = real_tdx_reader.read_daily_data(1, 'sh688001') + assert list(df.index.strftime('%Y-%m-%d')) == ['2019-07-22', '2019-07-23', '2019-07-24'] + first = df.iloc[0] + assert first['open'] == pytest.approx(55.40, abs=1e-9) + assert first['high'] == pytest.approx(72.02, abs=1e-9) + assert first['low'] == pytest.approx(39.59, abs=1e-9) + assert first['close'] == pytest.approx(55.50, abs=1e-9) + assert first['amount'] == pytest.approx(1.507398e9, rel=1e-6) # float32 精度 + assert first['volume'] == pytest.approx(290107.54, rel=1e-6) + + def test_lc5_real_head(self, real_tdx_reader): + df = real_tdx_reader.read_5min_data(0, 'sz000001') + assert list(df['datetime'].dt.strftime('%Y-%m-%d %H:%M')) == [ + '2025-01-21 09:35', '2025-01-21 09:40', '2025-01-21 09:45', + ] + first = df.iloc[0] + assert first['open'] == pytest.approx(11.45, abs=1e-5) # float32 + assert first['close'] == pytest.approx(11.38, abs=1e-5) + assert first['volume'] == 9444100 + + class TestLc5Parsing: def test_fivemin_records(self, tdx_reader): df = tdx_reader.read_5min_data(0, 'sz000001')