TradeReady.io
REST API

Strategy Management

Create, version, test, deploy, and manage rule-based trading strategies through the REST API.

Download .md

Strategy Management

The strategy system lets you define rule-based trading strategies as JSON, run them against historical data across multiple episodes, iterate on the definition, and deploy the best version to live trading status.

All strategy endpoints require authentication via X-API-Key or Authorization: Bearer.


Strategy Lifecycle

Strategies move through the following status progression:

draft → testing → validated → deployed

            archived
StatusDescription
draftJust created — definition may be incomplete
testingA test run has been initiated
validatedAt least one test run completed successfully
deployedActively running in live trading mode
archivedSoft-deleted — data preserved but strategy is inactive

A deployed strategy must be undeployed before it can be archived.


Strategy Definition Schema

The definition object is the core of every strategy. It specifies which pairs to trade, on what timeframe, and the exact conditions for entering and exiting positions.

{
  "pairs": ["BTCUSDT", "ETHUSDT"],
  "timeframe": "1h",
  "entry_conditions": {
    "rsi_below": 35,
    "macd_cross_above": true,
    "adx_above": 20
  },
  "exit_conditions": {
    "take_profit_pct": 5,
    "stop_loss_pct": 2,
    "trailing_stop_pct": 3,
    "max_hold_candles": 72
  },
  "position_size_pct": 10,
  "max_positions": 3
}

Top-level fields:

FieldTypeDescription
pairsstring arrayTrading pairs to monitor (e.g., ["BTCUSDT"])
timeframestringCandle interval: "1m", "5m", "15m", "1h", "4h", or "1d"
entry_conditionsobjectMap of condition keys to threshold values. All conditions must be true to open a position.
exit_conditionsobjectMap of condition keys to threshold values. Any condition being true triggers an exit.
position_size_pctnumberPercentage of total equity to allocate per position (e.g., 10 = 10%)
max_positionsintegerMaximum simultaneous open positions

Entry Condition Keys

KeyValueTrigger
rsi_belownumber (0–100)RSI-14 drops below threshold — oversold signal
rsi_abovenumber (0–100)RSI-14 rises above threshold — overbought momentum
macd_cross_abovetrueMACD line crosses above signal line — bullish
macd_cross_belowtrueMACD line crosses below signal line — bearish entry
price_above_smainteger (period)Price is above the SMA of the given period
price_below_smainteger (period)Price is below the SMA of the given period
price_above_emainteger (period)Price is above the EMA of the given period
price_below_emainteger (period)Price is below the EMA of the given period
bb_below_lowertruePrice is below the lower Bollinger Band — mean-reversion buy
bb_above_uppertruePrice is above the upper Bollinger Band — breakout signal
adx_abovenumberADX exceeds threshold — trend is strong enough to trade
volume_above_manumber (multiplier)Volume exceeds volume_ma_20 × multiplier — confirms momentum

Exit Condition Keys

Any single exit condition being true triggers a full market sell of the position.

KeyValueTrigger
stop_loss_pctnumberPrice drops this % below entry price
take_profit_pctnumberPrice rises this % above entry price
trailing_stop_pctnumberPrice drops this % below the highest price seen since entry
max_hold_candlesintegerExit after holding for this many candles regardless of price
rsi_abovenumber (0–100)RSI-14 rises above threshold — overbought exit
rsi_belownumber (0–100)RSI-14 falls below threshold — momentum lost
macd_cross_belowtrueMACD crosses below signal line — bearish signal

Create Strategy

POST /api/v1/strategies

Create a new strategy. The first version (version 1) is created automatically with the provided definition.

Authentication: API Key or JWT

Request Body:

FieldTypeRequiredDescription
namestringYesStrategy name (1–200 characters)
descriptionstringNoHuman-readable description (max 2,000 characters)
definitionobjectYesStrategy definition JSON (see schema above)

Example Request:

curl -X POST https://api.tradeready.io/api/v1/strategies \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_..." \
  -d '{
    "name": "BTC RSI Scalper",
    "description": "Buy oversold BTC on 1h timeframe, exit on recovery or stop",
    "definition": {
      "pairs": ["BTCUSDT"],
      "timeframe": "1h",
      "entry_conditions": {
        "rsi_below": 30,
        "adx_above": 20
      },
      "exit_conditions": {
        "take_profit_pct": 5,
        "stop_loss_pct": 2,
        "max_hold_candles": 48
      },
      "position_size_pct": 10,
      "max_positions": 3
    }
  }'
