Skip to content
Pro feature

Signals API

Pull any strategy's monthly signal, plus your portfolio's allocations and backtest, as JSON or CSV with a read-only API key. Wire BestFolio into QuantConnect, an Interactive Brokers bot, or a spreadsheet, or connect your AI assistant over MCP.

What it is

A read-only HTTP API that returns a strategy variant's monthly rebalancing signal in machine-readable form, so you can feed BestFolio signals straight into whatever executes your trades. It is the same signal you see on the site and in the monthly email, just in a format your code can read.

Authentication

Every request needs a BestFolio API key. Keys start with bf_live_ and are tied to your Pro subscription (access stops if the subscription lapses). Pass it either way:

  • Header: X-API-Key: bf_live_...
  • Or: Authorization: Bearer bf_live_...

Keys are read-only and should be treated like a password. Pro members generate and revoke keys in Settings, under API Keys.

Endpoint

GET /api/variants/{variant_id}/signal/export

Query parameters:

  • format: json or csv. CSV columns are signal_date, regime, then one column per ETF holding the target weight as a decimal (0.25 = 25%).
  • limit: number of most recent signals to return (1 to 1000, default 120). Returned oldest first.

Example JSON response

{
  "variant_id": 1,
  "count": 2,
  "current_signal": "2026-05-29",
  "next_signal": "2026-06-30",
  "as_of_date": "2026-06-15",
  "signals": [
    {"signal_date": "2026-05-29", "effective_date": "2026-05-29",
     "as_of_date": "2026-06-15", "status": "current", "regime": "aggressive",
     "allocations": {"IWM": 0.25, "QQQ": 0.25, "PDBC": 0.25, "VEA": 0.25}},
    {"signal_date": "2026-06-30", "effective_date": "2026-06-30",
     "as_of_date": "2026-06-15", "status": "preview", "regime": "aggressive",
     "allocations": {"IWM": 0.25, "QQQ": 0.25, "PDBC": 0.25, "VEA": 0.25}}
  ]
}

Active signal vs next-month preview

Read this before you automate

Signals are dated at their effective date. The newest signal effective on or before the response's UTC as_of_date is current. A signal with a later effective date is a preview and is not actionable until that date.

Do not blindly take the most recent row (limit=1), which may be the preview. Example: on 15 June the current signal is effective 2026-05-29 and the 2026-06-30 row is a preview. On 30 June, that preview becomes current.

To make this explicit, the JSON response includes top-level current_signal (the active allocation) and next_signal (the preview) dates. Each JSON row also includes status, as_of_date, and effective_date. Strategy summary and detail responses use the same fields inside current latest_signal and nullable preview_signal.

Finding a variant_id

Each strategy has one or more variants, each with a numeric variant_id. The quickest way is to resolve a slug to its variants with GET /api/strategies/slug/{slug}/variants (returns id, name, slug, and active per variant), or pull the full GET /api/strategies/summary. Common HAA (Hybrid Asset Allocation, Keller) variants:

variant_idvariantnotes
1HAA Standard (with QQQ)the canonical HAA
2HAA without QQQ
3HAA Leveraged (2x)
4HAA Leveraged, no QQQ
82HAA SmartLeverage 1.5x
66HAA SmartStack (Gold + MF)
155NLX HAA 60/40
185HAA-Simple
186HAA-Simple Leveraged 2x (SSO)

Examples

JSON, recent history

curl -H "X-API-Key: bf_live_..." \
  "https://bestfolio.app/api/variants/1/signal/export?format=json&limit=6"

CSV, for a spreadsheet

curl -H "X-API-Key: bf_live_..." \
  "https://bestfolio.app/api/variants/1/signal/export?format=csv&limit=24"

Python, pick the active signal correctly

import requests

KEY = "bf_live_..."
r = requests.get(
    "https://bestfolio.app/api/variants/1/signal/export",
    params={"format": "json", "limit": 6},
    headers={"X-API-Key": KEY},
    timeout=30,
)
payload = r.json()
signals = payload["signals"]  # oldest first

# BestFolio resolves the date in UTC. Use the declared current signal instead
# of choosing the maximum stored date, which may be a future preview.
active_date = payload["current_signal"]
active = next(s for s in signals if s["effective_date"] == active_date)
print(active["signal_date"], active["allocations"])

More endpoints

The same key also reaches your portfolio analytics and richer strategy data. Portfolio endpoints return only portfolios you own. All are read-only GET requests using the same authentication.

A machine-readable OpenAPI spec for these endpoints lives at /api/v1/openapi.json, for generating a client or importing into your tooling.

methodpathreturns
GET/api/strategies/summaryAll strategies with the current latest_signal and nullable future preview_signal, in your tier's view.
GET/api/strategies/slug/{slug}Full detail for one strategy: variants, metrics, signals.
GET/api/portfolios/{id}/rollupYour portfolio's net exposure: asset-class, regional, turnover.
GET/api/portfolios/{id}/rollup/executionExecution-ready allocation after small-position merging.
GET/api/portfolios/{id}/processed-allocationFinal ticker-to-weight map after UCITS and rollup.
GET/api/portfolios/{id}/driftTarget vs actual drift per sleeve for your portfolio.
GET/api/portfolios/{id}/trade-listBuy/sell/hold list. Params: portfolio_size, period (current or next).
GET/api/portfolios/{id}/backtestBlended NAV, returns, metrics, drawdown. Params: start, end, currency.
GET/api/portfolios/{id}/wf-navCached walk-forward NAV series and metrics.

Connect your AI assistant (MCP)

BestFolio runs a remote Model Context Protocol server, so you can ask Claude or ChatGPT about your strategies, signals, and portfolios directly. Add it as a custom connector and authenticate with your bf_live_ key.

MCP server URL

https://bestfolio.app/mcp

Add the URL above as a custom connector and sign in with your BestFolio account when prompted. There is no key to copy: the connector is authorised against your account directly, and you can disconnect it at any time. The server is read-only and Pro-gated, exactly like the HTTP API.

Claude Code and other terminal clients can skip the sign-in and present an API key instead:

Claude Code

claude mcp add --transport http bestfolio \
  https://bestfolio.app/mcp \
  --header "Authorization: Bearer bf_live_..."

Available tools:

list_strategiesget_strategy_signalget_strategy_detailget_portfolio_rollupget_portfolio_executionget_portfolio_allocationget_portfolio_driftget_portfolio_trade_listget_portfolio_backtestget_portfolio_walkforward

Errors

401Missing or invalid key.
403Key valid but the subscription is not Pro.
404Variant does not exist, or is not visible to you.

Fair use

Signals update at most once per trading day, after the daily scan. Polling once a day is plenty. Please do not hammer the endpoint.

Automate your TAA

The Signals API is included with BestFolio Pro.

BestFolio is an information and research tool. Nothing on this platform constitutes investment advice. Past performance does not guarantee future results.