{"approach":"Standalone local expected-edge maximizer. Each side scores 12 unrolled fee points against a 30 bp competitor. Retail order size is integrated with five-point Gauss-Hermite quadrature for the configured lognormal size distribution; routing and arb loss use the stated local approximations. The first small trade of a timestamp can refresh inferred fair price using the fee actually used for that trade; later trades receive only a low-weight fair-price update. Silent-step posterior uses W approximately equal to old bid plus old ask, rational exponential decay, and capped killed-kernel variance. The normal tail H is linearly interpolated from a 0.25-spaced table. These are approximations of the brief’s continuous model.","tried":[{"params":{"fee_grid_bps":[0,10,16,20,24,28,32,36,42,48,58,72],"sigma_per_step":0.000945,"retail_rate":0.8,"retail_mean_y":20,"quadrature_points":5,"fair_update_first":0.26,"fair_update_later":0.05},"seeds":"0..1999","n":2000,"mean_diff":-134.24625234590457,"se":0.8558850629469315}],"next":"Do not promote: the fresh paired result is materially negative. Test a better estimate of the competing AMM spot and conditional arb risk before another local-optimization comparison; YQ remains the reference.","code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {AMMStrategyBase} from \"./AMMStrategyBase.sol\";\nimport {TradeInfo} from \"./IAMMStrategy.sol\";\n\ncontract Strategy is AMMStrategyBase {\n    uint256 constant SIGMA = 945000000000000; // per-step price sigma\n    uint256 constant LAMBDA = 800000000000000000; // retail orders per step\n    uint256 constant ORDER_Y = 20 * WAD; // mean order size\n    uint256 constant ONE_QUARTER = 250000000000000000;\n    uint256 constant KILLED_VAR_FRAC = 47357633493984725; // 1/4 - 2/pi^2\n\n    // 0 bid, 1 ask, 2 fair estimate, 3 last timestamp,\n    // 4 last informative trade timestamp, 5 previous bid, 6 previous ask.\n    function afterInitialize(uint256 x, uint256 y) external override returns (uint256, uint256) {\n        slots[0] = 30 * BPS;\n        slots[1] = 30 * BPS;\n        slots[2] = x == 0 ? 100 * WAD : wdiv(y, x);\n        slots[3] = 0;\n        slots[4] = 0;\n        slots[5] = 30 * BPS;\n        slots[6] = 30 * BPS;\n        return (30 * BPS, 30 * BPS);\n    }\n\n    function afterSwap(TradeInfo calldata trade) external override returns (uint256 bidFee, uint256 askFee) {\n        uint256 pHat = slots[2];\n        uint256 oldBid = slots[0];\n        uint256 oldAsk = slots[1];\n        bool first = slots[7] == 0 || trade.timestamp > slots[3];\n        uint256 spot = wdiv(trade.reserveY, trade.reserveX);\n        uint256 feeUsed = trade.isBuy ? oldBid : oldAsk;\n        uint256 gamma = WAD - feeUsed;\n        uint256 implied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma);\n        uint256 ret = wdiv(absDiff(implied, pHat), pHat);\n        uint256 sizeRatio = wdiv(trade.amountY, trade.reserveY);\n        bool informative = first && sizeRatio < 8 * BPS && ret < 35 * BPS;\n        if (ret < 300 * BPS) {\n            uint256 alpha = first ? 260000000000000000 : 50000000000000000;\n            pHat = wmul(pHat, WAD - alpha) + wmul(implied, alpha);\n        }\n        if (informative) slots[4] = trade.timestamp;\n        slots[2] = pHat;\n        uint256 n = trade.timestamp > slots[4] ? trade.timestamp - slots[4] : 0;\n        if (n > 16) n = 16;\n        int256 m = (int256(spot) - int256(pHat)) * int256(WAD) / int256(pHat);\n        if (m > int256(150 * BPS)) m = int256(150 * BPS);\n        if (m < -int256(150 * BPS)) m = -int256(150 * BPS);\n        uint256 band = oldBid + oldAsk;\n        if (band < 30 * BPS) band = 30 * BPS;\n        uint256 sigma2 = wmul(SIGMA, SIGMA);\n        uint256 band2 = wmul(band, band);\n        // Killed Brownian posterior conditioned on no intervening arb.\n        uint256 x = (15 * sigma2 * n * WAD) / band2;\n        if (x > 10 * WAD) x = 10 * WAD;\n        uint256 x2 = wmul(x, x);\n        uint256 x3 = wmul(x2, x);\n        uint256 decay = wdiv(WAD, WAD + x + x2 / 2 + x3 / 6);\n        m = m * int256(decay) / int256(WAD);\n        uint256 varN = sigma2 * n;\n        uint256 varCap = wmul(band2, KILLED_VAR_FRAC);\n        if (varN > varCap) varN = varCap;\n        uint256 w = sqrt((sigma2 + varN) * WAD);\n        uint256 B = sqrt(wmul(trade.reserveX, trade.reserveY) * pHat);\n        int256 mClip = m;\n        if (mClip > int256(30 * BPS)) mClip = int256(30 * BPS);\n        if (mClip < -int256(30 * BPS)) mClip = -int256(30 * BPS);\n        // c is the competing 30-bp quote, translated by the local spot offset.\n        int256 cBid = int256(30 * BPS) + mClip;\n        int256 cAsk = int256(30 * BPS) - mClip;\n        bidFee = _bestFee(-m, cBid, B, w);\n        askFee = _bestFee(m, cAsk, B, w);\n        slots[0] = bidFee;\n        slots[1] = askFee;\n        slots[3] = trade.timestamp;\n        slots[7] = 1;\n    }\n\n    function _bestFee(int256 sideM, int256 c, uint256 B, uint256 w) internal pure returns (uint256 bestFee) {\n        int256 bestScore = type(int256).min;\n        (bestFee, bestScore) = _tryFee(0 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(10 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(16 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(20 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(24 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(28 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(32 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(36 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(42 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(48 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(58 * BPS, sideM, c, B, w, bestFee, bestScore);\n        (bestFee, bestScore) = _tryFee(72 * BPS, sideM, c, B, w, bestFee, bestScore);\n    }\n\n    function _tryFee(uint256 f, int256 sideM, int256 c, uint256 B, uint256 w,\n        uint256 bestFee, int256 bestScore) internal pure returns (uint256, int256) {\n        int256 d = int256(f) + sideM;\n        int256 offset = int256(B / 4) * (c - d) / int256(WAD);\n        int256 retail =\n            _retailAt(315804558311325312, 11257411327720692, offset, d, B) +\n            _retailAt(1913589614558730752, 222075922005612608, offset, d, B) +\n            _retailAt(9735045119199434752, 533333333333333312, offset, d, B) +\n            _retailAt(49525301951799468032, 222075922005612608, offset, d, B) +\n            _retailAt(300094159437121781760, 11257411327720692, offset, d, B);\n        retail = retail * int256(LAMBDA) / (2 * int256(WAD));\n        uint256 H = _h(d, w);\n        int256 score = retail - int256(wmul(B, H) / 4);\n        if (score > bestScore) return (f, score);\n        return (bestFee, bestScore);\n    }\n\n    function _retailAt(uint256 Q, uint256 weight, int256 offset, int256 d, uint256 B)\n        internal pure returns (int256) {\n        int256 qSigned = int256(Q / 2) + offset;\n        if (qSigned < 0) qSigned = 0;\n        if (qSigned > int256(Q)) qSigned = int256(Q);\n        uint256 q = uint256(qSigned);\n        int256 edge = qSigned * d / int256(WAD) + int256(q * q / B);\n        return edge * int256(weight) / int256(WAD);\n    }\n\n    // H(d,w)=w^2 E[(Z-d/w)_+^2]; normal tail tabulated at z=0,1/4,...,6.\n    function _h(int256 d, uint256 w) internal pure returns (uint256) {\n        uint256 ad = uint256(d >= 0 ? d : -d);\n        uint256 z = ad * WAD / w;\n        uint256 hp;\n        if (z >= 6 * WAD) hp = 0;\n        else {\n            uint256 idx = z / (WAD / 4);\n            uint256 frac = (z % (WAD / 4)) * 4;\n            uint256 lo;\n            uint256 hi;\n            if (idx == 0) { lo = 500000000000000000; hi = 329707499761181184; }\n        else if (idx == 1) { lo = 329707499761181184; hi = 209639260025333824; }\n        else if (idx == 2) { lo = 209639260025333824; hi = 128252163972753248; }\n        else if (idx == 3) { lo = 128252163972753248; hi = 75339783343770784; }\n        else if (idx == 4) { lo = 75339783343770784; hi = 42416188285039288; }\n        else if (idx == 5) { lo = 42416188285039288; hi = 22847010624951148; }\n        else if (idx == 6) { lo = 22847010624951148; hi = 11755016812861758; }\n        else if (idx == 7) { lo = 11755016812861758; hi = 5768726714519973; }\n        else if (idx == 8) { lo = 5768726714519973; hi = 2696648840956828; }\n        else if (idx == 9) { lo = 2696648840956828; hi = 1199322377955656; }\n        else if (idx == 10) { lo = 1199322377955656; hi = 506925820779248; }\n        else if (idx == 11) { lo = 506925820779248; hi = 203435080486933; }\n        else if (idx == 12) { lo = 203435080486933; hi = 77445866419001; }\n        else if (idx == 13) { lo = 77445866419001; hi = 27945864560546; }\n        else if (idx == 14) { lo = 27945864560546; hi = 9551549459190; }\n        else if (idx == 15) { lo = 9551549459190; hi = 3090208103498; }\n        else if (idx == 16) { lo = 3090208103498; hi = 945817284567; }\n        else if (idx == 17) { lo = 945817284567; hi = 273718919439; }\n        else if (idx == 18) { lo = 273718919439; hi = 74864282211; }\n        else if (idx == 19) { lo = 74864282211; hi = 19343295188; }\n        else if (idx == 20) { lo = 19343295188; hi = 4719578491; }\n        else if (idx == 21) { lo = 4719578491; hi = 1087024719; }\n        else if (idx == 22) { lo = 1087024719; hi = 236265006; }\n        else if (idx == 23) { lo = 236265006; hi = 48445767; }\n            else { lo = 236265006; hi = 48445767; }\n            hp = lo - wmul(lo - hi, frac);\n        }\n        if (d < 0) hp = WAD + wmul(z, z) - hp;\n        return wmul(wmul(w, w), hp);\n    }\n\n    function getName() external pure override returns (string memory) { return \"th-local\"; }\n}\n","code_sha256":"a1f86deafb56a4aaa62b6de864a4c5313d3f8e43f1a172c961093572d8d461b4","delta":"standalone","score":{"seed_start":0,"n":1000,"mean_edge":389.7665190445109,"se":1.8835966479202493},"paired":{"reference":"YQ 00fae418","seed_start":500000,"n":2000,"mean_diff":-134.60970360232022,"se":0.9315520350286566,"worst":[{"seed":500658,"diff":-384.0219556749573},{"seed":500471,"diff":-363.58377150012683},{"seed":501561,"diff":-345.62361051507247},{"seed":501890,"diff":-336.8477473935608},{"seed":501960,"diff":-311.7495058226423}]},"seconds_per_simulation":0.305376846164465,"validate_ok":true,"blocked":null,"citations":[{"claim":"Seed construction and per-seed randomized parameters","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py"},{"claim":"Default simulation length, order size distribution, and volatility range","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py"},{"claim":"Price, arbitrage, then retail step order","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs"},{"claim":"Optimal retail splitting formula","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/router.rs"},{"claim":"32-slot strategy storage","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/AMMStrategyBase.sol"},{"claim":"Fixed 30 bp normalizer fee","url":"https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol"},{"claim":"YQ source used as paired reference","url":"https://raw.githubusercontent.com/jiayaoqijia/amm-challenge-yq/3e9dc7d5a6192c88b562a0f8d9c172ca566ec94d/contracts/src/Strategy.sol"},{"claim":"Public discussion of fair-price and arb-informed fee mechanisms","url":"https://www.benedict.dev/optimization-arena-learnings"},{"claim":"Public discussion of first-in-block arb ordering","url":"https://www.linkedin.com/pulse/amm-fee-challenge-notes-from-our-run-optimization-arena-qe3ff"}]}
