API Documentation
REST API for the FX Realized Volatility Forecast — 28 pairs, 11 horizons (15m-24h). Base URL: https://api.fxengineer.com
The API is currently v1 (beta). Breaking changes will be announced at least 14 days in advance via email to registered API users.
Authentication
All signal endpoints require authentication via API key or JWT Bearer token. Track record and model info endpoints are publicly accessible.
curl -H "X-API-Key: fxe_your_key_here" \
https://api.fxengineer.com/rv/signals/latestcurl -H "Authorization: Bearer eyJhbG..." \
https://api.fxengineer.com/rv/signals/latestAPI keys are issued by your account administrator. Do not share keys or embed them in client-side code.
Access Tiers
| Tier | Pairs | Horizons | Rate Limit | Export |
|---|---|---|---|---|
| Free | -- | -- | -- | -- |
| Trial | 6 majors | 1h, 4h | 10/min | No |
| Pro | All 28 | All 11 (15m-24h) | 100/min | Yes |
Free tier: track record and model info only (no live signals). Trial: EURUSD, USDJPY, GBPUSD, AUDUSD, USDCAD, USDCHF at 1h and 4h horizons. 14 days.
Endpoints
/rv/signals/latestTrial: 6 pairs, 1h+4h | Pro: all 28, all 11 (15m-24h)Current predictions for all pairs and horizons. Returns the most recent signal for each pair/horizon combination, grouped by pair with full move distribution.
Auth: API key or JWT (Trial+)
/rv/signals/{pair}/{horizon}Example: /rv/signals/EURUSD/4Signal history for a specific pair and horizon. Returns up to 1,000 historical predictions. Horizon parameter is an integer representing hours (e.g., 1, 2, 3, 4, 6, 8, 12, 24). Sub-hourly horizons use decimals: 0.25 (15m), 0.5 (30m), 0.75 (45m).
Auth: API key or JWT (Trial+)
/rv/track-recordRolling AUC, Brier score, calibration stats, per-pair and per-horizon breakdowns, model metadata. This is the trust mechanism — available to all users.
Auth: Public (no auth required)
/rv/track-record/exportQuery param: ?format=json or ?format=csvFull scored outcomes as JSON or CSV. Every prediction, every outcome, every timestamp. For independent verification — pull this data, check it against any public candle source.
Auth: API key or JWT (Trial+)
/rv/modelCurrent model version, training dates, test AUC per horizon, feature count, training row count. Available to all users.
Auth: Public (no auth required)
Response Format
All responses are JSON. Timestamps are ISO 8601 UTC. Numeric values are floats rounded to 6 decimal places.
{
"generated_at": "2026-03-18T20:00:00+00:00",
"tier": "pro",
"pairs": 28,
"signals": [
{
"pair": "EURUSD",
"horizons": {
"1": {
"signal_ts": "2026-03-18T20:00:00",
"score": 0.142,
"calibrated_prob": 0.138,
"expected_move_pct": 0.00185,
"median_move_pct": 0.00142,
"p75_move_pct": 0.00258,
"p90_move_pct": 0.00401,
"threshold": 0.0012,
"confidence_tier": "normal",
"model_version": "lgbm_v2_20260318"
},
"4": { ... },
"8": { ... },
"24": { ... }
}
},
...
]
}{
"generated_at": "2026-03-18T20:00:00+00:00",
"total_signals": 5040,
"total_scored": 3200,
"pending": 1840,
"overall": {
"n_scored": 3200,
"auc_alltime": 0.721,
"brier_score": 0.0215,
"base_rate": 0.175
},
"by_horizon": [
{ "horizon_hours": 0.25, "n_scored": 400, "auc": 0.693 },
{ "horizon_hours": 1, "n_scored": 400, "auc": 0.714 },
// ... 9 more horizons (0.5, 0.75, 2, 3, 4, 6, 8, 12, 24)
],
"by_pair": [
{ "pair": "EURUSD", "n_scored": 120, "auc": 0.708 },
...
],
"model": {
"version": "lgbm_v2_20260318",
"trained_date": "2026-03-18",
"live_since": "2026-03-18T17:00:00"
}
}Signal Fields
| Field | Type | Description |
|---|---|---|
| score | float 0-1 | Raw model probability of a significant move |
| calibrated_prob | float 0-1 | Isotonic-calibrated true probability. When it says 0.30, ~30% of such predictions historically produced large moves. |
| expected_move_pct | float | Mean expected absolute return (percentage). E.g., 0.0025 = 0.25%. |
| median_move_pct | float | 50th percentile of the expected move distribution. |
| p75_move_pct | float | 75th percentile — moderate tail scenario. |
| p90_move_pct | float | 90th percentile — upper tail / stress scenario. |
| threshold | float | The move threshold for this horizon (e.g., 0.0025 for 4h). Moves exceeding this are "significant." |
| confidence_tier | string | Score classification: quiet (< 0.15), normal (0.15-0.30), elevated (0.30-0.50), high (> 0.50). |
Quick Start (Python)
import requests
API_KEY = "fxe_your_key_here"
BASE = "https://api.fxengineer.com"
# Get latest signals for all pairs
resp = requests.get(
f"{BASE}/rv/signals/latest",
headers={"X-API-Key": API_KEY}
)
data = resp.json()
# Note: sub-hourly horizons are keyed as decimals in the response
# "0.25" = 15m, "0.5" = 30m, "0.75" = 45m, "1" = 1h, etc.
for pair_data in data["signals"]:
pair = pair_data["pair"]
for horizon, signal in pair_data["horizons"].items():
score = signal["score"]
move = signal["expected_move_pct"]
h_label = {"0.25": "15m", "0.5": "30m", "0.75": "45m"}.get(horizon, f"{horizon}h")
if score > 0.30:
print(f"{pair} {h_label}: ELEVATED "
f"(score={score:.1%}, "
f"expected move={move:.4%})")# Track record (no auth needed)
resp = requests.get(f"{BASE}/rv/track-record")
tr = resp.json()
print(f"Total scored: {tr['total_scored']}")
print(f"Overall AUC: {tr['overall']['auc_alltime']}")
for h in tr["by_horizon"]:
print(f" {h['horizon_hours']}h: "
f"AUC={h['auc']}, n={h['n_scored']}")Error Codes
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Parse response body |
| 400 | Bad request — invalid pair, horizon, or parameter | Check request parameters |
| 401 | Invalid or missing API key / JWT | Verify your API key is correct and active |
| 403 | Insufficient tier — endpoint requires higher access | Upgrade subscription or check tier limits |
| 404 | Resource not found — no data for this pair/horizon | Verify pair name and horizon value |
| 429 | Rate limit exceeded | Back off and retry. Check X-RateLimit headers. |
| 500 | Internal server error | Retry after a few seconds. Contact support if persistent. |
Rate Limits
Rate limits are per API key. Limits are returned in response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1711029600If you exceed the limit, the API returns 429 Too Many Requests. Wait until the reset timestamp before retrying. Trial: 10 requests/minute. Pro: 100 requests/minute.
Polling guidance: Signals update hourly at :05 past. Sub-hourly signals update every 15 minutes. We recommend polling /rv/signals/latest no more than once per cycle.
Support
API questions: info@fxengineer.com