mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 16:44:15 +08:00
test_history_strategy_monitor_keeps_live_row_with_exclude_st_enabled used date(2026,7,20) as the "today" value, but MonitorRuleEngine.evaluate() calls cn_today() internally. The date mismatch caused the basic_filter + history filter to produce 0 rows, making the test fail 8 days after it was written. Also fixes test_live_enriched_cache_keeps_instrument_metadata_without_persisting_it which used the same hardcoded date — would break on any future run. Replace all hardcoded dates with cn_today() / cn_today()-timedelta(days=3) so the tests are timeless.
105 lines
3.3 KiB
Python
105 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import timedelta
|
|
from pathlib import Path
|
|
|
|
import polars as pl
|
|
|
|
from app.market_time import cn_today
|
|
from app.strategy.engine import StrategyEngine
|
|
from app.strategy.monitor import MonitorRuleEngine
|
|
from app.tickflow.repository import DataStore, KlineRepository
|
|
|
|
|
|
def _repo(tmp_path) -> KlineRepository:
|
|
repo = KlineRepository(DataStore(tmp_path))
|
|
repo._instruments_cache = pl.DataFrame({
|
|
"symbol": ["600000.SH", "000001.SZ"],
|
|
"name": ["浦发银行", "平安银行"],
|
|
"total_shares": [29_352_080_397.0, 19_405_918_198.0],
|
|
"float_shares": [29_352_080_397.0, 19_405_918_198.0],
|
|
})
|
|
return repo
|
|
|
|
|
|
def _live_row(symbol: str, close: float) -> pl.DataFrame:
|
|
return pl.DataFrame({
|
|
"symbol": [symbol],
|
|
"date": [cn_today()],
|
|
"open": [close],
|
|
"high": [close],
|
|
"low": [close],
|
|
"close": [close],
|
|
"volume": [1000.0],
|
|
"amount": [close * 1000.0],
|
|
"raw_close": [close],
|
|
"raw_high": [close],
|
|
"raw_low": [close],
|
|
})
|
|
|
|
|
|
def test_live_enriched_cache_keeps_instrument_metadata_without_persisting_it(tmp_path):
|
|
repo = _repo(tmp_path)
|
|
|
|
repo.flush_live_enriched_asset("stock", _live_row("600000.SH", 10.0))
|
|
repo.merge_live_enriched_asset("stock", _live_row("000001.SZ", 12.0))
|
|
|
|
cached, cached_date = repo.get_enriched_latest()
|
|
assert cached_date == cn_today()
|
|
assert cached.select("symbol", "name").sort("symbol").to_dicts() == [
|
|
{"symbol": "000001.SZ", "name": "平安银行"},
|
|
{"symbol": "600000.SH", "name": "浦发银行"},
|
|
]
|
|
assert cached["total_shares"].null_count() == 0
|
|
assert cached["float_shares"].null_count() == 0
|
|
|
|
persisted = pl.read_parquet(
|
|
tmp_path / "kline_daily_enriched" / f"date={cn_today().isoformat()}" / "part.parquet"
|
|
)
|
|
assert "name" not in persisted.columns
|
|
assert "total_shares" not in persisted.columns
|
|
assert "float_shares" not in persisted.columns
|
|
|
|
|
|
def test_history_strategy_monitor_keeps_live_row_with_exclude_st_enabled(tmp_path):
|
|
strategy_dir = tmp_path / "strategies"
|
|
strategy_dir.mkdir()
|
|
(strategy_dir / "history_strategy.py").write_text(
|
|
"""import polars as pl
|
|
|
|
META = {
|
|
"id": "history_strategy",
|
|
"name": "历史策略",
|
|
"basic_filter": {"exclude_st": True},
|
|
}
|
|
LOOKBACK_DAYS = 2
|
|
|
|
def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame:
|
|
return df
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
repo = _repo(tmp_path / "data")
|
|
live = _live_row("600000.SH", 10.0).with_columns(
|
|
pl.lit(30_000_000.0).alias("amount")
|
|
)
|
|
repo.flush_live_enriched_asset("stock", live)
|
|
current, _ = repo.get_enriched_latest()
|
|
history = current.with_columns(pl.lit(cn_today() - timedelta(days=3)).alias("date"))
|
|
|
|
monitor = MonitorRuleEngine()
|
|
monitor.set_strategy_engine(StrategyEngine([Path(strategy_dir)]))
|
|
monitor.set_history_loader(lambda _as_of, _lookback: history)
|
|
monitor.set_rules([{
|
|
"id": "history_strategy_monitor",
|
|
"name": "历史策略监控",
|
|
"type": "strategy",
|
|
"asset_type": "stock",
|
|
"strategy_id": "history_strategy",
|
|
"scope": "all",
|
|
}])
|
|
|
|
monitor.evaluate(current)
|
|
|
|
assert monitor.latest_strategy_results()["history_strategy"]["total"] == 1
|