77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""Integration test: one full engine recompute cycle in paper mode (no network)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import time
|
|
|
|
from polymaker.config import Config, PathsConfig, StrategyProfile
|
|
from polymaker.domain import Side
|
|
from polymaker.engine import Engine
|
|
from polymaker.strategy.regime import RegimeMachine
|
|
|
|
|
|
def _engine_with_market(tmp_path, meta) -> Engine:
|
|
cfg = Config(paths=PathsConfig(db=str(tmp_path / "state.db"),
|
|
journal_dir=str(tmp_path / "j"),
|
|
log_dir=str(tmp_path / "l")))
|
|
cfg.engine.journal = False
|
|
eng = Engine(cfg, paper=True)
|
|
cid = meta.condition_id
|
|
# inject one market directly, bypassing network resolution
|
|
eng.metas[cid] = meta
|
|
eng.profiles[cid] = StrategyProfile()
|
|
eng.est[cid] = Engine._make_estimators(eng.profiles[cid])
|
|
eng.regime_m[cid] = RegimeMachine()
|
|
eng._dirty[cid] = asyncio.Event()
|
|
for tok in (meta.yes.token_id, meta.no.token_id):
|
|
eng._token_cid[tok] = cid
|
|
eng.md.set_markets([(cid, [meta.yes.token_id, meta.no.token_id])])
|
|
eng._running = True
|
|
return eng
|
|
|
|
|
|
def _feed_book(eng, meta):
|
|
now = time.time() # fresh ts so the ws_stale guard doesn't HALT the market
|
|
yb = eng.md.book(meta.yes.token_id)
|
|
yb.apply_snapshot(bids=[(0.48, 500), (0.49, 500)], asks=[(0.51, 500), (0.52, 500)], ts=now)
|
|
nb = eng.md.book(meta.no.token_id)
|
|
nb.apply_snapshot(bids=[(0.48, 500), (0.49, 500)], asks=[(0.51, 500), (0.52, 500)], ts=now)
|
|
|
|
|
|
async def test_recompute_places_two_sided_paper_quotes(tmp_path, meta):
|
|
eng = _engine_with_market(tmp_path, meta)
|
|
_feed_book(eng, meta)
|
|
await eng._recompute(meta.condition_id)
|
|
|
|
yes_orders = eng.state.orders_for(meta.yes.token_id)
|
|
no_orders = eng.state.orders_for(meta.no.token_id)
|
|
assert yes_orders, "no YES quotes placed"
|
|
assert no_orders, "no NO quotes placed"
|
|
# entry quotes are BUYs on both tokens (the canonical two-sided quote)
|
|
assert all(o.side is Side.BUY for o in yes_orders)
|
|
assert all(o.side is Side.BUY for o in no_orders)
|
|
eng.state.close()
|
|
eng.catalog.close()
|
|
|
|
|
|
async def test_recompute_is_idempotent_within_tolerance(tmp_path, meta):
|
|
eng = _engine_with_market(tmp_path, meta)
|
|
_feed_book(eng, meta)
|
|
await eng._recompute(meta.condition_id)
|
|
n_after_first = len(eng.state.orders)
|
|
# same book -> reconcile should be a no-op, order count unchanged
|
|
await eng._recompute(meta.condition_id)
|
|
assert len(eng.state.orders) == n_after_first
|
|
eng.state.close()
|
|
eng.catalog.close()
|
|
|
|
|
|
async def test_recompute_skips_when_book_empty(tmp_path, meta):
|
|
eng = _engine_with_market(tmp_path, meta)
|
|
# no book fed
|
|
await eng._recompute(meta.condition_id)
|
|
assert len(eng.state.orders) == 0
|
|
eng.state.close()
|
|
eng.catalog.close()
|