FORMULA METHODOLOGY · 12 CALCULATORS · 54 TEST VECTORS

How TradingCalc formulas work

Every number TradingCalc returns is the result of a deterministic formula, published with its source and assumptions, regression-tested against exact-value vectors, and verifiable on demand. This page explains where each formula comes from and how correctness is enforced.

01CORE PRINCIPLE

Same inputs, same outputs

TradingCalc is not an AI. It does not estimate, approximate, or sample. Given the same inputs, it always produces the same outputs, down to the last cent. This property is not incidental; it is enforced by design and verified continuously.

DETERMINISTIC
No randomness. No model weights. Pure arithmetic.
TRACEABLE
Every formula links to exchange documentation or a derivation.
VERIFIABLE
Anyone can call system.verify and get pass/fail per vector.
02VERIFICATION SYSTEM

Three-layer verification system

Correctness is enforced at three independent levels. Breaking one layer surfaces in at least one other.

01
Canonical test vectors
src/lib/verify.ts

54 exact input/output pairs (linear and inverse/coin-margined cases), each with step-by-step arithmetic in the source field. Written independently of the formula code: they define the expected answer, not the implementation.

02
Automated test suite
src/lib/calculators/calculators.test.ts

Vitest exact-value vector tests + property tests (sign invariants, round-trips, monotonicity). Runs in CI on every push. A push that breaks any test does not deploy.

03
Live verification endpoint
/api/mcp → system.verify

Any caller (human or AI agent) can call system.verify via MCP to run all 54 vectors against the live production code. Returns pass/fail per vector with expected vs actual values.

03FORMULA REFERENCE

All 12 calculators

Each row shows the core formula, its source, and how many canonical test vectors cover it. 3 more vectors cover pre_trade_check, the composite of these calculators, for 54 in total.

PnL9 VECTORS
Net PnL (linear) = gross − entryPrice × size × feeOpenPct − exitPrice × size × feeClosePct; gross long = (exitPrice − entryPrice) × size, short = (entryPrice − exitPrice) × size. Inverse: size is USD contracts, gross(coin) long = size × (1/entryPrice − 1/exitPrice), short = size × (1/exitPrice − 1/entryPrice), fees on the coin notional at each fill.

Binance Futures documentation: "How to calculate PnL"

Liquidation Price10 VECTORS
Liq (linear) long = entryPrice × (1 − 1/leverage) / (1 − m), short = entryPrice × (1 + 1/leverage) / (1 + m), floored at 0, with m = mmr + liqFeeRate (maintenance margin on the position value at the liquidation price, the Bybit, KuCoin and Hyperliquid form; liqFeeRate defaults to 0). With mmBase "entry" (maintenance margin on the entry value, the MEXC form) long = entryPrice × (1 − 1/leverage + m), short = entryPrice × (1 + 1/leverage − m). Inverse long = entryPrice × (1 + m) / (1 + 1/leverage), short = entryPrice × (1 − m) / (1 − 1/leverage); with mmBase "entry" long = entryPrice / (1 + 1/leverage − m), short = entryPrice / (1 − 1/leverage + m). A denominator of 0 or below, or a result more than 1e9 times the entry price, means no liquidation price: liqPrice is null. When m >= 1/leverage (maintenance margin plus fee at least the initial margin) the position is liquidated the moment it opens: liqPrice is the entry price and liquidatedAtEntry is true. Isolated margin with one flat maintenance rate: no exchange tiers, no extra margin or tier deduction, cross margin not modelled.

Isolated-margin model with one flat rate. Default: maintenance margin on the position value at the liquidation price (the form in the Bybit, KuCoin and Hyperliquid documentation); mmBase "entry" takes it on the entry value (MEXC); liqFeeRate adds a liquidation fee (KuCoin). No tiers or extra margin; the figure shown by an exchange can differ

Breakeven Price4 VECTORS
Breakeven (linear) long = entryPrice × (1 + feeOpenPct) / (1 − feeClosePct), short = entryPrice × (1 − feeOpenPct) / (1 + feeClosePct). Inverse swaps the two fee roles.

Derived by solving net PnL = 0 with fees charged on the notional at entry and at exit

Position Size3 VECTORS
sizeBase (linear) = riskUsdt / (|entryPrice − stopLoss| + entryPrice × feeOpenPct + stopLoss × feeClosePct): the loss at the stop, both fees included, equals riskUsdt. Inverse: size in USD contracts.

Risk-based sizing derived from the PnL formula at the stop

