{"topic": "Liquidity-shadow: a fee-dependent continuation-value correction (residual-mispricing shadow price tau) for STACK; no simulator run, no performance claim.", "sources": ["engine.rs SimulationEngine::run: per step 1 GBM price, 2 arb on every AMM, 3 retail routed; edge += -arb.profit and retail edge = amount_x*fair - amount_y (or reverse). Edge is booked at fair price at trade time; no mark-to-market, no inventory term. (pnl is a separate map.)", "cfmm.rs CFMM::execute_buy_x / execute_sell_x / execute_buy_x_with_y: fee goes to accumulated_fees bucket, reserves get net amounts, so k=x*y is conserved by every trade; update_fees calls strategy.after_swap after EVERY fill (arb or retail) and the returned pair persists until the next callback (on EVM error old fees kept).", "arbitrageur.rs compute_buy_arb/compute_sell_arb: closed-form profit-max size, trades only if profit>0 (a no-trade band of ~fee per side), uses amm.fees() as left by the last callback.", "router.rs split_buy_two_amms/split_sell_two_amms + route_to_two_amms: orders sequential, each split to equalize fee-adjusted marginal prices (A_i=sqrt(x_i*gamma_i*y_i)); fees re-read after every fill callback.", "retail.rs RetailTrader::generate_orders: Poisson arrivals, lognormal sizes (Y terms), buy_prob 0.5 -> flow is side-symmetric and unforecastable.", "match.py HyperparameterVariance/_build_configs + config.py BASELINE_*: default_rng(seed) draws size U(19,21), rate U(0.6,1.0), sigma U(0.000882,0.001008); n_steps 10000, x0=100,y0=10000.", "IAMMStrategy.sol TradeInfo: isBuy, amountX, amountY, timestamp, POST-trade reserveX/reserveY only. AMMStrategyBase.sol: 32 slots, clampFee, MAX_FEE=10%. strategy.rs GAS_LIMIT_TRADE=250000. VanillaStrategy.sol: FEE=30bps both sides (the only opponent per the brief).", "STACK (api.imdnotdead.fun artifact c3372087..., sha256 of the artifact file verified = c33720874aa1...bdb27c1 as the URL id; the code field is what is analysed): slots 0-15 used, afterSwap L56-276."], "current_limitation": "STACK's fee level is an additive sum of EMAs (base+sigma+lambda+flowSize+tox+act, L211-213), a dirState skew (L219-227), a stale shift on instantaneous |spot-staleHat| (L229-242), a trade-aligned boost (L244-252) and caps (30bp first-in-step, 36bp, L262-268). Each term treats spot-vs-estimated-fair as an INSTANTANEOUS toxicity or an inventory-like skew. None is derived from the simulator's actual future cash flows, and none sees that today's asymmetric pair (f_b,f_a) itself defines the next arb no-trade band, hence how much displacement survives into the next retail fills. Verified from source: (1) edge has no inventory penalty (engine.rs); (2) k is constant for the whole run because fees leave the reserves (cfmm.rs), so 'liquidity change' is only movement along a fixed curve = displacement of spot from fair; (3) therefore the only intertemporal channel of a fill is the mispricing it leaves for the next arb (profit>0 rule) and the next retail quote vs the 30bp rival (router). An Avellaneda-Stoikov style inventory term gamma*sigma^2*(x-x0) has no counterpart in scored edge and is only a proxy for that channel.", "mechanism": "Shadow value of a fill. Let g=ln(fair/spot) (unobserved, estimated N(ghat,s^2) with ghat=ln(pHat/spot), s^2=sigmaHat^2+uncertainty from STACK slot 13), y=reserveY, Q=typical retail size. Small fills: a fill of size q on the ask side raises spot by 2q/y (d ln p = 2 dy/y on x*y=k) i.e. lowers g by 2q/y. Next-step expected arb loss is A=(y/4)(E[(g-f_a)+^2]+E[(-g-f_b)+^2]) (check: closed form in arbitrageur.rs numerically matches (y/4)(m-f)^2 to <1% for m>f; checked offline in plain python, no simulator). Differentiating A along a fill gives a continuation term, and the sum with immediate edge collapses to V_ask = f_a - tau, V_bid = f_b + tau, tau = E[clip(g,-f_b,f_a)] = expected residual displacement that the arb leaves standing (arb moves spot to the band edge, then retail meets that residual). Identity: V_ask+V_bid = f_a+f_b. If arb is certain (|g|>band) V=f_a+f_b on the displacement-increasing side and 0 on the displacement-reducing side. Control: choose the pair maximizing one-step J = sum_s R_s(V_s) - A(f_a,f_b) where R_s=m_s*sh_s*V_s, sh_s=clip(1/2+k(c-V_s),0,1) is the router share vs the 30bp rival (rival quote ~30bp - its own residual, assumed mean 0), k=y/(4Q) from router split algebra. The cross terms dV_a/df_b, dV_b/df_a = pi_b, pi_a are the new 'asymmetric fee coupling'. Implementation as a compact CAUSAL CORRECTION on STACK: compute STACK's (bid,ask), evaluate J on a small candidate set around it, move to the best, keep STACK's caps and gas margin. What is new vs STACK: tau from the fee-dependent clip expectation (not |spot-pHat|), pair-sum identity, cross-coupling pi, arb-gradient term (y/2)U in the fee level, router-slope k as a share model, and an explicit separation of measured edge channels from an assumed inventory penalty (A-S control arm).", "equations": ["g~N(ghat,s^2); z_a=(ghat-f_a)/s; z_b=(-ghat-f_b)/s", "pi_a=P(g>f_a)=Phi(z_a); pi_b=P(g<-f_b)=Phi(z_b)", "U_a=E(g-f_a)+ = s*(phi(z_a)+z_a*Phi(z_a)); U_b=E(-g-f_b)+ = s*(phi(z_b)+z_b*Phi(z_b))", "tau = ghat - U_a + U_b  (=E clip(g,-f_b,f_a))", "V_a=f_a-tau; V_b=f_b+tau; V_a+V_b=f_a+f_b", "A(f)= (y/4)*(E(g-f_a)+^2+E(-g-f_b)+^2); dA/df_a=-(y/2)U_a; dA/df_b=-(y/2)U_b", "dV_a/df_a=1-pi_a; dV_b/df_a=pi_a; dV_b/df_b=1-pi_b; dV_a/df_b=pi_b", "share vs rival quote c=30bp: sh_s=clip(1/2+k(c-V_s),0,1), k=y/(4Q)  (equal-depth pools; ln marginal gap -> 2*dy/y each)", "R_s=m_s*sh_s*V_s, m_s=lambdaHat*Qbar/2 (Y/step); R_s'(V)=m_s*(1/2+k*c-2kV) inside (0,1)", "dJ/df_a=(1-pi_a)R_a'+pi_a R_b'+(y/2)U_a ; dJ/df_b=(1-pi_b)R_b'+pi_b R_a'+(y/2)U_b", "static stationary point if no arb coupling and no clipping: V*=c/2+1/(4k)=15bp+Q/y (hypothesis scale only)", "calibration: rho_hat=EMA(probArb per step); c_s=rho_hat/(pi_a+pi_b) clamped [0.6,1.6]; s<-s*c_s", "fill-level shadow: dispTarget_s = sign * (V_s - V_s^STACK) added to STACK fee as kappa*(...) in family A"], "causal_features": ["ghat=ln(pHat/spot) using STACK pHat/fastHat (built from past callbacks only: pImplied=spot*gamma or spot/gamma using the fee actually used, TradeInfo post-trade reserves).", "s^2 = sigmaHat^2 + slot13 uncertainty (grows sigma^2*elapsed on silent steps, shrinks on arb prints).", "y=trade.reserveY (post-trade, legal); Qbar/y = sizeHat (STACK slot 8, amountY/reserveY EMA); m via lambdaHat (slot 7).", "Own fees f_a,f_b (candidates) and prevBid/prevAsk slots 0/1.", "firstInStep, silent, probArb (STACK L152-164): a first print with probArb high implies spot was moved to the band edge, so residual g is ~ clip-edge; this selects which branch of tau to use right after an arb callback (g=+f_a-ish or -f_b-ish, known from fee used).", "Rival 30bp constant only because VanillaStrategy source says so and STACK already hard-codes it (L139-143); NO rival reserves, fair price, future trade type or simulator labels are used."], "state_slots": {"free_in_STACK": "slots 16-31 (STACK writes 0-15)", "16": "tauHat (last tau, for calibration/logging and smoothing)", "17": "rhoHat EMA of probArb per step", "18": "calib gain c_s (WAD)", "19": "kHat EMA of retail first-fill frequency per lambdaHat (share-slope proxy, family D)", "20": "last-step band-edge side (1 ask/2 bid)", "21-23": "spare for family B candidate index / hysteresis", "note": "all 8 or fewer new slots; no packing needed"}, "gas_plan": "STACK peaks at 214k of 250k (brief) so only ~30k headroom (~35 cold SSTOREs are NOT affordable). Budget: reuse already-loaded locals; add <=4 SLOAD/SSTORE (16-19) warm-priced after first touch; Phi via 9-knot piecewise-linear table in constants (no exp), phi via STACK's _powWad(WAD/(WAD+z2/16),8) which already exists; U from piecewise formula; candidate set <=5 pairs x ~1.5k gas of wmul/wdiv arithmetic. Compute the correction ONLY when firstInStep or tradeRatio>SIGNAL_THRESHOLD (skip trivial prints) and drop the unused REVERT_U branch (L126-130, dead since REVERT_U=0) and slots[11] reads to save gas. Gate: count OOG with amm_sim_rs.gas_stats(); any OOG invalidates. If max>235k, reduce candidates to 3 and use tau only (family A).", "rule_family_search": [{"id": "A_additive_tau", "rule": "keep STACK; add dfee_a=-kappa*(tau-tauSTACK_proxy), dfee_b=+kappa*(...) where tau from the clip expectation; kappa in {0,.25,.5,1}", "sign_hypothesis": "retail edge up on displacement-reducing side, arb edge less negative; small"}, {"id": "B_candidate_argmax", "rule": "evaluate J on pairs (bid+d1,ask+d2), d in {-6,-3,0,+3,+6}bp restricted to 5-9 pairs; pick max J; with k from sizeHat", "sign_hypothesis": "arb loss down where U large, retail share lost where V>c; net tests the whole model"}, {"id": "C_band_target", "rule": "choose f_a,f_b so tau hits target tau*=0 (symmetric residual) with level fixed by STACK; width of band = 2*s*z*, z* in {0.5,1,1.5}", "sign_hypothesis": "arb edge better, retail slightly worse"}, {"id": "D_share_learning", "rule": "learn k online: kHat from retail-first-print frequency vs lambdaHat after fee changes; plug into R'; clamp k in [0.5k0,2k0]", "sign_hypothesis": "helps when size/rate differ from mean; may add noise"}, {"id": "E_pair_sum_split", "rule": "hold f_a+f_b=STACK level, optimise only the split via V_a-V_b=f_a-f_b-2tau; i.e. skew = tau instead of dirState/stale terms", "sign_hypothesis": "replaces 3 heuristics with 1; ablate each"}, {"id": "F_inventory_penalty_control", "rule": "A-S: skew=gamma*sigma^2*(spot-implied inventory offset) with no clip expectation", "sign_hypothesis": "null or negative; defines the 'assumed penalty' arm"}], "falsification": ["Identity test (offline, one seed block, STACK fees replayed): per fill record realized immediate edge + realized change in next-step arb loss; mean should equal f_side -/+ tau within noise. If slope on tau not in [0.5,1.5], linearization (q/y=0.2% fills, lognormal sigma 1.2 tails) fails -> stop.", "Ablation ladder over STACK: (0) STACK; (1) +tau with ghat instead of clip (instant, i.e. STACK-like); (2) +tau clip; (3) +cross-coupling pi; (4) +arb gradient term; (5) +share slope; (6) A-S control. Each reported as paired diff with retail_edge and arb_edge deltas separately (hypotheses only: tau mostly arb channel, share slope mostly retail channel, A-S ~0).", "Sign test: reverse sign of tau; must lose, otherwise mechanism is not what drives gains.", "Per-seed worst and gas oog=0; tune on 10000..999999, one confirm on fresh >=5,000,000, >=2000 seeds, local gain needs ~ +5.0 (0.65 transfer)."], "risks": ["Gain ceiling: prior goals cap fee-family tuning near +1.2; this is only worth it if the arb-clip tau differs materially from STACK's stale shift. No evidence either way yet.", "Quadratic/Gaussian approximations; fills are not infinitesimal and retail sizes are heavy-tailed; rival's residual assumed mean zero (its band is +-30bp, correlated with the same fair path).", "Estimation of ghat is the same noisy pHat STACK uses; errors in s inflate arb term (calibration c_s mitigates).", "Gas headroom ~30k; fees clamp interactions with first-in-step 30bp and 36bp caps may make candidates infeasible -> keep caps after correction.", "Board transfer 0.65 of local; board config may differ from default_rng configs (not verifiable here).", "Nothing here was run; all signs are hypotheses; formula checks were arithmetic only."], "integration": "Insert after STACK's fee computation and caps-before-last (between L260 and L262): (bid,ask)=_shadow(bid,ask,...); then re-apply L262-268 caps and clampFee. Pseudocode:\nfunction _shadow(uint bid,uint ask,uint pHat,uint spot,uint y,uint s2,uint lam,uint sizeHat) returns(uint,uint){\n int g=ln1p-approx((pHat-spot)/spot); uint s=_isqrt(s2*WAD);\n (uint piA,uint uA)=_gaussTail(g-int(ask),s); (uint piB,uint uB)=_gaussTail(-g-int(bid),s);\n int tau=g-int(uA)+int(uB); // E clip(g,-bid,ask)\n // candidates: dBid,dAsk in {-3,0,+3}bp\n best=J(bid,ask); for each cand: Va=fa-tau', Vb=fb+tau'; sh=clamp(HALF+k*(30bp-V));\n   J=m*(sh_a*Va+sh_b*Vb)-(y/4)*(E2(g-fa)+E2(-g-fb)); keep argmax;\n return (bidBest,askBest);}\nReads: pHat slot5, fastHat slot14, sigma slot6, slot13, lambda slot7, size slot8. Writes slots 16-19. Next-item brief: 'implement family A then B as test/scratch variants of STACK (sha 2eaafc79...), no change to afterInitialize; run paired vs STACK on seeds 10000+ with run_batch vs VanillaStrategy, 8 workers, report mean_diff/se/worst, retail & arb edge deltas, gas_stats OOG count; kill if identity test slope outside [0.5,1.5] or family A+B gain < +0.3; run ablation ladder only for survivors; one fresh confirm >=2000 seeds from 5,000,000.' Empirical tests required for: the V=f-tau identity at real fill sizes, k=y/(4Q) share model, rival residual mean-zero assumption, gain magnitude, gas."}