Fee Optimizer MCP
# Fee Optimizer MCP
An MCP (Model Context Protocol) server that helps AI agents answer questions about crypto exchange trading fees, fetch referral links for fee discounts, calculate savings, compare total cost (fees + funding + spread/slippage + withdrawal), annualize the all-in yearly cost with VIP upgrade savings, inspect funding rates (bundled averages or real-time live rates), measure order-book execution cost (bid-ask spread crossing + size-conditional depth slippage, bundled baselines or live book walks), compare direct fiat on/off-ramp costs (card / ACH / SEPA / FPS / wire / SWIFT / PIX deposits and withdrawals across venues, currencies and countries of residence), compare on-chain withdrawal fees per asset and network across venues (16 assets × TRC-20/ERC-20/L2/native routes with suspended-wallet flags and snapshot-price USD conversion), and run a research-anchored trader-persona analysis that annualizes the full cost stack (fees + funding + spread + withdrawals + fiat on/off-ramping) for seven trader archetypes and recommends the best exchange for a user's profile.
When a user asks *"which crypto exchange has the lowest fees for a limit-order trader?"*, *"give me a Gate.io discount registration link"*, *"how much can I save on 100k USDT futures held for 16 hours?"*, or *"where does this fee data come from?"*, the agent can call this server's tools to return concrete, sourced answers — including a referral link the user can register with to receive a fee discount.
## Features
Twenty read-only tools. Runs over **stdio or stateless Streamable HTTP** (v0.29: per-request isolated servers, JSON responses, `/health` probe — ready for remote/container hosting; v0.32 adds public-hosting hardening: opt-in bearer-token auth, per-IP rate limiting, structured JSON access logs and a production Dockerfile). All fee-bearing tools require a country code for compliance filtering. Every result carries a `data_as_of` stamp, and `get_data_sources` reports per-file `months_behind`/`is_stale` plus `stale_files` (v0.33), enforced by an offline `npm run audit:data` consistency gate. **v0.48 adds `get_fee_changes` (20th tool) — the auditable fee-schedule change feed (data moat)**: a curated, official-announcement-verified history of VIP rate moves, qualification-threshold changes, rung inserts/removes, promos, token-discount and pricing-model changes (each with effective date, source URL and bilingual summary), plus monthly deterministic fee-ladder snapshots in `snapshots/fee_ladders/` that are diffed automatically — snapshot-derived rows carry `confidence: "detected"` and are NEVER presented as confirmed (a delta can be a data correction); a monthly GitHub Actions workflow captures the new snapshot and opens a review-only PR, and a human verifies against the official fee page before curating into `data/fee_changes.json`. The curated feed ships in the npm package; snapshots are repo-only, and npm consumers degrade gracefully (`snapshot_coverage.available: false`). **v0.34 adds `volume_what_if`** — a volume what-if/sensitivity sweep: cross-venue cheapest ranking and per-venue fee/cost curves across monthly-volume levels (default points = the union of every venue's VIP thresholds), the exact tier-crossing list, and with `baseVolume` each venue's next rung, extra volume required and USD/year saved at today's volume (holding-gated rungs like Binance spot's BNB requirement flagged `blocked_by_holding_gate`). **v0.35 adds `compare_countries`** — one trader persona priced through the full annual all-in stack across up to 12 countries in a single call: per-country winner and realistic all-legs pick, the extra annual cost vs the cheapest country on a *comparable* basis (a rail-less headline winner cannot fake a country), a venue×country availability matrix that distinguishes compliance-blocked from product-unsupported (spot-only Coinbase for a futures trader), venue win counts and the cheapest/costliest gap. **v0.36 adds ready-to-paste matrix tables** — `compare_personas`, `volume_what_if` and `compare_countries` accept `format: "markdown" | "csv" | "both"` and return a `rendered` object alongside the unchanged JSON (`tableMetric` selects the slice: weighted fee / annual fee / tier for the sweep, availability symbols / cost for countries); markdown tables escape pipes and CSV follows RFC 4180 (quoted commas/quotes/newlines, CRLF) for direct paste into docs or spreadsheets; default calls stay byte-identical. **v0.37 adds BloFin as the 13th venue** — a derivatives-led Cayman/Marshall-Islands exchange (~$1.2B/24h perp volume, no KYC up to 20k USDT/day withdrawals): 6-tier spot/futures ladders (futures 0.020%/0.060% base → 0%/0.035%, spot 0.10%/0.10% → 0.01%/0.0325%), three-track OR qualification (30d futures volume / 30d spot volume / account assets — just $50k assets reaches futures VIP1), 8h funding, ~3 bps typical perp spread, TRC-20 withdrawals at ~1 USDT/USDC, no native token, no referral link, no direct fiat rails, and blocked in US/CA/CN/SG plus the EEA under MiCA (Germany explicitly modeled). **v0.38 adds Bitstamp as the 14th venue** — the most regulated venue in the model (founded 2011, Luxembourg, Robinhood-owned; EU MiCA CASP passport, NYDFS BitLicense, UK FCA, SG MAS): an 11-tier volume-only spot ladder (0.30%/0.40% entry → 0.00%/0.03% above $1B 30d turnover) plus regulated USD-margined perps at a flat **−0.005% maker rebate / 0.015% taker** with 8h peer-to-peer funding — the perps are EU/EEA-eligible-residents only, modeled with a venue×country **product gate** (v0.40: a positive EEA region allowlist — all 30 EEA states route both products, every other residency including AU/BR/CH gets futures `PRODUCT_BLOCKED_IN_COUNTRY` while spot stays open; CN is venue-blocked), deep direct fiat rails (free ACH both ways, free SEPA in / €3 out, 0.05%/0.1% SWIFT with floors/cap, ~4% card) and conservative ERC-20-heavy withdrawals (USDT ~20 ERC-20 only — the most expensive USDT route modeled). Funding math defaults to bundled long-run averages and can switch to real-time live rates via `fundingMode: "live"`. Execution cost (spread + slippage) defaults to bundled typical-spread baselines and can switch to real-time order-book walks via `spreadMode: "live"`. **v0.39 adds `get_account_fee_tier`** — the leap from the public fee schedule to the caller's *actual* account rate: pass a **read-only** API key (Hyperliquid needs only the public 0x wallet address; OKX/KuCoin-Futures take an API passphrase) and the tool calls the venue's authenticated fee endpoint via ccxt, returns the real maker/taker in percent and the signed gap in bps vs the bundled public VIP tier at the given monthly volume (captures server-side BNB deductions, the venue's own rolling-30d VIP window, negotiated/promo rates; 13/18 venues supported — Phemex/BloFin, Finst, Bitpanda and BISON (no public trading API / ccxt connector), plus the spot-only venues' perps (Bitstamp, Bitvavo), return a typed unsupported error). Credentials are per-request only, never cached, never written to logs (audit lines redact `apiKey`/`secret`/`password`; error strings scrub credential literals), and country/product compliance gates run before any authenticated call. **v0.40 adds positive region allowlists** (`regions` + `product_region_gates` in `country_restrictions.json`) replacing the v0.38 negative-list default key: Bitstamp perps now require membership of the declared **EEA** region (all 30 states — EU27 + Iceland/Liechtenstein/Norway), so unmodeled non-EEA residencies such as AU/BR/CH/TR/KR are correctly `PRODUCT_BLOCKED_IN_COUNTRY` instead of being silently over-opened, while every EEA member (FR/NL/ES/IT/…) routes both products; the gate is data-driven and reusable for future region-restricted venues. **v0.41 enforces the post-cliff MiCA regime** (Article 143(3) transition ended **2026-07-01**, no extension) with negative region gates (`region_blocked` + `product_region_blocked`): for EEA residents, **Binance, MEXC, Bitget, KuCoin, BingX, Phemex and BloFin are venue-blocked for every product** (no usable CASP authorization — withdrawn/pending applications or KuCoin's active FMA commencement-of-business ban), and **Bybit/Gate perps are product-blocked** pending separate MiFID II investment-firm authorization while their spot stays open; the EEA stack is therefore OKX/Gate/Bybit/Kraken/Coinbase/Bitstamp for spot and only **OKX (X-Perps), Kraken and Bitstamp** for perps, plus non-custodial Hyperliquid (no frontend geo-block — retained with an explicit gray-zone risk caveat). Negative gates narrow EEA results only; non-EEA markets (US/GB/AU/BR/JP/…) are byte-identical to before, including countries routed through the open default key. **v0.42 adds Bitvavo as the 15th venue** — the largest home-grown euro spot exchange (Amsterdam, founded 2018, ~4M+ users, roughly half of global EUR-denominated spot volume; AFM MiCA CASP registration #41000010 with EEA passporting) — and a new **venue-level positive service-area gate** (`region_allowed` in `country_restrictions.json`): Bitvavo serves only the 30 EEA states, so every other residency (US/GB/CH/JP/SG/AU/BR/CN/… including default-key countries) gets the venue filtered (`COUNTRY_BLOCKED` semantics), while a whitelist hit authorizes the venue even where a stale per-country `allowed` enum disagrees. Bitvavo is **spot-only**: a nine-rung single-track 30-day EUR-volume PRO ladder (0.15%/0.25% entry → 0.00%/0.02% above €25M; no token, no assets track; the Basic consumer UI's embedded spread is not modeled), the tightest EU EUR-book spread in the model at **1.0 bps** full / 0.5 bps crossing (Kaiko 2026-05 measured 0.981 bps — best of any European venue), **free SEPA/SEPA Instant both legs** in EUR (iDEAL/Bancontact ride SEPA; €25k/day cash-out cap) plus a ~1% EU card deposit with no card cash-out, and a dynamic **BTC-only** on-chain withdrawal modeled at 0.00005 BTC (no Lightning; USDT/USDC/ETH/alts surface as unsupported). The EEA spot stack grows to 8 venues; the futures stack is unchanged (Bitvavo lands in `unsupported_product` for a futures persona). The separate Bitvavo UK and Swiss entities are deliberately not modeled, so GB/CH stay outside the whitelist. **v0.43 adds Finst as the 16th venue** — the model's first *brokerage* rather than an order-book exchange (Amsterdam, founded 2022 by an ex-DEGIRO team; AFM MiCA CASP #41000015 granted 2025-07 with EEA passporting, ~30 countries / 110k+ users): a smart-order router (SOR) that aggregates external liquidity and charges a **flat 0.15%** on every buy/sell/swap/auto-invest — no maker/taker split, no volume tiers, no minimum, no spread markup (modeled as a single volume-independent ladder rung plus a 1.0/0.5 bps cohort spread proxy). The same venue-level `region_allowed: ["EEA"]` gate applies, bringing the **EEA spot stack to 9 venues**; Finst vanishes from every non-EEA result. It is **spot-only** (a futures persona sees `unsupported_product` inside the EEA, `blocked` outside), offers **free SEPA/SEPA Instant/iDEAL/Bancontact both legs in EUR only** — no card rail (explicit card queries return `available: false`), no PayPal, no USD/GBP — and models crypto withdrawals as dynamic network fee at cost **plus a flat €2.50 third-party charge**: because the schema has no surcharge field, BTC is priced all-in at **0.000085 BTC (≈$6.57)** with the two-part composition disclosed in the route note, while the other 400+ markets surface as unsupported. There is no referral program and no public trading API, so `get_account_fee_tier` is unsupported (live coverage stays 13 venues). **v0.44 adds Bitpanda as the 17th venue and the model's first spread-priced brokerage** (Vienna, founded 2014, 7.4M+ users; BaFin MiCA CASP authorization 2025-01-27 with EEA30 passporting + Austrian FMA license + UK FCA-registered Bitpanda Broker UK entity): the consumer app quotes an all-in price with the fee **embedded as a markup** and zero separate commission — a new `pricing_model: "spread"` (`order_book | flat | spread`) with no maker/taker split and no volume ladder — **1.49% per side** headline for most assets, **0.99% per side** for BTC and major stablecoin pairs via pair-level overrides, and **2.49%** for sub-€100M small caps (the 1.99% crypto-index band and the consumer app's 10x margin are not modeled; futures unsupported). Because the embedded markup *is* the spread cost, Bitpanda's bundled typical-spread baseline is pinned to **0 bps** so the premium and a spread line can never be double-charged, and a new `execution_quality` evidence block discloses the gap the broker hides: **advertised 2.98% round trip vs TUM's real-money €100 round-trip measurement of 6.23% — 4.25 percentage points of hidden markup** (Oct–Nov 2025, independently replicated by the Frankfurt School of Finance in 2026-03 with 432 round trips across 9 platforms) — the largest measured European retail cost gap in the research. Bitpanda serves **only the 30 EEA states plus Great Britain** via `region_allowed: ["EEA","GB"]` (GB added as a single-member region key — the same positive gate mechanism, no gate-code change), bringing the **EEA spot stack to 10 venues**; a futures persona sees `unsupported_product` inside the service area and `blocked` outside (US/CA/CN/CH/…); the separate **Bitpanda Fusion** pro exchange (0.02–0.25% aggregated-liquidity pricing) and stocks/metals/ETFs are deliberately not modeled and disclosed via notes. **All consumer-app fiat rails have been free since 2026** — SEPA/SEPA Instant, Visa/Mastercard cards (deposit-only, no card cash-out leg), PayPal and Apple/Google Pay in EUR, plus FPS and cards in GBP; there is **no USD route** (USD queries retain the venue row with `available:false`). Crypto withdrawals pass the dynamic network fee through with no markup: **BTC 0.00000598 (~$0.46)** and **ETH 0.0006 (~$1.51)** at the dated snapshot. There is no referral link and ccxt ships no `bitpanda` class, so `get_account_fee_tier` returns `ACCOUNT_FEES_UNSUPPORTED` (live coverage stays 13 of 17 venues). **v0.45 adds BISON as the 18th venue and the model's second spread-priced brokerage** (Boerse Stuttgart Group, Stuttgart, launched 2019, 1M+ active users; EUWAX AG quotes as principal counterparty for roughly 10 seconds with no order book; Boerse Stuttgart Digital Custody — formerly blocknox — held the **first BaFin MiCA crypto custody/transfer license** from 2025-01-17, passported to 29 states, and EUWAX AG's crypto exchange service has been MiCA-authorized since 2025-04-01): the consumer app quotes one all-in price, again modeled with `pricing_model: "spread"` (no maker/taker, no volume ladder) — **1.25% per side for BTC and ETH** via pair-level overrides, **1.75% per side for every other cryptocurrency** (round trip ≈2.5% vs ≈3.5%), undercutting Bitpanda's 1.49% headline. The spread baseline is pinned to **0 bps** (same anti-double-count guard), and the `execution_quality` evidence block tells the *opposite* story to Bitpanda's: **advertised 2.5% round trip vs TUM's real-money €100 measurement of 2.58% — only ~0.08 percentage points undisclosed** (Oct–Nov 2025, six MiCA-licensed platforms) — by far the closest published-vs-measured alignment of the tested field (Bitvavo next; Bitpanda 6.23%, Coinbase 7.49%), making BISON the European transparency benchmark. BISON serves **the 30 EEA states plus Switzerland** via `region_allowed: ["EEA","CH"]` — **CH is a new single-member region key** (DE/AT/CH actively marketed, other EEA residents served under passive freedoms) — and is **blocked for Great Britain**, the exact complementary gap to Bitpanda (EEA+GB, not CH), plus US/CA/JP/SG/AU/BR/CN/KR; the **EEA spot stack becomes 11 venues**, the **CH stack 15**, and BISON never appears in GB/US/JP results. It is **spot-only** (`futures: []` → `unsupported_product` in-service, `blocked` outside; no futures or margin exist). **Crypto withdrawals are officially free** — no network-fee line, on-chain costs absorbed by EUWAX/the group (unlike Bitpanda's pass-through) — modeled at **BTC 0 and ETH 0**, which makes BISON the globally cheapest modeled withdrawal for both assets (min 0.001 BTC, no Lightning/Taproot bc1p; Ethereum mainnet only, min 0.01 ETH, no L2 payouts). Fiat is **EUR only**: SEPA/SEPA Instant **free both legs including Swiss users funding in EUR**, plus **2.49% deposit-only** card/Apple Pay/Google Pay (Solaris SE/Deutsche Bank partner fee, no card cash-out; no GBP/USD/CHF rail — USD queries keep the unavailable row). The €1.99 German stocks/ETFs order fee and the 27% staking reward commission are not crypto-trading fees and are not modeled. The invite-a-friend program carries no affiliate URL (`NO_REFERRAL_LINK`) and ccxt 4.5.78 ships no `bison`/`euwax` class, so `get_account_fee_tier` returns `ACCOUNT_FEES_UNSUPPORTED` (live coverage stays 13 of 18 venues). **v0.46 adds `get_stablecoin_access` (18th tool) — MiCA stablecoin regional-access intelligence**: Tether never applied for MiCA EMT authorization, and after the CASP transitional cliff on **2026-07-01** (ESMA75-113276571-1679, confirmed non-extendable) USDT venue trading is unavailable across all **30 EEA states** — the model carries the full delisting timeline per venue (Coinbase 2024-12, the Binance/Kraken/OKX/Gate/Bitstamp/Bitpanda/Bitvavo wave through 2025-03, Revolut's 2026 buy-stop/residual-conversion dates) plus `venue_blocked` status for the six EEA-blocked venues and `never_offered` for BISON/Finst/Hyperliquid; the report distinguishes the **venue-side trading ban from personal rights** — holding, custody and on-chain withdrawal to self-custody stay legal (Convert/custody mostly retained, DEXs outside the perimeter; Switzerland and Great Britain are deliberately **not** in the EEA region), names the six modeled MiCA-authorized alternatives (USDC/EURC — Circle France EMI, EURI — Banking Circle, EURCV — SocGen FORGE, USDQ/EURQ — Quantoz) with issuer/authorization detail, and renders bilingual advice. The same `STABLECOIN_UNAVAILABLE_IN_REGION` warning is **auto-injected** into every USDT-quoted EEA flow — fee comparisons (per-venue `stablecoin_access` rows), savings/total-cost/annual-cost/recommendation (top-level `stablecoin_warning` in trading context), withdrawals (self-custody/withdrawal context), execution cost and persona analysis (5 of 7 personas habitually withdraw USDT) — so an agent can never recommend an EU resident trade USDT on a venue without the constraint surfacing. **v0.47 adds `compare_interface_costs` (19th tool) — consumer vs PRO dual-interface cost modeling**: the same account often runs a cheap order-book interface (Kraken Pro, Coinbase Advanced, Bitvavo trade) and an expensive consumer app whose spread is embedded in the quote — priced against the TUM real-money €100 round-trip study (2025-10..11, six MiCA-licensed EU platforms; independently replicated by Frankfurt School 2026-03 with 432 round trips across 9 platforms): retail round-trips span 13x — **Bitvavo 0.58%** (pass-through, transparency benchmark) < **BISON 2.58%** < **Kraken app 5.81%** (3.81pp hidden) < **Bitpanda 6.23%** (4.25pp hidden) < **Coinbase Simple 7.49%** (4.51pp hidden, worst — the $2.99 flat fee dominates small DCA buys and even simple LIMIT orders carry a 1% execution fee); per-venue rows give the consumer product name and fee model, a modeled one-way all-in cost, the measured round trip, the hidden markup pp, the PRO maker/taker base and the gap in pp, and with `monthly_volume_usd` the **annualized excess of staying on the app** (Coinbase at $1k/mo ≈ $168/yr), plus subscription caveats (Kraken+ $4.99/10k waiver, Coinbase One) and the fact that **app volume earns no PRO tier credit**; Bitpanda/BISON are broker-only (the premium IS the fee — no PRO interface to switch to), Bitstamp Basic is flagged unverified, residency gating applies, and the same gap auto-injects as `consumer_interface` hints + `CONSUMER_INTERFACE_MORE_EXPENSIVE` warnings into the fee/savings/total-cost/recommendation tools. **v0.30/v0.31 add bilingual narrative output** — the fifteen narrative-bearing tools accept `language: "en" | "zh"` and localize every advice/warnings/tradeoffs/reasons/tier_warning string (numbers, field names and error codes stay unchanged); v0.31 also fixes the held-back BNB tier warning, which previously rendered "holding at least undefined BNB".
| Tool | Trigger (EN / 中文) | Returns |
|---|---|---|
| `compare_exchange_fees` | "which exchange has the lowest fees" / "交易所手续费对比" | Exchanges sorted by weighted effective fee rate, maker/taker split, VIP tier, token + referral discounts |
| `get_referral_link` | "give me a Binance referral link" / "币安优惠注册链接" | Referral URL + discount % + notes |
| `calculate_savings` | "how much will I save on 100k USDT futures" / "10万U能省多少" | Original fee, fee after referral, fee after token, final fee, savings, optional funding cost |
| `compare_total_cost` | "true cost including funding and withdrawal" / "真实总成本对比" | Per-exchange trading fee + funding cost + withdrawal fee, ranked; **v0.26** optionally folds annualized direct fiat deposit/cash-out fees (`fiatDepositAmountUsd`/`fiatDepositsPerYear` + cashout equivalents) into `total_cost`, with `fiat_deposit_available`/`fiat_cashout_available` flags so a venue with no direct rail is marked and the leg excluded, never priced as zero |
| `recommend_exchange` | "which exchange should I use" / "我该选哪个交易所" | Scored best pick (0-100) with reasons, tradeoffs, advice, and ranked alternatives; **v0.27** folds the user's direct fiat deposit/cash-out habit into the score (dispersion-driven 0.2–0.5 weight), flags rail-less venues with an explicit tradeoff, and ranks a small card/SEPA on-ramper on fiat rails instead of trading fees alone |
| `calculate_annual_cost` | "what does trading cost me per year" / "一年手续费多少,升VIP能省多少" | Annualized trading fee + funding + withdrawals (+ v0.26 optional annual fiat deposit/cash-out legs in `annual_total_cost`), plus next-VIP-tier qualification path and yearly saving |
| `get_data_sources` | "where does the data come from" / "数据哪来的,多久更新" | Per-file `last_verified` dates and source URLs (official exchange fee pages) + caveats |
| `get_funding_rates` | "current funding rate on BTC perps" / "现在各所资金费率多少" | Per-exchange funding rate + interval for a perp pair (default BTC/USDT): bundled averages or real-time live rates with per-venue fallback |
| `get_execution_cost` | "spread and slippage on a 50k market order" / "点差滑点多少、大单冲击成本" | Per-exchange one-way execution cost in bps + USD for an order size: full spread, half-spread crossing, depth-walk slippage, levels consumed, fill status — bundled baselines or live top-100 book walks |
| `get_fiat_cost` | "cheapest way to deposit euros / cash out to bank" / "入金出金手续费、SEPA/ACH/电汇/PIX 哪个便宜" | Per-exchange direct fiat deposit or withdrawal quotes for an amount: fee (pct + fixed with min/max), USD-equivalent, effective %, net amount, ETA, cheapest rail per venue, overall best pick and saving vs worst — card / ACH / SEPA / FPS / wire / SWIFT / PIX in USD/EUR/GBP/BRL with residency-based rail filtering |
| `get_withdrawal_fees` | "cheapest network to withdraw USDT / ETH L2 提币费对比" / "各所提币手续费、TRC20/ERC20/ Layer2 哪个便宜、哪条链暂停了" | Per-exchange withdrawal quotes for an asset (and optional network): every route's native-unit fee + USD-converted fee with `available` flag (suspended wallets surfaced, never hidden), cheapest open route per venue, overall `best`, saving vs worst, warnings — 16 assets across TRC-20/ERC-20/BEP20/Arbitrum/Optimism/Base/Polygon/Avalanche C/Solana/TON/AssetHub and native chains; fully offline |
| `analyze_persona` | "which exchange fits a small buyer / scalper / HODLer" / "我这种情况哪个交易所划算、定投囤币/波段/高频场景推荐" | Seven research-anchored trader personas (casual buyer, HODL accumulator, active spot, swing futures, day scalper, VIP/institutional, DEX-native): annual all-in ranking over the FULL cost stack — trading fees + funding + spread + withdrawals + fiat on/off-ramping — with per-component cost mix, component leaders, a `best_complete` pick (cheapest venue with every persona leg priced; headline winners missing rails are flagged, never silently $0), warnings and actionable advice; **v0.25 cross-links `analyze_token_discount`** — when run with `useToken=false` (the default), the top-3 ranked venues each get a `token_discount_hint` (token, discount %, annual saving, payback months, holding cost, flat-vs-tiered) plus a consolidated `token_discount_hints` array and concrete advice, so one call answers both "which exchange fits me" and "is holding its token worth it"; all presets overridable |
| `analyze_token_discount` | "is holding BNB/GT/KCS for fee discounts worth it" / "持有平台币划算吗、折扣多久回本、币价跌多少不亏" | Native-token fee-discount payback: annual fee WITHOUT the token (zero-balance tier, no toggle) vs. WITH it (BNB/MX/BGB/KCS flat deduction, GT/MX/HYPE holding-tier ladder, Gate futures maker-to-zero, GT/KCS/BNB tier lift), annual USD saving, USD opportunity cost of the locked token balance, payback in months, and max one-year token price drop the saving can absorb; omit `tokenBalance` to get every achievable tier ranked by payback |
| `compare_personas` | "which exchange for EVERY kind of trader" / "全部画像对比、什么人用什么所、决策矩阵、最全能的交易所" (v0.28) | One call runs **all seven personas** (or a subset) for a country through the full annual all-in stack and returns a decision matrix: per-persona headline winner + realistic `best_complete` pick, a persona×venue `annual_all_in` grid (cheapest-first, rail/route flags per cell), cross-persona `venue_wins`, and `most_versatile` — e.g. in JP Hyperliquid headlines 3 personas but wins **zero** realistic picks (no fiat/withdrawal rails), while OKX is the most versatile all-legs winner |
| `volume_what_if` | "how do fees change if my volume grows / how much more trading to hit the next VIP tier" / "月交易量不同手续费差多少、再刷多少量升档省钱、各所档位跳变点、费率随成交量曲线" (v0.34) | Volume what-if sweep for spot/futures across every allowed venue: per-volume-point cross-venue cheapest ranking (tier + weighted fee + annual trading fee), per-venue sweep curves with `tier_crossed` markers, and a flat `tier_crossings` list; with `baseVolume`, per-venue `next_tier` gives the exact threshold, extra monthly volume and USD/year saving at the current volume — `blocked_by_holding_gate: true` marks rungs volume alone cannot reach (e.g. Binance spot BNB AND-gate). Default sweep points are the union of all venues' VIP thresholds (sampled past 16 with a warning); pass explicit `volumes` for custom points |
| `compare_countries` | "same profile across countries / I'm moving countries, what changes / which venues are blocked here" / "同样的习惯在哪个国家最便宜、搬家换居住地、各国有什么交易所、哪些所在我国不能用、国家差异矩阵" (v0.35) | Runs one persona (default active_spot_trader; any of the 7) through the full annual stack across multiple countries (default US/GB/DE/JP/SG/BR/CN, up to 12): per-row headline `winner` plus realistic `best_complete`, `comparison_annual_all_in`/`extra_vs_cheapest_country_*` on a comparable all-legs basis (Hyperliquid can headline for a card buyer yet be excluded from country math because it has no fiat rails), `blocked_venues` vs `unsupported_product_venues` (Coinbase for futures), a full venue×country `venue_availability` matrix, `winner_venue_counts`, `cheapest_country`/`costliest_country`/`spread_usd` and bilingual advice — e.g. the same small card buyer pays ~$125/yr in the US vs ~$73 in Germany (cheap SEPA/card rails) |
| `get_account_fee_tier` | "what is MY actual fee / my real VIP maker-taker / check my account fee with a read-only API key" / "我的实际费率、账户真实VIP档位、API查我的手续费、只读密钥查费率" (v0.39) | Authenticated real account maker/taker via read-only key + signed gap in bps vs the public schedule tier at the stated volume; 13/18 venues (Phemex/BloFin unsupported by ccxt, Finst, Bitpanda and Bison have no public API/connector; Bitstamp/Bitvavo spot-only so their perps unsupported); keys never cached or logged; compliance gates first; typed auth/network error codes |
| `get_stablecoin_access` | "can I still trade/withdraw USDT in the EU / is USDT delisted here / MiCA stablecoin alternatives" / "USDT在欧盟还能用吗、泰达币下架、欧洲稳定币、USDC/EURC合规稳定币" (v0.46) | MiCA regional access for a stablecoin (default USDT; also USDC/EURC/EURI/EURCV/USDQ/EURQ): issuer + MiCA EMT authorization, regional venue-trading restriction with cliff date (EEA30 post-2026-07-01), custody/withdrawal/self-custody rights, per-venue status (delisted + date / never_offered / venue_blocked, eea/global scope, availability in the queried country), compliant alternatives and bilingual advice; the same warning auto-injects into fee, withdrawal, execution-cost and persona tools for USDT/EEA requests |
| `compare_interface_costs` | "why is the Kraken/Coinbase app so expensive / hidden spread in Instant Buy or Simple" / "为什么App买币这么贵、App隐藏点差、两套价格、简单买卖手续费、TUM实测" (v0.47) | Per venue: consumer product name + fee model, modeled one-way all-in cost, TUM-measured round-trip, hidden markup pp, the PRO maker/taker base and gap in pp, and with `monthly_volume_usd` the annualized excess of the consumer app vs PRO (e.g. Coinbase $1k/mo ≈ $168/yr); subscription caveats (Kraken+/Coinbase One), no-PRO-tier-credit note, residency gating; Bitvavo surfaces as the 0.58% pass-through transparency benchmark |
| `get_fee_changes` | "did any exchange change its fees lately / fee change history / 哪家所最近调过手续费、费率变更历史、怎么监控费率调整" (v0.48) | Auditable fee-schedule change feed: curated high/medium-confidence records verified against official announcements (date, source URL, bilingual summary, before/after) merged with `detected` rows auto-derived from monthly ladder-snapshot diffs (clearly labeled unverified); filters `exchange`/`product`/`since_month`/`limit`, bilingual advice, plus `snapshot_coverage` (repo-only snapshots; npm consumers see `available: false`) |
Supported exchanges: **Binance**, **OKX**, **Gate.io**, **Bybit**, **MEXC**, **Bitget**, **KuCoin**, **Kraken** (spot + futures, full VIP tier tables; MEXC runs a flat Standard tier; Kraken runs one unified 17-tier schedule across both products), **Coinbase** (Advanced Trade spot-only, volume-only tiers), **Hyperliquid** (v0.20, the first DEX venue: on-chain L1 order book, 14-day rolling volume tiers, hourly funding, staked-HYPE fee discounts, no KYC), **BingX** (v0.21: VIP Club ladders with a volume-only Elite rung, a volume-OR-assets qualification track, and 8h funding), and **Phemex** (v0.24: Singapore-based, ex-Morgan Stanley team, the lowest maker fees in the industry — 0.01% spot/futures at the Standard tier, 30-day-volume-only VIP ladders, 8h funding, flat 20% PT token fee-deduction discount on spot+futures), and **BloFin** (v0.37: Cayman/Marshall-Islands derivatives venue live since 2023, ~$1.2B/24h perp volume — 6-tier ladders with futures 0.020%/0.060% base down to 0%/0.035% at VIP5, three-track OR qualification via 30d volume/spot-volume/account assets ($50k assets alone reaches futures VIP1), 8h funding, ~3 bps typical perp spread, no native token, no direct fiat rails; blocked US/CA/CN/SG and EEA under MiCA), and **Bitstamp** (v0.38: Luxembourg-founded (2011), Robinhood-owned, the most heavily regulated venue — MiCA CASP / NYDFS BitLicense / UK FCA / SG MAS; 11-tier volume-only spot ladder 0.30%/0.40% → 0%/0.03% at $1B; EEA30-only regulated USD perps at a flat −0.005% maker rebate / 0.015% taker with 8h P2P funding, gated per country×product via a positive region allowlist (v0.40); free US ACH, free SEPA in / €3 out, 0.05%/0.1% SWIFT, ~4% card; ERC-20-heavy withdrawals — USDT ~20 ERC-20 only, USDC also on Solana/L2; no native token), and **Bitvavo** (v0.42: Amsterdam (2018), the largest home-grown euro spot exchange — AFM MiCA CASP #41000010 with EEA passporting, ~4M+ users and roughly half of global EUR-denominated spot volume; nine-rung single-track 30d EUR-volume PRO spot ladder 0.15%/0.25% → 0%/0.02% above €25M, no token/assets track; the model's tightest EU EUR-book spread at 1.0 bps (Kaiko 2026-05); free SEPA/SEPA Instant both legs (iDEAL/Bancontact) + ~1% EU card deposit only; BTC-only dynamic withdrawal at 0.00005; spot-only — no perps; gated by a venue-level positive service-area allowlist (`region_allowed: EEA30`), so every non-EEA residency including GB/CH (separate unmodeled entities) is venue-blocked), and **Finst** (v0.43: Amsterdam (2022, ex-DEGIRO team), the model's first brokerage/SOR venue rather than an order-book exchange — AFM MiCA CASP #41000015 with EEA passporting; a FLAT 0.15% on every buy/sell/swap with no maker/taker split, tiers or spread markup, modeled as one volume-independent ladder rung; free SEPA/SEPA Instant/iDEAL/Bancontact both legs EUR-only, no card/PayPal/USD/GBP; BTC withdrawal 0.000085 (dynamic network fee ≈0.00005 + €2.50 flat third-party charge folded into the native fee), other assets unsupported; spot-only; EEA-only via the same `region_allowed: ["EEA"]` gate — the EEA spot stack is now 9 venues; no referral, no public trading API so account-fee lookup is unsupported), and **Bitpanda** (v0.44: Vienna (2014), the model's first spread-priced brokerage rather than an order-book venue — BaFin MiCA CASP (2025-01-27) with EEA30 passporting plus Austrian FMA and UK FCA entities, 7.4M+ users; the consumer app embeds its fee as an all-in price markup: 1.49%/side headline, 0.99%/side for BTC and major stablecoin pairs via pair overrides, 2.49% for sub-€100M small caps — no maker/taker split, no volume ladder, `pricing_model: "spread"` with the spread baseline pinned to 0 bps to prevent double-counting, plus `execution_quality` evidence (advertised 2.98% round trip vs TUM real-money measured 6.23%, 4.25pp hidden; Frankfurt School 2026-03 replication); free SEPA/SEPA Instant/deposit-only cards/PayPal/Apple-Google Pay in EUR and FPS/cards in GBP since 2026, no USD route; BTC 0.00000598 (~$0.46) and ETH 0.0006 (~$1.51) dynamic network-cost pass-through; spot-only; EEA30+GB service area via `region_allowed: ["EEA","GB"]` (GB single-member region key) — the EEA spot stack is now 10 venues and GB is included unlike Bitvavo/Finst; the separate Fusion pro exchange, stocks/metals and 10x margin are not modeled; no referral, no ccxt class so account-fee lookup is unsupported), and **BISON** (v0.45: Stuttgart (2019), Boerse Stuttgart Group — the model's 18th venue and second spread-priced brokerage — EUWAX AG quotes as principal (no order book, ~10s quote validity); Boerse Stuttgart Digital Custody held the first BaFin MiCA custody/transfer license (2025-01-17) and EUWAX's exchange service has been MiCA-authorized since 2025-04-01, 1M+ active users; the consumer app embeds 1.25%/side for BTC/ETH via pair overrides and 1.75%/side for every other coin (~2.5%/~3.5% round trip) — no maker/taker, no ladder, `pricing_model: "spread"` with the spread baseline pinned to 0 bps, plus `execution_quality` evidence (advertised 2.5% vs TUM real-money measured 2.58%, only ~0.08pp hidden — the closest published-vs-measured alignment of the six tested platforms); FREE SEPA/SEPA Instant both legs EUR-only including Swiss users + 2.49% deposit-only card/Apple/Google Pay, no GBP/USD/CHF rail; BTC and ETH on-chain withdrawals officially FREE at fee 0 (network costs absorbed by the group; min 0.001 BTC, no Lightning/Taproot; ETH mainnet only, no L2); spot-only, no futures/margin; service area EEA30+CH via `region_allowed: ["EEA","CH"]` (CH as a new single-member region key) — the EEA spot stack is now 11 venues, the CH stack 15, and GB is blocked (the complementary gap to Bitpanda); German stocks/ETFs (€1.99/order) and the 27% staking commission are not modeled; invite-a-friend but no affiliate URL, no ccxt class so account-fee lookup is unsupported). Referral links are optional per exchange — tools compare every exchange with fee data and only attach `referral_url` / `referral_discount` when a link is configured (Kraken, Coinbase, Hyperliquid, BingX, Phemex, BloFin, Bitstamp, Bitvavo, Finst, Bitpanda and BISON have none).
### Fee-model inputs
- **`monthlyVolumeUsd` / `volume`** — resolves the correct VIP tier per exchange.
- **`tokenBalance` (optional)** — native-token holdings, with exchange-specific ladder rules (verified against official fee pages 2026-09):
- **Binance spot — AND gate:** VIP1+ requires the volume threshold *and* BNB holdings (VIP1 = $1M + 5 BNB … VIP9 = $4B + 5,500 BNB). Omit it → the volume tier is quoted with a `tier_warning`; pass `0` → the tier is downgraded and priced correctly. (Binance futures have no holding gate.)
- **Gate spot + futures — OR dual-track:** VIP level is the *higher* of your 30-day volume rung and your GT-holdings rung (VIP1 = $1M *or* 1,000 GT … VIP9 = $1B *or* 200,000 GT). GT can only upgrade the tier, never downgrade it; results include a `next_tier` upgrade hint. GT holdings also unlock fee-payment discounts (100/500/2000/20000 GT → 10/20/35/50%).
- **KuCoin spot + futures — OR triple-track (v0.13):** VIP0–VIP12, and the level is the *higher* of your 30-day spot-volume rung, 30-day futures-volume rung (spot/futures thresholds differ and are applied per product), or your **KCS holdings** rung (VIP1 = 1,000 KCS … VIP12 = 150,000 KCS). KCS only upgrades, never downgrades; results include a `next_tier` / `requires_kcs` upgrade hint. KuCoin spot symbols are split into **Class A** (high-liquidity majors — the ladder quoted), **Class B** (exactly 2× Class A) and **Class C** (exactly 3×); spot results carry a `spot_class_note` reminding the caller to check the pair's class. Compliance note: KuCoin is filtered out for `US`, `CN`, `HK`, `SG`, `TH`.
- **Kraken spot + futures — unified 17-tier triple-track (v0.14):** since 2026-07-09 Kraken Pro applies **one** tier (Tier 1–12, then Pro 1–5) to *both* products, set by the *highest* of the 30-day spot-volume track, the 30-day futures-volume track (different thresholds per product), or real-time **assets on platform (AOP)** passed via `accountAssetsUsd` (Tier 3 = $20k AOP … Tier 9 = $1M … Pro 5 = $100M). Tier 1–2 have **no** asset path — holdings start at Tier 3. Spot runs 0.40%/0.80% at Tier 1 down to 0%/0.05% at Pro 5; futures run 0.02%/0.05% down to **-0.006%/0.0125%**, with negative maker rebates from Tier 11. Kraken has **no native token** (so `useToken` never applies) and no referral link. Every Kraken result carries `exchange_notes` with the qualification caveats (single-volume-input limitation, US/CA/NZ futures cross-qualification, consumer-app vs Pro pricing). Compliance: Kraken serves `US` (spot; CFTC-regulated Kraken/Bitnomial perps in 47 states), `HK`, `JP`, `TH` and is blocked for `CN` and `SG`.
- **Coinbase spot — volume-only tiers (v0.19):** Advanced Trade quotes pure order-book maker/taker rates that refresh hourly on 30-day rolling USD volume across all pairs (Tier 1 = 0.40%/0.60% … Tier 2 = 0.25%/0.40% at $10k … Tier 9 = 0%/0.04% at $400M). Qualification is **volume-only** — no holdings track, no native token, so `tokenBalance`/`useToken` never apply and `accountAssetsUsd` is ignored. Coinbase is a **spot-only venue**: it is automatically excluded from futures fee comparisons and from live funding fetches (retail nano BTC/ETH perps are not modeled). Spot execution cost uses a 2.0 bps typical full-spread baseline (live mode walks the `coinbaseexchange` book); withdrawal routes cover BTC / ETH / USDT (ERC-20, Base, Solana) / USDC (Base free, ERC-20) with dynamic gas-based fee notes. Compliance: served to `US` and `SG` residents, blocked for `CN`, `HK`, `TH`, `JP`.
- **Hyperliquid spot + futures — 14-day volume tiers + staked-HYPE discount (v0.20):** the first DEX venue — a fully on-chain L1 order book (HyperCore) with zero trading gas, USDC-margined perps and a USDC-quoted spot book (deposits arrive via Circle CCTP, min 5 USDC). Tiers refresh daily on a **14-day rolling weighted volume** window (spot volume counts 2× — not the 30-day window other venues use, so a steady-pace trader's real tier may sit one rung lower): perps 0.045%/0.015% at Tier 0 down to 0.024%/0% at Tier 6 ($7B), spot 0.070%/0.040% down to 0.025%/0%; maker is plain zero (not negative) from Tier 4. Qualification is **volume-only** — holding HYPE never qualifies a tier. The **staked-HYPE ladder** (10/100/1k/10k/100k/500k HYPE → 5/10/15/20/30/40% off *all* maker+taker fees, spot and perps) stacks **multiplicatively** with the volume tier; pass `useToken` + `tokenBalance` = the **staked** amount (merely holding HYPE gives nothing). Funding settles **every hour** — the bundled 0.00125%/1h equals the same neutral 0.01%/8h average as CEX venues, and live mode is supported. Withdrawals: a single flat ~1 USDC route to Arbitrum One / 22+ CCTP chains (USDC only — no USDT route; deposits are free). Typical BTC perp spread is 0.8 bps (bundled baseline; live mode walks the `hyperliquid` book). No KYC, no fiat rails, no referral link. Compliance: US front-end geo-blocked (ToS restricted list); accessible from `CN`, `HK`, `SG`, `JP`, `TH`.
- **BingX spot + futures — VIP Club ladders with a volume-only Elite rung (v0.21):** per-product 8-rung ladders (Regular → Elite → VIP1–5 → Supreme) on 30-day volume thresholds that differ between spot and futures. Futures run 0.020%/0.050% at Regular, 0.018%/0.045% at the **Elite** rung ($5M, inserted 2026-06-26), down to 0%/0.025% at Supreme ($500M); spot runs 0.10%/0.10% at Regular, 0.05%/0.08% at Elite ($0.5M), down to 0.005%/0.02% at Supreme ($15M). Qualification is the *highest* of three tracks — 30-day spot volume, 30-day Standard Contract futures volume, or previous-day **account assets** via `accountAssetsUsd` (futures VIP1 = $50k … VIP5 = $3M; levels refresh daily 03:00 UTC+8). The **Elite and Supreme rungs are volume-only** — assets can lift you to VIP1–VIP5 but never to Elite or Supreme (a $10B account still caps at VIP5). VIP4/VIP5/Supreme additionally require API-traded volume ≤20% of total volume (the engine assumes compliance). The close-only **Standard Futures** copy-trading product (flat 0.045%) is not modeled — ladders quote the Standard Contract order-book book. No native token (so `useToken` never applies), no referral link, no direct fiat rails (P2P/third-party gateways only). Funding settles every 8h at the standard 0.01% neutral average (live mode supported via the `bingx` ccxt class); bundled typical BTC spread is 4 bps. Withdrawals cover BTC / ETH / USDT / USDC across TRC-20/ERC-20/BEP20/Arbitrum/Optimism/Base/Polygon/Solana/TON/Aptos and more, with paused routes flagged per chain (e.g. USDC-TRC20, USDT Avalanche-C/opBNB). Every BingX result carries six `exchange_notes` (tracks, volume-only rungs, API-ratio rule, Standard Futures exclusion, no token/referral, source verification). Compliance: blocked for `US`, `CA`, `GB`, `CN`, `HK`, `SG` and — post-MiCA-cliff (v0.41, Austrian FMA application still only "advanced"/unapproved) — venue-blocked across the entire EEA; served in `JP`, `TH`, `AU`, `BR` and other non-EEA countries.
- **BloFin spot + futures — three-track OR 6-tier ladders (v0.37):** BuildLight Future Limited (Cayman/Marshall Islands), derivatives live since Jan 2023, ~$1.2B/24h perp turnover (CoinGecko), Fireblocks custody, ISO 27001, monthly 1:1 proof of reserves; no KYC required (20,000 USDT/day unverified withdrawal cap). Six tiers per product qualify via the *highest* of three tracks — 30-day futures volume, 30-day spot volume, or daily-snapshot **account assets** via `accountAssetsUsd` (levels refresh daily 00:00–12:00 UTC): futures Regular 0.020%/0.060% (<$10M vol and <$50k assets), VIP1 0.006%/0.050% at $10M *or* $50k assets (an unusually cheap asset track), through VIP5 0%/0.035% at $500M/$3M; spot 0.10%/0.10% → VIP1 0.035%/0.06% at $1M/$50k → VIP5 0.01%/0.0325% at $8M/$3M. VIP4/VIP5 also require ≥80% of qualifying volume to be non-API (assumed satisfied, caveat surfaced in notes). The single `monthlyVolumeUsd` is matched to the queried product's own thresholds — cross-product qualification (futures volume lifting the spot tier) is not modeled. No native token (no `useToken`), no operator referral link, no direct fiat rails (Checkout.com/Simplex/Alchemy third-party widgets only). Funding settles every 8h (00/08/16 UTC) at the 0.01% neutral average; bundled typical BTC perp spread is 3 bps. Withdrawals are dynamic network-cost pass-through with no exchange markup: BTC ~0.0002, USDT/USDC TRC-20 flat ~1, ETH ERC-20/L2 (Arbitrum/Optimism ~$0.5–2). Compliance: blocked for `US`, `CA`, `CN`, `SG` and (no MiCA CASP authorization past the 2026-07-01 grandfathering cliff) the EEA — `DE` is explicitly modeled blocked; served in `HK`, `JP`, `TH`, `GB`, `BR` and 150+ other countries.
- **Bitstamp spot + futures — 11-tier volume-only spot ladder + EU-only regulated perps with a venue×country product gate (v0.38):** founded 2011 in Luxembourg (the oldest exchange in the model), acquired by Robinhood in 2025 (~$200m); regulated under the EU MiCA CASP passport (CSSF Luxembourg), US NYDFS BitLicense + 40+ state MTLs, UK FCA, Singapore MAS and Canadian registration — the model's compliance anchor venue. Spot PRO/API fees run a single 30-day-USD-turnover track with no asset or token track: 0.30%/0.40% below $10k → 0.20%/0.30% at $10k → 0.10%/0.20% at $100k → 0.00%/0.03% at ≥$1B (11 rungs); the consumer Basic interface quotes spread-based prices and is not modeled, nor is the promotional first-$1,000 free tier or the FX/stablecoin/USDT half-rate sub-schedule. Regulated USD-margined perpetual futures are a single FLAT tier: **−0.005% maker (a rebate) / 0.015% taker**, peer-to-peer funding every 8h (00:00/08:00/16:00 UTC) with no platform take-rate (bundled average 0.01%). Because the perps are offered **only to EEA-eligible residents**, Bitstamp is modeled with a per-product gate backed (since v0.40) by a **positive region allowlist** — `product_region_gates.bitstamp.futures = ["EEA"]` against the `regions.EEA` membership table (the 30 EEA states: EU27 + Iceland/Liechtenstein/Norway). Venue-level access (spot) is open in `US`, `GB`, `CA`, `JP`, `SG`, `HK`, `TH`, `DE` and the catch-all default, and `CN` is venue-blocked; `futures` is product-blocked for EVERY residency outside the EEA — explicit-key markets (`US/GB/CA/JP/SG/HK/TH`) and unmodeled countries routed via `default` (AU/BR/CH/TR/KR/MX/IN/…) alike (trading tools return `PRODUCT_BLOCKED_IN_COUNTRY`, and `compare_countries` lists it under `unsupported_product`, not `blocked`); every EEA member routes both products. This replaces the v0.38 negative-list default key, which over-opened perps to non-EEA countries lacking an explicit entry. Product gating is deliberately NOT applied to `get_withdrawal_fees`, `get_fiat_cost` or `get_referral_link` — a US user can still use Bitstamp spot, withdrawals and fiat rails. Direct fiat is deep: US ACH free both directions; SEPA EUR deposits free / withdrawals a flat €3; international SWIFT USD/EUR/GBP 0.05% in ($7.5 floor, $300 cap) / 0.1% out ($25 floor); cards ~4% in USD/EUR/GBP. Withdrawals are conservative and ERC-20-heavy: BTC 0.0005 (no Lightning), ETH 0.005 ERC-20 only (no L2), USDT a flat 20 on ERC-20 only (no TRC-20/Solana — the most expensive USDT route in the model; USDT itself is not tradable on-exchange in the EU), USDC 4 ERC-20 (plus Solana/Arbitrum/Polygon/Optimism/Avalanche/Stellar routes not individually modeled). Bundled typical major-pair spot spread is 2 bps, on par with Coinbase Advanced. No native token (no `useToken`), no referral link.
- **Bitvavo spot — nine-rung EUR-volume PRO ladder + venue-level EEA service-area allowlist (v0.42):** founded 2018 in Amsterdam; Bitvavo B.V. is registered with the Netherlands AFM under MiCA as a Crypto-Asset Service provider (#41000010) and passportes across the EEA (~4M+ users, a dominant share of EUR-denominated spot volume). Unlike all prior gates (negative `region_blocked` bans or product-level `product_region_gates`), Bitvavo is modeled with a **venue-level positive service-area gate** — `region_allowed.bitvavo = ["EEA"]` against `regions.EEA` (30 states): ONLY EEA residents can onboard the venue, and every other residency — explicit-key markets and default-key countries alike, including `GB`/`CH` served in reality by separate Bitvavo entities that are deliberately not modeled — is venue-blocked (`COUNTRY_BLOCKED`); a whitelist match also overrides any stale per-country `allowed` entry. Gate precedence per venue: `region_blocked` ban → country `blocked` → `region_allowed` whitelist hit (authorize) → whitelist miss (deny) → per-country `allowed` enum (empty = open); absent country stays false-safe. Fees are the PRO/API order-book schedule on a SINGLE 30-day trailing EUR-volume track (thresholds treated as USD-equivalent): nine rungs 0.15%/0.25% (<€100k) → 0.10%/0.20% → 0.08%/0.16% → 0.06%/0.12% → 0.05%/0.10% → 0.04%/0.08% → 0.04%/0.06% → 0.00%/0.05% → 0.00%/0.02% (≥€25M, majors); no native token, no assets track, and the consumer **Basic** interface (embedded-spread pricing; a 2026 TUM study measured ~0.08 pp hidden markup) is not modeled. Bitvavo is **spot-only** — no perpetuals are offered, so it is absent from every futures stack/funding fetch and appears as `unsupported_product` (not `blocked`) in `compare_countries` for an EEA futures persona; outside the EEA it is `blocked`. EUR books quote in EUR (not USDT) with the tightest typical spread in the model: **1.0 bps full / 0.5 crossing** on majors (Kaiko 2026-05 measured 0.981 bps, the tightest of any European venue; long-tail alts run wider via pair-class multipliers). Fiat: SEPA/SEPA Instant EUR **free on both legs** (iDEAL and Bancontact ride SEPA; cash-out capped at €25,000/day), EU-issued cards ~1% deposit (third-party sources span 0.5–1.5%, modeled midpoint) with **no card cash-out leg**; PayPal (~2%) is noted but unmodeled; no USD/GBP rails. Withdrawals: dynamic network-cost BTC only, modeled at **0.00005 BTC** (no Lightning; an outlier 0.0000063 quote from one aggregator was discarded) — every other asset (USDT/USDC/ETH/…) returns `supported: false` rather than a fabricated fee. Account-fee lookup is supported on spot via the `bitvavo` ccxt class.
- **Finst spot — flat-fee SOR brokerage + venue-level EEA allowlist (v0.43):** founded 2022 in Amsterdam by an ex-DEGIRO team (KvK 85668117); Finst B.V. holds AFM MiCA CASP registration #41000015 (granted 2025-07) with EEA passporting and serves ~30 European countries. Finst is not an order-book venue: a smart-order-routing **brokerage** that aggregates external liquidity (400+ EUR/USDC markets) and publishes one **flat 0.15%** charge on every buy/sell/swap/auto-invest — no maker/taker distinction, no volume ladder, no minimum, and it claims no spread markup. The model therefore carries a **single volume-independent rung** (`tier: "Flat 0.15%"`, maker = taker = 0.15% at every volume; the monotonic-ladder audit passes trivially), with a **1.0 bps full / 0.5 bps crossing** cohort spread proxy (no order-book research exists for a SOR venue). Access uses the same venue-level positive gate as Bitvavo — `region_allowed.finst = ["EEA"]` — so only the 30 EEA states price the venue (the EEA spot stack becomes **9**: bitstamp, bitvavo, bybit, coinbase, finst, gate, hyperliquid, kraken, okx); every other residency, including GB/US/CH/JP/AU/BR, sees it venue-blocked/absent. Finst offers **no derivatives at all** — `futures: []` means no regulatory product gate fires (`isVenueUsableFor` stays true inside the EEA, mirroring Coinbase/Bitvavo semantics) but the venue never enters a futures pricing stack; `compare_countries` lists it as `unsupported_product` for an EEA futures persona and `blocked` outside the EEA. Fiat: a single EUR **SEPA** route (SEPA Instant/iDEAL/Bancontact) **free on both legs**; no card route (an explicit `method: "card"` query returns the venue with `available: false` / empty routes — it stays in the comparison array for EEA countries but can never be `best`), no PayPal, no USD/GBP. Withdrawals: the official schedule is a dynamic network fee at cost **plus a flat €2.50 third-party charge per crypto withdrawal**; `WithdrawalFee` has no surcharge field and the schema is deliberately not extended, so the BTC route is modeled all-in as **0.000085 BTC / ≈$6.57** (≈0.00005 BTC ≈$3.86 typical network component at the $77,298 snapshot + €2.50 ≈$2.72 at 0.92 EUR/USD), with the route `note` disclosing both parts; the other 400+ markets return `supported: false`. Deposits are free; unmodeled product lines (Bundle 0.10%/mo management, staking 25–45% fee share, new-customer €10k/2-week free window) are out of scope. Finst exposes no public trading API and ccxt 4.5.x ships no `finst` class, so `get_account_fee_tier` returns `ACCOUNT_FEES_UNSUPPORTED` (matrix deliberately omits the venue; the missing-spec path resolves unsupported) and there is no referral link.
- **Bitpanda spot — embedded-premium spread brokerage + measured-vs-advertised execution evidence (v0.44):** founded 2014 in Vienna; Bitpanda GmbH holds BaFin MiCA CASP authorization (2025-01-27) passported across the 30 EEA states, plus the Austrian FMA license, and serves Great Britain through the FCA-registered Bitpanda Broker UK Ltd (~7.4M users). The consumer app is NOT an order-book venue: it quotes one all-in price with the fee **embedded as a markup** and no separate commission line. The schema gains a third pricing model — `pricing_model: "spread"` alongside `"order_book"` and `"flat"` — with a **single volume-independent rung at 1.49% maker = taker** for most assets; **pair-level overrides apply 0.99% per side to BTC and the major stablecoin pairs** (BTC/EUR, BTC/GBP, BTC/USDC, BTC/USDT and the stablecoin EUR/GBP crosses) while generic alts keep 1.49%; the official **2.49% band for sub-€100M market-cap assets** and the 1.99% crypto-index band are disclosed in notes (not individually runged), as is the consumer app's 10x margin product (not modeled). Because the markup already IS a spread-crossing cost, `spread_baseline.bitpanda` is pinned to **0 bps full/crossing and `getSpreadEstimate` early-returns 0** — the anti-double-count guard that keeps the 1.49% premium from reappearing as an `annual_spread_cost` line. A new `execution_quality` object on the venue's fee spec carries independent real-money evidence: `advertised_roundtrip_pct: 2.98` vs TUM's measured **6.23%** mean €100 round trip (Oct–Nov 2025, 50 round trips per platform) — **4.25 percentage points hidden** — replicated by the Frankfurt School of Finance in 2026-03 (432 round trips across 9 platforms); the narrative is auto-appended to `exchange_notes`. Access is a venue-level positive gate — `region_allowed.bitpanda = ["EEA","GB"]` — where **GB is modeled as a single-member region key** (`regions.GB = ["GB"]`): the whitelist hit authorizes GB through the existing gate precedence with no gate-code change, while US/CA/CN/CH and every other residency is venue-blocked. The **EEA spot stack becomes 10** (bitstamp, bitpanda, bitvavo, bybit, coinbase, finst, gate, hyperliquid, kraken, okx) and GB is served (unlike Bitvavo/Finst); `futures: []` makes a futures persona see `unsupported_product` in-service and `blocked` outside. The professional **Bitpanda Fusion** exchange (aggregated external liquidity, 0.02–0.25%) is a separate product and deliberately not modeled; tokenized stocks/ETFs/metals are out of scope. Fiat: since 2026 **all consumer-app rails are free** — EUR SEPA/SEPA Instant, Visa/Mastercard **cards (deposit only; the withdraw leg is modeled `null`)**, PayPal, Apple/Google Pay, and GBP FPS + cards; there is no USD rail (a no-country USD query keeps the row with `available: false` / empty routes). Withdrawals pass dynamic network fees through with no markup, modeled only for **BTC 0.00000598 BTC ($0.4622 at the $77,298 snapshot)** and **ETH 0.0006 ETH ($1.5072)** — the JSON deliberately carries no `fee_usd` field so the engine recomputes from `asset_prices_usd`; every other asset returns `supported: false`. There is no referral program and ccxt 4.5.x ships no `bitpanda` class, so `get_account_fee_tier` returns `ACCOUNT_FEES_UNSUPPORTED` (live coverage stays 13 of 17 venues).
- **BISON spot — principal spread brokerage with near-perfect advertised-vs-measured alignment + free on-chain withdrawals (v0.45):** launched 2019 in Stuttgart by Boerse Stuttgart Group (~1M+ active users, 56 cryptocurrencies as of 2026-01); the trading counterparty is **EUWAX AG, which quotes in its own name as principal** — quotes stay valid roughly 10 seconds and there is no order book. Custody sits with Boerse Stuttgart Digital Custody GmbH (formerly blocknox), holder of the **first BaFin MiCA crypto custody/transfer license** (2025-01-17, passported to 29 states); EUWAX AG's crypto exchange service has been MiCA-authorized since 2025-04-01 (8-state passport) with order execution added 2025-11-21 (Germany only). Pricing reuses the spread model — a **single volume-independent rung at 1.75% maker = taker** for all cryptocurrencies except BTC/ETH, with **pair-level overrides at 1.25% per side for BTC/EUR and ETH/EUR** (rates float with market conditions and ticket size); the official spread is the *only* trading cost and there is no separate commission. As with Bitpanda, `spread_baseline.bison` is pinned to **0 bps and `getSpreadEstimate` early-returns 0** so the spread can never be double-counted in `annual_spread_cost`. The `execution_quality` block carries the study's transparency benchmark: `advertised_roundtrip_pct: 2.5` vs TUM measured **2.58%** — just **0.08 percentage points undisclosed** on 50 standardized €100 round trips over 12 trading days (Oct–Nov 2025, six MiCA platforms; BISON included in the six-platform sample), the closest published-vs-measured alignment of the sample (Bitvavo −0.58% next; Bitpanda 6.23%, Coinbase 7.49%). Access uses a venue-level positive gate — `region_allowed.bison = ["EEA","CH"]` — with **CH added as a second single-member region key** (`regions.CH = ["CH"]`): all 30 EEA states and Switzerland price the venue (DE/AT/CH actively marketed; other EEA states passively served under treaty freedoms), while **GB is venue-blocked** — deliberately complementary to Bitpanda (EEA+GB) — together with US/CA/JP/SG/AU/BR/CN/KR; the **EEA spot stack becomes 11**, the **CH stack 15**, and GB/US/JP results never contain BISON. `futures: []` (no exchange-hosted futures or margin is offered) → `unsupported_product` in-service, `blocked` outside. Fiat is **EUR only**: **SEPA/SEPA Instant free on both legs including Swiss users funding in EUR** (modeled as region-less routes gated by the venue allowlist, since Switzerland belongs to SEPA but not the EU region table), plus **2.49% instant card/Apple Pay/Google Pay deposits** (Solaris SE/Deutsche Bank partner fee; the withdraw leg is `null` — no card cash-out); there is no GBP/USD/CHF rail (a no-country USD query keeps the row with `available: false`). Withdrawals are **officially free with no network-fee line** — on-chain costs are absorbed by EUWAX/the group (a structurally different policy from Bitpanda's pass-through) — modeled only for **BTC 0 BTC / $0** (min 0.001; no Lightning, no Taproot bc1p payouts) and **ETH 0 ETH / $0** (Ethereum **mainnet only**, min 0.01; no Arbitrum/Base/Optimism/Polygon/BNB Chain L2), which makes BISON the global `best` for both assets; every other asset returns `supported: false`, and withdrawal comparison is deliberately not country-gated. The €1.99 German stocks/ETFs flat order (Germany only) and the 27% staking reward commission (ETH/SOL) are out of scope. The invite-a-friend program (DE/AT/CH ETH rewards) has no affiliate URL and ccxt 4.5.78 ships no `bison`/`euwax` class, so `getReferralLink` returns `NO_REFERRAL_LINK` and `get_account_fee_tier` returns `ACCOUNT_FEES_UNSUPPORTED` (live coverage stays 13 of 18 venues).
- **`accountAssetsUsd` (optional, OKX / Bybit / Bitget / Kraken / BingX / BloFin)** — total account assets in USD. VIP level is the *higher* of your 30-day volume rung and your asset rung, for both spot and futures (e.g. OKX VIP1 = $100k … VIP9 = $500M with negative maker rebates; Bybit VIP4 = $1M; Bitget VIP1 = $30k; Kraken Tier 3 = $20k AOP … Pro 5 = $100M; BingX VIP1 = $50k … VIP5 = $3M; BloFin VIP1 = $50k … VIP5 = $3M on either product's own thresholds). Assets can only upgrade, never downgrade; volume-only rows (e.g. Bybit Supreme, Kraken Tier 1–2, BingX Elite and Supreme) do not qualify via assets; BloFin VIP4/VIP5 additionally require ≥80% non-API volume (the engine assumes compliance, caveat in `exchange_notes`). Omitting the parameter quotes the volume tier and returns an asset-path upgrade hint (`next_min_assets`).
- **`pair` (optional, v0.12)** — a trading pair such as `BTC/USDT`, `BTC/FDUSD` or `BTCUSDT` (separators are normalized). When the pair has a known fee promo, the promo rates replace the account-tier rates and results carry `pricing_basis: "pair"` plus a `pair_note`; otherwise pricing stays `account_tier`. Verified pair promos: **MEXC** — all spot pairs 0% maker + 0% taker (0-fee program), 100+ futures pairs at 0/0 subject to per-account quotas; **Binance** — FDUSD pairs (BTC/ETH/BNB/DOGE/LINK/SOL/XRP) at 0% maker with tier-based taker, USDC pairs at 0% maker / 0.095% taker; **Bitget** — USDC/USDT and USDGO/USDT at 0/0 (volume does not count toward VIP); **Bitpanda (v0.44)** — the 0.99%/side embedded-premium band on BTC and major stablecoin pairs vs the 1.49% headline (a spread-broker pricing band, not a promo; non-promo flag); **Bison (v0.45)** — the 1.25%/side band on BTC/EUR and ETH/EUR vs the 1.75% headline (same non-promo spread-band pattern). A pair override can cover maker only, taker only, or both.
- **`makerShare` (0-1, default 0)** — fraction of volume executed as maker (limit orders). Weighted rate = `maker × share + taker × (1-share)`. Limit-order traders should pass 0.7-1.
- **`useToken`** — prices in native-token discounts: BNB (25% spot / 10% futures), GT (futures maker → 0 plus 10-50% holding-tier discount with `tokenBalance`), MX (20% spot + futures; 500+ MX lifts the discount to 50% — the greater applies, they do not stack), BGB (20% spot + futures), KCS (20% spot Class A/B/C + futures; at VIP8+ maker is already 0% so only the taker side benefits), OKB (baked into OKX tiers), and **staked HYPE** on Hyperliquid (10/100/1k/10k/100k/500k staked → 5/10/15/20/30/40% off all maker+taker fees, stacking multiplicatively with the volume tier; `tokenBalance` must be the staked amount — holding alone gives nothing).
- **Negative maker rates** — OKX VIP7+ makers are negative (spot/futures, down to -0.0075%) and Kraken futures makers are negative from Tier 11 (down to -0.006% at Pro 5), i.e. exchange-paid maker rebates. They pass through referral/token discounts unchanged (a discount cannot shrink a rebate), surface as negative fee estimates, and rank ahead of paid fees.
- **`holdingHours`** (futures) — monthly position exposure in hours; funding cost at each exchange's funding rate (8h interval for most venues; Hyperliquid settles **hourly** — its bundled 0.00125%/1h equals the neutral 0.01%/8h CEX average). `calculate_annual_cost` annualizes it ×12. Every funding figure carries **`funding_source`** (`bundled` or `live`) plus `funding_rate_ts` / `funding_pair` when live data was used.
- **`fundingMode` + `fundingPair` (optional, v0.15)** — funding inputs for `calculate_savings`, `compare_total_cost`, `recommend_exchange` and `calculate_annual_cost`. `fundingMode: "bundled"` (default) uses the offline long-run average (0.01%/8h for BTC/USDT — instant and deterministic). `fundingMode: "live"` fetches the venue's **current** funding rate in real time via ccxt for `fundingPair` (default `BTC/USDT`; accepts `ETH/USDT`, `SOL-USDT`, `BTCUSD` …). Each exchange is fetched independently with an 8s timeout; any venue that fails (timeout, geo-block, missing pair) transparently falls back to its bundled average and is listed in `failures` for the dedicated tool. Results are TTL-cached in memory for 5 minutes (funding only settles every few hours). Negative live rates pass through untouched — longs then get *paid*. The standalone **`get_funding_rates`** tool accepts `fundingMode`, `fundingPair`, optional `exchanges: [...]`, and optional `country` filtering.
- **`tradeSizeUsd` + `spreadMode` + `spreadPair` + `side` (v0.16)** — execution-cost inputs for `calculate_savings`, `compare_total_cost`, `recommend_exchange` and `calculate_annual_cost`. When `tradeSizeUsd` (a single marketable order size, e.g. `10000`) is passed, every cost result adds the **one-way bid-ask crossing cost** (half the typical full spread) for that order, tagged with `spread_source`. `spreadMode: "bundled"` (default) prices it from offline venue baselines scaled by pair class — majors (BTC/ETH) ×1.0, large caps (SOL/XRP/DOGE … 27 names) ×1.5, other alts ×3 — with zero modeled slippage. `spreadMode: "live"` fetches each venue's real **top-100 order book** via ccxt, resolves the correct spot or linear-swap market automatically (KuCoin spot uses the `kucoin` class, not `kucoinfutures`), and **VWAP-walks the depth** for `side: "buy" | "sell"` to measure size-conditional slippage beyond the best touch, plus `levels_consumed`, `available_depth_usd` and `fully_filled`. Per-venue failures (timeout, geo-block, missing market) fall back to the bundled baseline and are listed in `failures`; when visible depth is smaller than the order the measured value is kept with a `warnings` entry (impact beyond depth is not extrapolated). Book walks are TTL-cached for 30 seconds. `compare_total_cost` folds spread + slippage into `total_cost`; `calculate_annual_cost` scales them with annual traded notional (monthly ×12, assuming flow sliced into `tradeSizeUsd`-sized orders); `recommend_exchange` blends execution into the score (fee 70% / funding 15% / spread 15% when both apply). The standalone **`get_execution_cost`** tool accepts `tradeSizeUsd` (default $10,000), `pair`, `purpose`, `side`, `spreadMode`, optional `exchanges: [...]` and `country`.
- **Fiat on/off-ramp inputs (v0.17, `get_fiat_cost`)** — `direction: "deposit" | "withdraw"` (default deposit), `amount` in fiat or `amountUsd` (converted at the static display rate), `currency: "USD" | "EUR" | "GBP" | "BRL"` (default USD), `country` ISO residency (drives compliance filtering *and* regional-rail availability — e.g. Bybit's 1.1% EU-issued card vs 3.05% elsewhere, ACH US-only), optional `method: "card" | "ach" | "sepa" | "fps" | "wire" | "swift" | "pix"` filter, and optional `exchanges: [...]`. Only **exchange-operated direct rails** are modeled — third-party card gateways (Banxa/Simplex/MoonPay/Zen, typically 1.99–5.5% at checkout), P2P and bank-side charges are excluded by design (they vary per user and are called out in `advice`/`notes`). Fees support percent + fixed with min/max floors (e.g. Bybit SEPA 0.19% min €1, Binance SWIFT fixed 5 capped at 25). Results return per-rail fee, USD-equivalent, effective %, net amount, ETA, per-venue cheapest rail, an overall `best`, `saving_vs_worst_usd`, and warnings (venues with no qualifying rail, missing country for region-locked rails). Cards run 1.1–4.5% across venues while ACH/SEPA/FPS/PIX bank rails are free or near-free almost everywhere.
- **Fiat legs in the all-in cost tools (v0.26)** — `compare_total_cost` and `calculate_annual_cost` now accept `fiatCurrency`, `fiatDepositAmountUsd` + `fiatDepositsPerYear`, `fiatCashoutAmountUsd` + `fiatCashoutsPerYear`, and optional `fiatMethod`, and fold the cheapest direct rail fee × yearly count into the total as `fiat_deposit_cost` / `fiat_cashout_cost` (annual tools: `annual_fiat_deposit_cost` / `annual_fiat_cashout_cost`). This prices the FULL stack a retail trader actually pays — trading fees + funding + spread/slippage + on-chain withdrawals + bank/card deposits and cash-outs — in a single call. A free-but-real rail returns cost `0` with `fiat_deposit_available: true`; a venue with no direct rail (e.g. Hyperliquid/BingX/Phemex/BloFin) returns the leg excluded (`0`) with `fiat_deposit_available: false`, never silently treated as free. When no fiat habit is passed the keys are omitted and behavior is unchanged.
- **Fiat-aware recommendation (v0.27)** — `recommend_exchange` takes the same six fiat habit params and joins annualized direct-rail costs to the score. The fiat weight is **data-driven by cost dispersion**: `fiatWeight = 0.2 + 0.3 × dispFiat / (dispFee + dispFiat)` where dispersions are the annualized venue-to-venue cost ranges, so it rises from 0.2 to 0.5 exactly when fiat-fee differences dwarf trading-fee differences (small monthly on-rampers) and stays at 0.2 for high-volume traders; the remaining weight re-splits over fee/funding/spread. A rail-less venue scores **zero** on that direction (free-but-real rails score 100) and receives an explicit tradeoff naming the real third-party/P2P path (typically 1.99–5.5%); the advice also names the cheapest-fiat venue and yearly delta when the winner charges more for the exact same habit. Without the params, scoring is byte-identical to the pre-v0.27 weight table. Example flip (v0.41 EEA): DE spot $500/mo + 12×€1,000 SEPA — without the habit rail-less Hyperliquid wins 100 on fees among EEA-usable venues; with the habit OKX (free SEPA both legs) wins 92.2 vs Hyperliquid 62.7 (Binance/MEXC are no longer EEA-usable).
- **`withdrawalAsset` + `withdrawalNetwork` (v0.18 network coverage)** — adds network withdrawal fees. The bundled table covers **16 assets** (BTC, ETH, SOL, XRP, DOGE, LTC, TRX, ADA, AVAX, DOT, LINK, BCH, TON, POL, USDT, USDC) across TRC-20, ERC-20, BEP20, Arbitrum, Optimism, Base, Polygon, Avalanche C, Solana, TON, Polkadot/AssetHub and each asset's native chain at all 18 venues (route availability varies per venue; Coinbase, BingX, BloFin and Bitstamp cover BTC / ETH / USDT / USDC only; Bitvavo (v0.42) models dynamic BTC only at 0.00005, flagging every other asset unsupported; Finst (v0.43) models BTC only at 0.000085 all-in (dynamic network fee + €2.50 flat third-party charge folded together, disclosed per route note), every other asset unsupported; Bitpanda (v0.44) models dynamic pass-through BTC 0.00000598 ($0.4622) and ETH 0.0006 ($1.5072) only (no `fee_usd` stored — recomputed from the price snapshot), every other asset unsupported; Bison (v0.45) models **BTC and ETH with fee 0 — the group absorbs on-chain network costs, making it the global `best` for both assets** (BTC mainnet min 0.001; ETH mainnet only, min 0.01, no L2s), every other asset unsupported; Hyperliquid lists a single flat ~1 USDC route to Arbitrum / 22+ CCTP chains; BloFin quotes dynamic network-cost pass-through with TRC-20 stablecoins at ~1). Native-unit fees are converted to USD from a 2026-09-12 price snapshot (`asset_prices_usd`); routes paused in Aug–Sep 2026 (e.g. TON wallets at five venues, USDC-TRC20 at Gate/KuCoin/BingX, DOT relay chain) carry `suspended: true` and are never treated as open. When no network is passed the venue's cheapest *open* route is priced automatically; network input accepts aliases (`trc20`, `erc20`, `arb`, `matic`, `sol` …). `calculate_annual_cost` multiplies the per-event fee by `withdrawalsPerYear`. The standalone **`get_withdrawal_fees(asset?, network?, country?, exchanges?)`** tool (fully offline) returns the full per-route comparison with `best`, `saving_vs_worst_usd` and warnings; error codes: `INVALID_ASSET`, `INVALID_NETWORK`, `UNKNOWN_EXCHANGE`.
- **Trader-persona presets (v0.22, `analyze_persona`)** — seven research-anchored archetypes in [`data/personas.json`](data/personas.json) bundle a complete behavioral profile: market (spot/futures), monthly volume, maker share, monthly holding hours, typical clip size (`tradeSizeUsd`), withdrawal asset + yearly count, and yearly fiat deposits/cashouts (currency + rail habit). The personas are **casual_buyer** (small card-funded buyer — card fees dominate), **hodler_accumulator** (monthly DCA + BTC withdrawals to cold storage), **active_spot_trader**, **swing_futures_trader** (funding is the biggest line), **day_scalper** (high-volume, 90% maker), **vip_institutional** ($30M/mo, $3M assets, $100k clips → live spread advised), and **dex_native** (on-chain USDC flows, no KYC/fiat needs — missing rails are flagged, not zeroed). Each persona runs the same annualized stack the other tools price individually — trading fees + funding + execution + per-event withdrawals + fiat — returns the per-venue `cost_mix_pct`, `component_leaders`, a headline `best` plus a separate **`best_complete`**: the cheapest venue where *every* persona leg is actually priced (e.g. Hyperliquid can headline for a futures persona but lack fiat rails or a USDT/BTC route — it is flagged with `withdrawal_unsupported`/fiat-availability and the realistic all-legs pick is shown with its extra cost). Every preset is a default overridable via `monthlyVolumeUsd`, `makerShare`, `useToken`, `tokenBalance`, `accountAssetsUsd`, `holdingHours`, `tradeSizeUsd`, `pair`, `currency`, plus `fundingMode`/`fundingPair` and `spreadMode`/`spreadPair` live overrides; personas are validated to a schema and versioned like every other data file.
- **`currency`** — display currency `USD` (default), `EUR`, `JPY`, `CNH`, `GBP`. Static display rates only; all math stays USD-based.
- **`language` (v0.30, extended in v0.31/v0.36)** — output language for the narrative layer on `compare_exchange_fees`, `compare_total_cost`, `calculate_savings`, `calculate_annual_cost`, `get_fiat_cost`, `get_withdrawal_fees`, `recommend_exchange`, `analyze_persona`, `compare_personas`, `analyze_token_discount`, `volume_what_if` and `compare_countries`: `"en"` (default) or `"zh"`. All advice / warnings / tradeoffs / reasons / tier warnings are rendered from a centralized bilingual template catalog ([`src/i18n.ts`](src/i18n.ts)); English output is byte-identical to pre-v0.30, and numbers, field names, error codes and machine-oriented notes stay language-independent, so switching language never changes the data schema.
- **`format` / `tableMetric` (v0.36, the three matrix tools only)** — `compare_personas`, `volume_what_if` and `compare_countries` accept `format: "json"` (default) | `"markdown"` | `"csv"` | `"both"`. With any non-JSON format the result gains a `rendered: { metric, markdown?, csv? }` object: a titled, paste-ready table in English or Chinese according to `language`; persona matrix = venues × personas with annual all-in cost (rail-missing cells carry a ` †` marker in markdown only, CSV stays numeric); what-if = monthly-volume rows × venues with `tableMetric: "weighted_fee_pct"` (4-dp, default) | `"annual_fee_usd"` | `"tier"`; countries = venues × countries with `tableMetric: "availability"` (`✓`/`⛔`/`–`, default; CSV uses the raw `available`/`blocked`/`unsupported_product` tokens) | `"cost"`. CSV is RFC 4180 (fields with commas/quotes/newlines are quoted, `"` doubled, CRLF line endings); markdown volumes are compact (`$100K`/`$3.5M`) while CSV keeps raw numbers. Invalid values return `INVALID_INPUT`; the JSON payload itself is unchanged in every format.
- Every fee result carries a **`data_as_of`** freshness stamp, a **`tier_warning`** for the BNB AND gate and the GT/KCS/account-asset/AOP OR upgrade paths, and a **`freshness_warning`** once bundled data is more than 3 months past `last_verified`. Kraken results additionally carry **`exchange_notes`** — exchange-specific qualification caveats (unified-tier tracks, regional futures limitations, Pro vs consumer-app pricing).
## Install
### Use in Claude Desktop / Cursor / any MCP client
Add to your client's MCP config (e.g. `claude_desktop_config.json`):
```json
{
"mcpServers": {
"fee-optimizer-mcp": {
"command": "npx",
"args": ["-y", "fee-optimizer-mcp"]
}
}
}
```
### Run locally from source
```bash
git clone https://github.com/gaokai258/fee-optimizer-mcp.git
cd fee-optimizer-mcp
npm install
npm run build
npm start # starts stdio server (default)
```
### Streamable HTTP transport (v0.29)
Besides stdio, the server runs as a **stateless Streamable HTTP** MCP endpoint (MCP 2025-03-26 spec) — one isolated MCP server is created per POST, so requests are concurrency-safe and horizontally scalable without sticky sessions; responses are plain `application/json`, no `Mcp-Session-Id` is issued, and SSE `GET`/`DELETE` return 405 by design.
```bash
# CLI flags
node dist/index.js --transport http --host 0.0.0.0 --port 3333 --endpoint /mcp
# or
npm run start:http
# env overrides: FEE_MCP_TRANSPORT=http, FEE_MCP_HTTP_HOST, FEE_MCP_HTTP_PORT,
# FEE_MCP_HTTP_ENDPOINT (HOST/PORT also accepted)
node dist/index.js --help # all flags
```
- **`POST /mcp`** — JSON-RPC (single message or batch); requires `Accept: application/json, text/event-stream` and `Content-Type: application/json`. Because the service is fully stateless, a handshake-free bare `tools/call` POST works, and strict clients may also send `initialize` in its own POST first.
- **`GET /health`** — load-balancer probe: `{ status, service, version, transport, mode, endpoint, auth_required, rate_limit_per_min, uptime_s }` (no auth needed even when bearer auth is enabled).
- Unknown paths → `404`; non-POST on `/mcp` → `405` with `Allow: POST`; bad `Accept` → `406`.
#### Public hosting hardening (v0.32)
All protections are **opt-in via environment variables** — local/dev behavior is unchanged. Put a TLS-terminating reverse proxy (nginx/Caddy/Cloudflare) in front when binding `0.0.0.0`.
| Env var | Effect |
|---|---|
| `FEE_MCP_BEARER_TOKEN=<secret>` | Every MCP POST must send `Authorization: Bearer <secret>` (constant-time comparison). Missing/wrong → `401` + `WWW-Authenticate` (JSON-RPC code `-32002`). `/health` stays open for probes. |
| `FEE_MCP_RATE_LIMIT_PER_MIN=<n>` | Fixed-window per-client-IP cap on MCP POSTs; excess → `429` + `Retry-After` (`-32001`). Unauthenticated attempts count too, so token-less floods cannot bypass it. `0`/unset = unlimited. |
| `FEE_MCP_ACCESS_LOG=1` | One structured JSON line per request on stdout: `ts, ip, method, path, status, duration_ms, auth (none/ok/fail), rate_limited, user_agent`. |
| `FEE_MCP_TRUST_PROXY=0` | Ignore `X-Forwarded-For` (set this only when NOT behind a reverse proxy; default trusts the first XFF hop). |
Remote MCP client config (HTTP with bearer token):
```json
{
"mcpServers": {
"fee-optimizer-mcp": {
"type": "http",
"url": "https://your-host/mcp",
"headers": { "Authorization": "Bearer <secret>" }
}
}
}
```
#### Docker
```bash
docker build -t fee-optimizer-mcp . # or: npm run docker:build
docker run -d --name fee-mcp -p 3333:3333 \
-e FEE_MCP_BEARER_TOKEN=$(openssl rand -hex 32) \
-e FEE_MCP_RATE_LIMIT_PER_MIN=120 \
-e FEE_MCP_ACCESS_LOG=1 \
fee-optimizer-mcp # or: npm run docker:run
curl -s http://localhost:3333/health
```
The multi-stage image runs on `node:22-alpine` as a non-root user, ships production dependencies + `dist/` + `data/` only, and includes a `/health` `HEALTHCHECK`.
### Inspect with MCP Inspector
```bash
npm run inspector # stdio
npx @modelcontextprotocol/inspector --transport http http://127.0.0.1:3333/mcp # HTTP
```
## Tool reference
- **`compare_exchange_fees(purpose, country, monthlyVolumeUsd?, useToken?, makerShare?, tokenBalance?, accountAssetsUsd?, pair?)`** — Fee table comparison sorted by weighted effective rate.
- **`get_referral_link(exchange, country)`** — Resolves a referral URL; errors with `COUNTRY_BLOCKED` / `UNKNOWN_EXCHANGE` / `NO_REFERRAL_LINK` when applicable.
- **`calculate_savings(exchange, volume, type, country, useToken?, holdingHours?, makerShare?, currency?, tokenBalance?, accountAssetsUsd?, pair?, fundingMode?, fundingPair?, tradeSizeUsd?, spreadMode?, spreadPair?, side?)`** — Savings breakdown vs. the base tier rate; with `tradeSizeUsd` also returns `spread_cost` / `slippage_cost` / `spread_source` / `spread_ts` / `spread_pair`.
- **`compare_total_cost(purpose, country, volume, holdingHours?, useToken?, withdrawalAsset?, withdrawalNetwork?, makerShare?, currency?, tokenBalance?, accountAssetsUsd?, pair?, fundingMode?, fundingPair?, tradeSizeUsd?, spreadMode?, spreadPair?, side?, fiatCurrency?, fiatDepositAmountUsd?, fiatDepositsPerYear?, fiatCashoutAmountUsd?, fiatCashoutsPerYear?, fiatMethod?)`** — All-in cost ranking; with `tradeSizeUsd`, spread + slippage are folded into `total_cost`; with the v0.26 fiat habit params, annualized direct-rail deposit/cash-out fees are folded in too (venues without a rail flagged, leg excluded).
- **`recommend_exchange(purpose, country, volume, makerShare?, useToken?, holdingHours?, currency?, tokenBalance?, accountAssetsUsd?, pair?, fundingMode?, fundingPair?, tradeSizeUsd?, spreadMode?, spreadPair?, side?, fiatCurrency?, fiatDepositAmountUsd?, fiatDepositsPerYear?, fiatCashoutAmountUsd?, fiatCashoutsPerYear?, fiatMethod?)`** — Best exchange with score (fee/funding/spread blend when execution is priced), reasons, tier holding warnings, tradeoffs, actionable advice, and alternatives. **v0.27:** when the fiat habit is passed, annualized direct-rail deposit/cash-out costs join the score with a **dispersion-driven fiat weight (0.2→0.5)** — the more venue-to-venue fiat-fee differences dominate the year's trading-fee differences (typical for small monthly on-rampers), the more fiat decides; a venue with no direct rail scores zero on that leg and gets an explicit tradeoff instead of winning on an unpriced cost. Example: a German €1,000/month SEPA DCA buyer trading just $500/mo is recommended Binance (free SEPA) over the nominally fee-cheaper MEXC (~$16/yr SEPA fees), while a $100k/mo trader is still ranked on trading fees.
- **`calculate_annual_cost(exchange, purpose, country, monthlyVolumeUsd, makerShare?, useToken?, tokenBalance?, accountAssetsUsd?, holdingHours?, withdrawalAsset?, withdrawalNetwork?, withdrawalsPerYear?, currency?, pair?, fundingMode?, fundingPair?, tradeSizeUsd?, spreadMode?, spreadPair?, side?, fiatCurrency?, fiatDepositAmountUsd?, fiatDepositsPerYear?, fiatCashoutAmountUsd?, fiatCashoutsPerYear?, fiatMethod?)`** — Annualized trading fees (monthly ×12) + funding (monthly exposure ×12) + spread/slippage (annual traded notional × bps, when `tradeSizeUsd` is given) + withdrawals (per-event × yearly count) + v0.26 direct fiat deposits/cash-outs (cheapest rail × yearly count, leg flagged-and-excluded when the venue has no rail), plus an `upgrade` block: the next VIP tier, how to qualify (volume / OKX-Bybit-Bitget account assets / Kraken AOP / Gate GT / KuCoin KCS / Binance BNB), and estimated annual saving.
- **`get_data_sources()`** — Provenance report; no parameters. Returns all 15 bundle files with `last_verified`, full source list (official URLs and/or methodology notes), and **v0.33 per-file freshness**: each file carries `months_behind` and `is_stale` (older than 3 months or unparseable), plus report-level `stale_after_months` and `stale_files: [...]` so an agent can immediately see which bundle needs re-verification; `data_as_of` remains the oldest stamp across files.
- **`get_funding_rates(fundingMode?, fundingPair?, exchanges?, country?)`** — Funding-rate table for a perpetual pair. Bundled mode is offline; live mode fetches real-time rates venue-by-venue and returns `{ pair, mode, fetched_at, data_as_of, rates: [{ exchange, rate_pct, interval_hours, source, funding_timestamp?, note? }], failures: [{ exchange, error, fallback: "bundled" }] }`. The four cost tools additionally accept `fundingMode?` and `fundingPair?`.
- **`get_fiat_cost(direction?, amount? | amountUsd?, currency?, country?, method?, exchanges?)`** — Direct fiat on/off-ramp cost table; fully offline. Returns `{ direction, currency, amount, amount_usd, fx_rate, fetched_at, data_as_of, exchanges: [{ exchange, available, routes: [{ method, region?, fee, fee_usd, effective_pct, net, eta, note? }], cheapest_method?, cheapest_fee_usd?, notes? }], best: { exchange, method, fee, fee_usd, effective_pct, net } | null, saving_vs_worst_usd?, advice, warnings? }`. Error codes: `INVALID_CURRENCY`, `INVALID_AMOUNT`, `MISSING_FX_RATE`, `UNKNOWN_EXCHANGE`.
- **`get_execution_cost(tradeSizeUsd?, pair?, purpose?, side?, spreadMode?, exchanges?, country?)`** — One-way taker execution-cost table. Bundled mode is offline; live mode VWAP-walks each venue's real top-100 book and returns `{ pair, purpose, side, trade_size_usd, mode, fetched_at, data_as_of, costs: [{ exchange, spread_bps, crossing_bps, slippage_bps, total_bps, cost_usd, levels_consumed?, fully_filled?, available_depth_usd?, source, book_timestamp?, symbol?, pair_class, note? }], failures: [{ exchange, error, fallback: "bundled" }], warnings?: [{ exchange, message }] }`. The four cost tools additionally accept `tradeSizeUsd?`, `spreadMode?`, `spreadPair?`, `side?`.
- **`get_withdrawal_fees(asset?, network?, country?, exchanges?)`** — On-chain withdrawal-fee comparison; fully offline. `asset` defaults to `USDT`; `network` accepts canonical names and aliases (`trc20`, `erc20`, `bsc`, `arb`, `op`, `matic`, `c-chain`, `sol`, `assethub` …); without a network every route per venue is returned and ranked by the cheapest open one. Returns `{ asset, network?, asset_price_usd?, fetched_at, data_as_of, exchanges: [{ exchange, supported, networks: [{ network, fee, fee_usd, available, note? }], cheapest_network?, cheapest_fee_usd? }], best: { exchange, network, fee, fee_usd } | null, saving_vs_worst_usd?, advice, warnings? }`. Suspended routes stay in `networks` with `available: false`; venues with no route for the asset/network return `supported: false` and an empty `networks` list. Error codes: `INVALID_ASSET`, `INVALID_NETWORK`, `UNKNOWN_EXCHANGE`.
- **`analyze_persona(persona, country, monthlyVolumeUsd?, makerShare?, useToken?, tokenBalance?, accountAssetsUsd?, holdingHours?, tradeSizeUsd?, pair?, currency?, fundingMode?, fundingPair?, spreadMode?, spreadPair?, side?)`** — Annual all-in analysis for one of seven research-anchored trader personas. Fully offline in default mode. Returns `{ persona, country, purpose, inputs, currency, ranking: [{ exchange, tier, annual_trading_fee, annual_funding_cost, annual_execution_cost, annual_withdrawal_cost, annual_fiat_deposit_cost?, annual_fiat_cashout_cost?, annual_all_in, cost_mix_pct, withdrawal_unsupported?, fiat_deposit_available?, fiat_cashout_available?, pricing_basis, tier_warning?, referral_url?, exchange_notes? }], best: { exchange, annual_all_in, runner_up_exchange, saving_vs_runner_up, reasons, tradeoffs } | null, best_complete: { exchange, annual_all_in, extra_vs_winner } | null, component_leaders, warnings, advice, data_as_of, data_sources }`. Missing rails/routes are flagged and EXCLUDED from the row (never counted as $0); `INVALID_INPUT` for an unknown persona id (the valid id list is returned).
- **`analyze_token_discount(exchange, purpose, country, monthlyVolumeUsd, makerShare?, tokenBalance?, accountAssetsUsd?, tokenPriceUsd?, currency?)`** — Native-token fee-discount payback analysis; fully offline. Computes the annual fee WITHOUT the native token (zero-balance tier, no fee-deduction toggle) vs. WITH it (BNB/MX/BGB/KCS flat deduction, GT/MX/HYPE holding-tier ladder, Gate futures maker-to-zero, GT/KCS/BNB tier lift from holdings), the annual USD saving, the USD opportunity cost of locking the required token balance, payback in months, and the max one-year token price drop the saving can absorb (`breakeven_price_drop_pct`). When `tokenBalance` is omitted it returns `tiers_analysis` (every achievable discount level ranked) with a `recommended_tier_index` (shortest payback among positive-saving tiers). Venues with no separate toggle (OKX, Kraken, Coinbase, Bybit, BingX) report `has_native_discount: false` honestly rather than inventing a discount. Token price comes from `data/token_prices.json` (2026-09 snapshot) or the `tokenPriceUsd` override. Error codes: `UNKNOWN_EXCHANGE`, `COUNTRY_BLOCKED`, `INVALID_INPUT`, `NO_RESULTS`.
- **`compare_personas(country, personas?, useToken?, currency?, fundingMode?, fundingPair?, spreadMode?, spreadPair?, side?, language?, format?)`** (v0.28, `format` in v0.36) — Multi-persona decision matrix in one call; fully offline in default mode. Runs every persona (or the `personas: [...]` subset, order-preserving, deduped) through the same engine as `analyze_persona` and returns `{ country, currency, personas: [{ persona: {id, name_en, name_zh, tagline_zh}, purpose, monthly_volume_usd, best: { exchange, tier, annual_all_in, runner_up_exchange, saving_vs_runner_up, cost_mix_pct, tradeoffs } | null, best_complete: { exchange, annual_all_in, extra_vs_winner } | null, matrix: [{ exchange, annual_all_in, withdrawal_unsupported?, fiat_deposit_available?, fiat_cashout_available? }] }], venues, venue_wins: [{ exchange, headline_persona_ids, complete_persona_ids }], most_versatile, rendered?: { metric, markdown?, csv? }, data_as_of, data_sources, errors? }`. The matrix is cheapest-first per persona; a venue absent from a row is blocked in-country or spot-only. `venue_wins` is sorted by realistic (`best_complete`) wins then headline wins; `most_versatile` is the venue with the most all-legs wins. Live depth is resolved per persona (purpose + clip dependent). Error codes: `INVALID_INPUT` (unknown persona id / bad format), `NO_RESULTS`.
- **`volume_what_if(purpose, country, volumes?, baseVolume?, makerShare?, useToken?, tokenBalance?, accountAssetsUsd?, pair?, currency?, language?, format?, tableMetric?)`** (v0.34, `format`/`tableMetric` in v0.36) — Volume what-if sweep; fully offline. Returns `{ purpose, country, currency, maker_share, use_token, base_monthly_volume_usd?, volumes, data_as_of, points: [{ monthly_volume_usd, annual_traded_notional_usd, cheapest: { exchange, tier, weighted_fee_pct, annual_fee_usd }, ranking: [{ exchange, tier, volume_tier?, weighted_fee_pct, annual_fee_usd, tier_crossed? }] }], tier_crossings: [{ at_monthly_volume_usd, exchange, from_tier, to_tier }], exchanges: [{ exchange, current: { monthly_volume_usd, tier, weighted_fee_pct, annual_fee_usd } | null, next_tier?: { from_tier, to_tier, at_monthly_volume_usd, additional_monthly_volume_usd, weighted_fee_pct_now, weighted_fee_pct_next, saving_per_year_usd_at_current_volume, blocked_by_holding_gate? } | null, sweep: [{ monthly_volume_usd, tier, volume_tier?, effective_maker_pct, effective_taker_pct, weighted_fee_pct, annual_fee_usd, tier_crossed? }] }], advice, warnings?, rendered?: { metric, markdown?, csv? } }`. Default `volumes` = the sorted deduped union of every allowed venue's VIP tier thresholds plus `0` and `baseVolume`; unions over 16 points are stride-sampled across the full range (with a warning, always keeping 0/base/max) and explicit `volumes` allow up to 24 custom points. `next_tier` is present only when `baseVolume` is given (null = already at the venue's top volume rung); referral and optional platform-token discounts apply exactly as in `compare_exchange_fees`. Trading fees only — funding/spread/withdrawals/fiat are not included. `tableMetric` (with non-json `format`): `weighted_fee_pct` (default) | `annual_fee_usd` | `tier`. Error codes: `BAD_VOLUME`, `UNKNOWN_CURRENCY`, `INVALID_INPUT` (bad format/tableMetric), `NO_RESULTS`.
- **`compare_countries(persona?, countries?, monthlyVolumeUsd?, makerShare?, useToken?, tokenBalance?, accountAssetsUsd?, holdingHours?, tradeSizeUsd?, pair?, currency?, fundingMode?, fundingPair?, spreadMode?, spreadPair?, side?, language?, format?, tableMetric?)`** (v0.35, `format`/`tableMetric` in v0.36) — Country diff matrix; fully offline in default mode. Runs the same `analyzePersona` engine once per country and returns `{ persona: {id, name_en, name_zh}, purpose, currency, countries, data_as_of, rows: [{ country, available_venues, winner: {exchange, tier, annual_all_in} | null, best_complete: {exchange, annual_all_in, extra_vs_winner} | null, comparison_basis: "winner"|"best_complete", comparison_annual_all_in, extra_vs_cheapest_country_usd, extra_vs_cheapest_country_pct, blocked_venues, unsupported_product_venues, ranking, error?, error_code? }], cheapest_country: {country, exchange, tier?, annual_all_in, basis} | null, costliest_country, spread_usd, winner_venue_counts: [{exchange, count, countries}], venue_availability: [{exchange, per_country: {CC: available|blocked|unsupported_product}, blocked_in}], advice, warnings?, rendered?: { metric, markdown?, csv? } }`. Defaults: persona `active_spot_trader`, countries `US/GB/DE/JP/SG/BR/CN` (max 12, deduped). Cross-country deltas use `comparison_annual_all_in` = the all-legs `best_complete` cost when the headline winner misses rails, otherwise the winner — so a venue with no fiat/withdrawal rails cannot make a country look artificially cheap. Live overrides (funding/depth) are fetched once over the union of venues allowed in ANY selected country. `tableMetric` (with non-json `format`): `availability` (default) | `cost`. Error codes: `INVALID_INPUT` (unknown persona / bad format/tableMetric), `UNKNOWN_CURRENCY`.
- **`get_account_fee_tier(exchange, purpose, country, apiKey, secret?, password?, pair?, monthlyVolumeUsd?)`** (v0.39) — the personalized bridge from the public schedule to the caller's **actual account fee**. Uses a **read-only** API key against the venue's authenticated fee endpoint via ccxt (`fetchTradingFees` where available, else per-symbol `fetchTradingFee`), then returns `{ exchange, purpose, pair, credential_type, fetch_method, fetched_at, live_fee: {maker_pct, taker_pct}, bundled_fee: {tier, maker_pct, taker_pct, monthly_volume_usd}, delta_vs_bundled_bps: {maker, taker}, security_note, notes }` — a negative bps gap means the account pays less than the public tier at that volume (server-side BNB/fee-token deductions, the venue's own rolling-30d VIP window, negotiated or promo rates are all captured by the live leg). Coverage: **13 of 18 venues** — Binance, OKX (`password` = API passphrase), Gate, Bybit, MEXC, Bitget, KuCoin spot + `kucoinfutures` (passphrase), Kraken spot + `krakenfutures`, Coinbase spot (`coinbaseexchange` class), BingX, Bitstamp spot, Bitvavo spot (v0.42, `bitvavo` class); Hyperliquid takes only the **public 0x wallet address** in `apiKey` (no secret — it queries the public `userFees` endpoint). Phemex and BloFin have no authenticated fee endpoint in ccxt 4.5.x, Finst (v0.43) exposes no public trading API and ccxt 4.5.x ships no `finst` class, Bitpanda (v0.44) is a spread-quoting brokerage with no public trading API and no `bitpanda` class, Bison (v0.45) is an EUWAX principal-quoted brokerage with no `bison`/`euwax` class in ccxt 4.5.78, and Bitstamp/Bitvavo perps are not modeled (both venues are spot-only) → `ACCOUNT_FEES_UNSUPPORTED` (fails without any network call). Compliance runs first: `UNKNOWN_EXCHANGE` / `COUNTRY_BLOCKED` / `PRODUCT_BLOCKED_IN_COUNTRY` / `NO_FEE_DATA` are returned before credentials are used. Runtime failures are typed and credential-scrubbed: `ACCOUNT_MISSING_CREDENTIALS`, `ACCOUNT_AUTH_FAILED` (non-retryable — wrong key/secret/passphrase, IP restriction, KYC), `ACCOUNT_FEE_FETCH_FAILED` (`retryable: true` for network/timeout/rate-limit). Credentials are per-request only — never cached, never written to logs.
- **`get_stablecoin_access(asset?, country?, exchange?, language?)`** (v0.46) — MiCA stablecoin regional-access report; fully offline. `asset` defaults to `USDT` (also `USDC`/`EURC`/`EURI`/`EURCV`/`USDQ`/`EURQ`). Returns `{ asset, asset_name?, issuer?, mica_authorized, issuer_note?, fetched_at, data_as_of, restriction: { applies, region?, effective?, venue_trading?, custody_withdrawal?, self_custody_allowed?, note? }, venues: [{ exchange, status, scope, since?, note?, venue_available_in_country }], compliant_alternatives, regulation_note?, advice, data_sources? }`. With a country inside the EEA30 the USDT restriction applies (cliff `2026-07-01`) and all 18 venues are listed (`delisted`+date for the nine EEA-licensed venues, `venue_blocked` for the six banned CASPs, `never_offered` for the three global-scope venues); outside the EEA (US/GB/CH/…) `restriction.applies` is false and only global-scope rows return; `exchange` narrows to one row. Error codes: `INVALID_ASSET` (valid ids returned in `suggested_action`), `UNKNOWN_EXCHANGE`, `COUNTRY_BLOCKED`.
- **`compare_interface_costs(exchange?, country?, monthly_volume_usd?, language?)`** (v0.47) — consumer vs PRO dual-interface cost report; fully offline. Returns `{ generated_at, data_as_of, study_summary, venues: [{ exchange, venue_name, available_in_country, consumer: { product_name, fee_model, modeled_one_way_pct, published_one_way_pct?, measured_round_trip_pct?, measured_hidden_spread_pp?, subscription?, tier_credit, measurement }, pro?: { product_name, base_maker_pct, base_taker_pct, published_round_trip_pct }, consumer_vs_pro_round_trip_pp?, consumer_vs_pro_annual_excess_usd?, advice, notes? }], advice, data_sources? }`. Evidence: the TUM real-money €100 round-trip study (2025-10..11, six MiCA-licensed EU platforms) replicated by Frankfurt School (2026-03, 432 round trips/9 platforms) — Bitvavo 0.58% < BISON 2.58% < Kraken app 5.81% < Bitpanda 6.23% < Coinbase Simple 7.49%; Bitstamp Basic is flagged unverified (venue's own disclosure only), Bitpanda/BISON are broker-only (no PRO interface, `pro` omitted). `exchange` narrows to one venue, `country` applies the residency gate (Bitvavo/Bitpanda/BISON blocked outside their service areas), and `monthly_volume_usd` adds `consumer_vs_pro_annual_excess_usd` wherever the consumer one-way cost exceeds the PRO taker base. Error codes: `UNKNOWN_EXCHANGE`, `COUNTRY_BLOCKED`, `INVALID_VOLUME`.
- **`get_fee_changes(exchange?, product?, since_month?, limit?, language?)`** (v0.48) — auditable fee-schedule change feed; fully offline. Returns `{ generated_at, data_as_of, snapshot_coverage: { months, first?, last?, available }, changes: [{ id, date, exchange, product, kind, tier?, field?, before?, after?, confidence, summary_en, summary_zh?, effective_date?, url?, note?, detected_from_snapshot?, detected_to_snapshot? }], advice }`. Two evidence tiers: **curated** rows (`confidence: high|medium`) are human-verified against official venue announcements/fee pages and ship in [`data/fee_changes.json`](data/fee_changes.json); **detected** rows are auto-generated by diffing consecutive monthly deterministic snapshots in `snapshots/fee_ladders/*.json` (repo-only — absent from the npm tarball, where `snapshot_coverage.available` is `false`) and must never be treated as confirmed. `kind` is one of `rate | threshold | ladder_structure | promo | token_discount | pricing_model`; rate before/after values use the engine's round4 percent precision, and rungs are matched by tier name. Sorted date-descending then confidence rank; `product` accepts `spot|futures|all` (an `all` record matches either), `since_month` takes `YYYY-MM`. The monthly capture/review is automated via the `data-snapshot` GitHub Actions workflow (review-only PR — detected rows never enter the curated file without human verification). Local CLI: `npm run snapshot:fees -- snapshot|diff|latest`.
Errors are structured JSON: `{ error, code, retryable?, suggested_action? }` with codes such as `INVALID_INPUT`, `UNKNOWN_EXCHANGE`, `COUNTRY_BLOCKED`, `PRODUCT_BLOCKED_IN_COUNTRY`, `NO_RESULTS`, `UNKNOWN_CURRENCY`, `NO_REFERRAL_LINK`, `DATA_LOAD_FAILED`, `ACCOUNT_FEES_UNSUPPORTED`, `ACCOUNT_MISSING_CREDENTIALS`, `ACCOUNT_AUTH_FAILED`, `ACCOUNT_FEE_FETCH_FAILED`.
## Data files
All fee/VIP/withdrawal/spread data is local JSON. By default the server makes **no external API calls**; `fundingMode: "live"` requests fetch current funding rates and `spreadMode: "live"` requests fetch order books directly from exchange public endpoints via ccxt (best-effort, per-venue timeout, bundled fallback), and `get_account_fee_tier` (v0.39) makes one authenticated request per call to the venue's account-fee endpoint with a read-only key supplied by the caller (see [Credential handling](#credential-handling-v039-get_account_fee_tier)):
| File | Contents |
|---|---|
| [`data/fee_rates.json`](data/fee_rates.json) | VIP tier maker/taker rates, spot + futures; v0.44 adds per-venue `pricing_model` (`order_book\|flat\|spread`) and `execution_quality` evidence (advertised vs independently measured round-trip cost) for spread-broker venues (v0.44 Bitpanda, v0.45 Bison — the second spread venue) |
| [`data/referral_links.json`](data/referral_links.json) | Referral URLs, user discount %, operator rebate (internal) |
| [`data/token_discounts.json`](data/token_discounts.json) | BNB / OKB / GT / MX / BGB / KCS / PT discount rules + Hyperliquid staked-HYPE ladder (multiplicative, staking required) |
| [`data/pair_fees.json`](data/pair_fees.json) | Pair-level fee promos (MEXC 0-fee, Binance FDUSD/USDC, Bitget USDC/USDT), v0.44 Bitpanda spread-band pricing (0.99% BTC/stablecoin pairs vs the 1.49% headline, non-promo) and v0.45 Bison bands (1.25% BTC/EUR + ETH/EUR vs the 1.75% headline, non-promo) |
| [`data/funding_rates.json`](data/funding_rates.json) | Bundled average funding rate + settlement interval (live-mode fallback) |
| [`data/spread_baseline.json`](data/spread_baseline.json) | Typical full bid-ask spread per venue (BTC) + majors/large-cap/mid-alt multipliers (2026 order-book snapshot studies; live-mode fallback); v0.44 pins Bitpanda to 0 bps and v0.45 pins Bison to 0 bps because each venue's embedded premium IS the spread (anti-double-count) |
| [`data/withdrawal_fees.json`](data/withdrawal_fees.json) | Per-exchange withdrawal fees for 16 assets across native + multi-chain routes (TRC-20/ERC-20/BEP20/Arbitrum/Optimism/Base/Polygon/Avalanche C/Solana/TON/AssetHub), `asset_prices_usd` 2026-09-12 snapshot for USD conversion, `suspended` flags for paused wallets (Aug–Sep 2026) |
| [`data/fx_rates.json`](data/fx_rates.json) | Static display FX rates (USD base) |
| [`data/country_restrictions.json`](data/country_restrictions.json) | Per-country blocked/allowed exchanges, per-product negative gates (`product_blocked`), named region membership tables (`regions`, e.g. EEA30), positive product region allowlists (`product_region_gates`, v0.40), negative post-MiCA-cliff region bans (`region_blocked`, `product_region_blocked`, v0.41) and venue-level positive service-area whitelists (`region_allowed`, v0.42 Bitvavo and v0.43 Finst — both EEA-only; v0.44 Bitpanda = EEA+GB via a single-member `GB` region key; v0.45 Bison = EEA+CH via a single-member `CH` region key) |
| [`data/fiat_routes.json`](data/fiat_routes.json) | Direct exchange-operated fiat rails (card/ACH/SEPA/FPS/wire/SWIFT/PIX) per venue, currency, region and direction, with percent+fixed+min/max fees and ETAs (gateways/P2P excluded) |
| [`data/personas.json`](data/personas.json) | Seven research-anchored trader personas for `analyze_persona`: behavioral presets (volume, maker share, holding hours, clip size, withdrawal/fiat habits) with bilingual descriptions, assumptions and research sources (2026 retail-trader studies) |
| [`data/token_prices.json`](data/token_prices.json) | Static 2026-09 USD snapshot prices for native tokens (BNB/OKB/GT/MX/BGB/KCS/HYPE) used to estimate the opportunity cost of holding a token for fee discounts; overridable per call via `tokenPriceUsd` |
| [`data/stablecoin_access.json`](data/stablecoin_access.json) | v0.46 MiCA stablecoin registry: per-asset issuer/EMT authorization (`USDT` unauthorized; USDC/EURC/EURI/EURCV/USDQ/EURQ authorized), region rules (EEA30 USDT venue-trading restriction, 2026-07-01 cliff, custody/withdrawal/self-custody rights, alternatives) and per-venue rules across all 18 venues (`delisted` + since-date / `never_offered` / `venue_blocked`; `eea` vs `global` scope), with sources and `last_verified` 2026-09 |
| [`data/interface_costs.json`](data/interface_costs.json) | v0.47 dual-interface cost model for `compare_interface_costs`: per venue (kraken/coinbase/bitstamp/bitvavo/bitpanda/bison) the consumer product (name, fee model, published one-way fees, subscription waivers) vs the PRO order-book benchmark (base maker/taker, published round trip), TUM real-money measured round-trips and hidden-spread pp with Frankfurt School replication metadata, and `last_verified` 2026-09 |
| [`data/fee_changes.json`](data/fee_changes.json) | v0.48 curated fee-schedule change feed for `get_fee_changes`: human-verified rate/threshold/ladder/promo/token-discount/pricing-model changes with effective date, official source URL, bilingual summary and structured before/after where the source states numbers; `last_verified` 2026-09 (pre-2026-09 history is not reconstructable from primary sources — only officially evidenced records are seeded). The repo additionally carries **repo-only** monthly deterministic snapshots in `snapshots/fee_ladders/YYYY-MM.json` (NOT shipped in the npm tarball) which the engine diffs into `confidence: "detected"` rows |
Each file carries `last_verified` (YYYY-MM) and `sources` (official fee-page URLs, measurement studies or caveats). Override paths via env vars: `FEE_RATES_PATH`, `REFERRAL_LINKS_PATH`, `TOKEN_DISCOUNTS_PATH`, `PAIR_FEES_PATH`, `FUNDING_RATES_PATH`, `SPREAD_BASELINE_PATH`, `WITHDRAWAL_FEES_PATH`, `FX_RATES_PATH`, `COUNTRY_RESTRICTIONS_PATH`, `FIAT_ROUTES_PATH`, `PERSONAS_PATH`, `TOKEN_PRICES_PATH`, `STABLECOIN_ACCESS_PATH`, `INTERFACE_COSTS_PATH`, `FEE_CHANGES_PATH` (file) and `FEE_SNAPSHOTS_PATH` (directory of monthly `YYYY-MM.json` ladder snapshots; missing/unreadable degrades to an empty list — the curated feed still works).
**Accuracy note:** funding rates and withdrawal fees fluctuate; VIP tables change without notice. Treat outputs as estimates and verify via `get_data_sources` before financial decisions.
### Credential handling (v0.39 `get_account_fee_tier`)
The only tool that makes **authenticated** calls is `get_account_fee_tier`, and only when it is explicitly invoked. Security properties:
- **Read-only keys only** — always generate a key with information/read permissions and *no* trading, withdrawal or transfer permissions; the tool never needs them.
- **Per-request, never stored** — credentials live only for the duration of the call. There is deliberately no result cache (the public-data TTL caches never receive key material), nothing is written to disk, and credentials are never returned in the response.
- **Redacted everywhere** — the stderr `[audit]` log redacts `apiKey` / `secret` / `password` / `passphrase` / `walletAddress` arguments (`***REDACTED***`) before serialization, and exchange error strings are scrubbed of literal credential values and `signature=` parameters.
- **Compliance first** — venue/country/product gates run before any key is used, so a blocked request never touches an exchange auth endpoint.
- **Hyperliquid** needs just the public wallet address (the fee query is a public `userFees` call); no private key is ever requested.
## Examples
```
> User: I'm in Japan, trade 100k USDT futures/month, mostly limit orders, and hold positions ~16h. Which exchange?
Agent → recommend_exchange(purpose="futures", country="JP", volume=100000,
makerShare=0.8, holdingHours=16)
Server → {
"best": { "exchange": "...", "score": 100, "weighted_fee_rate": ...,
"reasons": [...], "tradeoffs": [...], "referral_url": "..." },
"alternatives": [...],
"advice": "Register via the ... link to lock 20% off ...",
"data_as_of": "2026-09"
}
```
```
> User: 数据是哪来的?费率多久更新一次?
Agent → get_data_sources()
Server → { "data_as_of": "2026-09",
"files": [{ "file": "fee_rates.json", "last_verified": "2026-09",
"sources": [{ "name": "Binance fee schedule",
"url": "https://www.binance.com/en/fee/schedule" }, ...] }, ...] }
```
```
> User: 我在币安每月交易 100 万U期货,持仓约 720 小时,每年提 12 次 USDT,一年真实成本多少?升 VIP1 能省多少?
Agent → calculate_annual_cost(exchange="binance", purpose="futures", country="JP",
monthlyVolumeUsd=1000000, holdingHours=720,
withdrawalAsset="USDT", withdrawalNetwork="TRC-20",
withdrawalsPerYear=12)
Server → {
"tier": "Regular",
"annual_trading_fee": 4800,
"annual_funding_cost": 108000,
"annual_withdrawal_cost": 18,
"annual_total_cost": 112818,
"upgrade": { "next_tier": "VIP1", "requires_volume_usd": 15000000,
"annual_savings": 960,
"hint": "Reach VIP1 via $15,000,000 30-day volume; estimated annual trading-fee saving $960 ..." }
}
```
```
> User: 我主要在 MEXC 现货刷 BTC/USDT,听说 0 手续费是真的吗?其他所呢?
Agent → compare_exchange_fees(purpose="spot", country="JP", pair="BTC/USDT", makerShare=0.5)
Server → [
{ "exchange": "mexc", "tier": "Standard", "effective_maker": 0, "effective_taker": 0,
"weighted_rate": 0, "pricing_basis": "pair",
"pair_note": "MEXC 0-fee program: all spot pairs trade at 0% maker + 0% taker ..." },
{ "exchange": "okx", ..., "pricing_basis": "account_tier" },
...
]
```
```
> User: 现在 BTC 永续各交易所资金费率多少?按实时费率我持 10 万U多单 16 小时要付多少资金费?
Agent → get_funding_rates(fundingMode="live", fundingPair="BTC/USDT")
Server → {
"pair": "BTC/USDT", "mode": "live",
"rates": [
{ "exchange": "binance", "rate_pct": 0.0124, "interval_hours": 8,
"source": "live", "funding_timestamp": "2026-09-12T00:00:00.000Z" },
{ "exchange": "kraken", "rate_pct": 0.01, "interval_hours": 8,
"source": "bundled", "note": "..." }
],
"failures": [{ "exchange": "kraken", "error": "Connect Timeout ...", "fallback": "bundled" }]
}
Agent → calculate_savings(exchange="binance", volume=100000, type="futures",
country="JP", holdingHours=16,
fundingMode="live", fundingPair="BTC/USDT")
Server → { "funding_cost": 24.8, "funding_source": "live",
"funding_rate_ts": "2026-09-12T00:00:00.000Z",
"funding_pair": "BTC/USDT", ... }
```
```
> User: 我一笔 5 万U的 BTC 市价吃单,各交易所点差加滑点实际要付多少?25 万U的大单呢?
Agent → get_execution_cost(tradeSizeUsd=50000, pair="BTC/USDT",
purpose="futures", side="buy", spreadMode="live")
Server → {
"pair": "BTC/USDT", "mode": "live", "trade_size_usd": 50000,
"costs": [
{ "exchange": "binance", "spread_bps": 1.0, "crossing_bps": 0.5,
"slippage_bps": 0.3, "total_bps": 0.8, "cost_usd": 4,
"levels_consumed": 3, "fully_filled": true, "source": "live",
"symbol": "BTC/USDT:USDT", "book_timestamp": "2026-09-12T..." },
{ "exchange": "kraken", "spread_bps": 5, "crossing_bps": 2.5,
"slippage_bps": 0, "total_bps": 2.5, "cost_usd": 12.5,
"source": "bundled", "pair_class": "majors" }
],
"failures": [{ "exchange": "kraken", "error": "Connect Timeout ...",
"fallback": "bundled" }]
}
Agent → compare_total_cost(purpose="futures", country="JP", volume=100000,
tradeSizeUsd=250000, spreadMode="live", side="buy")
Server → [ { "exchange": "binance", "trading_fee": 1000,
"spread_cost": 12.5, "slippage_cost": 28.2,
"spread_source": "live", "total_cost": 1040.7 }, ... ]
```
```
> User: 我在德国,想入 1000 欧元,刷卡和 SEPA 转账各所收多少?哪个最便宜?
Agent → get_fiat_cost(direction="deposit", currency="EUR", amount=1000, country="DE")
Server → {
"direction": "deposit", "currency": "EUR", "amount": 1000, "amount_usd": 1086.96,
"fx_rate": 0.92, "data_as_of": "2026-09",
"best": { "exchange": "binance", "method": "sepa", "fee": 0,
"fee_usd": 0, "effective_pct": 0, "net": 1000 },
"saving_vs_worst_usd": 5.43,
"exchanges": [
{ "exchange": "binance", "available": true, "cheapest_method": "sepa",
"cheapest_fee_usd": 0,
"routes": [ { "method": "sepa", "fee": 0, "fee_usd": 0, "effective_pct": 0,
"net": 1000, "eta": "1-2 business days" },
{ "method": "card", "fee": 20, ... } ] },
{ "exchange": "gate", "cheapest_method": "sepa",
"routes": [ { "method": "sepa", "fee": 5, "effective_pct": 0.5, ... } ] },
...
],
"advice": "binance offers a free sepa deposit for EUR — 1000 EUR arrives in full. ..."
}
```
```
> User: 我要提 USDT 到 TRC-20,8 家所分别收多少?不提网络的话哪家最便宜?最近有哪些链暂停了?
Agent → get_withdrawal_fees(asset="USDT", network="TRC-20")
Server → {
"asset": "USDT", "network": "TRC-20", "asset_price_usd": 1,
"data_as_of": "2026-09",
"exchanges": [
{ "exchange": "mexc", "supported": true,
"networks": [{ "network": "TRC-20", "fee": 0.5, "fee_usd": 0.5, "available": true }],
"cheapest_network": "TRC-20", "cheapest_fee_usd": 0.5 },
{ "exchange": "bybit", ..., "cheapest_fee_usd": 1 },
{ "exchange": "binance", ..., "cheapest_fee_usd": 1.5 },
...
],
"best": { "exchange": "mexc", "network": "TRC-20", "fee": 0.5, "fee_usd": 0.5 },
"saving_vs_worst_usd": 1,
"advice": "Cheapest USDT TRC-20 withdrawal: mexc charges 0.5 USDT (about $0.5) ..."
}
Agent → get_withdrawal_fees(asset="ETH") // no network: cheapest open L2 per venue
Server → {
"asset": "ETH", "asset_price_usd": 2512.03,
"best": { "exchange": "mexc", "network": "Base", "fee": 0.0000013, "fee_usd": 0.0033 },
"exchanges": [ { "exchange": "binance", "cheapest_network": "Optimism",
"cheapest_fee_usd": 0.0377, "networks": [ ... ] }, ... ],
"saving_vs_worst_usd": 0.32
}
```
## Development
```bash
npm test # vitest unit tests (457 tests: 361 tools + 50 live + 28 http + 13 account + 3 polyfill + 2 version)
npm run build # tsc → dist/
npm run audit:data # offline data-consistency gate (dates, sources, ladder monotonicity, coverage)
node scripts/smoke-test.mjs # end-to-end MCP stdio smoke test (68 requests)
npm run smoke:http # end-to-end Streamable HTTP smoke test
npm run inspector # MCP Inspector UI for manual testing
```
The same audit → build → test → HTTP-smoke pipeline plus an `npm pack` artifact/install check runs in CI on every push and pull request (Node 18/20/22, [`.github/workflows/ci.yml`](.github/workflows/ci.yml)). Release history lives in [CHANGELOG.md](CHANGELOG.md).
## License
MIT
TDQS
Scored across 19 tools
There is a large cluster of heavily overlapping 'compute a cross-venue cost' tools—compare_exchange_fees, compare_total_cost, calculate_annual_cost, calculate_savings, recommend_exchange, analyze_persona, compare_personas, compare_countries, and volume_what_if all return ranked fee comparisons with only subtly different lenses. The descriptions do cross-reference each other (e.g. 'for the all-in cost of a trade use compare_total_cost instead'), which helps, but an agent asked a generic 'which exchange is cheapest' question faces genuine selection ambiguity.
Nearly all tools follow a consistent snake_case verb_noun pattern (calculate_savings, compare_total_cost, get_funding_rates, analyze_persona, recommend_exchange). The only outlier is volume_what_if, which drops the verb prefix, but the set is otherwise predictable and readable.
At 19 tools the surface is on the heavy side for a fee-optimization server, and several tools appear consolidatable (e.g. compare_exchange_fees / compare_total_cost / calculate_annual_cost are variants of the same comparison). The breadth of the domain (multi-exchange, multi-cost-leg, personas, countries) justifies many of them, but 19 is borderline.
Coverage of the fee-optimization domain is exceptionally thorough: trading fees, funding rates, execution/spread, withdrawal fees, fiat on/off-ramps, token discounts, consumer-interface markups, stablecoin regional access, API-verified account tiers, referral links, data provenance, plus persona/country and what-if analysis. No obvious operational gaps or dead ends for the stated purpose.