Average Entry2 VECTORS
Average entry (linear) = Σ(price × quantity) / Σ(quantity). Inverse: Σ(quantity) / Σ(quantity / price), the harmonic mean.

Weighted average formula; the inverse form follows from USD-notional (contract) sizing

Target Exit4 VECTORS
Exit (linear) long = (targetPnl + entryPrice × sizeBase × (1 + feeOpenPct)) / (sizeBase × (1 − feeClosePct)), short = (entryPrice × sizeBase × (1 − feeOpenPct) − targetPnl) / (sizeBase × (1 + feeClosePct)). Inverse (sizeBase in USD contracts, PnL in the coin): long = (1 + feeClosePct) / ((1 − feeOpenPct) / entryPrice − targetPnl / sizeBase), short = (1 − feeClosePct) / (targetPnl / sizeBase + (1 + feeOpenPct) / entryPrice). An ROE target in percent points becomes targetPnl = targetValue / 100 × margin, margin = entryPrice × sizeBase / leverage (inverse: sizeBase / (entryPrice × leverage)).

Derived from the PnL formula by solving for exitPrice

Funding Cost4 VECTORS
totalCost (linear, sizeBase in the coin) = ± sizeBase × entryPrice × fundingRate × (24 / intervalHours) × days; inverse (sizeBase in USD contracts, cost in the coin) = ± (sizeBase / entryPrice) × fundingRate × (24 / intervalHours) × days. fundingRate is a decimal per funding interval of intervalHours hours (default 8, so 3 payments a day; some symbols pay every 4, 2 or 1 hours); + for a long, − for a short (a negative cost is funding received).

Binance Futures: "Funding Rate Mechanism"

Compound Funding4 VECTORS
Each funding period: earned = capital × fundingRatePct / 100. Funding received: capital += earned × reinvestPct / 100, the rest is withdrawn and still counts as earned. Funding paid comes out of capital in full, at most the capital there is (a rate of −100% or worse per interval wipes the account out in the first period). Days are rounded up to whole days; totalEarned = finalCapital + totalWithdrawn − initialCapital; APY % = (((finalCapital + totalWithdrawn) / initialCapital)^(365 / days) − 1) × 100, or −100 when that end value is 0.

Period-by-period compounding of funding income; no exchange-specific input

Funding Arbitrage2 VECTORS
Annualized yield % = (shortFundingRate − longFundingRate) × (24 / intervalHours) × 365, rates in percent per interval.

Standard carry trade formula; exchange-agnostic

Hedge Ratio4 VECTORS
Short notional = spotSize × hedgeRatio / 100; margin = short notional / leverage; funding per day = short notional × fundingRatePct / 100 × (24 / intervalHours), 3 payments a day at the default 8 hours. Inverse (needs entryPrice): the short is the same USD contracts, margin and funding are those USD figures divided by entryPrice, paid in the base coin.

Notional hedge of a USD spot value with a USDT-linear or coin-margined (inverse) perp; 8-hour funding interval

Max Safe Leverage3 VECTORS
Max leverage = maxDrawdownPct / (volatilityPct + mmr × 100), every term in percent points, rounded down to 0.1x, minimum 1x.

Rule of thumb: a one-sigma daily move plus the maintenance margin should stay inside the drawdown you accept

Scenario PnL2 VECTORS
The PnL formula applied at each move in deltasPct: exitPrice = entryPrice × (1 + delta / 100).

Composed from the PnL formula; no additional derivation

04TEST VECTOR ANATOMY

What a test vector looks like

Each vector in src/lib/verify.ts contains explicit step-by-step arithmetic so the expected answer can be verified by hand, independent of the implementation.

verify.ts
{
calc: 'pnl',
label: 'BTC long, 10× leverage, maker/taker fees',
input: {
side: 'long',
entryPrice: 60000,
exitPrice: 63000,
contractSize: 0.1,
leverage: 10,
feeOpenPct: 0.0002, // 0.02% maker
feeClosePct: 0.0005, // 0.05% taker
},
expected: {
grossPnl: 300,
openFee: 1.20,
closeFee: 3.15,
netPnl: 295.65,
roe: 49.275,
},
source: `
Gross = (63000 - 60000) × 0.1 = 300
Open fee = 60000 × 0.1 × 0.0002 = 1.20
Close fee = 63000 × 0.1 × 0.0005 = 3.15
Net = 300 - 1.20 - 3.15 = 295.65
Margin = 60000 × 0.1 / 10 = 600
ROE = 295.65 / 600 × 100 = 49.275%
`,
}
05SELF-VERIFICATION

