Skip to Content
MT5 TraderAPI Reference

API Reference

All endpoints are served by FastAPI at 127.0.0.1:8000. Interactive OpenAPI docs are available at GET /docs. Signal endpoints require the X-API-Key header (compared in constant time); a missing or wrong key returns 401 and logs only whether a key was present.

Endpoints

Method & pathAuthPurpose
POST /v1/signalsX-API-KeyValidate and execute a signal (idempotent by signal_id).
GET /v1/signals/{signal_id}X-API-KeyRetrieve the durable stored state of a signal.
GET /v1/market-data/candlesX-API-KeyHistorical OHLC from the connected terminal (for consumers like LuxAlgo).
GET /health/livenoneLiveness — the process is running.
GET /health/readynoneReadiness — terminal connected and TRADING_ENABLED=true (else 503).

Submitting a signal

POST /v1/signals. Required fields: signal_id, occurred_at, execution_type, symbol, direction, volume, source. entry_price is required for limit and stop, and prohibited for market. Optional: stop_loss, take_profit, stop_loss_distance, take_profit_distance, expires_at, deviation_points, note, ignore_signal_age. Unknown fields are rejected (extra="forbid"), and timestamps must be timezone-aware.

FieldTypeNotes
signal_idstring (UUID)Idempotency key. Never reuse with changed fields.
occurred_atRFC 3339 datetimeWhen the signal fired; used for freshness checks.
execution_typemarket | limit | stopOrder type.
symbolstringExact, case-sensitive broker symbol (must be in ALLOWED_SYMBOLS).
directionbuy | sellTrade side.
volumedecimal stringLots; validated against the broker volume step and MAXIMUM_VOLUME.
sourcestring slugSignal provider; must be listed in ALLOWED_SIGNAL_SOURCES (default trading_central, autochartist, lux_algo, ipda). Written to the MT5 order comment for attribution.
entry_pricedecimal stringRequired for limit/stop, prohibited for market.
stop_loss, take_profitdecimal stringOptional absolute prices; validated for precision and stop distance.
stop_loss_distance, take_profit_distancedecimal stringOptional distances in price units (unsigned magnitude). Cannot be combined with the absolute field for the same leg.
expires_atRFC 3339 datetimeOptional expiry for pending orders.
deviation_pointsintegerOptional slippage cap (bounded by MAX_DEVIATION_POINTS).
notestringOptional free-text tag.
ignore_signal_agebooleanWhen true, skips the SIGNAL_MAX_AGE_SECONDS freshness check. Future-tolerance and expires_at are still enforced. Defaults to true.

Absolute vs distance-based risk levels

Each leg accepts either an absolute price or a distance in price units — not both. Distances are resolved against the execution reference price (live ask for buy, live bid for sell, or entry_price for pending orders); the service applies the direction sign. Prefer distances when the caller decided on a stop size rather than a level (spread and fill drift are known only here). Send absolute prices when the level itself is the intent (structural level, Supertrend line).

Example — market entry

{ "signal_id": "3a939594-f36e-4dc7-96a5-97e84e21c36e", "occurred_at": "2026-07-14T15:00:00Z", "execution_type": "market", "symbol": "EURUSD", "direction": "buy", "volume": "0.10", "stop_loss": "1.08000", "take_profit": "1.10000", "deviation_points": 10, "source": "trading_central", "note": "strategy-a breakout" }

Example — expiring pending (limit) entry

{ "signal_id": "c0c95e51-13d4-4567-b543-a0e41098f008", "occurred_at": "2026-07-14T15:00:00Z", "execution_type": "limit", "symbol": "EURUSD", "direction": "buy", "volume": "0.10", "entry_price": "1.08500", "expires_at": "2026-07-14T18:00:00Z" }

Example — client call (PowerShell)

$headers = @{ "X-API-Key" = $env:API_KEY } $body = Get-Content .\signal.json -Raw Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/v1/signals ` -Headers $headers -ContentType "application/json" -Body $body

Response statuses

A successful response reports one of these states, plus broker tickets and the normalized result:

StateMeaning
filledThe order was fully executed.
partially_filledThe order was partially executed.
placedA pending (limit/stop) order was accepted and is resting.

GET /v1/signals/{signal_id} returns the durable stored state, including terminal states like rejected and unknown.

Error codes

HTTPCodeWhen
401Missing or invalid X-API-Key.
409idempotency_conflictSame signal_id re-sent with a different payload.
409signal_in_progressThe same signal is still being processed.
422validation errorPayload failed Pydantic validation (bad/missing fields, wrong types).
422source_not_allowedsource is not in ALLOWED_SIGNAL_SOURCES.
422preflight_rejectedThe broker’s order_check() preflight returned a nonzero retcode.
503not readyReadiness failed — terminal disconnected or TRADING_ENABLED=false.
503execution_outcome_unknownorder_send() result is ambiguous. The order is not retried — a human must inspect.

Idempotency contract. Re-sending an identical payload for a completed signal_id replays the stored response (or re-raises the stored error) — it never places a second trade. Changing any field for an existing signal_id is a 409 idempotency_conflict.

Market-data candles

GET /v1/market-data/candles requires X-API-Key. Query parameters:

ParamDefaultNotes
quoterequiredExact symbol from ALLOWED_SYMBOLS (URL-encode spaces for Deriv indices)
timeframeM1One of M1, M5, M15, M30, H1, H4, D1
count500Most recent bars; capped by MAX_CANDLES_LOOKBACK

time is epoch seconds; volume is MT5 tick volume. LuxAlgo’s default DATA_QUOTE_PARAM / DATA_COUNT_PARAM already match this endpoint.

$headers = @{ "X-API-Key" = $env:API_KEY } Invoke-RestMethod -Uri "http://127.0.0.1:8000/v1/market-data/candles?quote=EURUSD&count=120" -Headers $headers # Deriv symbols with spaces: $quote = "Volatility 75 Index" $uri = "http://127.0.0.1:8001/v1/market-data/candles?quote=$([uri]::EscapeDataString($quote))&count=5" Invoke-RestMethod -Uri $uri -Headers $headers

See Architecture for how signal outcomes are produced and reconciled.

Last updated on