diff --git a/pyproject.toml b/pyproject.toml index 8060e5d..5920541 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10" dependencies = [ "pyarrow>=14.0", "jsonschema>=4.20", - "quant-data-kit @ git+https://github.com/PureSaber/quant-data-kit.git@3b1684dfb1ecddd0c7df95f1fbac9b21119e9f55", + "quant-data-kit @ git+https://github.com/PureSaber/quant-data-kit.git@ab17ee7b8c417aa72a9707106f5455beba965b76", ] [project.optional-dependencies] diff --git a/requirements.lock b/requirements.lock index d68bab4..382e96e 100644 --- a/requirements.lock +++ b/requirements.lock @@ -69,7 +69,7 @@ pytz==2026.3.post1 # via pandas pyyaml==6.0.3 # via quant-data-kit -quant-data-kit @ git+https://github.com/PureSaber/quant-data-kit.git@3b1684dfb1ecddd0c7df95f1fbac9b21119e9f55 +quant-data-kit @ git+https://github.com/PureSaber/quant-data-kit.git@ab17ee7b8c417aa72a9707106f5455beba965b76 # via quant-execution (pyproject.toml) referencing==0.37.0 # via diff --git a/src/quant_execution/derivative_replay.py b/src/quant_execution/derivative_replay.py index 4847127..2f6959b 100644 --- a/src/quant_execution/derivative_replay.py +++ b/src/quant_execution/derivative_replay.py @@ -22,6 +22,7 @@ def replay(bundle, config, decide): Fees and adverse tick slippage apply to every fill. Daily-bar fills are a declared research assumption, not bid/ask or actual execution evidence. """ + bundle.require_mode("replay") groups = defaultdict(dict) for q in bundle.quotes: groups[q.session][q.instrument_id] = q diff --git a/tests/test_derivative_replay.py b/tests/test_derivative_replay.py index a30b2fd..bdcc245 100644 --- a/tests/test_derivative_replay.py +++ b/tests/test_derivative_replay.py @@ -9,6 +9,22 @@ from quant_execution.derivatives import DerivativeAccount +def test_analysis_only_bundle_cannot_enter_account_replay(tmp_path): + demo = write_demo(tmp_path / "demo", "future") + bundle = write_bundle( + tmp_path / "limited", + demo.contracts, + demo.quotes, + provider="test", + evidence_kind="synthetic", + rights_note="test", + limits="analysis only", + source={"allowed_modes": ["analysis"]}, + ) + with pytest.raises(ValueError, match="permits"): + replay(bundle, {"initial_cash": 10000}, lambda quotes, at: {}) + + def test_next_bar_fills_artifact_balance_and_tamper_rejection(tmp_path): bundle = write_demo(tmp_path / "bundle", "future") config = {