deviant/scripts/sim-anthemus-fx-market-vs-covenant.mjs
Local Dev debd6a6fbb chore: sweep in-flight work across all domains
Snapshot commit rolling up ~255 files of coherent-but-multi-domain in-flight
work that had accumulated on this branch. Split by area:

Contracts + covenants
- New: AsmFxSwap, DeviantOpenMintNBA, DeviantTieredMintOracleFT,
  TermCouponVault, UniformReserve, UniformReserveAggregate.
- Verify-artifact refresh (src/verify/artifacts/*.json + canonical.ts).

Wallet + shell (shells/app + src/wallet)
- App.tsx, MainScreen, ArtemisionScreen, AssetDetail, AgoraScreen,
  SettingsScreen, Unlock, TokenImportModal, UniformFiat/DepositPanel,
  KatalogosPanel (renamed from PinaxPanel), shell.css.
- src/wallet: wallet.ts, runtime.ts, index.ts. Core registry/chipnetFile.
- Deleted stale hook: useAllDevBalances.ts.

Cross-chain + correspondent (services/correspondent + scripts)
- Correspondent server/bch/config updates for PYUSD Solana, EURC Sepolia,
  aggregate reserve flows.
- New scripts: PYUSD roundtrip, EURC onboarding, GMX game loop /
  genesis / mint sanity, tiered mint fee, aggregate reserve, product2
  shares dividends, product3 t-bond, uniform fiat cell tests.

Telegram order-book (P2PExchange bot)
- db.ts, index.ts, en/ru locales — updates upstream from the extracted
  standalone repo at D:/Dev/P2PExchange.

Docs — Parameters (specs), wiki, snapshots, design mockups
- Parameters: FIATm/MBA_Shares/Potidaea/Anthemus refinements +
  ASM_CrossChain/DebitCredit + UniformFiat + Anthemus DEX MVP prompt +
  Artemision + Athenae Politeia + Philosophy + SSHkeyServer runbook +
  new dApp/{Artemision,Katalogos,Pinax,Pari_escrow,SURFACES}.
- wiki: cross-chain, games-tote, glossary, governance/voting-systems,
  infra, wallet, wallet-ui-design, decisions (ADR log).
- snapshots: catch-up entries and INDEX regeneration.
- design: mockups refreshed (agora, asset-detail, assets-tab, potidaea)
  + Potidaea assets + tote deploy notes.

Housekeeping
- .gitignore: exclude the new root test/session state files
  (.sol-vault-keys.json, .football-tote-state.json,
  .tote-platform-state.json, .redeem-roundtrip-state.json,
  .eurc-onboard-state.json — some contain oracle privkeys / vault
  secretKeyBase58; NEVER commit) + the .usdm-historical-chart.html
  chart output + MS Office `~$*` lock files + scripts/bundle-surfaces
  `build/` output. Also add scripts/bundle-surfaces.mjs.
- CLAUDE.md, WALLET-COORDINATION.md, snapshots/INDEX.md, design/README.md
  refreshed.
- package.json / package-lock.json bumps.

Verified: sensitive files at repo root confirmed ignored (git check-ignore
each). No `.env`, no raw WIF/xprv/mnemonic/secretKey/oraclePriv strings in
the staged diff. MS Word autosave file (`Parameters/Philosophy/~$*.docx`)
excluded and gitignored.

The WizardConnect responder work landed separately in the previous commit
(6987591); this is everything else that had accumulated alongside it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-29 01:14:33 +02:00

140 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* sim-anthemus-fx-market-vs-covenant.mjs — what does a counterparty-free covenant swap actually
* trade vs a market swap? And how does sharing the FX risk 50/50 change the allowed band?
*
* Setup (all cases): A holds 100 USD + 100 EUR (as BCH IOUs). A swaps ALL 100 EUR -> USD @ r0.
* CASE 2 MARKET swap: a real counterparty takes the EUR; A pays a SPREAD s; A is FX-LOCKED
* (holds USD, no residual EUR exposure). The counterparty now holds the FX position.
* CASE 1 COVENANT swap (no counterparty): A swaps at the ORACLE MID (no spread). But the swap
* leaves the POOL short EUR — an open FX position. WHO bears its drift is the design:
* - full-buffer : A bears 100% (marked-to-market => A stays FX-NEUTRAL, keeps EUR risk)
* - no-buffer : the DESK bears 100% (A is FX-LOCKED like the market, but pays NO spread)
* - hybrid 50/50: A and desk each bear half
*
* THE INSIGHT the numbers show: a covenant swap SAVES THE SPREAD but RETAINS FX RISK. FX is a
* martingale => bearing it is EXPECTED-zero but has VARIANCE. So the covenant swap beats the
* market swap by ~the spread in expectation; the design only moves WHO holds the variance. And
* because the desk's RISK per position scales with the fraction it bears, sharing 50/50 lets the
* same desk-risk budget (the band) cover 2x the notional — your band-doubling.
*
* Real EUR/USD 2021-23, seeded. Run: node scripts/sim-anthemus-fx-market-vs-covenant.mjs
*/
function mulberry32(a){return function(){a|=0;a=(a+0x6D2B79F5)|0;let t=Math.imul(a^(a>>>15),1|a);t=(t+Math.imul(t^(t>>>7),61|t))^t;return((t^(t>>>14))>>>0)/4294967296;};}
const gauss=(rng)=>{let u=0,v=0;while(u===0)u=rng();while(v===0)v=rng();return Math.sqrt(-2*Math.log(u))*Math.cos(2*Math.PI*v);};
const EURUSD_MONTHLY=[1.213,1.207,1.173,1.202,1.219,1.186,1.187,1.181,1.158,1.156,1.134,1.137,1.123,1.122,1.107,1.055,1.073,1.048,1.022,1.005,0.980,0.988,1.041,1.070,1.086,1.058,1.084,1.102,1.069,1.091,1.102,1.084,1.057,1.058,1.089,1.104];
function buildPath(seed){const rng=mulberry32(seed);const p=[];for(let m=0;m<EURUSD_MONTHLY.length-1;m++){const a=EURUSD_MONTHLY[m],b=EURUSD_MONTHLY[m+1];for(let w=0;w<4;w++){const f=w/4;p.push((a+(b-a)*f)*(1+gauss(rng)*0.004));}}p.push(EURUSD_MONTHLY.at(-1));return p;}
const r3=(n)=>Math.round(n*1000)/1000;
const $=(n)=>(n<0?'-':'')+'$'+Math.abs(Math.round(n*100)/100).toFixed(2);
const div=(c='=')=>console.log(c.repeat(94));
const head=(t)=>{console.log('\n');div();console.log(t);div();};
const SEED=20260718;const path=buildPath(SEED);const N=path.length;
const Dusd=100, Deur=100, r0=1.18; // A's holdings + entry rate
const SPREAD=0.003; // market swap all-in cost (EURC/USDC is thin ~0.3%)
// A's total wealth (USD) at settlement rate r1, per design:
const wMarket =(r1)=> Dusd + Deur*r0*(1-SPREAD); // FX-locked at r0, minus spread; const in USD
const wFullBuf =(r1)=> Dusd + Deur*r1; // FX-neutral (marked): keeps EUR exposure
const wNoBuf =(r1)=> Dusd + Deur*r0; // FX-locked at r0, NO spread (desk ate drift)
const wHybrid =(r1)=> Dusd + Deur*r0 - 0.5*Deur*(r0-r1); // locked half, kept half
// Desk wealth (USD) from the position (0 for market: counterparty holds it, not the desk):
const dMarket=(r1)=>0, dFullBuf=(r1)=>0, dNoBuf=(r1)=>Deur*(r1-r0), dHybrid=(r1)=>0.5*Deur*(r1-r0);
// ════════════════════════════════════════════════════════════════════════════
head('PART 1 — single swap, three rate scenarios. A\'s wealth + desk\'s wealth, vs the MARKET swap.');
console.log(`A: ${Dusd} USD + ${Deur} EUR. Swap all EUR->USD @ ${r0}. Market spread s=${(SPREAD*100).toFixed(1)}%. Values in USD at settle.\n`);
for(const [r1,label] of [[1.18,'FLAT (r1=1.18)'],[1.14,'EUR FELL -3.4% (r1=1.14)'],[1.22,'EUR ROSE +3.4% (r1=1.22)']]){
console.log(` --- ${label} ---`);
console.log(['design','A wealth','desk wealth','A vs market','A+desk'].map(s=>s.padStart(16)).join(''));
div('-');
const rows=[
['MARKET (case2)', wMarket(r1), dMarket(r1)],
['covenant no-buf', wNoBuf(r1), dNoBuf(r1)],
['covenant full-buf(case1)', wFullBuf(r1), dFullBuf(r1)],
['covenant hybrid', wHybrid(r1), dHybrid(r1)],
];
for(const [name,a,d] of rows){
console.log([name, $(a), $(d), $(a-wMarket(r1)), $(a+d)].map(s=>String(s).padStart(16)).join(''));
}
console.log('');
}
console.log(' Reading the "A vs market" column:');
console.log(' • FLAT: every covenant design beats market by the SAVED SPREAD ($0.35). No FX moved.');
console.log(' • EUR FELL: full-buffer A is WORSE than market (-$3.65) — A kept EUR exposure and ate the drop.');
console.log(' no-buffer A still beats market (+$0.35) — A locked in AND saved the spread; the DESK took -$4.');
console.log(' hybrid splits it: A ~-$1.65 vs market, desk -$2.');
console.log(' • EUR ROSE: full-buffer A BEATS market (+$4.35) — A kept EUR and caught the rise; desk flat.');
console.log(' => COVENANT SWAP = MARKET SWAP minus the spread, plus retained FX risk. The design just moves');
console.log(' WHO holds that risk (A / desk / shared). "A+desk" conserves — nothing is created or lost.');
// ════════════════════════════════════════════════════════════════════════════
head('PART 2 — difference in TOTAL VALUE (case1 covenant-buffer − case2 market), decomposed.');
console.log(' ΔWealth(A) = wFullBuf(r1) − wMarket(r1) = [saved spread] − [FX drift the market locked out]');
console.log(` = ${$(Deur*r0*SPREAD)} (spread saved) − ${Deur}·(r0−r1) (drift A retained)\n`);
console.log(['r1','saved spread','retained drift','Δ case1−case2'].map(s=>s.padStart(18)).join(''));
div('-');
for(const r1 of [1.18,1.16,1.14,1.10,1.20,1.22]){
const spread=Deur*r0*SPREAD, drift=Deur*(r0-r1);
console.log([r3(r1), $(spread), $(-drift), $(spread-drift)].map(s=>String(s).padStart(18)).join(''));
}
// realized outcome: enter at r0=1.18, settle at each future week on the real path
let sum=0; for(let i=1;i<N;i++){ sum += (Deur*r0*SPREAD) - Deur*(r0-path[i]); }
const meanDelta=sum/(N-1);
// martingale/round-trip control: average over every (entry, settle=entry+4wk) pair (no anchor bias)
let sum2=0,cnt=0; for(let s=0;s+4<N;s++){ sum2 += (Deur*path[s]*SPREAD) - Deur*(path[s]-path[s+4]); cnt++; }
const meanRT=sum2/cnt;
console.log(`\n HONEST caveat — the realized number depends on the PATH, not just the spread:`);
console.log(` • Enter at r0=${r0} (a 2021 HIGH), settle at each later week: E[Δ case1−case2] = ${$(meanDelta)} — NEGATIVE.`);
console.log(` Because the buffer covenant RETAINS EUR exposure and EUR fell 1.18→1.10 over this path, the`);
console.log(` retained-drift term dominated the saved spread. Buffer-swapping near a top and holding HURTS.`);
console.log(` • Anchor-free control (every entry, settle 4wk later): E[Δ] = ${$(meanRT)} ≈ 0 here — the +$0.33`);
console.log(` spread saving is offset by this sample's mild downward drift. Under a FAIR MARTINGALE it`);
console.log(` would be +the spread (~$0.33); this 2021-23 sample simply fell, so the drift term ate it.`);
console.log(` => The "beats by ~the spread" result is a MARTINGALE statement, not a guarantee. The buffer`);
console.log(` design's honest cost = the USER carries FX DIRECTION+variance; a directional loser (hold`);
console.log(` through a fall) underperforms the market swap. No free lunch — the spread buys certainty.`);
// ════════════════════════════════════════════════════════════════════════════
head('PART 3 — the band-doubling proof: desk RISK per position scales with the fraction it bears.');
console.log('The band caps DESK RISK. Desk risk on a position = (fraction desk bears) × notional × maxMove.');
console.log('For a fixed desk-risk budget (say 10% of reserve × maxMove), the allowed NOTIONAL band is:\n');
const maxMove=(()=>{let w=0;for(let s=0;s+1<N;s++){const e=path[s];for(let t=s+1;t<N;t++){w=Math.max(w,Math.abs(path[t]-e)/e);}}return w;})();
const reserve=1_000_000, riskBudget=0.10*reserve*maxMove; // the "10% band" expressed as a risk budget
console.log(['design','desk bears','max notional (same risk)','as % reserve'].map(s=>s.padStart(22)).join(''));
div('-');
for(const [name,frac] of [['no-buffer',1.0],['hybrid 50/50',0.5],['full-buffer',0.0]]){
if(frac===0){ console.log([name,'0%','∞ (user-bounded)','user balance'].map(s=>String(s).padStart(22)).join('')); continue; }
const maxNotional=riskBudget/(frac*maxMove);
console.log([name, `${frac*100}%`, $(maxNotional), `${(maxNotional/reserve*100).toFixed(0)}%`].map(s=>String(s).padStart(22)).join(''));
}
console.log('\n => YOUR CLAIM CONFIRMED: at 50/50 the desk bears half the drift per position, so the SAME 10%');
console.log(' desk-risk budget covers DOUBLE the notional — a 20% band. Full-buffer removes desk risk');
console.log(' entirely (band limited only by the user\'s own balance + the gap tail). One dial: how much');
console.log(' FX risk the user keeps sets both (a) how much they de-risk and (b) how large the band can be.');
// ════════════════════════════════════════════════════════════════════════════
head('PART 4 — the spectrum, and why the hybrid is the sweet spot.');
console.log(`
design A pays spread A de-risks FX desk FX risk max band (notional) product
------------ ------------- ------------- ----------- ------------------- -----------------------
MARKET swap full (~0.3%) 100% 0 (LP holds) ∞ (real liquidity) "convert & de-risk, pay LP"
no-buffer 0 100% 100% 10% (1× band) "convert free, desk insures"
HYBRID 50/50 0 (or ½) 50% 50% 20% (2× band) "convert free, share the risk"
full-buffer 0 0% (neutral) 0% user-bounded "spend cross-ccy, keep FX"
The hybrid is the sweet spot for a CONVERSION product (user wants to de-risk, not just spend):
• A de-risks HALF its FX for FREE (no spread) — genuinely better than the market for that half.
• The desk bears half — but FX is expected-zero, so the desk's cost is VARIANCE/capital, not an
expected loss. It needs only a small RISK PREMIUM (capital cost + gap tail), not a full spread.
• The band DOUBLES (20%) for the same desk risk — 2× the throughput at maturity.
• Beyond the band, route to the DEX (market swap) — the two compose: covenant for the first 20%,
market for the tail. Users always get filled; the desk's risk stays capped.
Honest caveats (carry to the ADR): the desk holds only a PAPER position, not a realized cost — the
band is a rebalancing WORKING-CAPITAL buffer; two-way flow rebalances at ~no cost, and the drift is
realized only if the short currency is withdrawn past its locked reserve (~90%+, see
sim-anthemus-fx-realized.mjs). A thin premium is OPTIONAL insurance for that bounded tail
(<= band x move), not compensation for a continuous loss. The hybrid is a partial FX position for
the user (a mild derivative — same per-jurisdiction gate as the credit modes).
`);