Self-verification via MCP

AI agents and trading systems can call system.verify before relying on results. The response includes pass/fail per vector, expected vs actual values, and a timestamp.

tools/call · system.verify
// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "system.verify", "arguments": {} }
}
 
// result.content[0].text
{
"status": "pass",
"passed": 46,
"failed": 0,
"total": 46,
"timestamp": "2026-09-18T..."
}

Live proof (runs on every page load, no cache): tradingcalc.io/verify

06IN PRACTICE

What this means in practice

AI AGENTS

Call system.verify before a trading session. If it passes, every formula call you make during that session returns auditable, exact outputs.

TRADING BOTS

Embed the MCP endpoint. Your bot gets the same liquidation price and position size for the same inputs, not LLM estimates that vary between calls.

RISK MANAGERS

The same formula runs in CI, in the API, and on the public /verify page. Three independent surfaces showing the same result.

DEVELOPERS EVALUATING THE API

Read the test vectors in verify.ts. If the arithmetic matches your manual calculation, you can trust the endpoint.

07PUBLIC ANCHORING

Public anchoring: verify a daily record yourself

Once a day (UTC) the state of the live verification is written as a record: pass/fail, vector counts, the SHA-256 of the vector set and of the results, the signing key id, the build, and the hash of the previous record. The record is signed with the same ECDSA P-256 key that signs MCP responses, and its SHA-256 is written to Solana mainnet in a Memo transaction from a dedicated wallet. Editing a past day would change its hash and break the link to the next day, and the chain copy cannot be changed.

1
Fetch the records

GET https://tradingcalc.io/api/anchors returns recordText (the exact bytes), hash, our signature, and the Solana transaction for each day.

2
Recompute the hash

sha256("tradingcalc-anchor-v1\n" + recordText) as lowercase hex must equal hash.

3
Read the chain

Open the transaction on any Solana explorer. Its Memo must read "tcalc1 {date} {hash}" and the fee payer must be the wallet named in the response.

4
Check the signature

Verify the ECDSA signature over "tradingcalc-mcp-v1\nsystem.anchor\n{signedAt}\n{recordText}" against the public key from GET /api/mcp/pubkey. Authenticity comes from this key, not from the wallet.

5
Walk the chain of days

Each record carries prevHash, the hash of the day before. A missing or rewritten day breaks the link.

verify a record · node
import { createHash, createVerify } from 'node:crypto';
 
const base = 'https://tradingcalc.io';
const { records } = await (await fetch(base + '/api/anchors?limit=1')).json();
const r = records[0];
 
// 2. the hash of the exact record bytes
const hash = createHash('sha256')
.update('tradingcalc-anchor-v1\n' + r.recordText)
.digest('hex');
console.log('hash matches:', hash === r.hash);
 
// 4. our signature over the record (public key from /api/mcp/pubkey)
const { publicKeyPem } = await (await fetch(base + '/api/mcp/pubkey')).json();
const sig = r.signature;
const ok = createVerify('SHA256')
.update('tradingcalc-mcp-v1\nsystem.anchor\n' + sig.signedAt + '\n' + r.recordText)
.verify(publicKeyPem, sig.signature, 'base64');
console.log('signature valid:', ok);

All five steps for every day in one script, no dependencies (Node 18+): verify-anchors.mjs. It exits non-zero if any day fails.

Latest record and streak: tradingcalc.io/verification

08CROSS-CHECK

Independent cross-check against QuantLib

The Black-Scholes price and Greeks and the implied-volatility solver are checked against QuantLib, the open-source quantitative finance library, which is separate code implementing the same model. On 5,000 random European options (spot 100 to 120,000, strike 50% to 150% of spot, 1 to 730 days, volatility 10% to 300%, risk-free rate 0% to 10%), drawn from a fixed seed (20261018) and priced with QuantLib 1.44, the largest difference per output was:

Call price (USD)3.6e-11
Put price (USD)4.4e-11
Delta (call and put)2.6e-15
Gamma9.7e-17
Vega per volatility point5.1e-13
Theta per calendar day2.0e-12
Rho per rate point6.8e-13

