# prespot-b: result **Outcome:** +0.3946 ± 0.0106 paired against NP2 on the confirmation block. That is a small gain, about 4% of the +9.6 needed for 1st. **The pre-spot idea as briefed did not work.** Updating pHat toward the recovered pre-trade spot or the band centre lost outright or came in below the plain alpha cut at every tested point (best: +0.20 with `omega=0.25, A1=0.22`). The gain comes from the part of the brief about large first prints: trusting pImplied less there, while keeping it as the target. ## delta Two constants and one line added to NP2; no slots, nothing else touched: ``` uint256 constant PHAT_ALPHA_LARGE = 200000000000000000; // 0.20 uint256 constant LARGE_FIRST_RATIO = 2500000000000000; // 0.0025 ... uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL; if (firstInStep && trade.reserveY > 0 && wdiv(trade.amountY, trade.reserveY) > LARGE_FIRST_RATIO) alpha = PHAT_ALPHA_LARGE; ``` A first print with amountY/reserveY > 0.0025 moves pHat at 0.20 instead of 0.27. Target stays pImplied. The contract does not compute a pre-trade spot: every variant that did scored below this (see tuning). ## code Full contract. The sha256 below is of this text, including its final newline. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; contract Strategy is AMMStrategyBase { uint256 constant ELAPSED_CAP = 8; uint256 constant SIGNAL_THRESHOLD = WAD / 650; uint256 constant DIR_DECAY = 750000000000000000; uint256 constant ACT_DECAY = 530000000000000000; uint256 constant SIZE_DECAY = 530000000000000000; uint256 constant TOX_DECAY = 910000000000000000; uint256 constant SIGMA_DECAY = 690000000000000000; uint256 constant LAMBDA_DECAY = 990000000000000000; uint256 constant SIZE_BLEND_DECAY = 828000000000000000; uint256 constant TOX_BLEND_DECAY = 51000000000000000; uint256 constant ACT_BLEND_DECAY = 985000000000000000; uint256 constant PHAT_ALPHA = 270000000000000000; uint256 constant PHAT_ALPHA_LARGE = 200000000000000000; uint256 constant LARGE_FIRST_RATIO = 2500000000000000; uint256 constant PHAT_ALPHA_RETAIL = 60000000000000000; uint256 constant PHAT_ALPHA_SAME = 120000000000000000; uint256 constant REVERT_U = 0; uint256 constant DIR_IMPACT_MULT = 4; uint256 constant GATE_SIGMA_MULT = 7200000000000000000; uint256 constant MIN_GATE = 30000000000000000; uint256 constant TRADE_TOX_BOOST = 3500 * BPS; uint256 constant STALE_ATTRACT_FRAC = 1050000000000000000; uint256 constant RET_CAP = WAD / 35; uint256 constant TOX_CAP = WAD / 5; uint256 constant TRADE_RATIO_CAP = WAD / 5; uint256 constant LAMBDA_CAP = 1820000000000000000; uint256 constant STEP_COUNT_CAP = 64; uint256 constant BASE_FEE = 4 * BPS; uint256 constant SIGMA_COEF = 200000000000000000; uint256 constant LAMBDA_COEF = 12 * BPS; uint256 constant FLOW_SIZE_COEF = 4842 * BPS; uint256 constant TOX_COEF = 300 * BPS; uint256 constant TOX_QUAD_COEF = 15000 * BPS; uint256 constant ACT_COEF = 91843 * BPS; uint256 constant DIR_COEF = 20 * BPS; uint256 constant DIR_TOX_COEF = 100 * BPS; uint256 constant STALE_DIR_COEF = 6850 * BPS; uint256 constant SIGMA_TOX_COEF = 500 * BPS; uint256 constant TAIL_KNEE = 600 * BPS; uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000; uint256 constant TAIL_SLOPE_ATTRACT = 850000000000000000; function afterInitialize(uint256 initialX, uint256 initialY) external override returns (uint256, uint256) { slots[0] = BASE_FEE; slots[1] = BASE_FEE; slots[2] = 0; slots[3] = WAD; slots[4] = 0; slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD; slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000; slots[9] = 0; slots[10] = 0; slots[11] = 0; slots[12] = 0; return (BASE_FEE, BASE_FEE); } function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) { uint256 prevBidFee = slots[0]; uint256 prevAskFee = slots[1]; uint256 lastTs = slots[2]; uint256 dirState = slots[3]; uint256 actEma = slots[4]; uint256 pHat = slots[5]; uint256 sigmaHat = slots[6]; uint256 lambdaHat = slots[7]; uint256 sizeHat = slots[8]; uint256 toxEma = slots[9]; uint256 stepTradeCount = slots[10]; bool isNewStep = trade.timestamp > lastTs; if (isNewStep) { uint256 elapsedRaw = trade.timestamp - lastTs; uint256 elapsed = elapsedRaw > ELAPSED_CAP ? ELAPSED_CAP : elapsedRaw; dirState = _decayCentered(dirState, DIR_DECAY, elapsed); actEma = wmul(actEma, _powWad(ACT_DECAY, elapsed)); sizeHat = wmul(sizeHat, _powWad(SIZE_DECAY, elapsed)); toxEma = wmul(toxEma, _powWad(TOX_DECAY, elapsed)); if (stepTradeCount > 0 && elapsedRaw > 0) { uint256 lambdaInst = (stepTradeCount * WAD) / elapsedRaw; if (lambdaInst > LAMBDA_CAP) lambdaInst = LAMBDA_CAP; lambdaHat = wmul(lambdaHat, LAMBDA_DECAY) + wmul(lambdaInst, WAD - LAMBDA_DECAY); } stepTradeCount = 0; } bool firstInStep = stepTradeCount == 0; uint256 spot = trade.reserveX > 0 ? wdiv(trade.reserveY, trade.reserveX) : pHat; if (pHat == 0) pHat = spot; uint256 feeUsed = trade.isBuy ? prevBidFee : prevAskFee; uint256 gamma = feeUsed < WAD ? WAD - feeUsed : 0; uint256 pImplied; if (gamma == 0) { pImplied = spot; } else { pImplied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma); } { uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0; uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL; // A large first print is often retail, so its pImplied carries its own impact: trust it less. if (firstInStep && trade.reserveY > 0 && wdiv(trade.amountY, trade.reserveY) > LARGE_FIRST_RATIO) alpha = PHAT_ALPHA_LARGE; uint256 prePhat = pHat; bool secondPrint = !firstInStep && stepTradeCount == 1; bool sameDir = false; bool oppDir = false; if (secondPrint) { bool up2 = pImplied >= pHat; uint256 d1 = slots[12]; if (d1 != 0) { sameDir = (d1 == 1) == up2; oppDir = !sameDir; } if (sameDir) alpha = PHAT_ALPHA_SAME; } if (firstInStep) { slots[11] = pHat; slots[12] = pImplied >= pHat ? 1 : 2; } uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT); if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE; if (ret <= adaptiveGate) { pHat = wmul(pHat, WAD - alpha) + wmul(pImplied, alpha); } if (oppDir && REVERT_U > 0) { uint256 pre = slots[11]; if (pre > pHat) pHat = pHat + wmul(pre - pHat, REVERT_U); else pHat = pHat - wmul(pHat - pre, REVERT_U); } if (firstInStep) { if (ret > RET_CAP) ret = RET_CAP; sigmaHat = wmul(sigmaHat, SIGMA_DECAY) + wmul(ret, WAD - SIGMA_DECAY); } } // Interior retail routing equalizes fee-adjusted marginal prices. // Subsequent trades in a step cannot be the initial arbitrage trade. if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) { uint256 normalSpot = trade.isBuy ? wdiv(wmul(spot, gamma), WAD - 30 * BPS) : wdiv(wmul(spot, WAD - 30 * BPS), gamma); pHat = wmul(pHat, 90 * WAD / 100) + wmul(normalSpot, 10 * WAD / 100); } uint256 tradeRatio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0; if (tradeRatio > TRADE_RATIO_CAP) tradeRatio = TRADE_RATIO_CAP; if (tradeRatio > SIGNAL_THRESHOLD) { uint256 push = tradeRatio * DIR_IMPACT_MULT; if (push > WAD / 4) push = WAD / 4; if (trade.isBuy) { dirState = dirState + push; if (dirState > 2 * WAD) dirState = 2 * WAD; } else { dirState = dirState > push ? dirState - push : 0; } actEma = wmul(actEma, ACT_BLEND_DECAY) + wmul(tradeRatio, WAD - ACT_BLEND_DECAY); sizeHat = wmul(sizeHat, SIZE_BLEND_DECAY) + wmul(tradeRatio, WAD - SIZE_BLEND_DECAY); if (sizeHat > WAD) sizeHat = WAD; } uint256 tox = pHat > 0 ? wdiv(absDiff(spot, pHat), pHat) : 0; if (tox > TOX_CAP) tox = TOX_CAP; toxEma = wmul(toxEma, TOX_BLEND_DECAY) + wmul(tox, WAD - TOX_BLEND_DECAY); uint256 toxSignal = toxEma; stepTradeCount = stepTradeCount + 1; if (stepTradeCount > STEP_COUNT_CAP) stepTradeCount = STEP_COUNT_CAP; uint256 flowSize = wmul(lambdaHat, sizeHat); uint256 fBase = BASE_FEE + wmul(SIGMA_COEF, sigmaHat) + wmul(LAMBDA_COEF, lambdaHat) + wmul(FLOW_SIZE_COEF, flowSize); uint256 fMid = fBase + wmul(TOX_COEF, toxSignal) + wmul(TOX_QUAD_COEF, wmul(toxSignal, toxSignal)) + wmul(ACT_COEF, actEma); fMid = fMid + wmul(SIGMA_TOX_COEF, wmul(sigmaHat, toxSignal)); uint256 dirDev; bool sellPressure; if (dirState >= WAD) { dirDev = dirState - WAD; sellPressure = true; } else { dirDev = WAD - dirState; sellPressure = false; } uint256 skew = wmul(DIR_COEF, dirDev) + wmul(DIR_TOX_COEF, wmul(dirDev, toxSignal)); uint256 bidFee; uint256 askFee; if (sellPressure) { bidFee = fMid + skew; askFee = fMid > skew ? fMid - skew : 0; } else { askFee = fMid + skew; bidFee = fMid > skew ? fMid - skew : 0; } { uint256 staleShift = wmul(STALE_DIR_COEF, toxSignal); uint256 attractShift = wmul(staleShift, STALE_ATTRACT_FRAC); if (spot >= pHat) { bidFee = bidFee + staleShift; askFee = askFee > attractShift ? askFee - attractShift : 0; } else { askFee = askFee + staleShift; bidFee = bidFee > attractShift ? bidFee - attractShift : 0; } } { bool tradeAligned = (trade.isBuy && spot >= pHat) || (!trade.isBuy && spot < pHat); if (tradeAligned) { uint256 tradeBoost = wmul(TRADE_TOX_BOOST, tradeRatio); if (trade.isBuy) { bidFee = bidFee + tradeBoost; } else { askFee = askFee + tradeBoost; } } } if (sellPressure) { bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_PROTECT)); askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_ATTRACT)); } else { askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_PROTECT)); bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_ATTRACT)); } slots[0] = bidFee; slots[1] = askFee; slots[2] = trade.timestamp; slots[3] = dirState; slots[4] = actEma; slots[5] = pHat; slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat; slots[9] = toxEma; slots[10] = stepTradeCount; return (bidFee, askFee); } function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) { if (fee <= TAIL_KNEE) return fee; return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope); } function _powWad(uint256 factor, uint256 exp) internal pure returns (uint256 result) { result = WAD; while (exp > 0) { if (exp & 1 == 1) result = wmul(result, factor); factor = wmul(factor, factor); exp >>= 1; } } function _decayCentered(uint256 centered, uint256 decayFactor, uint256 elapsed) internal pure returns (uint256) { uint256 mul = _powWad(decayFactor, elapsed); if (centered >= WAD) { return WAD + wmul(centered - WAD, mul); } uint256 below = wmul(WAD - centered, mul); return below < WAD ? WAD - below : 0; } function getName() external pure override returns (string memory) { return "no_cubic"; } } ``` ## sha256 `21d89fc048cf7f56701a64ef3f1707602d5bfa92b68735cb15f27609886b814d` NP2 base rebuilt from the two artifacts: `51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0`, which matches the prefix in the brief. ## tuning Method: separate `run_batch(x, vanilla, cfgs, 8)` runs, 16 seeds a call, d = x minus NP2 `edges['submission']`. All points are on seeds 10000..10699. There were 49 points, and the top three were re-checked on 10200..10699, which they had not seen. Key to the constants: - `T1`: first prints with amountY/reserveY above this use the alternate rule, and `A1` is their alpha. - `TB` with `M`: as `T1`, but pHat must also lie inside the pre-trade band, with margin M. - `A3`: alpha on first prints the classifier leaves alone. - `nf='replace'`: non-first prints use the alternate target; `A2` is their alpha, and `NT` is a ratio cut on them. - `target`: - `c`, band centre (the default when target is not listed) - `e`, the pre-band edge, which is pImplied with own impact removed - `w`, a blend of pImplied and that edge with weight `omega` - `k`, keep pImplied - `add`: an extra update after the NP block on non-first prints (`c` centre, `p` projection into the band), alpha `a`. - `np_beta=1`: NP block's normalSpot rescaled by preSpot/spot. - `sig_only`: pre-spot target used only for the sigma update. - `sigma_orig`: sigma still uses raw pImplied. - `smooth=(T0,S,Amin)`: first-print alpha falls linearly with the ratio. | constants | seeds | n | mean_diff | se | worst | |---|---|---|---|---|---| | `nf=replace` | 10000..10199 | 200 | -1.0142 | 0.0650 | -4.388 | | `nf=replace, A2=0.03` | 10000..10199 | 200 | -0.8742 | 0.1241 | -22.275 | | `nf=replace, A2=0.12` | 10000..10199 | 200 | -1.5486 | 0.0698 | -4.378 | | `T1=0.001` | 10000..10199 | 200 | -28.5320 | 0.4263 | -42.668 | | `T1=0.002` | 10000..10199 | 200 | -11.7671 | 0.2636 | -21.392 | | `T1=0.004` | 10000..10199 | 200 | -1.3151 | 0.1491 | -8.774 | | `T1=0.002, A1=0.1` | 10000..10199 | 200 | -3.7351 | 0.1206 | -8.593 | | `add=c, a=0.1` | 10000..10199 | 200 | -1.2824 | 0.0587 | -4.032 | | `np_beta=1.0` | 10000..10199 | 200 | -0.5352 | 0.0493 | -2.579 | | `nf=replace, target=e` | 10000..10199 | 200 | -0.3741 | 0.0499 | -4.648 | | `M=0.0, A1=0.0` | 10000..10199 | 200 | -74.3269 | 2.1417 | -230.276 | | `add=p, a=0.25` | 10000..10199 | 200 | -0.1077 | 0.0206 | -1.042 | | `np_beta=1.0, nf=replace, target=e` | 10000..10199 | 200 | -1.2981 | 0.0756 | -6.977 | | `M=0.0, A1=0.0, sigma_orig=True` | 10000..10199 | 200 | -96.8948 | 2.7380 | -242.255 | | `M=0.0005, A1=0.0, sigma_orig=True` | 10000..10199 | 200 | -108.9389 | 2.7556 | -269.440 | | `M=0.0, A1=0.15, target=k` | 10000..10199 | 200 | -3.2938 | 0.0928 | -10.345 | | `M=0.0, A1=0.27, target=k, A3=0.4` | 10000..10199 | 200 | +0.0119 | 0.0205 | -1.908 | | `M=0.0, A1=0.15, target=k, A3=0.4` | 10000..10199 | 200 | -3.2911 | 0.0906 | -8.213 | | `T1=0.004, A1=0.4, target=k` | 10000..10199 | 200 | -2.1261 | 0.0469 | -5.105 | | `T1=0.002, A1=0.15, target=k` | 10000..10199 | 200 | +0.2409 | 0.0512 | -2.301 | | `T1=0.002, sig_only=True` | 10000..10199 | 200 | -0.1588 | 0.0627 | -3.623 | | `M=0.0, sig_only=True` | 10000..10199 | 200 | -4.8246 | 0.0709 | -7.514 | | `T1=0.002, A1=0.15, target=e` | 10000..10199 | 200 | -1.4164 | 0.0824 | -5.747 | | `T1=0.002, A1=0.27, target=e` | 10000..10199 | 200 | -1.4926 | 0.0831 | -5.367 | | `T1=0.002, A1=0.1, target=k` | 10000..10199 | 200 | -0.3125 | 0.0682 | -2.919 | | `T1=0.0015, A1=0.2, target=k` | 10000..10199 | 200 | +0.3243 | 0.0388 | -0.846 | | `T1=0.0015, A1=0.15, target=k` | 10000..10199 | 200 | -0.0289 | 0.0549 | -3.035 | | `T1=0.003, A1=0.15, target=k` | 10000..10199 | 200 | +0.3510 | 0.0467 | -1.660 | | `T1=0.003, A1=0.08, target=k` | 10000..10199 | 200 | -0.1556 | 0.0716 | -3.198 | | `T1=0.002, A1=0.2, target=k` | 10000..10199 | 200 | +0.3962 | 0.0397 | -0.666 | | `M=0.0, TB=0.002, A1=0.1, target=k` | 10000..10199 | 200 | -0.1349 | 0.0678 | -3.333 | | `M=0.0, TB=0.002, A1=0.05, target=k` | 10000..10199 | 200 | -0.9544 | 0.0890 | -5.083 | | `M=0.0, TB=0.001, A1=0.1, target=k` | 10000..10199 | 200 | -2.0054 | 0.0867 | -5.379 | | `M=0.0, TB=0.001, A1=0.2, target=k` | 10000..10199 | 200 | +0.0554 | 0.0476 | -1.813 | | `smooth=[0.001, 60, 0.1]` | 10000..10199 | 200 | +0.0199 | 0.0624 | -2.668 | | `smooth=[0.001, 40, 0.15]` | 10000..10199 | 200 | +0.3664 | 0.0479 | -2.192 | | `smooth=[0.0005, 40, 0.15]` | 10000..10199 | 200 | +0.2022 | 0.0527 | -2.439 | | `smooth=[0.0015, 40, 0.1]` | 10000..10199 | 200 | +0.2920 | 0.0572 | -1.826 | | `T1=0.002, target=w, omega=0.25` | 10000..10199 | 200 | +0.0410 | 0.0383 | -1.400 | | `T1=0.002, target=w, omega=0.5` | 10000..10199 | 200 | -0.3305 | 0.0558 | -2.676 | | `T1=0.002, target=w, omega=0.25, A1=0.22` | 10000..10199 | 200 | +0.1966 | 0.0445 | -1.589 | | `nf=replace, target=w, omega=0.25` | 10000..10199 | 200 | -0.0637 | 0.0230 | -1.029 | | `T1=0.002, A1=0.2, nf=replace, NT=0.002, target=k, A2=0.03` | 10000..10199 | 200 | +0.2454 | 0.0478 | -1.407 | | `T1=0.002, A1=0.2, nf=replace, NT=0.002, target=k, A2=0.1` | 10000..10199 | 200 | +0.1313 | 0.0417 | -1.177 | | `T1=0.0025, A1=0.2, target=k` | 10000..10199 | 200 | +0.4074 | 0.0368 | -0.731 | | `T1=0.002, A1=0.23, target=k` | 10000..10199 | 200 | +0.3189 | 0.0340 | -0.493 | | `T1=0.0025, A1=0.2, target=k` | 10200..10699 | 500 | +0.3729 | 0.0225 | -2.419 | | `T1=0.002, A1=0.2, target=k` | 10200..10699 | 500 | +0.3759 | 0.0247 | -2.697 | | `smooth=[0.001, 40, 0.15]` | 10200..10699 | 500 | +0.3296 | 0.0320 | -4.427 | Not measured: `add='p', a=1.0`. The first sweep hit the command timeout before reaching it, so it was dropped. Reading of the results: - **Pre-spot targets lose.** Band centre on non-first prints is -1.01, and on large first prints with `T1=0.002` it is -11.77. Own-impact removal (`e`) is -0.37 on non-first prints and -1.49 on large first prints. Rescaling NP's normalSpot is -0.54. - **Partial removal does not rescue it.** With `omega=0.25` the results are -0.06 (non-first), +0.04 (first) and +0.20 (first, `A1=0.22`), all below the plain alpha cut. - **The band as a classifier fails.** Using "pHat inside the pre-band means retail" costs -3.29 when alpha is cut to 0.15. With no update at all it costs -74.33, because pHat stalls. - **The alpha cut has a plateau.** It sits at `T1` 0.002 to 0.003 and `A1` about 0.2. `T1=0.0025` and `T1=0.002` tie on the re-check, and I froze `T1=0.0025` for its better 500-seed worst case (-2.42 vs -2.70). - **Possible cause, not tested:** a pull toward own pre-spot may shrink the |spot - pHat| signal the fee constants were tuned on. Large first prints also look like a mix of retail and reversal arbs. I did not log trades, so neither explanation is confirmed. ## paired Confirm block 2650000..2651999, frozen code, run once, against NP2 (both sides vs Vanilla, run separately): ```json {"n": 2000, "mean_diff": 0.3945690120943292, "se": 0.010624604223147479, "worst": -2.814939168815499} ``` - Mean edge: candidate 525.6017, NP2 525.2071, on this block. - 82.45% of seeds improved. The worst seed is 2651998. Checks on this run: - CH on seeds 0..999 gave 525.525882178, the required value. - NP2 on seeds 0..999 gave 526.1156, as the brief states. - `amm-match validate` passed on the frozen contract. - Frozen code matched the tuned variant exactly on 16 seeds (max difference 0.0). - I did not measure gas. The change adds one division on first prints only. ## blocked null ## next Pair a pre-spot target with a re-tune of `STALE_DIR_COEF` and the tox coefficients. If the self-reference explanation above is right, those constants are what penalise a cleaner pHat. This task fixed them, so that was not tested here.