<!-- Generated from TradeReady.io docs. Visit https://tradeready.io/docs for the full experience. -->

---
title: Strategy Management
description: Create, version, test, deploy, and manage rule-based trading strategies through the REST API.
---

# 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
```

| Status | Description |
|--------|-------------|
| `draft` | Just created — definition may be incomplete |
| `testing` | A test run has been initiated |
| `validated` | At least one test run completed successfully |
| `deployed` | Actively running in live trading mode |
| `archived` | Soft-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.

```json
{
  "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:**

| Field | Type | Description |
|-------|------|-------------|
| `pairs` | string array | Trading pairs to monitor (e.g., `["BTCUSDT"]`) |
| `timeframe` | string | Candle interval: `"1m"`, `"5m"`, `"15m"`, `"1h"`, `"4h"`, or `"1d"` |
| `entry_conditions` | object | Map of condition keys to threshold values. **All** conditions must be true to open a position. |
| `exit_conditions` | object | Map of condition keys to threshold values. **Any** condition being true triggers an exit. |
| `position_size_pct` | number | Percentage of total equity to allocate per position (e.g., `10` = 10%) |
| `max_positions` | integer | Maximum simultaneous open positions |

### Entry Condition Keys

| Key | Value | Trigger |
|-----|-------|---------|
| `rsi_below` | number (0–100) | RSI-14 drops below threshold — oversold signal |
| `rsi_above` | number (0–100) | RSI-14 rises above threshold — overbought momentum |
| `macd_cross_above` | `true` | MACD line crosses above signal line — bullish |
| `macd_cross_below` | `true` | MACD line crosses below signal line — bearish entry |
| `price_above_sma` | integer (period) | Price is above the SMA of the given period |
| `price_below_sma` | integer (period) | Price is below the SMA of the given period |
| `price_above_ema` | integer (period) | Price is above the EMA of the given period |
| `price_below_ema` | integer (period) | Price is below the EMA of the given period |
| `bb_below_lower` | `true` | Price is below the lower Bollinger Band — mean-reversion buy |
| `bb_above_upper` | `true` | Price is above the upper Bollinger Band — breakout signal |
| `adx_above` | number | ADX exceeds threshold — trend is strong enough to trade |
| `volume_above_ma` | number (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.

| Key | Value | Trigger |
|-----|-------|---------|
| `stop_loss_pct` | number | Price drops this % below entry price |
| `take_profit_pct` | number | Price rises this % above entry price |
| `trailing_stop_pct` | number | Price drops this % below the highest price seen since entry |
| `max_hold_candles` | integer | Exit after holding for this many candles regardless of price |
| `rsi_above` | number (0–100) | RSI-14 rises above threshold — overbought exit |
| `rsi_below` | number (0–100) | RSI-14 falls below threshold — momentum lost |
| `macd_cross_below` | `true` | MACD 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:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Strategy name (1–200 characters) |
| `description` | string | No | Human-readable description (max 2,000 characters) |
| `definition` | object | Yes | Strategy definition JSON (see schema above) |

**Example Request:**

**curl:**

```bash
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
    }
  }'
```
**Python SDK:**

```python
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:**

```json
{
  "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:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `status` | string | No | — | Filter by status: `"draft"`, `"testing"`, `"validated"`, `"deployed"`, `"archived"` |
| `limit` | integer | No | `50` | Page size (1–100) |
| `offset` | integer | No | `0` | Pagination offset |

**Example Request:**

**curl:**

```bash
# 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_..."
```
**Python SDK:**

```python
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:**

```json
{
  "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:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `strategy_id` | UUID | Strategy identifier |

**Example Request:**

**curl:**

```bash
curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890 \
  -H "X-API-Key: ak_live_..."
```
**Python SDK:**

```python
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:**

```json
{
  "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):**

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | New strategy name (1–200 characters) |
| `description` | string | New description (max 2,000 characters) |

**Example Request:**

**curl:**

```bash
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"}'
```
**Python SDK:**

```python
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"`.

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

**Authentication:** API Key or JWT

**Example Request:**

**curl:**

```bash
curl -X DELETE \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890 \
  -H "X-API-Key: ak_live_..."
```
**Python SDK:**

```python
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:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `definition` | object | Yes | Updated strategy definition JSON |
| `change_notes` | string | No | Description of what changed (max 2,000 characters) |

**Example Request:**

**curl:**

```bash
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"
  }'
```
**Python SDK:**

```python
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:**

```json
{
  "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:**

```bash
curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions \
  -H "X-API-Key: ak_live_..."
```
**Python SDK:**

```python
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:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `strategy_id` | UUID | Strategy identifier |
| `version` | integer | Version number (e.g., `1`, `2`) |

**Example Request:**

**curl:**

```bash
curl https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/versions/1 \
  -H "X-API-Key: ak_live_..."
```
**Python SDK:**

```python
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:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | integer | Yes | Version number to deploy (must be ≥ 1) |

**Example Request:**

**curl:**

```bash
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}'
```
**Python SDK:**

```python
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:**

```bash
curl -X POST \
  https://api.tradeready.io/api/v1/strategies/s1a2b3c4-d5e6-7890-abcd-ef1234567890/undeploy \
  -H "X-API-Key: ak_live_..."
```
**Python SDK:**

```python
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:

```python
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](/docs/api/strategy-testing).