The implied-volatility tool was given the call price computed by QuantLib, not its own, and recovered the true volatility to within 0.0012 volatility points in all 4,934 cases where the price responds to volatility. In the other 66 cases (deep in the money or far out of the money) the price does not determine the volatility: the tool reported "not converged" for 7 and returned a volatility that reproduces the price for the other 59, which is not the only volatility that does. The result carries an identifiable flag for exactly this: when the price barely responds to volatility it is false and a warning says the returned value is one of them. Over the same 5,000 cases the 4,945 converged results with identifiable true were all within 0.0028 volatility points of the true volatility (a set defined by our own flag, so slightly larger than the 4,934 above), and 40 of the 48 converged results with identifiable false were off by more than 0.01 (the other 8 were within 0.01, the flag is deliberately conservative; none of the 4,934 well-posed cases was flagged). The flag assumes the price is exact; a price rounded to cents says less.

Two more tools were run the same way. The up/down window fair value of prediction-market contracts is a cash-or-nothing digital option, priced by the CashOrNothingPayoff class of QuantLib: on 3,000 random windows (5 minutes to 7 days, volatility 15% to 150%) the probability agreed to within 5.4e-12 percentage points. The parametric VaR and CVaR agreed to within 1e-16 on 500 random return series, but that is a narrower check: the Python interface of QuantLib has no Gaussian VaR, so it compares our sample mean, standard deviation and normal functions with those of QuantLib, not the whole formula. QuantLib has no counterpart for the GARCH, Hurst, cointegration and Sharpe tools; those are checked against numpy, scipy, statsmodels and arch instead.

The second order Greeks (vanna, vomma, charm, veta, speed, zomma, color) of the Option Greeks Calculator are checked two ways on 1,600 random options. Reference one: nested central differences of the Black-Scholes-Merton price at 100-digit precision (mpmath), which does not use the closed forms. Reference two, on 1,000 of them: central differences of the analytic delta, gamma and vega. The two references agree with each other to a relative 1e-4 or better on every Greek, the closed forms agree with the 100-digit reference to a relative 1e-7, and the test also covers expiries from about 0.01 day to 100 years, volatility from about 1% to 1000%, and rates and dividend yields up to 100%. Charm, veta and color are the change as one calendar day passes, so veta has the opposite sign to tables that differentiate with respect to time to expiry.

The Cash-Secured Put Calculator (premium income, cash held, return per year, effective buy price, breakeven, loss below it) is checked on 13 fixed cases against a Python reference that does not use these formulas: it builds the profit and loss from the definition of the option (premium received minus the shares bought at the strike when the price ends below it), finds the breakeven by root-finding (scipy) and does the money arithmetic in exact fractions. A zero premium is one of the cases, and nine inputs that must be refused, such as a premium at or above the strike, are checked too. The same script draws random inputs for a wider check (the --random option). Prices are the ones typed; nothing is fetched.

Conventions on both sides: European exercise, Actual/365 day count, continuously compounded flat risk-free rate and flat continuous dividend yield (zero in the main run). QuantLib reports vega and rho per 1.00 and theta per year; they are converted to per point and per calendar day, the units the tools return. Only the standard USD-denominated model is compared. Coin-settled quoting, as Deribit does it, is that price divided by spot and has no QuantLib counterpart.

Dividend yield (stock and ETF options): the Black-Scholes tool takes an optional continuous dividend yield, Black-Scholes with a continuous dividend yield q (percent per year in dividendYieldPct, 0 for crypto): d1 = [ln(S/K) + (r − q + σ²/2)T] / (σ√T), d2 = d1 − σ√T; Call = S·e^(−qT)·N(d1) − K·e^(−rT)·N(d2); Put = K·e^(−rT)·N(−d2) − S·e^(−qT)·N(−d1); Delta(call) = e^(−qT)·N(d1), Delta(put) = −e^(−qT)·N(−d1); Gamma = e^(−qT)·φ(d1) / (S·σ·√T); Vega = S·e^(−qT)·φ(d1)·√T; Theta(call) = −S·e^(−qT)·φ(d1)·σ/(2√T) + q·S·e^(−qT)·N(d1) − r·K·e^(−rT)·N(d2), Theta(put) = −S·e^(−qT)·φ(d1)·σ/(2√T) − q·S·e^(−qT)·N(−d1) + r·K·e^(−rT)·N(−d2), per year (the tool reports per day); Rho(call) = K·T·e^(−rT)·N(d2), Rho(put) = −K·T·e^(−rT)·N(−d2). A second run of 5,000 random options (seed 20261030, the same ranges, a dividend yield of 0.1% to 15%, with one case in ten drawn up to 100%, and a risk-free rate of 0% to 10% in every case) was priced with QuantLib 1.44 the same way, and the largest difference in price and in every Greek was 4.4e-11. With the yield at 0 every result is identical to the version without it.

