{
 "key": "f-partial-keep",
 "approach": "Overlay on N: when N cancels a partly filled order still on the right side of the competitor's quotes (bid below competitor ask, ask above competitor bid), the remainder stays in the book at its FIFO place and one of N's new client-id orders on that side shrinks by the remainder. Partial status comes from FIFO survivor matching against what was placed. The kept remainder is hidden from N and folded into the order it cut, so N sees the book it asked for. If N cancels that order, the remainder is judged again; a remainder that crosses to the wrong side is cancelled. Frozen form: any-level absorption, acting only at spread 1. N's check on seed 310000 came out at 17.1160017503, matching the expected 17.116002, and n.py's SHA-256 matched. Result: no measurable effect, not a promotion candidate.",
 "tried": [
  "Variant 1, same-level gate (keep only if N also places at the remainder's price), client-id orders absorb: exactly 0 difference on all 200 tuning seeds, so it never changed a result. Likely cause, not separately tested: in a 40-seed behaviour sample, N's same-price placements were almost always smaller than the remainder, and in a 20-seed sample of any-level absorption 1400 of 1945 remainders found no single client-id order big enough.",
  "Variant 2, any-level absorption, tuning 310000..310199 with all spreads on: all -1.0835 (se 0.2076); s=1 +0.0008 (se 0.0007); s=2 -0.0551 (se 0.0456), retail -0.107, arb +0.052; s=3 -1.5267 (se 0.4626), retail -1.795, arb +0.268; s=4 -3.0856 (se 0.6739), retail -4.442, arb +1.356. Keeping remainders cut arbitrage loss but cost about 2 to 7 times as much retail edge, plausibly because size moves off N's new better-priced quote to the old worse-priced one.",
  "Spread set: {1}, the only spread with a positive tuning mean. That mean is about 1 se from zero, so the choice is weak and the mechanism is nearly inert there.",
  "Disclosure 1: an earlier overlay excluded N's client-id orders from keeping and made no change on the tuning seeds. Every partly filled order N cancelled carried a client id, so this was a bug, not a measured idea; it was fixed by the hidden view before the two variants above ran. Both overlay builds used tuning seeds only.",
  "Disclosure 2: N's source was not printed or read, but I logged its returned actions and order-id prefixes on tuning seeds, and an assembly script parsed n.py to list which of six API names it imports. Giving N's unnamed orders client ids changed its result on seed 310000 (15.58 against 17.12), so N's order ids affect its behaviour; the overlay does not rewrite them.",
  "Holdout 410000..410499 was run once, S1 and N on every seed: mean_diff -0.0010 (se 0.0011), 0 failures. s=2..4 equal N exactly because the overlay is off there."
 ],
 "next": "Do not promote this form. Spreads 3 and 4 show the real trade-off: arbitrage improves but retail falls by more, so a useful version must stop taking size from N's best quote. Untested ideas, for a later item since this one's 2 variants are used: absorb only from N's unnamed deeper orders, split one remainder across several orders so the same-level case can act at all, and keep a remainder only while a fair-value estimate says its edge beats the replacement's retail edge.",
 "spreads_acted": [
  1
 ],
 "off_equals_n": true,
 "code": "# f-partial-keep overlay. When N cancels a partly filled order that is still on the\n# right side of the competitor's quotes, the remainder stays in the book (it holds its\n# FIFO place) and one of N's new orders on that side shrinks by the same quantity.\n# N is shown a view in which the kept remainder is part of that new order, so it sees\n# the book it asked for. If N later cancels that order the remainder is judged again.\nfrom dataclasses import replace as _replace\n\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import (\n    CancelAll,\n    CancelOrder,\n    OwnOrderView,\n    PlaceOrder,\n    Side,\n)\n\n\nclass Strategy(BaseStrategy):\n    SPREADS = frozenset({1})\n    SAME_LEVEL_ONLY = False\n\n    def __init__(self):\n        self._n = _N()\n        self._s = None\n        self._orig = {}  # real order id -> size placed\n        self._pend = {}  # (side, tick) -> sizes placed last step, in order\n        self._back = {}  # N's order id -> ids of kept remainders inside it\n        self._meta = {}  # N's order id -> (side, tick, step)\n\n    def on_step(self, state):\n        if self._s is None:\n            b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n            self._s = 0 if b is None or a is None else max(1, (a - b + 1) // 2)\n        if self._s not in self.SPREADS:\n            return self._n.on_step(state)\n        self._learn_sizes(state)\n        real = {o.order_id: o for o in state.own_orders}\n        forced = self._prune(state, real)\n        actions = self._n.on_step(self._view(state, real, forced))\n        out = self._apply(state, actions, real, forced, True)\n        self._remember(out)\n        return out\n\n    def _learn_sizes(self, state):\n        # Same side, price and step fill FIFO, so the survivors are the last placed.\n        groups = {}\n        for o in state.own_orders:\n            if o.order_id not in self._orig and o.submitted_step == state.step - 1:\n                groups.setdefault((o.side, o.price_ticks), []).append(o)\n        for key, views in groups.items():\n            qs = self._pend.get(key, [])\n            for o, q in zip(views, qs[max(0, len(qs) - len(views)):]):\n                self._orig[o.order_id] = q\n        self._pend = {}\n\n    def _remember(self, actions):\n        for a in actions:\n            if isinstance(a, PlaceOrder):\n                q = int(a.quantity * 100 + 1e-7) / 100\n                self._pend.setdefault((a.side, a.price_ticks), []).append(q)\n\n    @staticmethod\n    def _right_side(state, o):\n        if o.side is Side.BUY:\n            ask = state.competitor_best_ask_ticks\n            return ask is not None and o.price_ticks < ask\n        bid = state.competitor_best_bid_ticks\n        return bid is not None and o.price_ticks > bid\n\n    def _prune(self, state, real):\n        # Forget filled remainders; cancel any that crossed to the wrong side.\n        forced = []\n        for vid in list(self._back):\n            live = []\n            for oid in self._back[vid]:\n                o = real.get(oid)\n                if o is None:\n                    continue\n                if self._right_side(state, o):\n                    live.append(oid)\n                else:\n                    forced.append(oid)\n            if live:\n                self._back[vid] = live\n            else:\n                del self._back[vid]\n                self._meta.pop(vid, None)\n        return forced\n\n    def _view(self, state, real, forced):\n        if not self._back and not forced:\n            return state\n        hidden = set(forced)\n        for ids in self._back.values():\n            hidden.update(ids)\n        extra = {\n            v: sum(real[i].remaining_quantity for i in ids) for v, ids in self._back.items()\n        }\n        rows = []\n        for o in state.own_orders:\n            if o.order_id in hidden:\n                continue\n            if o.order_id in extra:\n                q = round(o.remaining_quantity + extra[o.order_id], 10)\n                o = _replace(o, remaining_quantity=q)\n            rows.append(o)\n        for v, q in extra.items():\n            if v not in real:\n                side, tick, step = self._meta[v]\n                rows.append(OwnOrderView(v, side, tick, round(q, 10), step))\n        rows.sort(key=lambda o: (o.side.value, o.price_ticks if o.side is Side.SELL else -o.price_ticks))\n        return _replace(state, own_orders=tuple(rows))\n\n    def _is_partial(self, o):\n        q = self._orig.get(o.order_id)\n        return q is not None and o.remaining_quantity < q - 1e-9\n\n    def _apply(self, state, actions, real, forced, allow):\n        hidden = set(forced)\n        for ids in self._back.values():\n            hidden.update(ids)\n        if any(isinstance(a, CancelAll) for a in actions):\n            cancelled = [o for o in real if o not in hidden]\n            cancelled += [v for v in self._back if v not in real]\n        else:\n            cancelled = [a.order_id for a in actions if isinstance(a, CancelOrder)]\n        places = [a for a in actions if isinstance(a, PlaceOrder)]\n        cands, drop = [], list(forced)\n        back = {k: list(v) for k, v in self._back.items()}\n        for vid in cancelled:\n            own = real.get(vid)\n            if own is not None and vid not in hidden:\n                if self._is_partial(own) and self._right_side(state, own):\n                    cands.append(own)\n                else:\n                    drop.append(vid)\n            for oid in back.pop(vid, ()):\n                if self._right_side(state, real[oid]):\n                    cands.append(real[oid])\n                else:\n                    drop.append(oid)\n        if not cands and not forced and not any(p.client_order_id in hidden for p in places):\n            self._back = back\n            return actions\n        sizes = {i: p.quantity for i, p in enumerate(places)}\n        meta = {}\n        for o in cands:\n            i = self._pick(o, places, sizes) if allow else None\n            if i is None:\n                drop.append(o.order_id)\n                continue\n            sizes[i] = round(sizes[i] - o.remaining_quantity, 10)\n            vid = places[i].client_order_id\n            back.setdefault(vid, []).append(o.order_id)\n            meta[vid] = (places[i].side, places[i].price_ticks, state.step)\n        # A new id equal to a hidden id would be refused by the book.\n        new_ids = {p.client_order_id for p in places}\n        for v in list(back):\n            keep = [x for x in back[v] if x not in new_ids]\n            drop += [x for x in back[v] if x in new_ids]\n            if keep:\n                back[v] = keep\n            else:\n                del back[v]\n        out = [CancelOrder(x) for x in drop]\n        for i, p in enumerate(places):\n            q = int(sizes[i] * 100 + 1e-7) / 100\n            if q >= 0.01:\n                out.append(p if sizes[i] == p.quantity else _replace(p, quantity=q))\n        # Collateral guard: kept reservations are not re-derived, so if the placements\n        # could not be paid from free cash alone, this step keeps nothing.\n        need = sum(\n            max(a.price_ticks, 100 - a.price_ticks) / 100 * a.quantity\n            for a in out\n            if isinstance(a, PlaceOrder)\n        )\n        if allow and cands and need > state.free_cash:\n            return self._apply(state, actions, real, forced, False)\n        self._back = back\n        self._meta = {k: v for k, v in self._meta.items() if k in back}\n        self._meta.update(meta)\n        return out\n\n    def _pick(self, o, places, sizes):\n        # Which of N's new tagged orders absorbs this remainder: same price, then the\n        # deepest level behind it, then the nearest better one. None means cancel it.\n        buy = o.side is Side.BUY\n        key = lambda p: p.price_ticks if buy else -p.price_ticks\n        side = [i for i, p in enumerate(places) if p.side is o.side]\n        if not side:\n            return None\n        mine = key(o)\n        if mine > max(key(places[i]) for i in side):\n            return None  # N has pulled back past this price: respect the cancel\n        if self.SAME_LEVEL_ONLY and not any(key(places[i]) == mine for i in side):\n            return None\n        best, rank = None, None\n        for i in side:\n            if places[i].client_order_id is None or sizes[i] < o.remaining_quantity - 1e-9:\n                continue\n            p = key(places[i])\n            r = (0, 0) if p == mine else ((1, p) if p < mine else (2, p))\n            if rank is None or r < rank:\n                best, rank = i, r\n        return best\n",
 "code_sha256": "ec0c7e6e7258241803cd1781e690287f211db7d1ff322a46c9c79ba18711e9d7",
 "assembled_sha256": "0fb7d12cdf380157cf5da73c851d059862c6f3c88707b7d71e7f385ad512a672",
 "tuning": {
  "n": 200,
  "mean_diff": 0.00018210142500000082,
  "se": 0.00016932320397428162
 },
 "paired": {
  "first_seed": 410000,
  "last_seed": 410499,
  "n": 500,
  "complete": true,
  "incumbent_mean": 104.4137531881468,
  "mean_diff": -0.0010023571944000052,
  "se": 0.0010808006472422462,
  "sum_d": -0.5011785972000026,
  "sum_d2": 0.29195080472285767,
  "retail_diff": 0.00018090335100005283,
  "arb_diff": -0.001183260545799989,
  "failures": 0
 },
 "by_spread": {
  "1": {
   "runs": 115,
   "incumbent_mean": 28.495154459731307,
   "mean_diff": -0.0043580747582608916,
   "se": 0.004701352767401744,
   "sum_d": -0.5011785972000026,
   "sum_d2": 0.29195080472285767,
   "retail_diff": 0.0007865363086958819,
   "arb_diff": -0.005144611068695604
  },
  "2": {
   "runs": 116,
   "incumbent_mean": 97.76626247947758,
   "mean_diff": 0.0,
   "se": 0.0,
   "sum_d": 0.0,
   "sum_d2": 0.0,
   "retail_diff": 0.0,
   "arb_diff": 0.0
  },
  "3": {
   "runs": 138,
   "incumbent_mean": 128.4054514027384,
   "mean_diff": 0.0,
   "se": 0.0,
   "sum_d": 0.0,
   "sum_d2": 0.0,
   "retail_diff": 0.0,
   "arb_diff": 0.0
  },
  "4": {
   "runs": 131,
   "incumbent_mean": 151.67248160310686,
   "mean_diff": 0.0,
   "se": 0.0,
   "sum_d": 0.0,
   "sum_d2": 0.0,
   "retail_diff": 0.0,
   "arb_diff": 0.0
  }
 },
 "seconds_per_simulation": 0.4572688934803009
}