{
 "key": "f-competing-risk",
 "approach": "Competing-risk overlay on N: per side, count fills followed by the side's quote moving through the filled price (bid lower / ask higher) as arbitrage sweeps, other fills as retail; ratio (retail+1)/(sweep+1), raised to POW, normalised by the two-side mean and clamped, scales each PlaceOrder's quantity on that side so total size is roughly unchanged (upscaling is dropped when collateral could exceed free_cash). Acts only when s=max(1,(ask-bid+1)//2) from the first step is in ACT.",
 "tried": [
  "v1: POW=1, clamp [0.6,1.4], all spreads 1..4: tuning 310000..310199 mean_diff -48.39 se 6.36; every spread negative",
  "v2: POW=0.5, clamp [0.85,1.15]: tuning mean_diff -41.39 se 4.74; by spread 1:-23.69(7.58) 2:-34.94(7.99) 3:-48.81(8.30) 4:-60.16(13.73)",
  "Frozen v2 with ACT={1}, the least negative spread (no spread was positive), and ran the 500-seed holdout once: -5.91 se 1.52 overall, -25.69 se 6.28 on spread 1"
 ],
 "next": "Reject. Changing the size of N's own orders is costly even with mild weights: retail edge falls most, so N likely reacts to the changed sizes it sees in own_orders, or size works as a lever in N. A retry should keep N's view unchanged (hide the resize by reporting N's intended sizes in a replaced state) or add or remove separate hidden orders rather than resize. The sweep detector (quote moved through the filled price) is also crude.",
 "spreads_acted": [
  1
 ],
 "off_equals_n": true,
 "code": "import dataclasses as _dc\nfrom orderbook_pm_challenge.types import CancelAll, CancelOrder, PlaceOrder, Side\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nACT = {1}\nPOW = 0.5\nLO, HI = 0.85, 1.15\n\n\nclass Strategy(BaseStrategy):\n    \"\"\"Competing-risk overlay: per side, retail-fill hazard vs sweep hazard.\n    A fill whose side's quote then moves through the filled price (bid down /\n    ask up) counts as a sweep; other fills count as retail. Each side's placed\n    size is scaled by its hazard ratio over the mean ratio (total unchanged).\"\"\"\n\n    def __init__(self):\n        self.n = _N()\n        self.s = None\n        self.prev = {\"BUY\": None, \"SELL\": None}\n        self.cnt = {\"BUY\": [0, 0], \"SELL\": [0, 0]}  # [retail, sweep]\n\n    def _quotes(self, state, acts):\n        live = {o.order_id: o for o in state.own_orders}\n        for a in acts:\n            if isinstance(a, CancelAll):\n                live = {}\n            elif isinstance(a, CancelOrder):\n                live.pop(a.order_id, None)\n        bb = [o.price_ticks for o in live.values() if o.side == Side.BUY]\n        aa = [o.price_ticks for o in live.values() if o.side == Side.SELL]\n        for a in acts:\n            if isinstance(a, PlaceOrder):\n                (bb if a.side == Side.BUY else aa).append(a.price_ticks)\n        return (max(bb) if bb else None), (min(aa) if aa else None)\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 = max(1, (a - b + 1) // 2) if (a is not None and b is not None) else 0\n        acts = list(self.n.on_step(state))\n        if self.s not in ACT:\n            return acts\n        bq, aq = self._quotes(state, acts)\n        pb, pa = self.prev[\"BUY\"], self.prev[\"SELL\"]\n        if state.buy_filled_quantity > 0 and pb is not None:\n            self.cnt[\"BUY\"][1 if (bq is None or bq < pb) else 0] += 1\n        if state.sell_filled_quantity > 0 and pa is not None:\n            self.cnt[\"SELL\"][1 if (aq is None or aq > pa) else 0] += 1\n        self.prev[\"BUY\"], self.prev[\"SELL\"] = bq, aq\n        rb = ((self.cnt[\"BUY\"][0] + 1.0) / (self.cnt[\"BUY\"][1] + 1.0)) ** POW\n        ra = ((self.cnt[\"SELL\"][0] + 1.0) / (self.cnt[\"SELL\"][1] + 1.0)) ** POW\n        m = 0.5 * (rb + ra)\n        w = {Side.BUY: min(HI, max(LO, rb / m)), Side.SELL: min(HI, max(LO, ra / m))}\n        if abs(w[Side.BUY] - 1) < 1e-9 and abs(w[Side.SELL] - 1) < 1e-9:\n            return acts\n        need = 0.0\n        for a in acts:\n            if isinstance(a, PlaceOrder):\n                p = a.price_ticks / 100.0\n                need += a.quantity * w[a.side] * (p if a.side == Side.BUY else 1 - p)\n        if need > state.free_cash:\n            w = {k: min(1.0, v) for k, v in w.items()}\n        out = []\n        for a in acts:\n            if isinstance(a, PlaceOrder) and w[a.side] != 1.0:\n                q = int(a.quantity * w[a.side] * 100) / 100.0\n                if q < 0.01:\n                    continue\n                a = _dc.replace(a, quantity=q)\n            out.append(a)\n        return out\n",
 "code_sha256": "5b4a3006e16e3ff48ba6be73948de2de03cefc00cbaff94f24990bac6f4e2ac5",
 "assembled_sha256": "c3a4f8c5c6b2f0bb9756f1370bff240e406ece940dc422f69bc557c6fd5f1a0f",
 "tuning": {
  "n": 200,
  "mean_diff": -41.394405191622496,
  "se": 4.73840452756909
 },
 "paired": {
  "first_seed": 410000,
  "last_seed": 410499,
  "n": 500,
  "complete": true,
  "incumbent_mean": 104.4137531881468,
  "mean_diff": -5.9084120034344,
  "se": 1.5193631281184425,
  "sum_d": -2954.2060017172,
  "sum_d2": 593416.5128150856,
  "retail_diff": -3.2141916298837994,
  "arb_diff": -2.694220373561,
  "failures": 0
 },
 "by_spread": {
  "1": {
   "runs": 115,
   "incumbent_mean": 28.495154459731307,
   "mean_diff": -25.68874784101913,
   "se": 6.282970456311677,
   "sum_d": -2954.2060017172,
   "sum_d2": 593416.5128150856,
   "retail_diff": -13.974746216886086,
   "arb_diff": -11.71400162417826
  },
  "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.71
}