{
 "approach": "Blind build from the simulator and its rules only. S0 tracks an interval for p from ladder sweeps, own fills and 0.01-share probes, quotes one tick inside the competitor, keeps an order that sits ahead of a competitor replacement in the queue, and sizes each quote from flow*gain*P(N>C)=adverse with the next-step p taken by quadrature at ONE fixed horizon (300). S1 is S0 with only the horizon mechanism: that quadrature uses true steps remaining R, so whether a quote pays (distance) and its size are explicit functions of R; R=1 uses the binary settlement outcome; p inside the outermost tick is estimated from R; cover buying is limited to what retail can take before settlement; the cash floor ramps to 0 over the last 200 steps. Result on 1000 holdout seeds, all complete, no failures: the mechanism gains +9.27 (se 0.64) over S0, but S1 is below B by 23.16 (se 2.69). S1 does not beat B and is not a promotion candidate as it stands; its value is the graft. Caution on size: on tuning seeds about two thirds of the gain came from R>=500, where S0's fixed horizon of 300 was too cautious, so a base already sized well early should gain less.",
 "tried": [
  {
   "strategy": "S0",
   "variant": 1,
   "tuning_mean": 26.788,
   "kept": false,
   "what": "Cancel-all each step, one quote per side inside the competitor, fixed horizon 800, cash floor 5. Cash ran out on low-p seeds."
  },
  {
   "strategy": "S0",
   "variant": 2,
   "tuning_mean": 43.396,
   "kept": false,
   "what": "Adds queue-front orders and a 100 floor on the side costing over 50c a share. Paired against variant 1: +16.61 (se 2.43)."
  },
  {
   "strategy": "S0",
   "variant": 3,
   "tuning_mean": 43.405,
   "kept": false,
   "what": "Variant 2 with fixed horizon 300. Paired against variant 2: +0.01 (se 1.52); retail -15.29, arb +15.30, so a flat trade."
  },
  {
   "strategy": "S0",
   "variant": 4,
   "tuning_mean": 67.42,
   "kept": true,
   "what": "Variant 3 plus cover buying: when cash is out, a bid just above p buys YES from the arbitrageur to cover asks. Paired against variant 3: +24.02 (se 2.68). Frozen as S0."
  },
  {
   "strategy": "S1",
   "variant": 1,
   "tuning_mean": 76.024,
   "kept": false,
   "what": "Horizon = steps remaining, binary settlement at R=1. Paired against S0: +8.60 (se 1.49)."
  },
  {
   "strategy": "S1",
   "variant": 2,
   "tuning_mean": 77.917,
   "kept": false,
   "what": "Variant 1 plus tail estimate from R and cover limited by turnover before settlement. Paired against variant 1: +1.89 (se 0.21)."
  },
  {
   "strategy": "S1",
   "variant": 3,
   "tuning_mean": 76.423,
   "kept": false,
   "what": "Variant 2 plus early boost, horizon R*(1+R/2000). Paired against variant 2: -1.49 (se 0.35); retail +3.38, arb -4.88. Rejected."
  },
  {
   "strategy": "S1",
   "variant": 4,
   "tuning_mean": 78.233,
   "kept": true,
   "what": "Variant 2 plus cash floor ramping to 0 over the last 200 steps. Paired against variant 2: +0.32 (se 0.05). Frozen as S1."
  }
 ],
 "next": "1) Graft the R schedule onto B and measure it paired; do not assume +9: on tuning seeds (S1 variant 2 minus S0, net edge by steps remaining) R>=1000 gave +5.51, 500-999 +1.51, 200-499 +0.10, 50-199 +0.68, 10-49 +2.30, below 10 +0.42. The last 50 steps are the part least tied to S0's fixed horizon. 2) Two S0 parts may matter more than the schedule and were measured on tuning seeds only, never alone on holdout: cover buying +24.02 (se 2.68), queue-front plus capital floor +16.61 (se 2.43). B was not read, so whether B has them is unknown; each deserves its own paired item. 3) S1's gap to B is not closed: holdout S1 retail 104.31, arb -27.78. By competitor spread on holdout S1 earns 2.3 (s=1), 54.3 (s=2), 103.1 (s=3), 144.1 (s=4), so s=1 seeds are nearly dead and are the plainest place left to look. 4) A horizon above R is worse (variant 3), so do not widen early aggression further.",
 "code": "\"\"\"S1: S0 plus a quoting schedule over the horizon. Distance and size are explicit functions of steps remaining, through settlement.\n\nThe mechanism is everything marked HORIZON: the adverse-selection and gain terms that set whether a quote pays (its\ndistance) and how large it is are computed with the true steps remaining instead of one fixed horizon; the last step\nuses the binary settlement outcome; and the tail estimate, cover buying and the capital floor run on the same clock.\n\"\"\"\nfrom __future__ import annotations\n\nimport math\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelOrder, PlaceOrder, Side, StepState\n\nSIGMA, JUMP_RATE, JUMP_VAR = 0.02, 0.0019, 0.1739  # diffusion per step; middles of the jump bands\nFLOW, LN_SD = 0.1265, 1.2  # retail arrivals per side per step; log-normal notional spread\nLN_MU = math.log(4.488) - 0.5 * LN_SD**2\nMAX_NOTIONAL, CASH_FLOOR, HOG_FLOOR = 100.0, 5.0, 100.0  # the capital-hungry side (over 50c a share) stops at HOG_FLOOR\nPROBE_SIZE, N_PROBES = 0.01, 3  # tiny orders on the ticks nearest the estimate; their sweeps locate p\nSWEEP_ODDS = 0.1  # with a queue-front order, add an inside order only if the far side may be swept next step\nHOG_RAMP = 200  # HORIZON: the capital floor falls to zero over this many final steps\nCOVER_NOTIONAL = 15.0  # YES inventory worth this much at the ask, bought cheaply from the arbitrageur when cash is out\nGH7 = ((0.0, 0.457143), (1.154405, 0.240123), (-1.154405, 0.240123), (2.366759, 0.030757), (-2.366759, 0.030757), (3.750440, 0.000548), (-3.750440, 0.000548))\nGH5 = ((0.0, 0.533333), (1.355626, 0.222076), (-1.355626, 0.222076), (2.856970, 0.011257), (-2.856970, 0.011257))\n\ndef cdf(x: float) -> float:\n    return 0.5 * math.erfc(-x / math.sqrt(2.0))\n\ndef ppf(q: float) -> float:\n    q = min(max(q, 1e-9), 1.0 - 1e-9)\n    if q > 0.5:\n        return -ppf(1.0 - q)\n    t = math.sqrt(-2.0 * math.log(q))\n    return -(t - (2.515517 + 0.802853 * t + 0.010328 * t * t) / (1.0 + t * (1.432788 + t * (0.189269 + 0.001308 * t))))\n\ndef scale(horizon: int) -> float:\n    \"\"\"Z scale so Phi(Z / scale) has the slope at Z=0 of the jump-mixed probability with this many steps left.\"\"\"\n    lam = JUMP_RATE * horizon\n    weight, total = math.exp(-lam), 0.0\n    for n in range(14):\n        total += weight / math.sqrt(horizon * SIGMA * SIGMA + n * JUMP_VAR)\n        weight *= lam / (n + 1)\n    return 1.0 / total\n\ndef next_prob_nodes(p: float, err: float, horizon: int) -> tuple[list[tuple[float, float]], float]:\n    \"\"\"Weighted nodes for the probability one step ahead, and its diffusion sd.\"\"\"\n    v, v1, u = scale(horizon), scale(horizon - 1), ppf(min(max(p, 1e-4), 1.0 - 1e-4))\n    slope = math.exp(-0.5 * u * u) / math.sqrt(2.0 * math.pi) / v\n    z, sd = v * u, math.sqrt(SIGMA * SIGMA + (err / slope) ** 2)\n    js = math.sqrt(sd * sd + JUMP_VAR)\n    nodes = [(cdf((z + sd * x) / v1), w * (1.0 - JUMP_RATE)) for x, w in GH7] + [(cdf((z + js * x) / v1), w * JUMP_RATE) for x, w in GH5]\n    return nodes, slope * SIGMA\n\ndef horizon_nodes(p: float, err: float, remaining: int) -> tuple[list[tuple[float, float]], float]:\n    \"\"\"HORIZON: next-step distribution with this many steps left; on the last step p settles to 1 or 0.\"\"\"\n    return ([(1.0, p), (0.0, 1.0 - p)], 0.0) if remaining <= 1 else next_prob_nodes(p, err, remaining)\n\ndef tail_estimate(edge: float, mid: float, remaining: int) -> float:\n    \"\"\"HORIZON: mean of p below a small bound, with Z flat over a unit range; shrinks with scale(steps left).\"\"\"\n    z = ppf(edge)\n    return min(mid, scale(max(remaining, 1)) * (math.exp(-0.5 * z * z) / math.sqrt(2.0 * math.pi) + z * edge))\n\ndef target_notional(sgn: int, x: float, nodes) -> float:\n    \"\"\"Solve flow * gain * P(N > C) = adverse for the resting notional C at price x; 0 when no size pays.\"\"\"\n    gain = sum(w * max(sgn * (x - n), 0.0) for n, w in nodes)\n    adverse = sum(w * max(sgn * (n - x), 0.0) for n, w in nodes)\n    if gain <= 0.0 or adverse >= FLOW * gain:\n        return 0.0\n    r = max(adverse / (FLOW * gain), 1e-6)\n    return min(MAX_NOTIONAL, math.exp(LN_MU + LN_SD * ppf(1.0 - r)))\n\ndef read_fills(levels: list[tuple[int, float]], filled: float, sweep_is_arb: bool) -> tuple[float | None, float | None]:\n    \"\"\"(tick still resting, so p is on our side of it; tick an arbitrageur swept, so p is beyond it).\"\"\"\n    swept, total = 0, 0.0\n    while swept < len(levels) and filled >= total + levels[swept][1] - 1e-9:\n        total, swept = total + levels[swept][1], swept + 1\n    resting = levels[swept][0] / 100.0 if swept < len(levels) else None\n    clean = swept and abs(filled - total) < 1e-9 and (swept < len(levels) or sweep_is_arb)\n    return resting, levels[swept - 1][0] / 100.0 if clean else None\n\nclass Strategy(BaseStrategy):\n    def __init__(self) -> None:\n        self.low, self.high, self.vol, self.hog = 0.0, 1.0, 0.0, HOG_FLOOR\n        self.prev = {1: 100, -1: 0}  # competitor best last step; +1 asks, -1 bids\n        self.levels: dict[int, list[tuple[int, float]]] = {1: [], -1: []}  # own orders, best first\n        self.sweep_is_arb = {1: False, -1: False}\n        self.front: dict[int, str | None] = {1: None, -1: None}  # order resting ahead of the competitor\n\n    def _track(self, s: StepState, bid: int, ask: int) -> None:\n        \"\"\"Interval for p: widened by one step of diffusion, cut by what the ladder and own fills reveal.\"\"\"\n        width = self.high - self.low\n        pad = 0.5 * (math.sqrt(width * width + 12.0 * self.vol * self.vol) - width)\n        low, high = max(0.0, self.low - pad), min(1.0, self.high + pad)\n        lo, hi = bid / 100.0, ask / 100.0\n        lo = max(lo, (ask - 1) / 100.0) if ask > self.prev[1] else lo\n        hi = min(hi, (bid + 1) / 100.0) if bid < self.prev[-1] else hi\n        rest, swept = read_fills(self.levels[1], s.sell_filled_quantity, self.sweep_is_arb[1])  # asks\n        hi, lo = hi if rest is None else min(hi, rest), lo if swept is None else max(lo, swept)\n        rest, swept = read_fills(self.levels[-1], s.buy_filled_quantity, self.sweep_is_arb[-1])\n        lo, hi = lo if rest is None else max(lo, rest), hi if swept is None else min(hi, swept)\n        lo, hi = (bid / 100.0, ask / 100.0) if lo > hi else (lo, hi)\n        self.low, self.high = (lo, hi) if low > hi or high < lo else (max(low, lo), min(high, hi))\n\n    def _cover(self, tick: int, p: float, nodes, cash: float, yes: float, remaining: int) -> list[tuple[int, float]]:\n        \"\"\"Asks below 50c cost about $1 a share uncovered: when cash is out, a bid just above p buys cover from the arbitrageur.\"\"\"\n        buy = int(p * 100.0) + 1\n        if not 1 <= tick <= 49 or tick - buy < 1:\n            return []\n        cover = min(COVER_NOTIONAL, FLOW * (remaining - 1) * 4.488)  # HORIZON: no more cover than retail can take before settlement\n        short = min(target_notional(1, tick / 100.0, nodes), cover) / (tick / 100.0) - yes - max(cash - self.hog, 0.0) / (1.0 - tick / 100.0)\n        return [(buy, short)] if short >= 0.01 else []\n\n    def _side(self, sgn: int, comp: dict[int, int], kept, p: float, nodes, cash: float, yes: float, actions: list, cover=()):\n        \"\"\"Probes from the estimate outward, the quote one tick inside the competitor, then any queue-front order.\"\"\"\n        tick, far = comp[sgn] - sgn, comp[-sgn] / 100.0\n        main = target_notional(sgn, tick / 100.0, nodes) / (tick / 100.0 if sgn > 0 else max(p, 0.05)) if 1 <= tick <= 99 else 0.0\n        main = 0.0 if kept and sum(w for n, w in nodes if sgn * (far - n) > 0.0) < SWEEP_ODDS else main\n        first = int(p * 100.0) + (1 if sgn > 0 else 0)\n        orders = list(cover) + [(t, PROBE_SIZE) for t in range(first, first + sgn * N_PROBES, sgn)\n                  if 1 <= t <= 99 and sgn * (tick - t) >= (main >= 0.01)]\n        orders += [(tick, main)] if main >= 0.01 else []\n        levels: list[tuple[int, float]] = []\n        for t, qty in orders:\n            unit, free = (1.0 - t / 100.0, yes) if sgn > 0 else (t / 100.0, 0.0)\n            room = max(cash - (self.hog if unit > 0.5 and qty > PROBE_SIZE else 0.0), 0.0)\n            qty = math.floor(min(qty, free + room / unit) * 100.0) / 100.0\n            if qty < 0.01:\n                continue\n            cash, yes = cash - unit * max(qty - free, 0.0), max(yes - qty, 0.0) if sgn > 0 else yes\n            actions.append(PlaceOrder(Side.SELL if sgn > 0 else Side.BUY, t, qty))\n            levels.append((t, qty))\n        self.levels[sgn] = levels + ([kept[1:]] if kept else [])\n        if self.levels[sgn]:\n            top = self.levels[sgn][-1][0] / 100.0\n            held = sum(q for _, q in self.levels[sgn]) * (top if sgn > 0 else max(p, 0.05))\n            cross = sum(w for n, w in nodes if sgn * (n - top) > 0.0)\n            self.sweep_is_arb[sgn] = cross > FLOW * (1.0 - cdf((math.log(held) - LN_MU) / LN_SD))\n        return cash, yes\n\n    def on_step(self, s: StepState):\n        bid, ask = s.competitor_best_bid_ticks or 0, s.competitor_best_ask_ticks or 100\n        comp = {1: ask, -1: bid}\n        if s.step == 0:\n            self.low, self.high = (ask + bid - 1) / 200.0, (ask + bid + 1) / 200.0\n            self.prev = dict(comp)\n        else:\n            self._track(s, bid, ask)\n        p, err, remaining = 0.5 * (self.low + self.high), (self.high - self.low) / math.sqrt(12.0), s.steps_remaining\n        if self.high <= 0.011:  # HORIZON: inside the outermost tick p is judged by the steps left\n            p = tail_estimate(self.high, p, remaining)\n            err = min(err, p)\n        elif self.low >= 0.989:\n            p = 1.0 - tail_estimate(1.0 - self.low, 1.0 - p, remaining)\n            err = min(err, 1.0 - p)\n        self.hog = HOG_FLOOR * min(1.0, remaining / HOG_RAMP)  # HORIZON\n        nodes, self.vol = horizon_nodes(p, err, remaining)  # HORIZON\n        actions: list = []\n        kept: dict[int, tuple | None] = {1: None, -1: None}\n        cash, yes = s.cash - CASH_FLOOR, s.yes_inventory\n        for o in s.own_orders:\n            sgn, tick = (1 if o.side is Side.SELL else -1), o.price_ticks\n            ahead = tick == comp[sgn] and (sgn * (self.prev[sgn] - tick) > 0 or o.order_id == self.front[sgn])\n            if ahead and o.remaining_quantity > PROBE_SIZE and target_notional(sgn, tick / 100.0, nodes) > 0.0:\n                kept[sgn] = (o.order_id, tick, o.remaining_quantity)\n                cash -= o.remaining_quantity * ((1.0 - tick / 100.0) if sgn > 0 else tick / 100.0)\n                yes -= o.remaining_quantity if sgn > 0 else 0.0\n            else:\n                actions.append(CancelOrder(o.order_id))\n        self.front, self.prev = {k: v[0] if v else None for k, v in kept.items()}, dict(comp)\n        yes = max(yes, 0.0)\n        cash, yes = self._side(-1, comp, kept[-1], p, nodes, cash, yes, actions, self._cover(ask - 1, p, nodes, cash, yes, remaining))\n        self._side(1, comp, kept[1], p, nodes, cash, yes, actions)\n        return actions\n",
 "code_sha256": "7df8ececb4960c3b7770305e99055dcdcb2786d3c929f3610cacb77a6863c2f5",
 "code_s0": "\"\"\"S0: quotes one tick inside the competitor (or ahead of it in queue), sized by retail flow against adverse selection.\"\"\"\nfrom __future__ import annotations\n\nimport math\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelOrder, PlaceOrder, Side, StepState\n\nSIGMA, JUMP_RATE, JUMP_VAR = 0.02, 0.0019, 0.1739  # diffusion per step; middles of the jump bands\nFLOW, LN_SD = 0.1265, 1.2  # retail arrivals per side per step; log-normal notional spread\nLN_MU = math.log(4.488) - 0.5 * LN_SD**2\nMAX_NOTIONAL, CASH_FLOOR, HOG_FLOOR = 100.0, 5.0, 100.0  # the capital-hungry side (over 50c a share) stops at HOG_FLOOR\nPROBE_SIZE, N_PROBES = 0.01, 3  # tiny orders on the ticks nearest the estimate; their sweeps locate p\nSWEEP_ODDS = 0.1  # with a queue-front order, add an inside order only if the far side may be swept next step\nREF_HORIZON = 300  # the one horizon S0 assumes for every step\nCOVER_NOTIONAL = 15.0  # YES inventory worth this much at the ask, bought cheaply from the arbitrageur when cash is out\nGH7 = ((0.0, 0.457143), (1.154405, 0.240123), (-1.154405, 0.240123), (2.366759, 0.030757), (-2.366759, 0.030757), (3.750440, 0.000548), (-3.750440, 0.000548))\nGH5 = ((0.0, 0.533333), (1.355626, 0.222076), (-1.355626, 0.222076), (2.856970, 0.011257), (-2.856970, 0.011257))\n\ndef cdf(x: float) -> float:\n    return 0.5 * math.erfc(-x / math.sqrt(2.0))\n\ndef ppf(q: float) -> float:\n    q = min(max(q, 1e-9), 1.0 - 1e-9)\n    if q > 0.5:\n        return -ppf(1.0 - q)\n    t = math.sqrt(-2.0 * math.log(q))\n    return -(t - (2.515517 + 0.802853 * t + 0.010328 * t * t) / (1.0 + t * (1.432788 + t * (0.189269 + 0.001308 * t))))\n\ndef scale(horizon: int) -> float:\n    \"\"\"Z scale so Phi(Z / scale) has the slope at Z=0 of the jump-mixed probability with this many steps left.\"\"\"\n    lam = JUMP_RATE * horizon\n    weight, total = math.exp(-lam), 0.0\n    for n in range(14):\n        total += weight / math.sqrt(horizon * SIGMA * SIGMA + n * JUMP_VAR)\n        weight *= lam / (n + 1)\n    return 1.0 / total\n\ndef next_prob_nodes(p: float, err: float, horizon: int) -> tuple[list[tuple[float, float]], float]:\n    \"\"\"Weighted nodes for the probability one step ahead, and its diffusion sd.\"\"\"\n    v, v1, u = scale(horizon), scale(horizon - 1), ppf(min(max(p, 1e-4), 1.0 - 1e-4))\n    slope = math.exp(-0.5 * u * u) / math.sqrt(2.0 * math.pi) / v\n    z, sd = v * u, math.sqrt(SIGMA * SIGMA + (err / slope) ** 2)\n    js = math.sqrt(sd * sd + JUMP_VAR)\n    nodes = [(cdf((z + sd * x) / v1), w * (1.0 - JUMP_RATE)) for x, w in GH7] + [(cdf((z + js * x) / v1), w * JUMP_RATE) for x, w in GH5]\n    return nodes, slope * SIGMA\n\ndef target_notional(sgn: int, x: float, nodes) -> float:\n    \"\"\"Solve flow * gain * P(N > C) = adverse for the resting notional C at price x; 0 when no size pays.\"\"\"\n    gain = sum(w * max(sgn * (x - n), 0.0) for n, w in nodes)\n    adverse = sum(w * max(sgn * (n - x), 0.0) for n, w in nodes)\n    if gain <= 0.0 or adverse >= FLOW * gain:\n        return 0.0\n    r = max(adverse / (FLOW * gain), 1e-6)\n    return min(MAX_NOTIONAL, math.exp(LN_MU + LN_SD * ppf(1.0 - r)))\n\ndef read_fills(levels: list[tuple[int, float]], filled: float, sweep_is_arb: bool) -> tuple[float | None, float | None]:\n    \"\"\"(tick still resting, so p is on our side of it; tick an arbitrageur swept, so p is beyond it).\"\"\"\n    swept, total = 0, 0.0\n    while swept < len(levels) and filled >= total + levels[swept][1] - 1e-9:\n        total, swept = total + levels[swept][1], swept + 1\n    resting = levels[swept][0] / 100.0 if swept < len(levels) else None\n    clean = swept and abs(filled - total) < 1e-9 and (swept < len(levels) or sweep_is_arb)\n    return resting, levels[swept - 1][0] / 100.0 if clean else None\n\nclass Strategy(BaseStrategy):\n    def __init__(self) -> None:\n        self.low, self.high, self.vol = 0.0, 1.0, 0.0\n        self.prev = {1: 100, -1: 0}  # competitor best last step; +1 asks, -1 bids\n        self.levels: dict[int, list[tuple[int, float]]] = {1: [], -1: []}  # own orders, best first\n        self.sweep_is_arb = {1: False, -1: False}\n        self.front: dict[int, str | None] = {1: None, -1: None}  # order resting ahead of the competitor\n\n    def _track(self, s: StepState, bid: int, ask: int) -> None:\n        \"\"\"Interval for p: widened by one step of diffusion, cut by what the ladder and own fills reveal.\"\"\"\n        width = self.high - self.low\n        pad = 0.5 * (math.sqrt(width * width + 12.0 * self.vol * self.vol) - width)\n        low, high = max(0.0, self.low - pad), min(1.0, self.high + pad)\n        lo, hi = bid / 100.0, ask / 100.0\n        lo = max(lo, (ask - 1) / 100.0) if ask > self.prev[1] else lo\n        hi = min(hi, (bid + 1) / 100.0) if bid < self.prev[-1] else hi\n        rest, swept = read_fills(self.levels[1], s.sell_filled_quantity, self.sweep_is_arb[1])  # asks\n        hi, lo = hi if rest is None else min(hi, rest), lo if swept is None else max(lo, swept)\n        rest, swept = read_fills(self.levels[-1], s.buy_filled_quantity, self.sweep_is_arb[-1])\n        lo, hi = lo if rest is None else max(lo, rest), hi if swept is None else min(hi, swept)\n        lo, hi = (bid / 100.0, ask / 100.0) if lo > hi else (lo, hi)\n        self.low, self.high = (lo, hi) if low > hi or high < lo else (max(low, lo), min(high, hi))\n\n    def _cover(self, tick: int, p: float, nodes, cash: float, yes: float) -> list[tuple[int, float]]:\n        \"\"\"Asks below 50c cost about $1 a share uncovered: when cash is out, a bid just above p buys cover from the arbitrageur.\"\"\"\n        buy = int(p * 100.0) + 1\n        if not 1 <= tick <= 49 or tick - buy < 1:\n            return []\n        short = min(target_notional(1, tick / 100.0, nodes), COVER_NOTIONAL) / (tick / 100.0) - yes - max(cash - HOG_FLOOR, 0.0) / (1.0 - tick / 100.0)\n        return [(buy, short)] if short >= 0.01 else []\n\n    def _side(self, sgn: int, comp: dict[int, int], kept, p: float, nodes, cash: float, yes: float, actions: list, cover=()):\n        \"\"\"Probes from the estimate outward, the quote one tick inside the competitor, then any queue-front order.\"\"\"\n        tick, far = comp[sgn] - sgn, comp[-sgn] / 100.0\n        main = target_notional(sgn, tick / 100.0, nodes) / (tick / 100.0 if sgn > 0 else max(p, 0.05)) if 1 <= tick <= 99 else 0.0\n        main = 0.0 if kept and sum(w for n, w in nodes if sgn * (far - n) > 0.0) < SWEEP_ODDS else main\n        first = int(p * 100.0) + (1 if sgn > 0 else 0)\n        orders = list(cover) + [(t, PROBE_SIZE) for t in range(first, first + sgn * N_PROBES, sgn)\n                  if 1 <= t <= 99 and sgn * (tick - t) >= (main >= 0.01)]\n        orders += [(tick, main)] if main >= 0.01 else []\n        levels: list[tuple[int, float]] = []\n        for t, qty in orders:\n            unit, free = (1.0 - t / 100.0, yes) if sgn > 0 else (t / 100.0, 0.0)\n            room = max(cash - (HOG_FLOOR if unit > 0.5 and qty > PROBE_SIZE else 0.0), 0.0)\n            qty = math.floor(min(qty, free + room / unit) * 100.0) / 100.0\n            if qty < 0.01:\n                continue\n            cash, yes = cash - unit * max(qty - free, 0.0), max(yes - qty, 0.0) if sgn > 0 else yes\n            actions.append(PlaceOrder(Side.SELL if sgn > 0 else Side.BUY, t, qty))\n            levels.append((t, qty))\n        self.levels[sgn] = levels + ([kept[1:]] if kept else [])\n        if self.levels[sgn]:\n            top = self.levels[sgn][-1][0] / 100.0\n            held = sum(q for _, q in self.levels[sgn]) * (top if sgn > 0 else max(p, 0.05))\n            cross = sum(w for n, w in nodes if sgn * (n - top) > 0.0)\n            self.sweep_is_arb[sgn] = cross > FLOW * (1.0 - cdf((math.log(held) - LN_MU) / LN_SD))\n        return cash, yes\n\n    def on_step(self, s: StepState):\n        bid, ask = s.competitor_best_bid_ticks or 0, s.competitor_best_ask_ticks or 100\n        comp = {1: ask, -1: bid}\n        if s.step == 0:\n            self.low, self.high = (ask + bid - 1) / 200.0, (ask + bid + 1) / 200.0\n            self.prev = dict(comp)\n        else:\n            self._track(s, bid, ask)\n        p = 0.5 * (self.low + self.high)\n        nodes, self.vol = next_prob_nodes(p, (self.high - self.low) / math.sqrt(12.0), REF_HORIZON)\n        actions: list = []\n        kept: dict[int, tuple | None] = {1: None, -1: None}\n        cash, yes = s.cash - CASH_FLOOR, s.yes_inventory\n        for o in s.own_orders:\n            sgn, tick = (1 if o.side is Side.SELL else -1), o.price_ticks\n            ahead = tick == comp[sgn] and (sgn * (self.prev[sgn] - tick) > 0 or o.order_id == self.front[sgn])\n            if ahead and o.remaining_quantity > PROBE_SIZE and target_notional(sgn, tick / 100.0, nodes) > 0.0:\n                kept[sgn] = (o.order_id, tick, o.remaining_quantity)\n                cash -= o.remaining_quantity * ((1.0 - tick / 100.0) if sgn > 0 else tick / 100.0)\n                yes -= o.remaining_quantity if sgn > 0 else 0.0\n            else:\n                actions.append(CancelOrder(o.order_id))\n        self.front, self.prev = {k: v[0] if v else None for k, v in kept.items()}, dict(comp)\n        yes = max(yes, 0.0)\n        cash, yes = self._side(-1, comp, kept[-1], p, nodes, cash, yes, actions, self._cover(ask - 1, p, nodes, cash, yes))\n        self._side(1, comp, kept[1], p, nodes, cash, yes, actions)\n        return actions\n",
 "tuning_score": {
  "seeds": "115000..115499",
  "n": 500,
  "s1_mean": 78.233,
  "s0_mean": 67.42
 },
 "paired": {
  "seeds": "200000..200999",
  "n": 1000,
  "complete": true,
  "mechanism_diff": 9.27,
  "mechanism_se": 0.639,
  "mechanism_retail_diff": 10.556,
  "mechanism_arb_diff": -1.285,
  "reference_diff": -23.163,
  "reference_se": 2.691,
  "s1_mean": 76.533,
  "s0_mean": 67.263,
  "b_mean": 99.696,
  "failures": []
 },
 "graft": "Compute adverse and gain with steps left R: Z=V(R)*ppf(p), next p=Phi((Z+dZ)/V(R-1)), V matched over Poisson jumps; at R=1 next p is 1 with probability p. Size from P(N>C)=adverse/(flow*gain), no quote when that is >=1. Inside the outer tick use p=V(R)*(pdf(z)+z*edge). Limit bought cover to flow*(R-1)*mean notional; ramp any cash floor to 0 over the last 200.",
 "seconds_per_simulation": 0.206
}