Signal backtest results
Signal backtest results (BTC / ETH only)
/api/signal/backtest/:coinRequest
Query parameters
| Name | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
| coin path | string | Required | — | BTC, ETH | Coin; other values return 400. Example: BTC |
Parameters marked “path” are part of the URL.
Example request
curl -s "https://www.coinboss.com/api/signal/backtest/BTC"Response fields
The field table is generated from real responses, so it lists exactly what the endpoint returns. Paths use a[] for array items and {*} for objects keyed by a dynamic name such as a coin or an exchange.
| Field | Type | Unit | Description |
|---|---|---|---|
| success | boolean | — | true when the request succeeded. On failure the body is `{ success: false, code, error, request_id }`. |
| coin | string | — | Coin symbol, upper case (for example BTC). |
| backtest_basis | string | — | Coin the backtest statistics were measured on (`ETH`). |
| basis_note_code | string | — | `basis_native` when the requested coin is the backtested coin, `basis_borrowed` when ETH statistics are shown for another coin. |
| basis | string | — | Futures price minus spot price, or the basis block. |
| note_code | string | — | Fixed code `eth_only_basis`: every statistic in this response comes from ETHUSDT history. |
| daily | object | — | Daily values. |
| daily.dataset | object | — | Size and date range of the daily candle history behind the daily statistics (full history and recent window). |
| daily.dataset.bars_full | number | count | Number of daily candles in the full history. |
| daily.dataset.range_full | string | — | First and last date of the full history, as text. |
| daily.dataset.bars_recent | number | count | Number of daily candles in the recent window. |
| daily.dataset.range_recent | string | — | First and last date of the recent window, as text. |
| daily.dataset.src | string | — | Source. |
| daily.baseline | object | — | Reference result of buying on any day and holding 30 days, for the full history and the recent window. |
| daily.baseline.full | object | — | Full-resolution data. |
| daily.baseline.full.n | number | — | Number of items counted. |
| daily.baseline.full.hold30_winrate | number | % | Share of all 30-day holds in the full history that ended in profit. |
| daily.baseline.full.hold30_pf | number | ratio | Profit factor of all 30-day holds in the full history: sum of gains ÷ absolute sum of losses. |
| daily.baseline.recent | object | — | Most recent entries. |
| daily.baseline.recent.n | number | — | Number of items counted. |
| daily.baseline.recent.hold30_winrate | number | % | Share of all 30-day holds in the recent window that ended in profit. |
| daily.baseline.recent.hold30_pf | number | ratio | Profit factor of all 30-day holds in the recent window: sum of gains ÷ absolute sum of losses. |
| daily.timing | object | — | Return of buy-and-hold compared with simple trend-filter rules, for the full history and the recent window. |
| daily.timing.full | object | — | Full-resolution data. |
| daily.timing.full.buy_hold_pct | number | % | Buy-and-hold return over the full history, measured from the 210th candle on. |
| daily.timing.full.above_ema200_pct | number | % | Return over the full history when holding only on days the close is above the 200-day EMA. |
| daily.timing.full.below_ema200_pct | number | % | Return over the full history when holding only on days the close is below the 200-day EMA. |
| daily.timing.full.ema20_gt_ema50_pct | number | % | Return over the full history when holding only while the 20-day EMA is above the 50-day EMA. |
| daily.timing.full.days_above | string | — | Text `days held/total days` for the close-above-EMA200 rule, full history. |
| daily.timing.full.days_fast | string | — | Text `days held/total days` for the EMA20-above-EMA50 rule, full history. |
| daily.timing.recent | object | — | Most recent entries. |
| daily.timing.recent.buy_hold_pct | number | % | Buy-and-hold return over the recent window. |
| daily.timing.recent.above_ema200_pct | number | % | Return over the recent window when holding only on days the close is above the 200-day EMA. |
| daily.timing.recent.below_ema200_pct | number | % | Return over the recent window when holding only on days the close is below the 200-day EMA. |
| daily.timing.recent.ema20_gt_ema50_pct | number | % | Return over the recent window when holding only while the 20-day EMA is above the 50-day EMA. |
| daily.timing.recent.days_above | string | — | Text `days held/total days` for the close-above-EMA200 rule, recent window. |
| daily.timing.recent.days_fast | string | — | Text `days held/total days` for the EMA20-above-EMA50 rule, recent window. |
| daily.signals | object | — | Signal entries. dynamic keys: bull_regime,bear_regime,multi_long,fast_filter,pullback_add,streak5_up |
| daily.signals.{*} | object | — | Signal entries. |
| daily.signals.{*}.hold | string | — | Holding rule used in the backtest of the signal named by the map key, for example `30d`, `7d` or a take-profit / stop-loss rule in ATR multiples. |
| daily.signals.{*}.full | object | — | Full-resolution data. |
| daily.signals.{*}.full.n | number | — | Number of items counted. |
| daily.signals.{*}.full.winrate | number|null | — | Win rate. |
| daily.signals.{*}.full.pf | number|null | — | Profit factor. |
| daily.signals.{*}.recent | object | — | Most recent entries. |
| daily.signals.{*}.recent.n | number | — | Number of items counted. |
| daily.signals.{*}.recent.winrate | number|null | — | Win rate. |
| daily.signals.{*}.recent.pf | number|null | — | Profit factor. |
| daily.signals.{*}.src | string | — | Source. |
| daily.signals.{*}.full.total_pct | number | % | Share of the total. may be absent |
| daily.signals.{*}.full.mdd_pct | number | % | Maximum drawdown. may be absent |
| daily.signals.{*}.recent.total_pct | number | % | Share of the total. may be absent |
| daily.signals.{*}.recent.mdd_pct | number | % | Maximum drawdown. may be absent |
| m15 | object | — | Backtest on 15-minute ETHUSDT candles: exits in ATR(14) multiples, round-trip cost included. |
| m15.dataset | object | — | Size, date range and completeness of the 15-minute candle history used. |
| m15.dataset.bars | number | — | Bars. |
| m15.dataset.range | string | — | Window requested. |
| m15.dataset.completeness | string | — | Text giving candles present versus candles expected in the 15-minute history. |
| m15.dataset.src | string | — | Source. |
| m15.signals | object | — | Signal entries. dynamic keys: knife_25,knife_30,cum8_4,cum16_6 |
| m15.signals.{*} | object | — | Signal entries. |
| m15.signals.{*}.signals | number | — | Signal entries. |
| m15.signals.{*}.n | number | — | Number of items counted. |
| m15.signals.{*}.winrate | number | — | Win rate. |
| m15.signals.{*}.pf | number | — | Profit factor. |
| m15.signals.{*}.total_pct | number | % | Share of the total. |
| m15.signals.{*}.mdd_pct | number | % | Maximum drawdown. |
| m15.signals.{*}.tp | number | x | Take-profit distance used for the signal named by the map key, as a multiple of ATR(14). |
| m15.signals.{*}.sl | number | x | Stop-loss distance used for the signal named by the map key, as a multiple of ATR(14). |
| m15.signals.{*}.src | string | — | Source. |
| m15.threshold_scan | array | — | Backtest results by size of the single-candle drop that triggers a buy. |
| m15.threshold_scan[] | object | — | Result for one drop threshold. |
| m15.threshold_scan[].th | number | % | Single-candle price change that triggers the entry (negative). |
| m15.threshold_scan[].signals | number | — | Signal entries. |
| m15.threshold_scan[].n | number | — | Number of items counted. |
| m15.threshold_scan[].winrate | number | — | Win rate. |
| m15.threshold_scan[].pf | number | — | Profit factor. |
| m15.threshold_scan[].total_pct | number | % | Share of the total. |
| m15.filter_test | array | — | Results of the −2.0 % dip entry with one extra filter each (RSI, volume, EMA200). |
| m15.filter_test[] | object | — | Result for one filter variant. |
| m15.filter_test[].code | string | — | Code. |
| m15.filter_test[].n | number | — | Number of items counted. |
| m15.filter_test[].winrate | number | — | Win rate. |
| m15.filter_test[].pf | number | — | Profit factor. |
| m15.filter_test[].total_pct | number | % | Share of the total. |
| m15.confirm_test | array | — | Results by entry timing: immediately, or after waiting for one or two confirming candles. |
| m15.confirm_test[] | object | — | Result for one entry-timing variant. |
| m15.confirm_test[].code | string | — | Code. |
| m15.confirm_test[].n | number | — | Number of items counted. |
| m15.confirm_test[].winrate | number | — | Win rate. |
| m15.confirm_test[].pf | number | — | Profit factor. |
| m15.confirm_test[].total_pct | number | % | Share of the total. |
| m15.cost_test | array | — | Results under different assumed round-trip trading costs. |
| m15.cost_test[] | object | — | Result for one cost assumption. |
| m15.cost_test[].cost_pct | number | % | Round-trip trading cost assumed in this run, as a percentage of notional. |
| m15.cost_test[].pf | number | — | Profit factor. |
| m15.cost_test[].total_pct | number | % | Share of the total. |
| m15.hour_test | array | — | Results of the −1.5 % dip entry split by UTC hour window. |
| m15.hour_test[] | object | — | Result for one UTC hour window. |
| m15.hour_test[].code | string | — | Code. |
| m15.hour_test[].n | number | — | Number of items counted. |
| m15.hour_test[].winrate | number | — | Win rate. |
| m15.hour_test[].pf | number | — | Profit factor. |
| m15.hour_test[].total_pct | number | % | Share of the total. |
| m15.short_side | array | — | Results of the mirror trade: shorting after a single-candle surge. |
| m15.short_side[] | object | — | Result for one surge threshold. |
| m15.short_side[].code | string | — | Code. |
| m15.short_side[].n | number | — | Number of items counted. |
| m15.short_side[].winrate | number | — | Win rate. |
| m15.short_side[].pf | number | — | Profit factor. |
| m15.short_side[].total_pct | number | % | Share of the total. |
| weekday | array | — | Day of week. |
| weekday[] | object | — | Day of week. |
| weekday[].d | number | — | Calendar date (UTC). |
| weekday[].up_rate | number | — | Share of periods that closed higher. |
| weekday[].mean_pct | number | % | Mean daily price change on that weekday (`d` 1 = Monday … 7 = Sunday), full history. |
| month | array | — | Calendar month. |
| month[] | object | — | Calendar month. |
| month[].m | number | — | Calendar month number, 1–12. |
| month[].up_rate | number | — | Share of periods that closed higher. |
| month[].median_pct | number | % | Median cumulative price change of that calendar month across the years in the full history. |
Generated 2026-11-11 23:01 UTC from 1 real responses.
Example response
/api/signal/backtest/BTC · Real response captured 2026-11-13 03:59:07 UTC. Long arrays and maps are shortened for display: month had 12 items; weekday had 7 items; m15.signals had 4 items; daily.signals had 12 items; m15.cost_test had 5 items; m15.hour_test had 3 items.
- "success"true
- "coin""BTC"
- "backtest_basis""ETH"
- "basis_note_code""basis_borrowed"
- "basis""ETHUSDT"
- "note_code""eth_only_basis"
- "daily"
- "dataset"
- "baseline"
- "timing"
- "signals"
- "m15"
- "dataset"
- "signals"
- "threshold_scan"
- "filter_test"
- "confirm_test"
- "cost_test"
- "hour_test"
- "short_side"
- "weekday"
- "month"
Details
- Authentication
- None. Public endpoint.
- Rate limit
- 1200 requests per minute per IP
- Server cache
- 60m
- Edge micro-cache
- 10s
- Window
- fixed: daily bars 2017-08-17 to 2026-07-30, 15-minute bars 2023-01 to 2026-07
- Data sources
- Static summary of an offline backtest on exchange ETHUSDT klines; not recomputed.
- Exchange coverage
- ETH backtest only; BTC returns the same ETH-based numbers.
- Units
- win rate in percent, profit factor, sample counts
- Timestamps
- Unix epoch milliseconds (UTC) unless the field description says otherwise
- Response format
- json
- Stability
- Stable
Live status
Availability, last 30 days
100% of 408 checks passed
Errors
Failed calls share one shape on every endpoint. The full list is on the errors page. Errors and rate limits →
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
| INVALID_PARAM | 400 | A required parameter is missing or a value is not accepted. `param` names the parameter when it is known. | Do not retry unchanged; fix the request. |
| UNAUTHORIZED | 401 | The `CB-API-KEY` header was sent but the key is unknown or revoked. Public data needs no key — drop the header or use a valid key. | Do not retry unchanged. |
| FORBIDDEN | 403 | The route is not part of the public API (internal or account-only). | Do not retry. |
| NOT_FOUND | 404 | Unknown route, or the requested coin / exchange / fund does not exist. | Do not retry; check the path and identifiers against the catalog. |
| RATE_LIMITED | 429 | More requests than the per-minute limit. `Retry-After` gives the seconds to wait. | Wait for `Retry-After`, then retry with backoff. |
| INTERNAL | 500 | Unexpected server error. The message is generic by design; quote `request_id` when reporting it. | Retry once after a few seconds; report it with the request id if it persists. |
| UPSTREAM_FAILED | 503 | The data source behind this endpoint did not answer in time. No stale or substitute numbers are returned in its place. | Retry with backoff; check the status page. |
| UNAVAILABLE | 501 / 503 | The dataset is temporarily not ready (cache warming) or the endpoint has no lawful public source yet. | Retry later; the catalog marks endpoints that are unavailable by design. |
| REQUEST_FAILED | 200 | Some older endpoints answer HTTP 200 with `success: false`. Always check `success`, not only the HTTP status. | Depends on the message; treat as a failed request. |
Try it
/api/signal/backtest/:coinAvailablestring — Coin; other values return 400.
https://www.coinboss.com/api/signal/backtest/BTCMore in this category
- AHR999 accumulation indicator series /api/indicators/ahr999
- Bitcoin bubble index /api/indicators/bitcoin-bubble
- Full BTC daily close history /api/indicators/btc-history
- Bull-market peak signal checklist /api/indicators/bull-peak-signals
- CBBI bull-run composite index /api/indicators/cbbi
- Derivatives risk index (CoinBoss method) /api/indicators/cdri
- Derivatives composite index (CoinBoss method) /api/indicators/cgdi
- BTC correlation with gold / S&P 500 /api/indicators/correlation
- Correlation matrix of major assets /api/indicators/correlation-matrix
- Crypto legal status by country /api/indicators/crypto-legality
- Cycle-top valuation bands /api/indicators/cycle-caps
- BTC price doubling-time series /api/indicators/doubling-time
- Google search-interest trend /api/indicators/google-trends
- Macro series /api/indicators/macro-series
- Price-forecast model output /api/indicators/price-forecast
- Drawdown-from-ATH series /api/indicators/price-no-turning-back
- Reddit Bitcoin subreddit subscriber count /api/indicators/reddit-subs
- Wikipedia page views /api/indicators/wikipedia-pageviews
- Altcoin season index (CoinBoss method) /api/indices/altseason
- Bottom radar /api/indices/bottom-radar
- Bottom-radar historical case study /api/indices/bottom-radar/case-0819
- BTC multi-factor signal dashboard /api/indices/btc-signal
- Backtest of the BTC signal /api/indices/btc-signal/backtest
- Fear & Greed index /api/indices/fear-greed
- Fear & Greed index (current and history) /api/market/fear-greed
- Signal backtest results /api/signal/backtest/:coin
- Signal monitor dashboard /api/signal/monitor/:coin