Skip to content

Known Limitations

The server supports two FIX sessions: TRADE (orders/positions) and QUOTE (real-time market data).

  • With QUOTE session enabled (default): get_quote returns live bid/ask prices with spread
  • Without QUOTE session: get_quote falls back to the last known fill price from recent trades
  • The response includes a staleness warning when data is older than the configured threshold
  • QUOTE session requires separate Price credentials from your broker (often same host/password, different port)

Tip: If you see stale prices, check ctrader://health to verify the QUOTE session state is ACTIVE.

FIX Symbol IDs are numeric identifiers assigned by each broker independently.

  • EURUSD might be ID 1 with one broker and ID 100 with another
  • Always verify Symbol IDs with your broker
  • You can find the Symbol ID in cTrader: Active Symbol Panel -> Symbol Info
  • Use get_symbols or the ctrader://symbols resource to query all configured symbols and their IDs

In paper mode:

  • All 8 risk checks run normally
  • Orders are validated and logged to the journal
  • No orders are sent to the broker
  • No actual fills, no real P&L
  • State is updated in-memory for simulation consistency

Paper mode is designed for testing strategy logic and risk configuration, not for realistic backtesting or paper trading with simulated fills.

After every FIX reconnection, the server performs state reconciliation:

  1. Requests current positions from the broker
  2. Receives the broker’s position snapshot
  3. Compares local state with broker state

During this period (typically 5-10 seconds):

  • Trading operations are blocked with RECONCILING error
  • The FIX session state shows RECONCILING
  • Wait for the state to transition to ACTIVE before trading

Auto-reconnect: The server automatically retries up to 10 times with exponential backoff (5s, 10s, 20s, … 60s max). If all attempts fail, use reconnect_trade_session or reconnect_quote_session to manually trigger a fresh connection.

The QUOTE session provides top-of-book bid/ask prices only:

  • No market depth (Level 2 / order book) data
  • No tick-by-tick trade history
  • Snapshot and incremental refresh updates only (not streaming ticks)
  • Market data is limited to symbols subscribed via subscribe_quotes or auto-subscribe

Daily PnL resets at 17:00 New York time (DST-adjusted; 22:00 UTC in winter, 21:00 UTC in summer) — the standard FX market rollover time.

  • This aligns with standard FX trading day conventions
  • The kill switch daily loss trigger also resets at this time
  • The reset timing is not configurable

Each session connects to one broker only:

  • TRADE and QUOTE sessions must be with the same broker
  • In multi-tenant mode, different users can connect to different brokers simultaneously
  • Each session is fully isolated with its own positions, risk limits, and journal

The server only tracks currently pending orders and open positions:

  • Filled orders are removed from active tracking
  • Cancelled orders are removed from active tracking
  • Historical order data is available only in the audit journal

When the server reconnects to the broker, the session starts fresh:

  • Message sequence numbers are not preserved across reconnections
  • Any messages sent by the broker while disconnected are not recovered
  • The server reconciles positions from the broker to ensure consistency

Position data in get_positions comes from local in-memory state, not a live broker query.

How local state is populated:

  • At logon: the server requests and receives the current position snapshot from the broker
  • During session: updated only by trade confirmations from MCP-initiated trades

When state may be stale:

  • Trades placed directly in cTrader UI or other tools are not reflected until reconnect
  • Switching between Claude chats: each new MCP connection reconciles fresh, but a long-running session does not auto-refresh after external platform activity

How to get fresh data: Use get_positions with refresh: true. This fetches fresh position data from the broker and repopulates the state before returning.

Use refresh: true when:

  • You have been trading directly in cTrader or another tool during this session
  • You are unsure whether position data reflects the current broker state
  • You switched context (different chat, tool restart) and the session has been active a while

Default (refresh: false) is sufficient when all trades were placed through this MCP server.

11. P&L Requires QUOTE Session for Currency Conversion

Section titled “11. P&L Requires QUOTE Session for Currency Conversion”

cTrader does not provide P&L data for open positions directly. This is a known limitation of the cTrader FIX API.

All P&L values are reported in USD. For non-USD-quoted instruments (e.g. USDJPY where P&L is natively in JPY), the server converts to USD using the live mid-price from the QUOTE session. Both the USD value and the raw quote-currency value are included in every response for transparency.

Result without QUOTE session: unrealizedPnL is 0, priceSource: "unavailable", and currency conversion is unavailable — check the pnlCurrency field (it shows “USD” when converted, or the raw quote currency like “JPY” when conversion is unavailable).

P&L response fields:

  • unrealizedPnL / realizedPnL — primary value in USD
  • unrealizedPnLRaw / realizedPnLRaw — original value in quote currency
  • quoteCurrency — instrument’s quote currency (e.g. “JPY”, “GBP”, “USD”)
  • pnlCurrency — “USD” when converted, quote currency when fallback
  • conversionRate — multiply-to-get-USD factor (rawPnL × conversionRate = usdPnL)

How P&L is calculated (when QUOTE session is active):

  • BUY position: unrealizedPnL = (bid − entryPrice) × volume → converted to USD
  • SELL position: unrealizedPnL = (entryPrice − ask) × volume → converted to USD

Recommended workflow for accurate P&L:

  1. Call get_positions to discover open position symbols
  2. Call get_quote for each unique symbol (warms the price cache)
  3. Call get_positions again → priceSource: "live_quote", accurate USD P&L

