ALGO TRADING SANDBOX

Your strategy. Every broker.
Zero real money.

A full-stack trading environment for quant devs and AI agents — a data-backed execution engine (synthetic spread, market impact, partial fills on real prices), five broker commission models, auto-loaded backtests, and a native MCP server so your LLM can be the strategy.

View the API →
5 broker profilesData-backed execution engineMCP-native · Claude-ready

No credit card · Free paper account · Live in under a minute

bash — POST /accounts
# Create a paper trading account
$ curl -s -X POST https://simulator.dailytickers.com/api/accounts \
-H "Authorization: Bearer $SIM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"broker":"alpaca","label":"Demo","initial_cash":50000}'
# Response:
{
  "id":           "acct_01HXQT9BJSZKFP4NW5Y2M3R8E",
  "label":        "Demo",
  "broker":       "alpaca",
  "account_type": "paper",
  "cash":         50000.00,
  "total_equity": 50000.00,
  "currency":     "USD",
  "created_at":   "2026-06-12T09:00:00Z"
}

One engine. Production-grade. Consequence-free.

Everything a strategy needs to take off — the same engine, exposed identically over REST, a native MCP server, and the dashboard.

What it is, and isn't: a data-backed execution engine — real market prices, a synthetic bid/ask spread, market impact, partial fills, broker-accurate fees, FX-aware P&L. It models a single party against the price series; it is not a multi-party order book with resting counterparties. The honest equivalent of an exchange for strategy validation.

Five Broker Models, One API

Simulate IBKR, Alpaca, T212, Saxo, and Binance commission structures with a single REST API. Switch brokers without touching your strategy logic.

IBKRAlpacaT212SaxoBinance

Data-Backed Execution Engine

Market, limit, stop, trailing stop, OCO, and bracket orders — filled against real market prices with a synthetic bid/ask spread, market impact, and partial fills. A realistic single-party model, not a multi-party order book.

MARKETLIMITSTOPTRAILINGOCOBRACKET

Backtesting Without Boilerplate

Point at a ticker and a date range. OHLCV data loads automatically. Get Sharpe, Sortino, Calmar, drawdown, and equity curve in one response.

MCP Server for AI Agents

Claude and any MCP-compatible AI agent can place orders, query positions, and read analytics natively — no glue code, no wrappers.

Remote Strategy Protocol

Your strategy code connects to the simulator over WebSocket. Run it in any language, on any machine — or let an LLM drive it in real time.

Portfolio Analytics Built In

Every session produces risk-adjusted return metrics, drawdown curves, and trade logs. No external analytics library required.

Isolated Multi-Account Simulation

Run parallel accounts with separate capital, broker models, and strategies. Ideal for comparing approaches or simulating multi-strategy portfolios.

What will you ship with it?

From solo quant scripts to AI agents running live paper books — here's what teams are building on BrokerSim.

REST API

Base URL: https://simulator.dailytickers.com/api — Authenticate with Authorization: Bearer bsim_…

Open interactive API reference →Full OpenAPI spec, rendered live with Stoplight Elements.
bashCreate a paper trading account
curl -X POST https://simulator.dailytickers.com/api/accounts \
  -H "Authorization: Bearer bsim_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"broker":"alpaca","label":"My Strategy","account_type":"paper","initial_cash":100000}'
bashPlace a market order
curl -X POST https://simulator.dailytickers.com/api/accounts/{id}/orders \
  -H "Authorization: Bearer bsim_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"symbol":"AAPL","side":"BUY","type":"MARKET","qty":10,"time_in_force":"DAY"}'
bashRun a backtest (auto-loads OHLCV data)
# 1. Create session
curl -X POST https://simulator.dailytickers.com/api/backtest \
  -H "Authorization: Bearer bsim_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"AAPL momentum","start_time":"2024-01-01","end_time":"2024-12-31",
       "tick_size":"1d","symbols":["AAPL","MSFT"],"account_ids":["acct_xxx"]}'

# 2. Run to completion
curl -X POST https://simulator.dailytickers.com/api/backtest/{id}/run \
  -H "Authorization: Bearer bsim_YOUR_KEY"

# 3. Get equity curve + performance metrics
curl https://simulator.dailytickers.com/api/backtest/{id}/equity-curve \
  -H "Authorization: Bearer bsim_YOUR_KEY"
bashGet portfolio snapshot
curl https://simulator.dailytickers.com/api/accounts/{id}/portfolio \
  -H "Authorization: Bearer bsim_YOUR_KEY"
# → { "cash": 89450.20, "positions": [...], "total_equity": 107820.50 }

Remote Strategy

LLM-READY

Connect any strategy — Go, Python, JavaScript, or an LLM agent — to the backtest engine over a simple WebSocket protocol. The simulator is the WebSocket server: create a session, then connect your strategy to its unique WS endpoint. No public port, no tunneling needed — your code connects outbound to the simulator.