from agentexchange import AgentExchangeClient

client = AgentExchangeClient(api_key="ak_live_...")

# Use the raw HTTP client for strategy endpoints
import httpx

response = httpx.post(
    "https://api.tradeready.io/api/v1/strategies",
    headers={"X-API-Key": "ak_live_..."},
    json={
        "name": "BTC RSI Scalper",
        "description": "Buy oversold BTC on 1h timeframe",
        "definition": {
            "pairs": ["BTCUSDT"],
            "timeframe": "1h",
            "entry_conditions": {"rsi_below": 30, "adx_above": 20},
            "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2},
            "position_size_pct": 10,
            "max_positions": 3,
        },
    },
)
strategy = response.json()
strategy_id = strategy["strategy_id"]
print(f"Created strategy: {strategy_id}")

Example Response — HTTP 201:

{
  "strategy_id": "s1a2b3c4-d5e6-7890-abcd-ef1234567890",
  "name": "BTC RSI Scalper",
  "description": "Buy oversold BTC on 1h timeframe, exit on recovery or stop",
  "current_version": 1,
  "status": "draft",
  "deployed_at": null,
  "created_at": "2026-03-19T10:00:00Z",
  "updated_at": "2026-03-19T10:00:00Z"
}

List Strategies

GET /api/v1/strategies

List all strategies for the authenticated account.

Authentication: API Key or JWT

Query Parameters:

ParameterTypeRequiredDefaultDescription
statusstringNoFilter by status: "draft", "testing", "validated", "deployed", "archived"
limitintegerNo50Page size (1–100)
offsetintegerNo0Pagination offset

Example Request:

# All deployed strategies
curl "https://api.tradeready.io/api/v1/strategies?status=deployed" \
  -H "X-API-Key: ak_live_..."

# All strategies, paginated
curl "https://api.tradeready.io/api/v1/strategies?limit=20&offset=0" \
  -H "X-API-Key: ak_live_..."
import httpx

response = httpx.get(
    "https://api.tradeready.io/api/v1/strategies",
    headers={"X-API-Key": "ak_live_..."},
    params={"status": "deployed"},
)
strategies = response.json()["strategies"]

Example Response:

{
  "strategies": [
    {
      "strategy_id": "s1a2b3c4-d5e6-7890-abcd-ef1234567890",
      "name": "BTC RSI Scalper",
      "description": "Buy oversold BTC on 1h timeframe",
      "current_version": 2,
      "status": "deployed",
      "deployed_at": "2026-03-19T11:00:00Z",
      "created_at": "2026-03-19T10:00:00Z",
      "updated_at": "2026-03-19T11:00:00Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

Get Strategy Detail

GET /api/v1/strategies/{strategy_id}

Get full strategy detail including the current version's definition and latest test results.

Authentication: API Key or JWT

Path Parameters:

ParameterTypeDescription
strategy_idUUIDStrategy identifier

Example Request:

curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890 \
  -H "X-API-Key: ak_live_..."
import httpx

response = httpx.get(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890",
    headers={"X-API-Key": "ak_live_..."},
)
detail = response.json()
print(detail["current_definition"])
print(detail["latest_test_results"])

Example Response:

{
  "strategy_id": "s1a2b3c4-d5e6-7890-abcd-ef1234567890",
  "name": "BTC RSI Scalper",
  "description": "Buy oversold BTC on 1h timeframe",
  "current_version": 2,
  "status": "validated",
  "deployed_at": null,
  "created_at": "2026-03-19T10:00:00Z",
  "updated_at": "2026-03-19T10:30:00Z",
  "current_definition": {
    "pairs": ["BTCUSDT"],
    "timeframe": "1h",
    "entry_conditions": {"rsi_below": 35, "adx_above": 20},
    "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2},
    "position_size_pct": 10,
    "max_positions": 3
  },
  "latest_test_results": {
    "avg_roi_pct": 4.8,
    "avg_sharpe": 1.12,
    "avg_max_drawdown_pct": 6.8,
    "win_rate_pct": 68.5,
    "total_trades": 98,
    "episodes_completed": 20
  }
}

latest_test_results is null if no test runs have been completed for this strategy.


Update Strategy

PUT /api/v1/strategies/{strategy_id}

Update strategy metadata (name and/or description). This does not change the definition — use POST /{id}/versions to create an updated definition.

Authentication: API Key or JWT

Request Body (all fields optional):

FieldTypeDescription
namestringNew strategy name (1–200 characters)
descriptionstringNew description (max 2,000 characters)

Example Request:

curl -X PUT https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890 \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_..." \
  -d '{"name": "BTC RSI Scalper v2", "description": "Tuned RSI threshold to 35"}'
import httpx

httpx.put(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890",
    headers={"X-API-Key": "ak_live_..."},
    json={"name": "BTC RSI Scalper v2"},
)

Returns the updated StrategyResponse.


Archive Strategy

DELETE /api/v1/strategies/{strategy_id}

Archive a strategy (soft delete). The strategy and all its versions remain in the database but the status changes to "archived".

A deployed strategy must be undeployed first (POST /{id}/undeploy) before it can be archived.

Authentication: API Key or JWT

Example Request:

curl -X DELETE \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890 \
  -H "X-API-Key: ak_live_..."
import httpx

httpx.delete(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890",
    headers={"X-API-Key": "ak_live_..."},
)

Returns the updated StrategyResponse with status: "archived".


Create New Version

POST /api/v1/strategies/{strategy_id}/versions

Create a new version of a strategy with an updated definition. The version number is auto-incremented and becomes the new current_version. The old version is preserved.

Authentication: API Key or JWT

Request Body:

FieldTypeRequiredDescription
definitionobjectYesUpdated strategy definition JSON
change_notesstringNoDescription of what changed (max 2,000 characters)

Example Request:

curl -X POST \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_..." \
  -d '{
    "definition": {
      "pairs": ["BTCUSDT", "ETHUSDT"],
      "timeframe": "1h",
      "entry_conditions": {
        "rsi_below": 35,
        "adx_above": 20
      },
      "exit_conditions": {
        "take_profit_pct": 5,
        "stop_loss_pct": 2,
        "trailing_stop_pct": 3
      },
      "position_size_pct": 10,
      "max_positions": 3
    },
    "change_notes": "Added ETHUSDT to pairs list; loosened RSI threshold from 30 to 35; added trailing stop"
  }'
import httpx

response = httpx.post(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions",
    headers={"X-API-Key": "ak_live_..."},
    json={
        "definition": {
            "pairs": ["BTCUSDT", "ETHUSDT"],
            "timeframe": "1h",
            "entry_conditions": {"rsi_below": 35, "adx_above": 20},
            "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2, "trailing_stop_pct": 3},
            "position_size_pct": 10,
            "max_positions": 3,
        },
        "change_notes": "Loosened RSI threshold; added trailing stop",
    },
)
version = response.json()
print(f"Created version {version['version']}")

Example Response — HTTP 201:

{
  "version_id": "v2b3c4d5-e6f7-8901-bcde-f23456789012",
  "strategy_id": "s1a2b3c4-d5e6-7890-abcd-ef1234567890",
  "version": 2,
  "definition": {
    "pairs": ["BTCUSDT", "ETHUSDT"],
    "timeframe": "1h",
    "entry_conditions": {"rsi_below": 35, "adx_above": 20},
    "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2, "trailing_stop_pct": 3},
    "position_size_pct": 10,
    "max_positions": 3
  },
  "change_notes": "Loosened RSI threshold; added trailing stop",
  "parent_version": 1,
  "status": "draft",
  "created_at": "2026-03-19T10:30:00Z"
}

List Versions

GET /api/v1/strategies/{strategy_id}/versions

List all versions of a strategy in descending order (newest first).

Authentication: API Key or JWT

Example Request:

curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions \
  -H "X-API-Key: ak_live_..."
import httpx

response = httpx.get(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions",
    headers={"X-API-Key": "ak_live_..."},
)
versions = response.json()
for v in versions:
    print(f"v{v['version']}: {v['change_notes']}")

Returns an array of StrategyVersionResponse objects.


Get Specific Version

GET /api/v1/strategies/{strategy_id}/versions/{version}

Get a specific version by version number.

Authentication: API Key or JWT

Path Parameters:

ParameterTypeDescription
strategy_idUUIDStrategy identifier
versionintegerVersion number (e.g., 1, 2)

Example Request:

curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions/1 \
  -H "X-API-Key: ak_live_..."
import httpx

response = httpx.get(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions/1",
    headers={"X-API-Key": "ak_live_..."},
)
v1 = response.json()
print(v1["definition"]["entry_conditions"])

Returns a single StrategyVersionResponse.


Deploy Strategy

POST /api/v1/strategies/{strategy_id}/deploy

Deploy a specific version to live trading status. Sets status to "deployed" and records deployed_at.

Authentication: API Key or JWT

Request Body:

FieldTypeRequiredDescription
versionintegerYesVersion number to deploy (must be ≥ 1)

Example Request:

curl -X POST \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/deploy \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_..." \
  -d '{"version": 2}'
import httpx

response = httpx.post(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/deploy",
    headers={"X-API-Key": "ak_live_..."},
    json={"version": 2},
)
strategy = response.json()
print(strategy["status"])      # "deployed"
print(strategy["deployed_at"]) # ISO timestamp

Returns the updated StrategyResponse with status: "deployed" and deployed_at set.


Undeploy Strategy

POST /api/v1/strategies/{strategy_id}/undeploy

Stop a deployed strategy. Sets status back to "validated".

Authentication: API Key or JWT

Request Body: None

Example Request:

curl -X POST \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/undeploy \
  -H "X-API-Key: ak_live_..."
import httpx

response = httpx.post(
    "https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/undeploy",
    headers={"X-API-Key": "ak_live_..."},
)
strategy = response.json()
print(strategy["status"])  # "validated"

Returns the updated StrategyResponse with status: "validated".


Full Development Workflow

The recommended strategy development loop:

import httpx

BASE = "https://api.tradeready.io/api/v1"
HEADERS = {"X-API-Key": "ak_live_..."}

# 1. Create the strategy
r = httpx.post(f"{BASE}/strategies", headers=HEADERS, json={
    "name": "BTC RSI Scalper",
    "definition": {
        "pairs": ["BTCUSDT"],
        "timeframe": "1h",
        "entry_conditions": {"rsi_below": 30},
        "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2},
        "position_size_pct": 10,
        "max_positions": 3,
    },
})
strategy_id = r.json()["strategy_id"]

# 2. Run a test across 20 episodes
r = httpx.post(f"{BASE}/strategies/{strategy_id}/test", headers=HEADERS, json={
    "version": 1,
    "episodes": 20,
    "date_range": {"start": "2025-01-01T00:00:00Z", "end": "2025-12-31T00:00:00Z"},
    "episode_duration_days": 30,
    "starting_balance": "10000",
})
test_run_id = r.json()["test_run_id"]

# 3. Poll for results
import time
while True:
    r = httpx.get(f"{BASE}/strategies/{strategy_id}/tests/{test_run_id}", headers=HEADERS)
    result = r.json()
    if result["status"] == "completed":
        print(result["results"])
        break
    time.sleep(5)

# 4. Create an improved version
r = httpx.post(f"{BASE}/strategies/{strategy_id}/versions", headers=HEADERS, json={
    "definition": {
        "pairs": ["BTCUSDT"],
        "timeframe": "1h",
        "entry_conditions": {"rsi_below": 35, "adx_above": 20},  # tuned
        "exit_conditions": {"take_profit_pct": 5, "stop_loss_pct": 2, "trailing_stop_pct": 3},
        "position_size_pct": 10,
        "max_positions": 3,
    },
    "change_notes": "Loosened RSI entry; added ADX filter; added trailing stop",
})

# 5. Deploy the best version
httpx.post(f"{BASE}/strategies/{strategy_id}/deploy", headers=HEADERS, json={"version": 2})

For running and evaluating test episodes, see Strategy Testing.

On this page