Check priceSource field on each position to know the data quality:

  • "live_quote" — calculated from current bid/ask (accurate)
  • "broker" — broker provided P&L data directly (rare for cTrader)
  • "unavailable" — no price in cache, P&L is 0

AI agents performing volume and price calculations can make mistakes that have real financial consequences. A single misplaced zero in a volume field means 10× the intended trade size.

Built-in safeguards:

  • Server instructions field: delivered to the AI agent at connection time via MCP protocol, instructs the agent to show calculations step-by-step and get user confirmation before trading
  • Tool annotations: trading tools are marked with destructiveHint: true and idempotentHint: false, signaling to MCP clients that these operations are irreversible
  • Input validation: volume must be a positive number (fractional allowed for instruments like BTCUSD), prices must be positive, symbols must match pattern
  • Risk guard: 8 automated checks including per-asset-class position size limits and daily loss limits

What the server CANNOT enforce:

  • Whether the agent computed the correct number of lots → units
  • Whether the agent picked the right side (BUY vs SELL)
  • Whether the user actually confirmed the trade parameters

Recommendation: Always verify the agent’s calculation before confirming a trade. Use paper mode for testing. Read order-guide topic for volume conversion formulas and examples.

13. HTTP Mode: SSRF Allowlist Restricts FIX Hosts

Section titled “13. HTTP Mode: SSRF Allowlist Restricts FIX Hosts”

In multi-tenant mode, only explicitly configured broker servers are allowed:

  • The FIX host must match a server in the dropdown on the OAuth form
  • Only standard FIX ports are accepted
  • Private/loopback IPs are always blocked

If your broker server is not in the dropdown, contact the server administrator to have it added.

14. HTTP Mode: FIX Session State Is In-Memory

Section titled “14. HTTP Mode: FIX Session State Is In-Memory”

Tenant FIX session state (positions, orders, daily P&L) is stored in memory. This means:

  • FIX state is rebuilt from the broker on each reconnection (positions will be re-reconciled automatically)
  • Daily P&L tracking starts fresh after a session restart

Your OAuth session persists — you don’t need to re-authorize after brief interruptions. Only the FIX session reconnects and reconciles.

The brute force lockout (5 failures → 15-min lockout) is enforced per server process. Server-side rate limiting provides additional IP-based throttling.

16. HTTP Mode: Guest Sessions Are Read-Only

Section titled “16. HTTP Mode: Guest Sessions Are Read-Only”

When connecting without credentials (before completing OAuth), the server creates a guest session:

  • Only 2 tools available: get_symbols and get_knowledge
  • All 12 resources are listed, but state resources (ctrader://positions, ctrader://orders, ctrader://health) return a “not_connected” stub with setup instructions
  • All 3 prompts work (especially useful: setup-guide)
  • No FIX connection, no trading, no state tracking

Guest mode lets AI agents discover the server’s capabilities and learn how to connect before providing credentials. Complete the OAuth flow to upgrade to a full trading session.

SL/TP orders are implemented as STOP and LIMIT orders linked to a position via positionId. The server implements OCO (One-Cancels-Other) logic: when a position closes (volume reaches 0), all pending orders linked to that positionId are automatically cancelled.

Best-effort: OCO cancellations may fail if the FIX session is disconnected or if an order has already been filled or cancelled. While failures are logged, they do not block execution processing. In rare cases, a linked order may remain active; use get_orders to verify status if necessary.

OAuth 2.1 requires HTTPS for all endpoints. The server requires HTTPS for all connections. OAuth will not work over plain HTTP.

The cTrader FIX API does not provide account balance, equity, or margin data. The server cannot report how much capital is in the account or calculate margin utilization.

Implications:

  • Risk management operates on position sizes and realized P&L only — not on equity-based metrics
  • Drawdown-from-peak and margin-based limits are not possible without balance data
  • The daily loss limit is based on realized losses, not unrealized equity changes

Workaround: Check your account balance directly in the cTrader platform or your broker’s web portal.

20. Trade History Only Tracks MCP-Initiated Closes

Section titled “20. Trade History Only Tracks MCP-Initiated Closes”

get_trade_history only records positions that were closed through this MCP server session. Trades closed via cTrader UI, another MCP chat, a different tool, or the broker’s mobile app are NOT captured — the server does not receive trade confirmations for trades initiated by other channels.

Workaround: After trading outside this server, call get_positions with refresh: true to reconcile positions from the broker. However, already-closed positions cannot be recovered into trade history — they are gone from broker state too.

The audit journal is likewise limited to events observed by this server process.

The cTrader broker enforces a strict one active FIX connection per SenderCompID rule. This means:

  • You cannot run two separate AI agent clients (e.g., Claude and Manus) on the same broker account simultaneously — the second connection will be rejected.
  • When re-authenticating, the server cannot open a validation probe while your session is active. The server handles this by skipping validation when your configuration hasn’t changed, or by closing the existing session first when it has.
  • Password changes create a different server-side identity. If you change your FIX password at the broker while a session is active, the server cannot find the old session to close it. Use reset_session before changing your password, or wait for the old session’s idle timeout.

To use multiple AI clients simultaneously, you need separate broker accounts (different SenderCompIDs).