Costs
Fees read the non-promotional tier, and cost is checked before anything else because most ideas die here.
Check costs first#
cost_model_refresh()
cost_breakeven(trades_per_day=20)
This is step one of the order of work, before data ingest and long before any statistics. The reason is arithmetic.
At the published Coinbase Exchange entry tier — 60 bps taker per side, non-promotional, so a 120 bps round trip — twenty trades a day costs:
120 bps × 20 trades/day × 365 days / 100 = 8,760% per year
No signal fixes that. An idea requiring 20 trades a day at the entry tier is dead before it is tested, and finding that out costs one tool call rather than a week of backtesting and a chunk of your trial budget.
The fee is named explicitly so the figure can be audited and recomputed against your own cost model rather than taken on trust.
The ladder is Coinbase's, and only Coinbase's#
Every fee figure on this page is Coinbase's published schedule. If you ingested
data from another venue with source="url", these numbers do not describe it.
That is not an oversight to be smoothed over with a generic "crypto fee". Fees are venue- and tier-specific, and cost drag is the thing that kills most strategies before any statistic is reached — so a guessed cost model is exactly the kind of number this server exists to reject. A cost model always names the venue it came from; check it against your own venue's schedule before trusting a breakeven computed from it.
Where the numbers come from#
With Coinbase credentials configured the server reads your tier from the account. Without them it falls back to the published schedule, and every cost model says which it is:
{"pricing_tier": "$0-$10K", "taker_bps": 60.0,
"source": "fallback_published_schedule", "is_live": false}
is_live: false means the entry-tier figures quoted throughout these docs — 60
bps taker per side, a 120 bps round trip — are the published rates rather than a
reading of an account. They are the correct rates for a new account, which is
what most readers have, but they are not personalised until a key is set.
Non-promotional tiers, on purpose#
Fees read fee_tier_without_promotion.current_tier, not the promotional
fee_tier object.
Promotional rates expire. A backtest priced against a promotion is a backtest of a business relationship rather than of a strategy, and it will look worse the moment the promotion ends — which is exactly when you would be trading it live.
Prices and fees describe the same venue#
Candles come from Coinbase Advanced Trade (350 bars per request), not
Coinbase Exchange. Earlier versions pulled candles from Exchange while
reading Advanced Trade fees, which meant prices and fees described two
different products. gate_check warns on a mismatch.
Staleness#
The cost model carries a one-hour staleness horizon. server_status reports
age_seconds and source for every cost model, so an old model is visible
as old.
A fallback ladder — the hardcoded table used when no API key is
configured — reports its fetched_at as when the table was assembled, not
when anything was retrieved. Refreshing a fallback returns the same table, so
it is reported as old rather than as stale: "stale" means refresh this, and
there is no refresh that would help.
Fee share of returns#
backtest_result reports gross and net side by side, plus the fee share of
gross return. A strategy whose fee share is above 100% is not a marginal
strategy; it is a fee-generation mechanism.
Breakeven hit rate#
stats_triple_barrier(...)
Triple-barrier labelling reports a breakeven hit rate — the win rate you would need for the strategy to break even after costs. When barriers are tighter than the round-trip fee, this exceeds 1.0, meaning no achievable hit rate is sufficient. That is a complete answer, and it arrives before any model is fitted.
Read this page as Markdown:
/docs/concepts/costs.md