Portfolio Backtest API
The Stratium Portfolio Backtest API lets you simulate copy-trading portfolios across historical data for any combination of tracked Solana wallets, with configurable capital allocation, trade sizing modes (FIXED_SIZE or PERCENTAGE), slippage modeling in basis points, and multi-wallet strategy comparison across up to 10 configurations.
Quick Start
# Submit a backtest
curl -X POST "https://api.stratiumsol.com/v1/backtest/run" \
-H "X-API-Key: sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"wallets": [
{ "address": "7xKXLkq...9bPq", "allocation": 0.6, "slippageBps": 50 },
{ "address": "4mNpT2k...3vRw", "allocation": 0.4, "slippageBps": 50 }
],
"capital": { "solAmount": 100 },
"period": { "start": "2026-01-01", "end": "2026-04-01" },
"sizing": { "mode": "PERCENTAGE", "positionCapPercent": 5 }
}'
# Poll for results
curl "https://api.stratiumsol.com/v1/backtest/bt_abc123" \
-H "X-API-Key: sk_live_your_key"const API_KEY = process.env.STRATIUM_API_KEY!;
const BASE = "https://api.stratiumsol.com/v1";
const headers = { "X-API-Key": API_KEY, "Content-Type": "application/json" };
// Submit backtest
const { data: job } = await fetch(`${BASE}/backtest/run`, {
method: "POST",
headers,
body: JSON.stringify({
wallets: [
{ address: "7xKXLkq...9bPq", allocation: 0.6, slippageBps: 50 },
{ address: "4mNpT2k...3vRw", allocation: 0.4, slippageBps: 50 },
],
capital: { solAmount: 100 },
period: { start: "2026-01-01", end: "2026-04-01" },
sizing: { mode: "PERCENTAGE", positionCapPercent: 5 },
}),
}).then((r) => r.json());
// Poll until complete
let result;
do {
await new Promise((r) => setTimeout(r, 2000));
result = await fetch(`${BASE}/backtest/${job.backtest_id}`, { headers })
.then((r) => r.json());
} while (result.data.status === "running");
console.log(`ROI: ${result.data.roi_percent}%`);import os, time, requests
API_KEY = os.environ["STRATIUM_API_KEY"]
BASE = "https://api.stratiumsol.com/v1"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# Submit backtest
job = requests.post(f"{BASE}/backtest/run", headers=HEADERS, json={
"wallets": [
{"address": "7xKXLkq...9bPq", "allocation": 0.6, "slippageBps": 50},
{"address": "4mNpT2k...3vRw", "allocation": 0.4, "slippageBps": 50},
],
"capital": {"solAmount": 100},
"period": {"start": "2026-01-01", "end": "2026-04-01"},
"sizing": {"mode": "PERCENTAGE", "positionCapPercent": 5},
}).json()
# Poll until complete
while True:
result = requests.get(f"{BASE}/backtest/{job['data']['backtest_id']}", headers=HEADERS).json()
if result["data"]["status"] != "running":
break
time.sleep(2)
print(f"ROI: {result['data']['roi_percent']}%")# Submit a backtest
curl -X POST "https://api.stratiumsol.com/v1/backtest/run" \
-H "X-API-Key: sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"wallets": [
{ "address": "7xKXLkq...9bPq", "allocation": 0.6, "slippageBps": 50 },
{ "address": "4mNpT2k...3vRw", "allocation": 0.4, "slippageBps": 50 }
],
"capital": { "solAmount": 100 },
"period": { "start": "2026-01-01", "end": "2026-04-01" },
"sizing": { "mode": "PERCENTAGE", "positionCapPercent": 5 }
}'
# Poll for results
curl "https://api.stratiumsol.com/v1/backtest/bt_abc123" \
-H "X-API-Key: sk_live_your_key"const API_KEY = process.env.STRATIUM_API_KEY!;
const BASE = "https://api.stratiumsol.com/v1";
const headers = { "X-API-Key": API_KEY, "Content-Type": "application/json" };
// Submit backtest
const { data: job } = await fetch(`${BASE}/backtest/run`, {
method: "POST",
headers,
body: JSON.stringify({
wallets: [
{ address: "7xKXLkq...9bPq", allocation: 0.6, slippageBps: 50 },
{ address: "4mNpT2k...3vRw", allocation: 0.4, slippageBps: 50 },
],
capital: { solAmount: 100 },
period: { start: "2026-01-01", end: "2026-04-01" },
sizing: { mode: "PERCENTAGE", positionCapPercent: 5 },
}),
}).then((r) => r.json());
// Poll until complete
let result;
do {
await new Promise((r) => setTimeout(r, 2000));
result = await fetch(`${BASE}/backtest/${job.backtest_id}`, { headers })
.then((r) => r.json());
} while (result.data.status === "running");
console.log(`ROI: ${result.data.roi_percent}%`);import os, time, requests
API_KEY = os.environ["STRATIUM_API_KEY"]
BASE = "https://api.stratiumsol.com/v1"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# Submit backtest
job = requests.post(f"{BASE}/backtest/run", headers=HEADERS, json={
"wallets": [
{"address": "7xKXLkq...9bPq", "allocation": 0.6, "slippageBps": 50},
{"address": "4mNpT2k...3vRw", "allocation": 0.4, "slippageBps": 50},
],
"capital": {"solAmount": 100},
"period": {"start": "2026-01-01", "end": "2026-04-01"},
"sizing": {"mode": "PERCENTAGE", "positionCapPercent": 5},
}).json()
# Poll until complete
while True:
result = requests.get(f"{BASE}/backtest/{job['data']['backtest_id']}", headers=HEADERS).json()
if result["data"]["status"] != "running":
break
time.sleep(2)
print(f"ROI: {result['data']['roi_percent']}%")Endpoints
/api/v1/backtest/runSubmit a new backtest simulation. Returns a backtest_id for polling results.
/api/v1/backtest/{id}/progressPoll backtest execution progress. Returns status and progress_percent (0-100).
/api/v1/backtest/{id}Retrieve completed backtest results with full performance metrics.
/api/v1/backtest/{id}/stepsPaginated FIFO calculation steps for the simulated portfolio. Same schema as PnL Analytics steps.
/api/v1/backtest/compareCompare up to 10 strategy configurations side by side with normalized metrics.
/api/v1/backtest/available-walletsList wallets with sufficient historical data for backtesting in a given time period.
Request Body
POST /api/v1/backtest/run
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
wallets | array | Required | — | Array of wallet configs: { address, allocation (0-1), slippageBps (0-1000) } |
capital.solAmount | number | Required | — | Starting capital in SOL |
period.start | string | Required | — | Backtest start date (ISO 8601 or YYYY-MM-DD) |
period.end | string | Required | — | Backtest end date (ISO 8601 or YYYY-MM-DD) |
sizing.mode | string | Required | — | Trade sizing: FIXED_SIZE or PERCENTAGE |
sizing.fixedAmountSol | number | Optional | — | SOL per trade (when mode = FIXED_SIZE) |
sizing.positionCapPercent | number | Optional | 5 | Max % of capital per position (when mode = PERCENTAGE) |
interface BacktestRequest {
wallets: Array<{
address: string; // Solana wallet address
allocation: number; // Capital allocation weight (0-1)
slippageBps: number; // Simulated slippage in basis points
}>;
capital: {
solAmount: number; // Starting capital in SOL
};
period: {
start: string; // ISO 8601 or YYYY-MM-DD
end: string; // ISO 8601 or YYYY-MM-DD
};
sizing: {
mode: "FIXED_SIZE" // Fixed SOL amount per trade
| "PERCENTAGE"; // Percentage of current capital
fixedAmountSol?: number; // Required for FIXED_SIZE
positionCapPercent?: number; // Max % per position (PERCENTAGE)
};
}interface BacktestRequest {
wallets: Array<{
address: string; // Solana wallet address
allocation: number; // Capital allocation weight (0-1)
slippageBps: number; // Simulated slippage in basis points
}>;
capital: {
solAmount: number; // Starting capital in SOL
};
period: {
start: string; // ISO 8601 or YYYY-MM-DD
end: string; // ISO 8601 or YYYY-MM-DD
};
sizing: {
mode: "FIXED_SIZE" // Fixed SOL amount per trade
| "PERCENTAGE"; // Percentage of current capital
fixedAmountSol?: number; // Required for FIXED_SIZE
positionCapPercent?: number; // Max % per position (PERCENTAGE)
};
}POST /api/v1/backtest/compare
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
strategies | array | Required | — | Array of up to 10 backtest configurations to compare side by side |
normalize | boolean | Optional | true | Normalize all strategies to the same starting capital for fair comparison |
Query Parameters
GET /api/v1/backtest/{id}/steps
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit | integer | Optional | 50 | Results per page (max 200) |
offset | integer | Optional | 0 | Pagination offset |
action | string | Optional | — | Filter by trade action: BUY or SELL |
token_mint | string | Optional | — | Filter by specific token mint address |
GET /api/v1/backtest/available-wallets
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period_start | string | Optional | — | Filter wallets with data starting from this date |
period_end | string | Optional | — | Filter wallets with data up to this date |
min_trades | integer | Optional | 10 | Minimum trade count in the period |
limit | integer | Optional | 50 | Results per page |
offset | integer | Optional | 0 | Pagination offset |
Response Schema
interface BacktestResult {
backtest_id: string; // Unique identifier (bt_*)
status: "pending" | "running"
| "completed" | "failed";
progress_percent: number; // 0-100 during execution
wallets: string[]; // Input wallet addresses
capital_sol: number; // Starting capital
period_start: string; // ISO 8601
period_end: string; // ISO 8601
sizing_mode: string; // FIXED_SIZE | PERCENTAGE
total_trades: number; // Trades simulated
successful_trades: number;
failed_trades: number;
final_pnl_sol: number; // Cumulative realized PnL
roi_percent: number; // PnL / max_capital_deployed
roi_annualized_percent: number; // Annualized ROI
max_capital_deployed_sol: number; // Peak capital in positions
max_drawdown_percent: number; // Worst peak-to-trough
win_rate_percent: number; // % profitable sells
profit_factor: number; // Gross profit / gross loss
sharpe_ratio: number; // Risk-adjusted return
best_trade_pnl_sol: number;
worst_trade_pnl_sol: number;
median_trade_pnl_sol: number;
created_at: string; // ISO 8601
completed_at: string | null; // ISO 8601
}{
"success": true,
"data": {
"backtest_id": "bt_abc123",
"status": "completed",
"progress_percent": 100,
"wallets": ["7xKXLkq...9bPq", "4mNpT2k...3vRw"],
"capital_sol": 100,
"period_start": "2026-01-01T00:00:00Z",
"period_end": "2026-04-01T00:00:00Z",
"sizing_mode": "PERCENTAGE",
"total_trades": 342,
"successful_trades": 338,
"failed_trades": 4,
"final_pnl_sol": 28.4,
"roi_percent": 22.1,
"roi_annualized_percent": 88.4,
"max_capital_deployed_sol": 128.5,
"max_drawdown_percent": 8.2,
"win_rate_percent": 68.4,
"profit_factor": 2.84,
"sharpe_ratio": 1.42,
"best_trade_pnl_sol": 12.6,
"worst_trade_pnl_sol": -3.2,
"median_trade_pnl_sol": 0.08,
"created_at": "2026-04-14T12:00:00Z",
"completed_at": "2026-04-14T12:00:32Z"
},
"timestamp": "2026-04-14T12:01:00Z"
}interface BacktestResult {
backtest_id: string; // Unique identifier (bt_*)
status: "pending" | "running"
| "completed" | "failed";
progress_percent: number; // 0-100 during execution
wallets: string[]; // Input wallet addresses
capital_sol: number; // Starting capital
period_start: string; // ISO 8601
period_end: string; // ISO 8601
sizing_mode: string; // FIXED_SIZE | PERCENTAGE
total_trades: number; // Trades simulated
successful_trades: number;
failed_trades: number;
final_pnl_sol: number; // Cumulative realized PnL
roi_percent: number; // PnL / max_capital_deployed
roi_annualized_percent: number; // Annualized ROI
max_capital_deployed_sol: number; // Peak capital in positions
max_drawdown_percent: number; // Worst peak-to-trough
win_rate_percent: number; // % profitable sells
profit_factor: number; // Gross profit / gross loss
sharpe_ratio: number; // Risk-adjusted return
best_trade_pnl_sol: number;
worst_trade_pnl_sol: number;
median_trade_pnl_sol: number;
created_at: string; // ISO 8601
completed_at: string | null; // ISO 8601
}{
"success": true,
"data": {
"backtest_id": "bt_abc123",
"status": "completed",
"progress_percent": 100,
"wallets": ["7xKXLkq...9bPq", "4mNpT2k...3vRw"],
"capital_sol": 100,
"period_start": "2026-01-01T00:00:00Z",
"period_end": "2026-04-01T00:00:00Z",
"sizing_mode": "PERCENTAGE",
"total_trades": 342,
"successful_trades": 338,
"failed_trades": 4,
"final_pnl_sol": 28.4,
"roi_percent": 22.1,
"roi_annualized_percent": 88.4,
"max_capital_deployed_sol": 128.5,
"max_drawdown_percent": 8.2,
"win_rate_percent": 68.4,
"profit_factor": 2.84,
"sharpe_ratio": 1.42,
"best_trade_pnl_sol": 12.6,
"worst_trade_pnl_sol": -3.2,
"median_trade_pnl_sol": 0.08,
"created_at": "2026-04-14T12:00:00Z",
"completed_at": "2026-04-14T12:00:32Z"
},
"timestamp": "2026-04-14T12:01:00Z"
}Trade Sizing Modes
FIXED_SIZE
Allocates a constant SOL amount to each trade, regardless of portfolio size. Useful for simulating conservative strategies with predictable per-trade risk.
PERCENTAGE
Allocates a percentage of current portfolio value to each position. Naturally compounds gains and de-risks during drawdowns. More realistic for active portfolio management.
Rate Limits
Pricing Tiers
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
Backtest tier | $499/mo | Optional | 120 req/min + 50 sim/day | Full access to all endpoints including Portfolio Backtest |
Portfolio Backtest requires the Backtest tier. Simulation runs are limited to 50 per day. Starting from. Pricing details finalized at launch.
Use Cases
Strategy selection
Compare different wallet combinations and allocation weights to find the optimal copy-trading portfolio before committing real capital. Test 10 configurations simultaneously.
Risk parameter tuning
Sweep through slippage assumptions and sizing modes to understand how sensitive your strategy is to execution quality. Identify the break-even slippage threshold.
Historical stress testing
Run backtests across volatile periods (market crashes, memecoin cycles) to understand worst-case drawdown and recovery behavior for a proposed portfolio.
Performance attribution
Use the /steps endpoint to analyze which wallets and tokens contributed most to portfolio returns. Identify concentration risk and diversification opportunities.
Start Building with Portfolio Backtest
The API is in private beta. Request access to simulate copy-trading strategies across historical Solana data.
Request API AccessFrequently Asked Questions
What wallets can I backtest?
You can backtest any wallet that has been tracked and backfilled by Stratium's historical data pipeline. Use the /backtest/available-wallets endpoint to list wallets with sufficient historical data for the time period you want to simulate. Wallets must have at least 10 historical trades in the specified period.
What is the difference between FIXED_SIZE and PERCENTAGE sizing?
FIXED_SIZE allocates a constant SOL amount to each trade (e.g., 0.5 SOL per buy). PERCENTAGE allocates a fraction of current portfolio value (e.g., 5% of capital per position). PERCENTAGE mode naturally scales position sizes as the portfolio grows or shrinks, providing more realistic simulation of compounding effects.
How is slippage modeled?
Slippage is applied as a fixed basis point deduction on each simulated trade. For example, slippageBps: 50 means each trade execution price is adjusted by 0.5% against the trader (worse fill on buys, worse fill on sells). This approximates real-world DEX slippage but does not model liquidity depth or market impact.
How long does a backtest take?
Backtest duration depends on the number of wallets, time period, and total trades to simulate. Most backtests complete within 10-60 seconds. Use the /backtest/{id}/progress endpoint to poll completion status. The progress_percent field provides a real-time estimate.
Can I compare multiple strategies?
The /backtest/compare endpoint accepts up to 10 strategy configurations and returns side-by-side results with normalized metrics. This is useful for A/B testing different wallet combinations, capital allocations, sizing modes, and slippage assumptions against the same historical period.