Run it yourself: quantlib-check.py draws options from the same kind of seed, prices them with QuantLib, calls workflow.run_black_scholes and workflow.run_implied_volatility on the live endpoint and prints the largest difference per output. The default 30 cases use 60 calls, inside the 100 calls/day an anonymous caller gets.

09MODELS ON THEIR OWN

How often language models get trading math right

A monthly test of how reliably language models compute the same kind of numbers these tools return, and how sure they say they are when they are wrong. It measures the models on their own with web search off; it does not test models that call a tool. Latest run: October 2026, 6 models, 630 answers.

Tasks

21 task types in two tiers. Spec tier: every convention is written into the question (Black-Scholes price, delta, gamma, vega, implied volatility; forex lot size; parametric VaR and CVaR; Sharpe from 12 monthly returns; Kelly fraction for a binary contract; inverse liquidation, inverse average entry, inverse and linear PnL with fees). Realistic tier: phrased the way a trader asks, with market-standard conventions left unstated, longer series and two-step tasks (lots for a USD account, Bybit inverse PnL, VaR from 40 daily returns, Sharpe from 30 daily returns, call delta at the implied volatility of a quoted price, Deribit coin-settled straddle breakeven).

Inputs

Drawn fresh for every run from a seeded generator, so no task can come from a public test set. Five tasks per type.

References

Computed by the same functions the MCP tools call (options math cross-checked against QuantLib, above). The return-series references were also re-derived independently with the Python statistics module.

Models

A flagship and a smaller model from each of OpenAI, Anthropic and Google, called through one API with web search off. Each reply must end with a JSON line giving the answer, to at least 4 significant digits, and a confidence from 0 to 100.

Scoring

Correct: within 1% of the reference. Confidently wrong: more than 1% off with a stated confidence of 80 or more.

Reference check

The reference answers of all 21 task types were recomputed independently, in plain Python without TradingCalc code: 105 of 105 matched. Every wrong reply was read in full and none came from an unclear question: slip in hand arithmetic, right formula (11); wrong side or sign, right idea (5); numerical solve stopped early (1). The script is audit-references.py.

613 of 630 answers were correct (97%): 99% in the spec tier and 93% in the realistic tier. 12 of the 17 wrong answers came with a stated confidence of 80 or more. Statistics over a series of returns and the direction of inverse (coin-margined) contracts account for most of them. Most errors by task type: VaR from 40 daily returns, 6 of 30 wrong; Annualized Sharpe from 30 daily returns, 3 of 30 wrong; Call delta at the implied volatility of a quoted price, 2 of 30 wrong. No errors from any model: Black-Scholes price, delta, gamma and vega; implied volatility; forex lot sizing, including a USD account on JPY, CHF and CAD pairs; parametric VaR and CVaR from a given mean and deviation; Kelly fraction for a binary contract; inverse average entry; linear PnL with fees; Deribit coin-settled straddle breakeven. Cost: the run was charged $3.92 for 630 answers, as charged by the API the models are called through, not the vendors' list prices; the per-model figures below add what each model's replies cost and the cost per correct answer, wrong replies included.

claude-opus-5-5105/105 correct, 0 wrong, 0 confidently wrong, $1.68 for 105 answers, $0.016 per correct answer
gpt-6.1-sol104/105 correct, 1 wrong, 1 confidently wrong, $0.527 for 105 answers, $0.00507 per correct answer
gemini-3.8-flash104/105 correct, 1 wrong, 1 confidently wrong, $0.434 for 105 answers, $0.00418 per correct answer
gpt-5.4-mini103/105 correct, 2 wrong, 2 confidently wrong, $0.477 for 105 answers, $0.00463 per correct answer
gemini-4-argon99/105 correct, 6 wrong, 6 confidently wrong, $0.700 for 105 answers, $0.00707 per correct answer
claude-haiku-5-598/105 correct, 7 wrong, 2 confidently wrong, $0.095 for 105 answers, $0.00097 per correct answer

One sample per task, so per-type shares are indicative until several monthly runs agree. Single-step questions only; multi-step agent workflows and models using a calculation tool are not covered yet.

Every task, reference answer and full model reply of this run: llm-math-2026-10.json. Results by month: tradingcalc.io/benchmark.

Start using deterministic calculations

93 MCP tools across perp futures, options, forex, on-chain, and prediction markets. Free, no signup required. Add to Claude Desktop, Cursor, or call the MCP endpoint directly.