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

POST
/api/v1/backtest/run

Submit a new backtest simulation. Returns a backtest_id for polling results.

GET
/api/v1/backtest/{id}/progress

Poll backtest execution progress. Returns status and progress_percent (0-100).

GET
/api/v1/backtest/{id}

Retrieve completed backtest results with full performance metrics.

GET
/api/v1/backtest/{id}/steps

Paginated FIFO calculation steps for the simulated portfolio. Same schema as PnL Analytics steps.

POST
/api/v1/backtest/compare

Compare up to 10 strategy configurations side by side with normalized metrics.

GET
/api/v1/backtest/available-wallets

List wallets with sufficient historical data for backtesting in a given time period.

Request Body

POST /api/v1/backtest/run

ParameterTypeRequiredDefaultDescription
walletsarrayRequiredArray of wallet configs: { address, allocation (0-1), slippageBps (0-1000) }
capital.solAmountnumberRequiredStarting capital in SOL
period.startstringRequiredBacktest start date (ISO 8601 or YYYY-MM-DD)
period.endstringRequiredBacktest end date (ISO 8601 or YYYY-MM-DD)
sizing.modestringRequiredTrade sizing: FIXED_SIZE or PERCENTAGE
sizing.fixedAmountSolnumberOptionalSOL per trade (when mode = FIXED_SIZE)
sizing.positionCapPercentnumberOptional5Max % of capital per position (when mode = PERCENTAGE)
TypeScript Interface
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

ParameterTypeRequiredDefaultDescription
strategiesarrayRequiredArray of up to 10 backtest configurations to compare side by side
normalizebooleanOptionaltrueNormalize all strategies to the same starting capital for fair comparison

Query Parameters

GET /api/v1/backtest/{id}/steps

ParameterTypeRequiredDefaultDescription
limitintegerOptional50Results per page (max 200)
offsetintegerOptional0Pagination offset
actionstringOptionalFilter by trade action: BUY or SELL
token_mintstringOptionalFilter by specific token mint address

GET /api/v1/backtest/available-wallets

ParameterTypeRequiredDefaultDescription
period_startstringOptionalFilter wallets with data starting from this date
period_endstringOptionalFilter wallets with data up to this date
min_tradesintegerOptional10Minimum trade count in the period
limitintegerOptional50Results per page
offsetintegerOptional0Pagination offset

Response Schema

TypeScript Interface
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
}
Example Response
{
  "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.

fixedAmountSol: 0.5 = 0.5 SOL per buy

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.

positionCapPercent: 5 = max 5% of capital per position

Rate Limits

Pricing Tiers

ParameterTypeRequiredDefaultDescription
Backtest tier$499/moOptional120 req/min + 50 sim/dayFull 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 Access

Frequently 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.