{
 "approach": "Blind S0: fair = competitor ladder mid (arb keeps competitor bid<=p<=ask) minus inventory skew; 6-share bid/ask inside the competitor spread but at least EDGE ticks from fair. S1 adds a CUSUM on x_t=|change in competitor mid (ticks)| + |buy_fill-sell_fill|/SIZE: S=max(0,S+x-K); alarm when S>H pulls all orders for PULL steps, then S resets. Only USE_CUSUM differs.",
 "tried": [
  {
   "variant": "S0 EDGE=1",
   "seeds": "115000..115499",
   "n": 500,
   "total": -3.765
  },
  {
   "variant": "S0 EDGE=2",
   "seeds": "115000..115249",
   "n": 250,
   "total": -2.24
  },
  {
   "variant": "S0 EDGE=3",
   "seeds": "115000..115249",
   "n": 250,
   "total": -1.253
  },
  {
   "variant": "S0 EDGE=4 (frozen)",
   "seeds": "115000..115249",
   "n": 250,
   "total": -0.566
  },
  {
   "variant": "S1 K=1 H=1.5 PULL=3",
   "seeds": "115000..115249",
   "n": 250,
   "total": 0.126
  },
  {
   "variant": "S1 K=0.5 H=1 PULL=5",
   "seeds": "115000..115249",
   "n": 250,
   "total": 0.114
  },
  {
   "variant": "S1 K=1 H=1.5 PULL=8 (frozen)",
   "seeds": "115000..115249",
   "n": 250,
   "total": 0.388
  },
  {
   "variant": "S1 K=1.5 H=2 PULL=5",
   "seeds": "115000..115249",
   "n": 250,
   "total": 0.145
  }
 ],
 "next": "Mechanism gain is entirely arb-loss reduction (+0.99 arb, ~0 retail), paired SE 0.08, on a weak baseline (S0 ~-0.7 vs B ~99.7); graft onto the current best and measure paired on fresh seeds \u2014 gain may scale with quoted size. Try longer PULL (gain rose 3->8) and a one-sided pull in the jump direction.",
 "code": "from orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelAll, PlaceOrder, Side\n\n# S1 = S0 + CUSUM jump detector (USE_CUSUM=True). Set USE_CUSUM=False for S0.\nUSE_CUSUM = True\nSIZE = 6.0        # shares per side\nEDGE = 4         # min ticks between quote and estimated fair\nSKEW = 0.02       # ticks of fair shift per share of inventory\nCUSUM_K = 1.0     # allowance (ticks of |mid change| + fill signal per step)\nCUSUM_H = 1.5     # alarm threshold\nPULL = 8         # steps to stay out after an alarm\n\n\nclass Strategy(BaseStrategy):\n    def __init__(self):\n        self.prev_mid = None\n        self.s = 0.0\n        self.pull = 0\n\n    def on_step(self, st):\n        bb, ba = st.competitor_best_bid_ticks, st.competitor_best_ask_ticks\n        if bb is None and ba is None:\n            return [CancelAll()]\n        if bb is None:\n            bb = ba - 2\n        if ba is None:\n            ba = bb + 2\n        mid = 0.5 * (bb + ba)\n        acts = [CancelAll()]\n        if USE_CUSUM:\n            # observable jump statistic: competitor-mid move plus one-sided fill burst\n            x = 0.0\n            if self.prev_mid is not None:\n                x += abs(mid - self.prev_mid)\n            x += abs(st.buy_filled_quantity - st.sell_filled_quantity) / max(SIZE, 1e-9)\n            self.s = max(0.0, self.s + x - CUSUM_K)\n            if self.s > CUSUM_H:\n                self.pull = PULL\n                self.s = 0.0\n        self.prev_mid = mid\n        if self.pull > 0:\n            self.pull -= 1\n            return acts\n        inv = st.yes_inventory - st.no_inventory\n        fair = mid - SKEW * inv\n        bid = min(bb + 1, int(fair - EDGE + 1e-9))\n        ask = max(ba - 1, int(-(-(fair + EDGE) // 1)))\n        bid = max(1, min(98, bid))\n        ask = max(bid + 1, min(99, ask))\n        q = SIZE\n        if bid * q / 100.0 < st.free_cash and inv < 200:\n            acts.append(PlaceOrder(side=Side.BUY, price_ticks=bid, quantity=q))\n        need = max(0.0, q - st.yes_inventory) * (1 - ask / 100.0)\n        if need < st.free_cash - bid * q / 100.0 and inv > -200:\n            acts.append(PlaceOrder(side=Side.SELL, price_ticks=ask, quantity=q))\n        return acts\n",
 "code_sha256": "f6b217646905f5748af2875b01b00ac72b1ce5a76b3a29a13db057cf6a2981aa",
 "code_s0": "from orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelAll, PlaceOrder, Side\n\n# S1 = S0 + CUSUM jump detector (USE_CUSUM=True). Set USE_CUSUM=False for S0.\nUSE_CUSUM = False\nSIZE = 6.0        # shares per side\nEDGE = 4         # min ticks between quote and estimated fair\nSKEW = 0.02       # ticks of fair shift per share of inventory\nCUSUM_K = 1.0     # allowance (ticks of |mid change| + fill signal per step)\nCUSUM_H = 1.5     # alarm threshold\nPULL = 8         # steps to stay out after an alarm\n\n\nclass Strategy(BaseStrategy):\n    def __init__(self):\n        self.prev_mid = None\n        self.s = 0.0\n        self.pull = 0\n\n    def on_step(self, st):\n        bb, ba = st.competitor_best_bid_ticks, st.competitor_best_ask_ticks\n        if bb is None and ba is None:\n            return [CancelAll()]\n        if bb is None:\n            bb = ba - 2\n        if ba is None:\n            ba = bb + 2\n        mid = 0.5 * (bb + ba)\n        acts = [CancelAll()]\n        if USE_CUSUM:\n            # observable jump statistic: competitor-mid move plus one-sided fill burst\n            x = 0.0\n            if self.prev_mid is not None:\n                x += abs(mid - self.prev_mid)\n            x += abs(st.buy_filled_quantity - st.sell_filled_quantity) / max(SIZE, 1e-9)\n            self.s = max(0.0, self.s + x - CUSUM_K)\n            if self.s > CUSUM_H:\n                self.pull = PULL\n                self.s = 0.0\n        self.prev_mid = mid\n        if self.pull > 0:\n            self.pull -= 1\n            return acts\n        inv = st.yes_inventory - st.no_inventory\n        fair = mid - SKEW * inv\n        bid = min(bb + 1, int(fair - EDGE + 1e-9))\n        ask = max(ba - 1, int(-(-(fair + EDGE) // 1)))\n        bid = max(1, min(98, bid))\n        ask = max(bid + 1, min(99, ask))\n        q = SIZE\n        if bid * q / 100.0 < st.free_cash and inv < 200:\n            acts.append(PlaceOrder(side=Side.BUY, price_ticks=bid, quantity=q))\n        need = max(0.0, q - st.yes_inventory) * (1 - ask / 100.0)\n        if need < st.free_cash - bid * q / 100.0 and inv > -200:\n            acts.append(PlaceOrder(side=Side.SELL, price_ticks=ask, quantity=q))\n        return acts\n",
 "tuning_score": {
  "seeds": "115000..115249 (S0 EDGE=1 also on 115000..115499); time forced 250-seed tuning",
  "n": 250,
  "s1_mean": 0.388,
  "s0_mean": -0.566
 },
 "paired": {
  "seeds": "200000..200999",
  "n": 1000,
  "complete": true,
  "mechanism_diff": 0.9645,
  "mechanism_se": 0.0805,
  "mechanism_retail_diff": -0.0299,
  "mechanism_arb_diff": 0.9945,
  "reference_diff": -99.4171,
  "reference_se": 5.6445,
  "s1_mean": 0.2788,
  "s0_mean": -0.6857,
  "b_mean": 99.6959,
  "failures": []
 },
 "graft": "Each on_step: mid=(comp_bid+comp_ask)/2; x=|mid-prev_mid|+|buy_filled-sell_filled|/size; S=max(0,S+x-1.0); if S>1.5: pull=8,S=0. While pull>0: decrement and return [CancelAll()] only (no new quotes). Keep prev_mid updated every step.",
 "seconds_per_simulation": 0.47
}