Strategy Management
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.
{
"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 -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:
| 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:
# 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:
| Parameter | Type | Description |
|---|---|---|
strategy_id | UUID | Strategy 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):
| Field | Type | Description |
|---|---|---|
name | string | New strategy name (1–200 characters) |
description | string | New 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:
| 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 -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:
| Parameter | Type | Description |
|---|---|---|
strategy_id | UUID | Strategy identifier |
version | integer | Version 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:
| Field | Type | Required | Description |
|---|---|---|---|
version | integer | Yes | Version 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 timestampReturns 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.