Your StrategyWS client
BrokerSimWS server
connect
wss://simulator.dailytickers.com/api/backtest/<id>/ws
session metadata + data-plane contract
INIT
init_ok
strategy ready
repeats
date + account state (cash, positions, orders)
TICK
repeats
actions
place / cancel orders
session complete — metrics available
DONE

🔵 Go

Use the remotestrategy package bundled in this repo. Implement Strategy (Init + OnTick), call client.Connect(ctx, wsURL) — done.

🐍 Python

60 lines of asyncio. Connect to the session WS URL, receive INIT, respond with init_ok, handle ticks as plain dicts.

🤖 JavaScript / LLM

Any WS client works. Wire Claude directly: feed each TICK JSON as the user prompt, parse the JSON response as orders.

Three ways to get your session WS URL

REST API

1POST /backtest with your params
2Extract { id } from the response
3WS URL: wss://simulator.dailytickers.com/api/backtest/<id>/ws

Dashboard UI

1Go to /app/backtest → New session
2Fill in dates and symbols, click Create
3Click "Connect strategy" — WS URL is copied

MCP (Claude Desktop)

1Ask: "Create a backtest for AAPL, 2023"
2Claude calls create_backtest tool
3WS URL: wss://simulator.dailytickers.com/api/backtest/<id>/ws
bash1. Create a backtest session — get the session ID
# API_BASE = "https://simulator.dailytickers.com/api"

SESSION=$(curl -s -X POST https://simulator.dailytickers.com/api/backtest \
  -H "Authorization: Bearer $SIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":      "aapl-momentum-2023",
    "start_time": "2023-01-01",
    "end_time":   "2023-12-31",
    "tick_size":  "1d",
    "symbols":    ["AAPL"]
  }')

SESSION_ID=$(echo "$SESSION" | jq -r '.id')

echo "WS URL: wss://simulator.dailytickers.com/api/backtest/$SESSION_ID/ws"
go2. Go — connect with the remotestrategy client
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/hbfs-cloud/broker-simulator/remotestrategy"
)

// WS_BASE = "wss://simulator.dailytickers.com/api"

type BuyAndHoldAAPL struct {
	bars   map[string][]remotestrategy.Bar
	bought bool
}

func (s *BuyAndHoldAAPL) Init(bars map[string][]remotestrategy.Bar) error {
	s.bars = bars
	return nil
}

func (s *BuyAndHoldAAPL) OnTick(tick remotestrategy.Tick) ([]remotestrategy.AccountActions, error) {
	var all []remotestrategy.AccountActions
	for _, acct := range tick.Accounts {
		actions := remotestrategy.AccountActions{AccountID: acct.AccountID}
		var pos *remotestrategy.Position
		for i := range acct.Positions {
			if acct.Positions[i].Symbol == "AAPL" {
				pos = &acct.Positions[i]
			}
		}
		if pos == nil && !s.bought {
			actions.Create = []remotestrategy.OrderRequest{{Symbol: "AAPL", Side: "BUY", Type: "MARKET", Qty: 10}}
			s.bought = true
		} else if pos != nil {
			gain := (pos.CurrentPrice - pos.AvgEntry) / pos.AvgEntry
			if gain > 0.20 {
				actions.Create = []remotestrategy.OrderRequest{{Symbol: "AAPL", Side: "SELL", Type: "MARKET", Qty: pos.Qty}}
				s.bought = false
			}
		}
		all = append(all, actions)
	}
	return all, nil
}

func main() {
	sessionID := os.Getenv("SESSION_ID")
	if sessionID == "" {
		log.Fatal("SESSION_ID env var required")
	}
	wsURL := fmt.Sprintf("wss://simulator.dailytickers.com/api/backtest/%s/ws", sessionID)
	client := remotestrategy.NewClient(&BuyAndHoldAAPL{})
	log.Fatal(client.Connect(context.Background(), wsURL))
}
python3. Python — asyncio WebSocket client
"""Simple momentum strategy: buy AAPL if the 5-day return exceeds 2%.

Usage:
  export SESSION_ID=<your-backtest-session-id>
  export SIM_API_KEY=bsim_...
  pip install websockets
  python strategy.py
"""
# WS_BASE = "wss://simulator.dailytickers.com/api"
import asyncio, json, os
import websockets

SESSION_ID = os.environ["SESSION_ID"]
API_KEY    = os.environ.get("SIM_API_KEY", "")
WS_URL     = f"wss://simulator.dailytickers.com/api/backtest/{SESSION_ID}/ws"

MOMENTUM_THRESHOLD = 0.02
LOOKBACK_DAYS      = 5

