{"approach": "Particle filter (100 particles) over the latent score x. Each step: weight particles by exact hard/soft constraints on the true probability p=P(x,steps_left) (Poisson-mixture formula from the simulator): competitor best bid<=p<=best ask (the arbitrageur sweeps every crossed quote), far-side soft bound using the competitor spread (read exactly at step 0 as (ask-bid)/2, which also pins p0 to one tick), own resting orders that survived the arbitrageur (survival of own ask at k => p<=k, own bid at k => p>=k) and own orders that vanished (crossed, or retail ate all: 0.1 weight if not crossed). Resample with jitter; reseed uniformly on the constraint interval (inverted through p) when the cloud loses the score after a jump. Propagate with diffusion (sigma 0.02, known) plus one jump particle per expected jump (lambda 0.0019, jump sd 0.416 are fixed prior means, not estimated). The propagated particles give the predictive law of next-step p, bucketed per tick; quoting then maximises, per side, over tick k (strictly inside the competitor quote) and size from a fixed list, retail_rate*E[min(size,Q)]*E[edge|not crossed] + size*E[edge|crossed by arbitrageur] (the second is negative). S0 is the same quoting code with a Gaussian belief around the competitor midpoint.", "tried": [{"variant": "S0 A c1=0.30 step_sd=0.008 min_value=0 (frozen)", "tuning_mean_seeds_115000_115039": -9.48, "n": 40}, {"variant": "S0 B c1=0.20 step_sd=0.006 min_value=0", "tuning_mean_seeds_115000_115039": -27.02, "n": 40}, {"variant": "S1 A margin=0 min_value=0 (frozen)", "tuning_mean_seeds_115000_115023": 21.74, "n": 24, "note": "run killed by my own 10-minute command timeout after 24 of 40 seeds"}, {"variant": "S1 B margin=0.3 (adverse-selection loss weight x1.3) min_value=0", "tuning_mean_seeds_115000_115023": 19.66, "n": 24}, {"note": "Before those, S0 had 4 other quick trials on 8 seeds each (partial, 115000..115007, c1/step_sd in {0.2/.005,.12/.004,.25/.003,.15/.007}, means -21.6,-77.9,-15.6,-31.6) and S0 default c1=.35 step_sd=.01 min_value=.0005 almost never quoted; so S0 saw more than 4 variants. S1 saw 2 variants plus a speed rewrite (same logic) checked on 3 seeds."}], "next": "Not competitive: S1 is 68 below reference B on seeds 200000..200249. Likely causes (not tested): fixed prior jump parameters mis-scale p dynamics; the predictive law ignores that the arbitrageur takes whole-size orders at any crossing so sizes are probably too large; retail rate/size fixed instead of estimated from own fills; no inventory/cash handling beyond a 45% cash guard. Next: estimate lambda and jump sd with parameter particles, shrink sizes, and use the filter's p-interval only to choose the tick of a B-like quoting rule instead of replacing it.", "code": "\"\"\"S0: quotes around a crude probability estimate (competitor-quote midpoint), sized by expected retail flow vs adverse selection.\"\"\"\nimport math\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelAll, PlaceOrder, Side\n\nSIZES = (1, 2, 3, 4, 6, 8, 12, 16, 24, 32)\n\n\ndef _phi(x):\n    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))\n\n\ndef _fill_table(mean_notional=4.5, sigma=1.2):\n    \"\"\"F[k][s] = E[min(s, Q)] where Q = retail notional / price(k) shares.\"\"\"\n    t = {}\n    for k in range(1, 100):\n        mu = math.log(mean_notional) - 0.5 * sigma * sigma - math.log(k / 100.0)\n        row = []\n        for s in SIZES:\n            ls = math.log(s)\n            part = math.exp(mu + 0.5 * sigma * sigma) * _phi((ls - mu - sigma * sigma) / sigma)\n            row.append(part + s * (1.0 - _phi((ls - mu) / sigma)))\n        t[k] = row\n    return t\n\n\nclass QuoteBase(BaseStrategy):\n    retail_rate = 0.126      # expected retail orders per step per side\n    margin = 0.0             # extra weight on adverse-selection loss\n    c1 = 0.30                # S0 belief: sd as fraction of competitor spread\n    step_sd = 0.008          # S0 belief: one-step price noise\n    min_value = 0.0          # skip quote if expected edge below this\n\n    def __init__(self):\n        self.F = _fill_table()\n        self.zs = [i * 0.5 for i in range(-6, 7)]\n        ws = [math.exp(-0.5 * z * z) for z in self.zs]\n        tot = sum(ws)\n        self.zw = [w / tot for w in ws]\n\n    # ---- belief over next-step probability, as per-tick buckets (S0: Gaussian around quote midpoint)\n    def belief(self, state):\n        b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        if a is None and b is None:\n            a, b = 51, 49\n        elif a is None:\n            a = b + 4\n        elif b is None:\n            b = a - 4\n        mid = (a + b) / 200.0\n        sd = math.hypot(self.c1 * (a - b) / 100.0, self.step_sd)\n        pts = [(mid + sd * z, w) for z, w in zip(self.zs, self.zw)]\n        return pts\n\n    def on_step(self, state):\n        pts = self.belief(state)\n        W = [0.0] * 102\n        M = [0.0] * 102\n        for p, w in pts:\n            j = min(100, max(0, int(p * 100.0)))\n            W[j] += w\n            M[j] += w * min(1.0, max(0.0, p))\n        return self.quote(state, W, M)\n\n    def quote(self, state, W, M):\n        b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        # prefix sums over the occupied bucket range only\n        j0 = next((j for j in range(102) if W[j] > 0.0), 0)\n        j1 = next((j for j in range(101, -1, -1) if W[j] > 0.0), 0)\n        PW, PM = [0.0] * 103, [0.0] * 103\n        accw = accm = 0.0\n        for j in range(102):\n            if j0 <= j <= j1:\n                accw += W[j]\n                accm += M[j]\n            PW[j + 1], PM[j + 1] = accw, accm\n        tw, tm = PW[102], PM[102]\n        cash = state.cash\n        acts = [CancelAll()]\n        # ask: crossing (arb takes whole size) iff bucket >= k\n        best = None\n        for k in range(max(1, j0 - 1, (b or 1)), min(a if a else 100, j1 + 3)):\n            c = k / 100.0\n            A = c * PW[k] - PM[k]                       # non-crossing, retail edge\n            B = c * (tw - PW[k]) - (tm - PM[k])         # crossing, negative\n            for i, s in enumerate(SIZES):\n                v = self.retail_rate * self.F[k][i] * A + s * B * (1.0 + self.margin)\n                if best is None or v > best[0]:\n                    best = (v, k, s)\n        if best and best[0] > self.min_value:\n            _, k, s = best\n            cov = min(s, state.yes_inventory)\n            cost = (1.0 - k / 100.0) * (s - cov)\n            if cost < cash * 0.45:\n                acts.append(PlaceOrder(Side.SELL, k, float(s)))\n        # bid: crossing iff bucket < k\n        best = None\n        for k in range(max((b if b else 0) + 1, j0 - 1), min(99, (a if a else 100), j1 + 2) + 1):\n            c = k / 100.0\n            A = (tm - PM[k]) - c * (tw - PW[k])\n            B = PM[k] - c * PW[k]\n            for i, s in enumerate(SIZES):\n                v = self.retail_rate * self.F[k][i] * A + s * B * (1.0 + self.margin)\n                if best is None or v > best[0]:\n                    best = (v, k, s)\n        if best and best[0] > self.min_value:\n            _, k, s = best\n            if k / 100.0 * s < cash * 0.45:\n                acts.append(PlaceOrder(Side.BUY, k, float(s)))\n        return acts\n\n\n# ================= S1 mechanism: particle filter over the latent score =================\nimport random\n\n\nclass Strategy(QuoteBase):\n    N = 100\n    lam = 0.0019            # prior mean jump intensity\n    sj = 0.416              # prior rms jump sigma\n    sig = 0.02              # diffusion sigma (known)\n    far_pen = 0.5           # soft penalty per tick for ask/bid being too far from p\n    ghost = 0.1             # prob. an own order vanished without being crossed (retail filled it)\n    jitter = 0.15\n\n    def __init__(self):\n        super().__init__()\n        self.rng = random.Random(20260)\n        self.xs = [self.rng.uniform(-0.75, 0.75) for _ in range(self.N)]\n        self.s = 2\n        self.pool = [self.rng.gauss(0.0, self.sig) for _ in range(30000)]\n        self.last = []       # own orders placed last step: (side, tick)\n        self.pwc = {}\n        self.Pprev = None\n\n    # --- exact conditional probability P(score_T > 0 | x, R steps left): Poisson mixture of Gaussians\n    def _terms(self, R):\n        t = self.pwc.get(R)\n        if t is None:\n            m = self.lam * R\n            w = math.exp(-m)\n            t, cum, n = [], 0.0, 0\n            while True:\n                var = R * self.sig ** 2 + n * self.sj ** 2\n                t.append((w, 1.0 / math.sqrt(2.0 * var)))\n                cum += w\n                if 1.0 - cum < 1e-7 or n > 40:\n                    break\n                n += 1\n                w *= m / n\n            tot = sum(x[0] for x in t)\n            t = [(w / tot, iv) for w, iv in t]\n            self.pwc[R] = t\n        return t\n\n    def _p(self, x, R):\n        if R <= 0:\n            return 1.0 if x > 0 else 0.0\n        return sum(w * 0.5 * (1.0 + math.erf(x * iv)) for w, iv in self._terms(R))\n\n    def _pvec(self, xs, R):\n        \"\"\"P for all particles via interpolation on a grid sized to the local sd.\"\"\"\n        if R <= 0:\n            return [1.0 if x > 0 else 0.0 for x in xs]\n        lo, hi = min(xs), max(xs)\n        sd = math.sqrt(R * self.sig ** 2 + self.lam * R * self.sj ** 2)\n        if hi - lo < 1e-9:\n            return [self._p(lo, R)] * len(xs)\n        M = max(3, min(48, int((hi - lo) / (sd / 3.5)) + 2))\n        h = (hi - lo) / (M - 1)\n        g = [self._p(lo + i * h, R) for i in range(M)]\n        out = []\n        ih = 1.0 / h\n        for x in xs:\n            f = (x - lo) * ih\n            i = int(f)\n            if i >= M - 1:\n                i = M - 2\n            out.append(g[i] + (g[i + 1] - g[i]) * (f - i))\n        return out\n\n    def _invert(self, pt, R):\n        lo, hi = -6.0, 6.0\n        for _ in range(30):\n            mid = 0.5 * (lo + hi)\n            if self._p(mid, R) * 100.0 < pt:\n                lo = mid\n            else:\n                hi = mid\n        return 0.5 * (lo + hi)\n\n    def _constraints(self, state):\n        b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        lo, hi = (b if b is not None else -1e9), (a if a is not None else 1e9)\n        here = {(o.side, o.price_ticks) for o in state.own_orders}\n        soft = []                                    # (side, tick) absent -> vanished\n        for side, k in self.last:\n            if (side, k) in here:\n                if side is Side.SELL:\n                    hi = min(hi, k)\n                else:\n                    lo = max(lo, k)\n            else:\n                soft.append((side, k))\n        return b, a, lo, hi, soft\n\n    def _update(self, state, R):\n        xs = self.xs\n        n = len(xs)\n        b, a, lo, hi, soft = self._constraints(state)\n        if state.step == 0 and a is not None and b is not None:\n            self.s = max(1, int(round((a - b) / 2.0)))\n            lo, hi = b + self.s - 1, b + self.s            # p0 sits in this tick interval\n        s1 = self.s + 1\n        P = self.Pprev if self.Pprev is not None and len(self.Pprev) == n else self._pvec(xs, R)\n        lo2, hi2 = lo - 0.02, hi + 0.02\n        flo = (a - s1) if a is not None else -1e9\n        fhi = (b + s1) if b is not None else 1e9\n        ws = []\n        for p in P:\n            pt = 100.0 * p\n            if lo2 <= pt <= hi2 and flo <= pt <= fhi and not soft:\n                ws.append(1.0)\n                continue\n            w = 1.0\n            if pt < lo2:\n                w = 0.003 * math.exp(-0.7 * (lo - pt))\n            elif pt > hi2:\n                w = 0.003 * math.exp(-0.7 * (pt - hi))\n            else:\n                if pt < flo:\n                    w *= math.exp(-self.far_pen * (flo - pt))\n                if pt > fhi:\n                    w *= math.exp(-self.far_pen * (pt - fhi))\n            for side, k in soft:                      # order gone: crossed, or retail ate all of it\n                if not ((pt > k) if side is Side.SELL else (pt < k)):\n                    w *= self.ghost\n            ws.append(w)\n        live = sum(1 for w in ws if w > 0.3)\n        tot = sum(ws)\n        if live < 10 or tot < 1e-12:                  # cloud lost the score (jump): reseed on the constraint interval\n            l2 = max(lo, 0.0 if b is None else b - 0.5)\n            h2 = min(hi, 100.0 if a is None else a + 0.5)\n            if l2 > h2:\n                l2, h2 = (b or 1) - 0.5, (a or 99) + 0.5\n            x1, x2 = self._invert(max(0.0, l2), R), self._invert(min(100.0, h2), R)\n            self.xs = [self.rng.uniform(min(x1, x2), max(x1, x2)) for _ in range(n)]\n            self.Pprev = None\n            return\n        ess = tot * tot / sum(w * w for w in ws)\n        if ess < 0.7 * n:\n            mean = sum(w * x for w, x in zip(ws, xs)) / tot\n            sd = math.sqrt(sum(w * (x - mean) ** 2 for w, x in zip(ws, xs)) / tot)\n            u0 = self.rng.random() * tot / n\n            new, c, j = [], ws[0], 0\n            for i in range(n):\n                u = u0 + i * tot / n\n                while c < u and j < n - 1:\n                    j += 1\n                    c += ws[j]\n                new.append(xs[j] + self.rng.gauss(0.0, self.jitter * sd))\n            self.xs = new\n            self.Pprev = None\n        else:\n            self.wts = ws\n\n    def on_step(self, state):\n        R = state.steps_remaining\n        self.wts = None\n        self._update(state, R)\n        xs, rng = self.xs, self.rng\n        wts = self.wts\n        n = len(xs)\n        g = rng.gauss\n        o = int(rng.random() * (len(self.pool) - n))\n        xs = [x + z for x, z in zip(xs, self.pool[o:o + n])]   # diffusion\n        if rng.random() < n * self.lam:               # compound-Poisson jump (one particle per expected jump)\n            j = rng.randrange(n)\n            xs[j] += g(0.0, self.sj)\n        self.xs = xs\n        P = self._pvec(xs, R - 1)\n        self.Pprev = P\n        W, M = [0.0] * 102, [0.0] * 102\n        tw = sum(wts) if wts else float(n)\n        for i in range(n):\n            p = P[i]\n            w = (wts[i] if wts else 1.0) / tw\n            j = int(p * 100.0)\n            W[j] += w\n            M[j] += w * p\n        acts = self.quote(state, W, M)\n        self.last = [(x.side, x.price_ticks) for x in acts if isinstance(x, PlaceOrder)]\n        return acts\n", "code_sha256": "0b7a0692b324abb15f7fa1bd0bca909cd795c0e2af78e12e163f2aae2ea22ea0", "code_s0": "\"\"\"S0: quotes around a crude probability estimate (competitor-quote midpoint), sized by expected retail flow vs adverse selection.\"\"\"\nimport math\nfrom orderbook_pm_challenge.strategy import BaseStrategy\nfrom orderbook_pm_challenge.types import CancelAll, PlaceOrder, Side\n\nSIZES = (1, 2, 3, 4, 6, 8, 12, 16, 24, 32)\n\n\ndef _phi(x):\n    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))\n\n\ndef _fill_table(mean_notional=4.5, sigma=1.2):\n    \"\"\"F[k][s] = E[min(s, Q)] where Q = retail notional / price(k) shares.\"\"\"\n    t = {}\n    for k in range(1, 100):\n        mu = math.log(mean_notional) - 0.5 * sigma * sigma - math.log(k / 100.0)\n        row = []\n        for s in SIZES:\n            ls = math.log(s)\n            part = math.exp(mu + 0.5 * sigma * sigma) * _phi((ls - mu - sigma * sigma) / sigma)\n            row.append(part + s * (1.0 - _phi((ls - mu) / sigma)))\n        t[k] = row\n    return t\n\n\nclass Strategy(BaseStrategy):\n    retail_rate = 0.126      # expected retail orders per step per side\n    margin = 0.0             # extra weight on adverse-selection loss\n    c1 = 0.30                # S0 belief: sd as fraction of competitor spread\n    step_sd = 0.008          # S0 belief: one-step price noise\n    min_value = 0.0          # skip quote if expected edge below this\n\n    def __init__(self):\n        self.F = _fill_table()\n        self.zs = [i * 0.5 for i in range(-6, 7)]\n        ws = [math.exp(-0.5 * z * z) for z in self.zs]\n        tot = sum(ws)\n        self.zw = [w / tot for w in ws]\n\n    # ---- belief over next-step probability, as per-tick buckets (S0: Gaussian around quote midpoint)\n    def belief(self, state):\n        b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        if a is None and b is None:\n            a, b = 51, 49\n        elif a is None:\n            a = b + 4\n        elif b is None:\n            b = a - 4\n        mid = (a + b) / 200.0\n        sd = math.hypot(self.c1 * (a - b) / 100.0, self.step_sd)\n        pts = [(mid + sd * z, w) for z, w in zip(self.zs, self.zw)]\n        return pts\n\n    def on_step(self, state):\n        pts = self.belief(state)\n        W = [0.0] * 102\n        M = [0.0] * 102\n        for p, w in pts:\n            j = min(100, max(0, int(p * 100.0)))\n            W[j] += w\n            M[j] += w * min(1.0, max(0.0, p))\n        return self.quote(state, W, M)\n\n    def quote(self, state, W, M):\n        b, a = state.competitor_best_bid_ticks, state.competitor_best_ask_ticks\n        # prefix sums over the occupied bucket range only\n        j0 = next((j for j in range(102) if W[j] > 0.0), 0)\n        j1 = next((j for j in range(101, -1, -1) if W[j] > 0.0), 0)\n        PW, PM = [0.0] * 103, [0.0] * 103\n        accw = accm = 0.0\n        for j in range(102):\n            if j0 <= j <= j1:\n                accw += W[j]\n                accm += M[j]\n            PW[j + 1], PM[j + 1] = accw, accm\n        tw, tm = PW[102], PM[102]\n        cash = state.cash\n        acts = [CancelAll()]\n        # ask: crossing (arb takes whole size) iff bucket >= k\n        best = None\n        for k in range(max(1, j0 - 1, (b or 1)), min(a if a else 100, j1 + 3)):\n            c = k / 100.0\n            A = c * PW[k] - PM[k]                       # non-crossing, retail edge\n            B = c * (tw - PW[k]) - (tm - PM[k])         # crossing, negative\n            for i, s in enumerate(SIZES):\n                v = self.retail_rate * self.F[k][i] * A + s * B * (1.0 + self.margin)\n                if best is None or v > best[0]:\n                    best = (v, k, s)\n        if best and best[0] > self.min_value:\n            _, k, s = best\n            cov = min(s, state.yes_inventory)\n            cost = (1.0 - k / 100.0) * (s - cov)\n            if cost < cash * 0.45:\n                acts.append(PlaceOrder(Side.SELL, k, float(s)))\n        # bid: crossing iff bucket < k\n        best = None\n        for k in range(max((b if b else 0) + 1, j0 - 1), min(99, (a if a else 100), j1 + 2) + 1):\n            c = k / 100.0\n            A = (tm - PM[k]) - c * (tw - PW[k])\n            B = PM[k] - c * PW[k]\n            for i, s in enumerate(SIZES):\n                v = self.retail_rate * self.F[k][i] * A + s * B * (1.0 + self.margin)\n                if best is None or v > best[0]:\n                    best = (v, k, s)\n        if best and best[0] > self.min_value:\n            _, k, s = best\n            if k / 100.0 * s < cash * 0.45:\n                acts.append(PlaceOrder(Side.BUY, k, float(s)))\n        return acts\n", "tuning_score": {"seeds": "115000..115023", "n": 24, "s1_mean": 21.74, "s0_mean": -14.16}, "paired": {"seeds": "200000..200249 (250 of the 1000 requested; timing forced fewer, see seconds_per_simulation)", "n": 250, "complete": false, "mechanism_diff": 34.06, "mechanism_se": 4.87, "mechanism_retail_diff": 22.8, "mechanism_arb_diff": 11.26, "reference_diff": -68.02, "reference_se": 10.96, "s1_mean": 17.1, "s0_mean": -16.96, "b_mean": 85.11, "failures": []}, "graft": "Keep a cloud of score particles; each step weight them by P(x,steps_left) lying between competitor best bid and ask, and by survival of your own orders (surviving ask at k means p<=k/100); resample, reseed on the interval after jumps, propagate with diffusion plus jumps, and quote from the predictive p distribution.", "seconds_per_simulation": {"s1": 9.64, "s0": 6.26, "note": "measured with S0 and S1 running as two concurrent processes on a machine that gave about one core of throughput; alone S1 about 6 s and S0 about 3 s; engine alone about 1.6 s"}}