{
  "key": "f-endgame-stop",
  "approach": "Finite-horizon Bellman stopping table over 350 remaining steps, spread, probability tick and side. Probability is estimated from competitor midpoint and own fill imbalance in StepState history. The table compares modeled next-step retail gain to Gaussian and jump adverse-selection cost, with a permanent stop option. Stop decisions cancel existing N orders and suppress new N orders on that side; N still receives every state and the overlay adds no orders. Only first-step spread 4 is acted on.",
  "tried": [
    "Variant 1, all spreads 1-4: 200 tuning pairs, mean difference -19.514390807857502, SE 3.7211329950518532; spread 4 alone was +3.4833368455697684, SE 5.584273605351444.",
    "Variant 2, same stopping table restricted to spread 4: 200 tuning pairs reconstructed exactly from variant 1 on spread 4 and identity elsewhere; mean difference 0.748917421798, SE 1.193871248394."
  ],
  "next": "Promote only if the independent paired holdout gain exceeds twice its standard error; otherwise retain N. Holdout result: does not pass.",
  "spreads_acted": [
    4
  ],
  "off_equals_n": true,
  "code": "import math\nfrom dataclasses import replace\nfrom statistics import NormalDist\nfrom orderbook_pm_challenge.types import CancelAll, CancelOrder, PlaceOrder, Side\n\nACTIVE_SPREADS = {4}\n_TABLE = None\n\n\ndef _stopping_table():\n    \"\"\"Finite-horizon option to stop quoting either side permanently.\"\"\"\n    global _TABLE\n    if _TABLE is not None:\n        return _TABLE\n    norm = NormalDist()\n    pdf = lambda x: math.exp(-0.5 * x * x) / math.sqrt(2.0 * math.pi)\n    table = {}\n    for spread in range(1, 5):\n        width = spread * 0.01\n        for side in (Side.BUY, Side.SELL):\n            values = [[0.0] * 99]\n            stops = [[False] * 99]\n            for h in range(1, 351):\n                row = [0.0] * 99\n                stop = [False] * 99\n                prev = values[-1]\n                for i in range(99):\n                    p = (i + 1) / 100.0\n                    z = norm.inv_cdf(p)\n                    sigma = pdf(z) / math.sqrt(h)\n                    if side == Side.BUY:\n                        quote = max(0.01, p - width)\n                        distance = p - quote\n                        jump_loss = 0.0009 * quote\n                    else:\n                        quote = min(0.99, p + width)\n                        distance = quote - p\n                        jump_loss = 0.0009 * (1.0 - quote)\n                    a = distance / max(sigma, 1e-12)\n                    tail = 0.5 * math.erfc(a / math.sqrt(2.0))\n                    arb_loss = sigma * pdf(a) - distance * tail + jump_loss\n                    reward = 0.04 * distance - arb_loss\n                    continuation = 0.0\n                    for offset, weight in ((-2, 0.05), (-1, 0.25), (0, 0.40), (1, 0.25), (2, 0.05)):\n                        j = min(98, max(0, round((p + offset * sigma) * 100) - 1))\n                        continuation += weight * prev[j]\n                    continuation = 0.9982 * continuation + 0.0009 * (prev[0] + prev[98])\n                    v = reward + continuation\n                    row[i] = max(0.0, v)\n                    stop[i] = v <= 0.0\n                values.append(row)\n                stops.append(stop)\n            table[(spread, side)] = stops\n    _TABLE = table\n    return table\n\n\nclass Strategy(BaseStrategy):\n    def __init__(self):\n        self.n = _N()\n        self.spread = None\n        self.p = None\n        self.stopped = set()\n\n    def on_step(self, state):\n        # N receives its own complete order history. This overlay adds no orders.\n        actions = self.n.on_step(state)\n        if state.step == 0:\n            bid, ask = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n            if bid is not None and ask is not None:\n                self.spread = max(1, (ask - bid + 1) // 2)\n                self.p = (bid + ask) / 200.0\n        if self.spread not in ACTIVE_SPREADS:\n            return actions\n        bid, ask = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        if bid is not None and ask is not None and state.step:\n            midpoint = (bid + ask) / 200.0\n            self.p = 0.6 * self.p + 0.4 * midpoint\n            flow = state.sell_filled_quantity - state.buy_filled_quantity\n            self.p += max(-0.015, min(0.015, 0.0002 * flow))\n            self.p = max(0.01, min(0.99, self.p))\n        h = state.steps_remaining\n        if h <= 350 and self.p is not None:\n            idx = min(98, max(0, round(self.p * 100) - 1))\n            table = _stopping_table()\n            for side in (Side.BUY, Side.SELL):\n                if table[(self.spread, side)][h][idx]:\n                    self.stopped.add(side)\n        if not self.stopped:\n            return actions\n        kept = [a for a in actions if not (isinstance(a, PlaceOrder) and a.side in self.stopped)]\n        if not any(isinstance(a, CancelAll) for a in kept):\n            cancelled = {a.order_id for a in kept if isinstance(a, CancelOrder)}\n            kept.extend(CancelOrder(o.order_id) for o in state.own_orders\n                        if o.side in self.stopped and o.order_id not in cancelled)\n        return kept\n",
  "code_sha256": "fad593aa209f973286ed505d9524f5be1c2ede6acc7b28ea2ee8b42e691a59e5",
  "assembled_sha256": "54547bcab6845a2b286a48d52433e36e194057598e6b7f8a02e89921f0ee9972",
  "tuning": {
    "n": 200,
    "mean_diff": 0.7489174217975002,
    "se": 1.1938712483943008
  },
  "paired": {
    "first_seed": 410000,
    "last_seed": 410499,
    "n": 500,
    "complete": true,
    "incumbent_mean": 104.4137531881468,
    "mean_diff": -1.2806409814948008,
    "se": 0.453000171696227,
    "sum_d": -640.3204907474004,
    "sum_d2": 52019.70497316637,
    "retail_diff": -1.4237439286181994,
    "arb_diff": 0.14310294712500007,
    "failures": []
  },
  "by_spread": {
    "1": {
      "runs": 115,
      "incumbent_mean": 28.495154459731307,
      "mean_diff": 0.0,
      "se": 0.0,
      "sum_d": 0.0,
      "sum_d2": 0.0,
      "retail_diff": 0.0,
      "arb_diff": 0.0
    },
    "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": -4.887942677461072,
      "se": 1.6943458027529323,
      "sum_d": -640.3204907474004,
      "sum_d2": 52019.70497316637,
      "retail_diff": -5.434137132130532,
      "arb_diff": 0.5461944546755728
    }
  },
  "seconds_per_simulation": 0.4007315399646759
}