async def run():
    headers = {"Authorization": f"Bearer {API_KEY}"} if API_KEY else {}
    async with websockets.connect(WS_URL, additional_headers=headers) as ws:
        # Receive full OHLCV history
        init = json.loads(await ws.recv())
        assert init["type"] == "init"
        bars: dict = init["bars"]
        await ws.send(json.dumps({"type": "init_ok"}))

        async for raw in ws:
            msg = json.loads(raw)
            if msg["type"] == "done":
                break
            if msg["type"] != "tick":
                continue

            account_actions = []
            for acct in msg["accounts"]:
                positions = {p["symbol"]: p for p in acct["positions"]}
                orders = []
                aapl_bars = bars.get("AAPL", [])
                if len(aapl_bars) >= LOOKBACK_DAYS + 1:
                    ret_5d = (aapl_bars[-1]["c"] - aapl_bars[-(LOOKBACK_DAYS+1)]["c"]) / aapl_bars[-(LOOKBACK_DAYS+1)]["c"]
                    if ret_5d > MOMENTUM_THRESHOLD and "AAPL" not in positions:
                        orders.append({"symbol": "AAPL", "side": "BUY", "type": "MARKET", "qty": 10})
                    elif ret_5d <= 0 and "AAPL" in positions:
                        orders.append({"symbol": "AAPL", "side": "SELL", "type": "MARKET", "qty": positions["AAPL"]["qty"]})
                account_actions.append({"account_id": acct["account_id"], "create": orders})

            await ws.send(json.dumps({"type": "actions", "accounts": account_actions}))

asyncio.run(run())
js4. LLM agent (JavaScript) — Claude drives the strategy
// LLM trading agent: streams tick JSON to Claude, executes its order decisions.
// npm install ws @anthropic-ai/sdk
// export SIM_API_KEY=bsim_...  ANTHROPIC_API_KEY=sk-ant-...  SESSION_ID=...

// WS_BASE = "wss://simulator.dailytickers.com/api"
import Anthropic from "@anthropic-ai/sdk";
import WebSocket  from "ws";

const { SIM_API_KEY, ANTHROPIC_API_KEY, SESSION_ID } = process.env;
const WS_URL = `wss://simulator.dailytickers.com/api/backtest/${SESSION_ID}/ws`;

const anthropic = new Anthropic({ apiKey: ANTHROPIC_API_KEY });
const ws = new WebSocket(WS_URL, { headers: { Authorization: `Bearer ${SIM_API_KEY}` } });

let bars = {};

async function askClaude(tick, recentBars) {
  const msg = await anthropic.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 256,
    messages: [{
      role: "user",
      content: `You are a quant trader. Given the tick and recent bars, decide orders.
Return a JSON array: [{account_id, symbol, side, type, qty}] or [].

Tick: ${JSON.stringify(tick)}
Recent bars: ${JSON.stringify(recentBars.slice(-10))}`,
    }],
  });
  try { return JSON.parse(msg.content[0].text.trim()); }
  catch { return []; }
}

ws.on("message", async (raw) => {
  const msg = JSON.parse(raw.toString());
  if (msg.type === "init") { bars = msg.bars; ws.send(JSON.stringify({ type: "init_ok" })); return; }
  if (msg.type === "done") { ws.close(); return; }
  if (msg.type !== "tick") return;

  const orders = await askClaude(msg, bars["AAPL"] ?? []);
  const byAccount = {};
  for (const o of orders) {
    if (!byAccount[o.account_id]) byAccount[o.account_id] = { account_id: o.account_id, create: [] };
    const { account_id, ...req } = o;
    byAccount[o.account_id].create.push(req);
  }
  ws.send(JSON.stringify({ type: "actions", accounts: Object.values(byAccount) }));
});

No public port needed

Your strategy is the outbound connector — it dials the simulator's WS endpoint using the session ID. Works locally, in Docker, in CI, or from a notebook. The session stays paused until you connect, then runs to completion automatically.

MCP Server

CLAUDE-NATIVE

BrokerSim exposes a native Model Context Protocol server at https://simulator.dailytickers.com/mcp. Claude and any MCP-compatible AI agent can trade, inspect positions, and read analytics as first-class tool calls. No REST wrappers, no prompt hacks — your agent connects directly to the engine.

Try it: Tell Claude “buy 500 NVDA, run a 90-day backtest, and show me the Sharpe ratio” — BrokerSim executes all three calls and streams the equity curve back, no code required.

The full tool catalog (accounts, orders, portfolio, backtests, workspaces) is discovered automatically by your MCP client at connect time — see the live API reference.

jsonConfigure in Claude Desktop (claude_desktop_config.json)
{
  "mcpServers": {
    "broker-simulator": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://simulator.dailytickers.com/mcp", "--header", "Authorization: Bearer <your-bsim-key>"]
    }
  }
}

Ready to run your first backtest?

Free account. No credit card. Live sandbox in under a minute.