Every figure here is an engine settlement, not a spreadsheet. The SDK opens a real position at the real barrier and the real rung, settles it at the governed splits, and reports what each party received — so the only things on this page anybody chose are the six controls and the rows tagged caller or hand-chosen at the bottom.
What you are askingevery one of these is a field of ProjectionInput
Demandunobservable until there are traders
The chain has an opinion about the stake and none at all about the count: it accepts $0.25 to $2.00 and refuses either side of that, which is why the middle option is the only one of the three this page had to choose. At these settings the venue admits 15.0 trades a day.
Rungwhich take-profit the population buys
One rung at a time, and that is not a simplification — it is what makes the bounds exact. A single cell is one binomial, so the percentiles come out of binomialQuantile rather than out of an expansion around it. The table below runs all four side by side. 2x is the conservative end: every deeper rung pays the house more, so opening on it cannot flatter this page.
Poolderived, never picked
$420.00 is what launchProjectionInput() defaults to, which is what is seeded. Whether that is a lot or a little is the whole question this ladder answers.
What it pays10%–90% percentiles, over 30 days
Over the horizon450 trades admitted of 450 requested
The pool's middle number and its bounds are different questions, and only the bounds answer the one an LP is asking. 7.46% of horizons like this one end below zero — with a positive expectation, at the published edge, with nothing wrong. That is the product working at 450 trades, and it is why a losing first month would tell you nothing.
Where each dollar goesper trade, and over 30 days
| Party | Per trade, expected | Lower (10%) | Expected | Upper (90%) | What the income IS |
|---|---|---|---|---|---|
| LP pool | $0.0640 | $2.20 | $28.81 | $54.38 | counterparty risk — it wins the barrier or it pays the rung, every single trade |
| Protocol treasury | $0.0394 | $17.52 | $17.77 | $18.00 | fees — its entry leg is charged whoever wins, which is why its band is the tight one |
| Insurance fund | $0.0105 | $4.45 | $4.72 | $4.98 | its share of the loss tax and nothing else, so it earns only when a trader loses |
| Submitter / liquidator | $0.0000 | $0.00 | $0.00 | $0.00 | the gas floor on every close that has one, plus its share of the loss tax |
| Traders, in aggregate | -$0.1140 | -$77.38 | -$51.31 | -$24.19 | negative by construction: the house edge IS this row, seen from the other side |
The five rows sum to zero at every point in the band, which is the check that catches an invented number: every dollar a trader loses arrives somewhere, and every dollar a trader wins came from somewhere. Compare the WIDTH of the pool's band against the treasury's — same protocol, same edge, completely different certainty. The treasury is paid a fee on every trade whoever wins; the pool is the counterparty.
The insurance line is true for the first 3,996 trades. At that point Vault::accrue_insurance reaches its target, accrual stops, and the overflow stays with the LPs — so beyond it the insurance row above overstates and the pool row understates. The SDK reports the crossing rather than capping the line, because a figure that quietly stopped growing is a figure nobody can check.
What it returnsthe same dollars, divided by capital that is named
Which capital a return is perderived from the reserve, not assumed
Every position reserves the whole capped payout plus the exit fee, so a $420.000000 pool holds 4 at once whatever any exposure cap says — and at this demand it holds 0.044 of them on average. That is why there are two denominators below and neither is a default: they differ by about 96x. The first is what an LP's dollar earns, which is the number they are entitled to. The second is what the deployed portion earns, which is the number about the mechanism. Quoting only the second is how an LP disclosure becomes a lie; quoting only the first hides that the mechanism works and the pool is oversized for the flow.
LP returnover 30 days, annualised
| Per dollar of | Capital | Lower (10%) | Expected | Upper (90%) | Compounded (APY) | What the denominator means |
|---|---|---|---|---|---|---|
| Total pool capital | $420.0000 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | Earnings raise lp_assets and the share price with it, so an LP dollar does compound here. What the compounded figure additionally assumes is the SAME DAILY FLOW against the larger pool. At 1.0405 % utilisation this pool is not capacity-bound, so a pool grown by its own earnings would earn the same dollars on a bigger base and the true rate would fall. Read the APR as the floor of the two and the APY as the ceiling. |
| Utilised capital | $4.3702 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | Not compoundable, and the APY on this base must not be shown. How much of the pool is reserved is set by how many people trade, not by what the pool earned last month, so there is no way to reinvest INTO utilised capital. The simple rate is the honest one: it says what the deployed portion returns while it is deployed. |
NOT OBSERVABLE, and that is the answer. NOT OBSERVABLE: 450 admitted trades against the 907 — 60 days at this demand — needed before the mean is 2 standard errors clear of zero. A rate annualised from a sample this short is not a projection of anything; it is arithmetic performed on noise. A percentage printed here would be the most confident thing on the page and the least true — the mean is not yet distinguishable from zero, so annualising it produces a number about noise. Raise the demand or the horizon until the trade count clears the bar and it appears.
Compounding is refused on the utilised base and permitted on the pool. Earnings raise lp_assets and the share price with it, so an LP dollar genuinely compounds; how much of the pool is reserved is set by how many people trade, so there is nothing to reinvest into. At 1.0405% utilisation even the pool's APY is the ceiling rather than the answer: a pool grown by its own earnings would earn the same dollars on a bigger base until capacity binds.
Who has a return at allfour of the five parties do not, for four different reasons
| Party | Income is | Per trade | Per day | Over 30 days | On total pool | On utilised | Trades to prove it | Why that denominator |
|---|---|---|---|---|---|---|---|---|
| LP pool | capital-at-risk | $0.0640 | $0.9605 | $28.81 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | 907 | per dollar of the $420.00 pool, and per dollar of the $4.37 of it reserved against open positions on average — 1.0405 % of the pool at this demand |
| Protocol treasury | fee-revenue | $0.0394 | $0.5923 | $17.77 | none | none | 1 | NONE. The treasury deploys no capital: it is paid an entry-fee leg and an exit-fee leg on every trade whoever wins, so there is nothing at risk for a return to be ON. Dividing its revenue by the LP pool would quote somebody else's capital as the treasury's base. |
| Insurance fund | fund-accrual | $0.0105 | $0.1576 | $4.72 | none | none | 4 | NONE, and an APY here would be a category error. The fund takes its share of the loss tax and fills toward insurance_target_bps; nobody deposits into it and nobody withdraws a yield from it. See insuranceFund(), which reports balance, target and time to target instead. |
| Submitter / liquidator | per-close-fee | $0.0000 | $0.0000 | $0.00 | none | none | ∞ | NONE. Paid per close — the gas floor plus a share of the loss tax — against a cost denominated in SOL rather than in USDC. See submitterPay(): per close and per day. |
| Traders, in aggregate | trader-cost | -$0.1140 | -$1.7105 | -$51.31 | none | none | 297 | NONE, and the sign is the point. This is the house edge seen from the other side; it is a cost of buying the position, not a return on capital deployed into it. |
Only the LP pool deploys capital, so only the LP pool has a rate. The treasury is paid a fee on every trade whoever wins and risks nothing; dividing its revenue by the LP pool would be quoting somebody else's capital as its base. Read the trades to prove it column across the rows: the treasury clears its own noise in 1 trades and the pool takes 907. Same protocol, same edge, completely different certainty — and that gap is invisible on any page that prints one APY.
Insurance is a fund, not a positiona fill with an end
There is no insurance APY, and asking for one is a category error. Nobody deposits into this fund and nobody withdraws a yield from it — Vault::accrue_insurance carves it out of the token balance at settlement, so there is no principal a rate could be per and nobody to quote one to. It is also capped: at the target, accrual stops and the overflow stays with the LPs, so a percentage here would go to zero on success. The fund takes 1500 bps of the loss tax and nothing else, so it earns only when a trader loses. At the target, Vault::insurance_accrual returns zero and the overflow stays with the LPs — which is why this is a fill with an end rather than a rate that continues. Since ADR-0030 the fund is its own PDA with its own token account; nothing programmatic spends it, and its one exit is withdraw_insurance, which the config authority signs. Nobody deposits into it and nobody withdraws a yield from it, so it has no APY to quote.
A submitter is paid nothingretired 2026-08-19; the panel stays so the zero is visible
Two numbers rather than a ratio, because the two sides are denominated in different assets: the income is USDC and the cost is SOL. Paid per settle, never on a balance. The gas floor is an absolute amount and the loss-tax leg is a percentage, so the two move against each other with the stake. The cost side is denominated in SOL and the income side in USDC, which is why this is two numbers and not a ratio of one asset to itself — ADR-0016 puts the crossing at a SOL price, not at a volume.
Beside the projection: what the venue actually paid146 settled closes, 146 verified against the engine
Realisedlive · archive tail slot 442145572, 2026-08-27T16:47:05.000Z · https://knockout-api.asymmetra.xyz/v0/trades
| Party | Realised, total | Realised, per close | Realised, points of stake | Projected, points of stake | Projected, per trade |
|---|---|---|---|---|---|
| LP pool | $3.652771 | $0.025019 | 8.3492 | 6.4039 | $0.064039 |
| Protocol treasury | $1.517129 | $0.010391 | 3.4677 | 3.9491 | $0.039491 |
| Insurance fund | $0.000000 | $0.000000 | 0.0000 | 1.0510 | $0.010510 |
| Submitter / liquidator | $0.334190 | $0.002289 | 0.7639 | 0.0000 | $0.000000 |
| Traders, in aggregate | -$5.504090 | -$0.037699 | -12.5808 | -11.4040 | -$0.114040 |
THE MODEL PRICES 28 OF THESE 146 CLOSES. 70 voluntary (not priced), 36 userExpiry (not priced), 22 knockout, 12 tenorExpiry (not priced), 6 takeProfit. The projection weighs two outcomes — the barrier and the rung — and 80.8% of real closes so far have been neither. So these two columns are not two measurements of one quantity; they are a measurement and a model of different populations, and most of the gap between them is that. A voluntary close pays the exit fee with no chance of the rung, which is why the realised points of stake run above the modelled edge rather than below it.
The points-of-stake column is the one to argue from: it needs no pool and no clock, so it is the only comparison here that carries none of this page's assumptions. The realised columns fold the entry fee back in — the settlement event never sees it, because prepare_open sweeps it at open — which is what makes them the same quantity the projected columns are. Every chain integer is unchanged by that fold, and the five rows still sum to zero.
payout_cap_multiple = 100x — not carried by SettlementPriced; supplied by the caller. It scales the utilisation denominator and no realised dollar figure.
The entry fee is swept at OPEN and never reaches the settlement event, so every total here is net of it: the LP and treasury lines understate by exactly their entry legs.
lp_assets is not in the archive. A return on total pool needs a pool this window cannot state.
101 of 146 closes have no holding time — the open transaction was not indexed, or the reconstruction failed — and are excluded from the utilisation integral rather than given an assumed one.
The rules that divide itgoverned, read live at settlement
Read off ProjectionInput.governed and entrySplit, not typed here. These are the dials that move without a redeploy, and the per-party rows above are whatever the engine did with them at this stake — which is why the shares change with the stake even though the edge does not.
Who wins, by rungthe same demand, one rung at a time
| Rung | Edge, points of stake | LP pool, lower | LP pool, expected | LP pool, upper | LP return on pool | Treasury, expected | Trades to prove it |
|---|---|---|---|---|---|---|---|
| 2x | 11.4040 | $2.20 | $28.81 | $54.38 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 907 trades. | $17.77 | 907 |
| 3x | 13.0408 | -$3.78 | $33.45 | $69.53 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 1,315 trades. | $19.06 | 1,315 |
| 5x | 14.2974 | -$15.69 | $37.01 | $87.89 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 2,109 trades. | $20.05 | 2,109 |
| 10x | 15.2107 | -$33.65 | $39.58 | $115.33 | NOT OBSERVABLE — Not yet distinguishable from zero: 450 of 4,091 trades. | $20.76 | 4,091 |
No rung is bad for us, and the deep ones are better. The edge moves from 11.40 points at 2x to 15.21 points at 10x purely on which bet a trader picks — so nobody has to be steered toward one. What grows faster than the edge is the variance: the last column is how many trades it takes before the extra profit is distinguishable from luck, and it grows faster than the edge does. A book that fills with 10x bets is more profitable and much harder to prove.
Pool size is a ceiling, not an enginewhat the pool actually buys
Capacity at this pool$420.000000
Refused trades are earned by nobody. That is the only way pool size touches revenue at all — it does not create trades, it declines them, and at launch volume it declines almost none. The thing that changes revenue is people trading.
The laddereach pool is where something becomes true
| Tier | Pool | What becomes true here | How it was found |
|---|---|---|---|
| Launch the pool that is actually seeded | $420.000000 | $420.00 is what launchProjectionInput() defaults to, which is what is seeded. Whether that is a lot or a little is the whole question this ladder answers. | launchProjectionInput().pool |
| Minimum viable the pool can hold one trade | $200.030000 | Below $200.03 the pool cannot hold its $100 seed AND reserve one $1.00 position. It is not a small venue; it is a venue that refuses every open. | MIN_SEED_DEPOSIT + Position::required_reserve(largest cell) = 100000000 + 100030000 base units |
| Good the projection starts to mean something | NOT OBSERVABLE — At this volume and horizon, no pool admits enough trades for the mean to clear 2 standard errors. The projection is a statement about variance, not about revenue. Raise the volume or the horizon. | At this volume and horizon, no pool admits enough trades for the mean to clear 2 standard errors. The projection is a statement about variance, not about revenue. Raise the volume or the horizon. | bisection on project() for admittedTrades >= tradesForDominance |
| Great capacity stops refusing trades | $200.582736 | At $200.58 fewer than 1 % of opens are refused at 15 trades a day. Below it, demand is turned away rather than earned, and the refused trades are earned by nobody. | bisection on project() for the Erlang-B refusal rate <= 1 % |
| Best case capacity stops refusing trades, at the largest stake the chain permits | $400.258096 | At $400.26 fewer than 1 % of opens are refused at 15 trades a day. Below it, demand is turned away rather than earned, and the refused trades are earned by nobody. | bisection on project() for the Erlang-B refusal rate <= 1 % |
the treasury covers the keeper — NOT a pool size. NOT OBSERVABLE: no live SOL/USD price was supplied (solUsd), so the keeper's real cost cannot be priced. This is refused rather than guessed at a plausible-looking default — pass a live SOL/USD read (e.g. monitor.ts::readSolPrice) to see this line.
Assumptions, and which ones to argue with25 of them, each with its value
| Assumption | Value used | Source | Where it comes from | What goes wrong if it is wrong |
|---|---|---|---|---|
| How a horizon becomes a year | APR = r x 365 / 30; APY = (1 + r) ^ (365 / 30) - 1 — both shown | model | returns.ts::annualise | Scaling a horizon to a year assumes THIS demand runs for a year. The compounded figure additionally assumes the same daily flow against a pool grown by its own earnings, which is true only where capacity binds — at 1.0405% utilisation it does not, so the APY is the ceiling and the APR the floor. On the UTILISED base compounding is refused outright: nobody can deposit into utilisation. |
| Which capital a return is per | total pool $420.00, of which $4.37 is reserved on average and $19.88 can never be | engine | returns.ts::capitalAtWork, over gates.ts::requiredReserve and the Erlang carried load | The single largest lever on any percentage here. The same dollars are a 1.0405% utilisation of the pool, so the two rates differ by about 96x. Quoting only the utilised one is how an LP disclosure becomes a lie; quoting only the total one hides that the mechanism works and the pool is oversized for the flow. |
| The pool the REALISED column is measured against | $420.00 — the pool that was seeded | caller | launchProjectionInput().pool. The archive records TRADES, not the vault | A SettlementPriced event carries no lp_assets, so nothing in the archive states what the pool was while these trades ran. Every realised dollar figure is exact; every realised PERCENTAGE inherits this one assumption. The realised points-of-stake column does not, which is why it is the one to argue from. |
| How much of the realised record the projection actually prices | 5 of 55 closes — 90.9% censored | measurement | realised.ts::realisedWindow over data/trades-*.jsonl | The projection prices two outcomes, the barrier and the rung. Almost every real close so far has been voluntary or a user timer, which it prices neither of. So the realised and projected columns are not two measurements of one quantity — they are a measurement and a model of DIFFERENT populations, and the gap between them is mostly that. |
| Active traders per day | 5 | caller | this page. UNOBSERVABLE until there are traders | The one number nobody can derive, and the one everything below scales with. Revenue is linear in it right up to the point where capacity refuses, and that point is far above any launch volume. |
| Trades each active trader opens per day | 3 | caller | this page | Multiplies with the line above. The pair of them is the whole demand model. |
| The horizon projected | 30 days | caller | this page; ProjectionInput.days | Variance is a short-horizon problem. The same book that can finish a day down finishes a year up, so a horizon is not a presentation choice — it decides whether the pool row carries a loss in it. |
| Average position size | $1.00 — the chain permits $0.25 to $2.00 | caller | lib/revenue.ts::ASSUMED_AVERAGE_STAKE. The BOUNDS are governed — LAUNCH.minCollateral and LAUNCH.maxCollateral — the average inside them is assumed | Below the volume where capacity binds, halving it halves every revenue figure here. At capacity it very nearly cancels, because smaller positions each reserve less and more of them fit at once — so this assumption matters MOST at exactly the launch volumes. |
| What the upper and lower bounds are | the 10% and 90% percentiles | model | ProjectionInput.tailQuantile, through projection.binomialQuantile | A band over LUCK at a fixed population, not over the population. One trader in ten thousand days is outside it; a rung mix nobody has measured is not in it at all. |
| Which edge this projection uses | per-rung, settled at each cell; blended across the mix | engine | risk_engine::settle, through projection.cellOutcome | The published 11.402 % is the 2x RUNG figure and overstates a mixed population; the 15.207 % at 10x understates it. A separate 7.8-point "realised" edge exists in the record, is measured against an unmeasured 55/25/15/5 population mix, is asserted by nothing in this tree, and is NOT used here. |
| How a projected position closes | two outcomes: barrier or rung. Censored share stated at 0.0 % | model | projection.ts; CloseReason has five variants and this weights two | Voluntary closes, user timers and tenor expiries are not priced. A voluntary close is unclamped and pays to the payout cap, so a population that closes voluntarily costs the pool MORE than this shows, not less. |
| How opens arrive, for the refusal model | Poisson, Erlang-B on 4 slots | model | projection.erlangB | Real flow is bursty and correlated across traders, which refuses MORE than Poisson does at the same daily average. Erlang-B is insensitive to the holding-time distribution, so that part is not an assumption. |
| How the percentiles were produced | exact-binomial | model | projection.binomialQuantile / cornishFisher | Exact. The mix is one cell, so the pool is a linear function of a single binomial. |
| The asset's annualised volatility, which sets how fast a position resolves | 33.0 % | measurement | sim/roster.py 7-day realised; canonical.rs publishes the interval 24 %-80 % | Only the position LIFE depends on it, never the odds. It moves capacity and therefore the refusal rate; at 7 observations the relative standard error is 26.7 %. |
| SOL/USD, for the operator's real cost | NOT OBSERVABLE | caller | launchProjectionInput() has no default here on purpose — a market price typed into source is the defect this file exists to refuse (it read a stale $150, roughly double SOL's real price, until 2026-08-11). Pass a live read, e.g. monitor.ts::readSolPrice. | operatorCost and protocolNet below are NOT A NUMBER, on purpose: refusing to show a figure is safer than showing a plausible wrong one, and this repo already prefers that elsewhere (app/'s Money/moneyText already render a non-finite figure as NOT OBSERVABLE). |
| What one settle costs its sender | 15,037 lamports | engine | cover.ts::settleCostLamports, pinned to FeePolicy::LAUNCH by cover.test.ts | Measured at the priority floor on an uncongested network. A congested bid costs more. |
| Settles the operator pays for, per trade | 1.00 | hand-chosen | the caller. At launch there is no keeper, so the honest value is 0 | One settle per trade is the upper bound on the operator cost. Trader-submitted closes cost the operator nothing, and nothing in this tree measures the split. |
| Which rungs traders pick | 2x@$1.00:100% | caller | UNOBSERVABLE until there are traders | The single largest lever on this page. The edge moves 11.40 to 15.21 points purely on the rung mix, and no measurement anywhere in this repository constrains it. |
| The LP pool the projection is run against | $420.00 | caller | Vault::lp_assets | Sets capacity: 4 concurrent positions at a MEAN reserve of $100.03. Below the point where capacity binds, extra demand is refused rather than earned. **The slot count uses the mean reserve across the mix, and the chain does not.** `Vault::withdrawable` is checked against each open individually, so a pool with less free than one $1.00 position needs refuses that open while still admitting a $0.25 one. A single-server-type queue cannot express that, and it errs toward ADMITTING — the optimistic direction — whenever the mix has large stakes in it. |
| The submitter's minimum payment | 5000 base units | governed | ADR-0016; programs/exchange/src/lib.rs launch_for_test().gas_floor | An ABSOLUTE amount against percentage shares, so it moves the per-party SPLIT with the stake even though it cannot move the edge. crates/risk-engine/examples/canonical.rs still computes its published table at the RETIRED 15,000; do not cross-read the two. |
| How the loss tax divides | 2000/4000/1500/2500 bps | governed | TaxSplit::LAUNCH, read live at settlement | Insurance takes exactly its share of the loss tax and nothing else, so it earns only when traders lose. |
| How the exit fee divides between the pool and the treasury | 5000/5000 bps | governed | ADR-0012 | The submitter's gas top-up is charged to the TREASURY's leg before the pool's. |
| How the entry fee divides | 5000/5000 bps | governed | ADR-0010. A separate dial from the exit split, and settle never sees this fee | |
| The insurance target, past which accrual stops and the overflow stays with LPs | 1000 bps of the pool = $42.00 | governed | programs/exchange/src/vault.rs::accrue_insurance | NOT applied to the insurance line below — it is reported as tradesToInsuranceTarget instead. Past that trade count the insurance figure here overstates and the pool figure understates, and the target itself rises with the pool it is a share of. |
| Oracle-deviation leaks, feed drift and entry arbitrage | NOT modelled — zero, and that is a known overstatement | model | docs/ORACLE-COST.md — no figure is quoted, because the published one is retired | This projection prices a correctly calibrated feed. The entry arb costs the pool 4.4500 points per attacked open and the LP-solvency crossing sits at 49.16 % arbitrage share. ui/revenue.html put a number on this and the number was retired; a zero that says it is a zero is more honest than a stale float. |
An assumption a reader cannot see is indistinguishable from a fact. The tag is the column to read first: engine and governed rows are not really assumptions at all and are listed for audit, measurement rows have a measurement behind them, and caller, model and hand-chosen rows are somebody's judgement — which every figure on this page inherits.