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.
No credit card · Free paper account · Live in under a minute
{
"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.
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.
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_…
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}'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"}'# 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"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-READYConnect 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.
🔵 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
Dashboard UI
MCP (Claude Desktop)
# 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"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))
}"""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())// 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-NATIVEBrokerSim 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.
{
"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.