simudyne-pulse 0.9.0__tar.gz → 0.9.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simudyne_pulse-0.9.0/src/simudyne_pulse.egg-info → simudyne_pulse-0.9.0.dev2}/PKG-INFO +1 -1
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/pyproject.toml +1 -1
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/validation.py +40 -20
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2/src/simudyne_pulse.egg-info}/PKG-INFO +1 -1
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/tests/test_validation.py +30 -2
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/LICENSE +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/README.md +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/setup.cfg +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/__init__.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/client.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/exceptions.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/__init__.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/api_keys.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/data.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/fix.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/fm.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/profile.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne/resources/simulation.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/SOURCES.txt +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/dependency_links.txt +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/requires.txt +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/top_level.txt +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/tests/test_api_contract.py +0 -0
- {simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/tests/test_new_resources.py +0 -0
|
@@ -70,10 +70,13 @@ _AREA_FLAGS = (
|
|
|
70
70
|
)
|
|
71
71
|
|
|
72
72
|
#: ``lob`` marks the frames as L2 snapshots, which switches off anything
|
|
73
|
-
#: needing the message stream; ``
|
|
74
|
-
#:
|
|
75
|
-
#: of plot ids.
|
|
76
|
-
_EXTRA_FIELDS = ("lob", "
|
|
73
|
+
#: needing the message stream; ``resample_method`` and ``sessions`` say how the
|
|
74
|
+
#: historical day is put onto the generated frames' grid; ``plots`` is False,
|
|
75
|
+
#: True, or a list of plot ids.
|
|
76
|
+
_EXTRA_FIELDS = ("lob", "resample_method", "sessions", "plots")
|
|
77
|
+
|
|
78
|
+
#: How the historical day can be put onto the generated grid in lob mode.
|
|
79
|
+
RESAMPLE_METHODS = ("last", "pulseflow")
|
|
77
80
|
|
|
78
81
|
|
|
79
82
|
def _frame_to_parquet(entry, index: int):
|
|
@@ -257,8 +260,8 @@ class ValidationResource:
|
|
|
257
260
|
fid=None,
|
|
258
261
|
mind=None,
|
|
259
262
|
lob=None,
|
|
260
|
-
|
|
261
|
-
|
|
263
|
+
resample_method=None,
|
|
264
|
+
sessions=None,
|
|
262
265
|
n_levels: int = 10,
|
|
263
266
|
plots=None,
|
|
264
267
|
) -> dict:
|
|
@@ -318,15 +321,22 @@ class ValidationResource:
|
|
|
318
321
|
lob : bool, optional
|
|
319
322
|
The frames are L2 snapshots. Anything needing the message stream
|
|
320
323
|
is skipped, with the reason reported in
|
|
321
|
-
``metadata["areas_skipped"]``.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
324
|
+
``metadata["areas_skipped"]``. The historical day is resampled
|
|
325
|
+
onto your generated frames' own grid, read off them (e.g. one
|
|
326
|
+
second); event-level frames are left as they are.
|
|
327
|
+
resample_method : {"last", "pulseflow"}, optional
|
|
328
|
+
How the historical day is put onto that grid in lob mode.
|
|
329
|
+
``"last"`` (the default when unset) keeps the last event in each
|
|
330
|
+
interval. ``"pulseflow"`` reproduces PulseFLOW's training-data
|
|
331
|
+
preprocessing exactly — the first event per interval on a fixed
|
|
332
|
+
session grid, forward-filled to the session edges, sizes clipped
|
|
333
|
+
at each session's 99th percentile — so a PulseFLOW run is scored
|
|
334
|
+
against the data it was trained on. Needs ``sessions``.
|
|
335
|
+
sessions : list of [start_h, start_m, end_h, end_m], optional
|
|
336
|
+
The model's trading sessions, for ``resample_method="pulseflow"``
|
|
337
|
+
only; the end is exclusive. ``[[8, 0, 16, 30]]`` for LSE
|
|
338
|
+
continuous trading, ``[[9, 30, 12, 0], [13, 0, 16, 0]]`` for
|
|
339
|
+
HKEX.
|
|
330
340
|
n_levels : int, default 10
|
|
331
341
|
Book levels to measure over.
|
|
332
342
|
plots : bool or list of str, optional
|
|
@@ -408,14 +418,16 @@ class ValidationResource:
|
|
|
408
418
|
... plots=["statistical.radar", "stylised_facts.overall"],
|
|
409
419
|
... )
|
|
410
420
|
|
|
411
|
-
|
|
421
|
+
A PulseFLOW run on its one-second grid, scored against the historical
|
|
422
|
+
day downsampled exactly as PulseFLOW's training data was:
|
|
412
423
|
|
|
413
424
|
>>> job = client.validation.run(
|
|
414
425
|
... symbol="BARC", date="2025-09-02",
|
|
415
426
|
... provider="bmll", exchange="lse",
|
|
416
|
-
... sim_files=["
|
|
427
|
+
... sim_files=["pulseflow_sample.parquet"],
|
|
417
428
|
... lob=True,
|
|
418
|
-
...
|
|
429
|
+
... resample_method="pulseflow",
|
|
430
|
+
... sessions=[[8, 0, 16, 30]],
|
|
419
431
|
... )
|
|
420
432
|
"""
|
|
421
433
|
if sim_ids is None and sim_files is None:
|
|
@@ -433,6 +445,14 @@ class ValidationResource:
|
|
|
433
445
|
)
|
|
434
446
|
if n_levels < 1:
|
|
435
447
|
raise ValueError("n_levels must be at least 1")
|
|
448
|
+
if resample_method is not None and resample_method not in RESAMPLE_METHODS:
|
|
449
|
+
raise ValueError(f"resample_method must be one of {RESAMPLE_METHODS}")
|
|
450
|
+
if resample_method == "pulseflow" and not sessions:
|
|
451
|
+
raise ValueError(
|
|
452
|
+
"resample_method='pulseflow' needs sessions, e.g. [[8, 0, 16, 30]]"
|
|
453
|
+
)
|
|
454
|
+
if sessions and resample_method != "pulseflow":
|
|
455
|
+
raise ValueError("sessions only applies with resample_method='pulseflow'")
|
|
436
456
|
|
|
437
457
|
config = _build_config(
|
|
438
458
|
n_levels,
|
|
@@ -443,8 +463,8 @@ class ValidationResource:
|
|
|
443
463
|
fid=fid,
|
|
444
464
|
mind=mind,
|
|
445
465
|
lob=lob,
|
|
446
|
-
|
|
447
|
-
|
|
466
|
+
resample_method=resample_method,
|
|
467
|
+
sessions=sessions,
|
|
448
468
|
plots=plots,
|
|
449
469
|
)
|
|
450
470
|
|
|
@@ -106,14 +106,42 @@ class TestMetricFlags:
|
|
|
106
106
|
"flag,value",
|
|
107
107
|
[("statistical", False), ("stylised_facts", True), ("impact", False),
|
|
108
108
|
("volume_correlation", True), ("fid", False), ("mind", True),
|
|
109
|
-
("lob", True), ("
|
|
110
|
-
("match_generated_sample", True),
|
|
109
|
+
("lob", True), ("resample_method", "last"),
|
|
111
110
|
("plots", ["statistical.radar"])],
|
|
112
111
|
)
|
|
113
112
|
def test_explicit_options_are_forwarded(self, flag, value):
|
|
114
113
|
client, _ = _run([{"job_id": "v1"}], **{flag: value})
|
|
115
114
|
assert client.calls[0][2]["json"]["config"][flag] == value
|
|
116
115
|
|
|
116
|
+
def test_pulseflow_resampling_is_forwarded_with_its_sessions(self):
|
|
117
|
+
client, _ = _run([{"job_id": "v1"}], lob=True, resample_method="pulseflow",
|
|
118
|
+
sessions=[[8, 0, 16, 30]])
|
|
119
|
+
config = client.calls[0][2]["json"]["config"]
|
|
120
|
+
assert config["resample_method"] == "pulseflow"
|
|
121
|
+
assert config["sessions"] == [[8, 0, 16, 30]]
|
|
122
|
+
|
|
123
|
+
@pytest.mark.parametrize(
|
|
124
|
+
"kwargs,match",
|
|
125
|
+
[({"resample_method": "mean"}, "resample_method must be one of"),
|
|
126
|
+
({"resample_method": "pulseflow"}, "needs sessions"),
|
|
127
|
+
({"sessions": [[8, 0, 16, 30]]}, "only applies"),
|
|
128
|
+
({"resample_method": "last", "sessions": [[8, 0, 16, 30]]}, "only applies")],
|
|
129
|
+
)
|
|
130
|
+
def test_bad_resampling_is_refused_before_any_request(self, kwargs, match):
|
|
131
|
+
client = FakeClient()
|
|
132
|
+
with pytest.raises(ValueError, match=match):
|
|
133
|
+
ValidationResource(client).run(sim_ids=SIM_IDS, **IDENTITY, **kwargs)
|
|
134
|
+
assert client.calls == []
|
|
135
|
+
|
|
136
|
+
def test_the_old_grid_options_are_gone(self):
|
|
137
|
+
"""Replaced by resample_method: in lob mode the grid is read off the
|
|
138
|
+
generated frames."""
|
|
139
|
+
for dead in ("sample_period", "match_generated_sample"):
|
|
140
|
+
with pytest.raises(TypeError):
|
|
141
|
+
ValidationResource(FakeClient()).run(
|
|
142
|
+
sim_ids=SIM_IDS, **IDENTITY, **{dead: "1s"}
|
|
143
|
+
)
|
|
144
|
+
|
|
117
145
|
def test_the_legacy_aliases_are_gone(self):
|
|
118
146
|
"""run_* and l2_only/plot_data were two names for one thing."""
|
|
119
147
|
for dead in ("run_metrics", "run_impact", "run_stylised_facts",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.9.0 → simudyne_pulse-0.9.0.dev2}/src/simudyne_pulse.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|