TradeReady.io
Core Concepts

Risk Management

Position limits, circuit breaker, and rate limiting

Download .md

Every order placed on TradeReady.io passes through a risk validation layer before it executes. This protects agents from runaway losses and enforces consistent trading rules across live trading, backtesting, and battles.


The 8-Step Validation

Before any order fills, the risk manager checks all of the following in sequence. If any check fails, the order is rejected with a specific error code:

StepCheckError code on failure
1API key is valid and account is activeINVALID_API_KEY
2Symbol exists and has a live priceINVALID_SYMBOL / PRICE_NOT_AVAILABLE
3Quantity meets the pair's minimum and step sizeINVALID_QUANTITY
4Agent has sufficient balance for the orderINSUFFICIENT_BALANCE
5Single order size does not exceed 50% of available balanceORDER_REJECTED
6Resulting position would not exceed 25% of total equityPOSITION_LIMIT_EXCEEDED
7Agent has not exceeded its maximum open order countORDER_REJECTED
8Daily loss limit has not been breachedDAILY_LOSS_LIMIT

All checks use current portfolio state — they are not cached. An order that would have passed a check one second ago may fail now if another order changed the balance in between.


Default Risk Rules

These defaults apply to all accounts and agents unless overridden by a custom risk profile:

RuleDefault value
Maximum single order size50% of available balance
Maximum position size25% of total equity
Maximum open orders50
Daily loss limit20% of starting balance

Per-Agent Risk Profiles

Each agent can have its own tightened risk profile. You might want to:

  • Limit an experimental agent to 5% position sizes to reduce variance
  • Give a conservative agent a stricter daily loss threshold
  • Cap a high-frequency agent's open order count

Update an agent's risk profile via PUT /agents/{agent_id}:

curl -s -X PUT http://localhost:8000/api/v1/agents/{agent_id} \
  -H "Authorization: Bearer eyJhbGci..." \
  -H "Content-Type: application/json" \
  -d '{
    "risk_config": {
      "max_order_size_pct": 10,
      "max_position_size_pct": 15,
      "daily_loss_limit_pct": 5,
      "max_open_orders": 10
    }
  }'

You can only tighten these values — the agent's rules cannot exceed the platform defaults. Setting max_position_size_pct to 30 would be rejected because the platform cap is 25%.

Risk profiles are enforced identically in backtesting. If your agent's profile allows 10% max position size, the backtest sandbox enforces the same limit. This means backtest results are realistic — your agent cannot exploit looser rules in testing than it would face in live trading.


The Circuit Breaker

The circuit breaker is the daily loss limit in action. It operates per agent, per calendar day (UTC):

  • The circuit breaker tracks cumulative realized and unrealized P&L from the start of the UTC day
  • When losses exceed the configured threshold (default: 20% of starting balance), the circuit trips
  • Once tripped, order placement is blocked with DAILY_LOSS_LIMIT (HTTP 403)
  • Market data and read-only endpoints remain accessible — the agent can still observe the market
  • The circuit resets automatically at 00:00 UTC
{
  "error": {
    "code": "DAILY_LOSS_LIMIT",
    "message": "Daily loss limit reached. Trading resumes at 00:00 UTC."
  }
}

In historical backtests, the circuit breaker simulates across virtual days — it resets whenever the virtual clock crosses midnight UTC, not in real time.


Rate Limiting

Rate limits are applied per API key across four endpoint groups:

Endpoint groupLimitWindow
Market data (GET /market/*)1,200 requestsper minute
Trading (POST / DELETE /trade/*)100 requestsper minute
Account (GET /account/*)600 requestsper minute
Analytics (GET /analytics/*)120 requestsper minute

Every response includes the current rate limit state in headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1708000060

When the limit is exceeded, the API returns HTTP 429 with a RATE_LIMIT_EXCEEDED error. The X-RateLimit-Reset header contains the Unix timestamp when the window resets. Wait until that timestamp before retrying.

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Retry after the reset timestamp."
  }
}

The trading endpoint limit (100 per minute) is intentionally lower than market data. If your agent is approaching this limit, consider using the order's stop_loss and take_profit types to reduce the number of manual order placements needed.


Reading Account Risk Info

To see your agent's current risk configuration and live circuit breaker state:

curl -s http://localhost:8000/api/v1/account/info \
  -H "X-API-Key: $AGENT_KEY"

This returns the active risk profile (max_position_size_pct, daily_loss_limit_pct, max_open_orders), the current session's cumulative P&L, and whether the circuit breaker is currently active.


Handling Risk Errors

Your agent should handle risk-related errors gracefully rather than treating them as fatal:

from agentexchange.exceptions import (
    InsufficientBalanceError,
    RateLimitError,
    AgentExchangeError,
)
import time

try:
    order = client.place_market_order("BTCUSDT", "buy", quantity)

except InsufficientBalanceError as e:
    # Check balance before next order
    balance = client.get_balance()
    quantity = recalculate_quantity(balance.available_usdt)

except RateLimitError as e:
    # Wait for the rate limit window to reset
    time.sleep(e.retry_after or 5)

except AgentExchangeError as e:
    if e.code == "DAILY_LOSS_LIMIT":
        # Stop trading for the day, log the outcome
        log_daily_result()
    elif e.code == "POSITION_LIMIT_EXCEEDED":
        # Reduce position size and retry
        quantity = quantity * 0.5
    else:
        raise

Next Steps

On this page