TRADELYBOX — Backtest API
A drag-and-drop forex strategy backtesting engine built with FastAPI , PostgreSQL , and Cloudflare R2 . Design trading strategies as visual block graphs and backtest them on historical OHLCV data — or let the AI Copilot generate strategies from natural language.
Live API: https://tradelybox-api.fly.dev
Docs: https://tradelybox-api.fly.dev/docs
31 drag-and-drop blocks — indicators (SMA, EMA, RSI, MACD, Bollinger, ATR, Stochastic, ADX), ICT concepts (FVG, order blocks, BOS, CHoCH, liquidity sweeps), price action (engulfing, pin bar), comparators, logic gates, and action blocks (buy, sell, stop loss, take profit, position sizing)
Graph-based strategy engine — topological sort + bar-by-bar forex simulator with lots, pips, spread, intra-bar SL/TP, and support for long & short trades
28 performance metrics — total return, Sharpe ratio, max drawdown, win rate, profit factor, consecutive wins/losses, and more
AI Copilot — describe a strategy in plain English and get a complete block canvas back (powered by Gemini 2.5 Flash)
15 built-in strategy templates — trend following, mean reversion, ICT, scalping, and more
OHLCV data from Cloudflare R2 — monthly CSV files, multiple timeframes (M1 to W1)
Results persistence — save, retrieve, and compare backtest results in PostgreSQL
Component
Technology
Framework
FastAPI 0.115.0
Database
PostgreSQL (Neon)
ORM
SQLAlchemy 2.x
Price Data
Cloudflare R2 (S3-compatible)
AI Copilot
Google Gemini 2.5 Flash
Data Processing
Pandas, NumPy
Deployment
Fly.io (Docker)
Python
3.10
Python 3.10+
PostgreSQL database (or a Neon project)
Cloudflare R2 bucket with OHLCV CSV files
Google AI API key (for the Copilot feature — get one here )
(Optional) Docker & Fly.io CLI for deployment
Create a .env file in the project root:
# ─── Database ─────────────────────────────────────────────────
DATABASE_URL = postgresql://user:password@host/database
# ─── Cloudflare R2 ────────────────────────────────────────────
R2_ENDPOINT = https://<account-id>.r2.cloudflarestorage.com
R2_BUCKET = your-bucket-name
R2_ACCESS_KEY_ID = your-r2-access-key
R2_SECRET_ACCESS_KEY = your-r2-secret-key
# ─── AI Copilot ───────────────────────────────────────────────
GEMINI_API_KEY = your-gemini-api-key
# ─── Optional ─────────────────────────────────────────────────
ENV = development # "development" enables hot reload
PORT = 8000 # local port (Docker uses 8080)
OHLCV data must be stored as monthly CSV files in R2 with this naming convention:
<symbol>_<timeframe>_<YYYY-MM>.csv
Examples: eurusd_d1_2024-08.csv, gbpusd_h1_2025-01.csv
Each CSV must have columns: timestamp (Unix ms), open, high, low, close, volume.
# 1. Clone the repo
git clone git@github.com:TRADELYBOX/backtest_api.git
cd backtest_api
# 2. Create a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Set up environment variables
cp .env.example .env # then fill in your values
# 5. Start the server
python main.py
The API will be available at http://localhost:8000 with interactive docs at /docs .
# Build the image
docker build -t tradelybox-api .
# Run the container
docker run -p 8080:8080 --env-file .env tradelybox-api
The Dockerfile uses python:3.10-slim, installs system deps (gcc, libpq-dev), and runs uvicorn on port 8080 .
# 1. Install the Fly CLI
curl -L https://fly.io/install.sh | sh
# 2. Login
fly auth login
# 3. Launch (first time only — creates the app)
fly launch
# 4. Set secrets (environment variables)
fly secrets set DATABASE_URL=" postgresql://..."
fly secrets set R2_ENDPOINT=" https://..."
fly secrets set R2_BUCKET=" your-bucket"
fly secrets set R2_ACCESS_KEY_ID=" ..."
fly secrets set R2_SECRET_ACCESS_KEY=" ..."
fly secrets set GEMINI_API_KEY=" ..."
# 5. Deploy
fly deploy
# 6. Check status
fly status
fly logs
Current config (fly.toml): app tradelybox-api, region cdg (Paris), 1 GB RAM, auto-stop enabled.
Method
Path
Description
GET
/api/blocks
List all available block types (flat)
GET
/api/blocks/categories
List blocks grouped by category
POST
/api/blocks/seed
Seed/reset the block catalog (31 blocks)
Strategies — /api/strategies
Method
Path
Description
GET
/api/strategies
List strategies (filter by user_id, is_template, category)
POST
/api/strategies
Create a new strategy from canvas data
PUT
/api/strategies/{id}
Update a strategy
GET
/api/strategies/{id}/canvas
Get canvas data formatted for React Flow
POST
/api/strategies/{id}/backtest
Backtest a saved strategy
Backtests — /api/backtests
Method
Path
Description
POST
/api/backtests/run
Run a backtest with raw nodes + edges from canvas
Method
Path
Description
GET
/api/results
List results (filter by strategy_id, status)
GET
/api/results/{id}
Get full result with trades
GET
/api/results/{id}/trades
Get just the trade list
GET
/api/results/{id}/equity
Get just the equity curve
DELETE
/api/results/{id}
Delete a result
Method
Path
Description
GET
/api/prices/ohlcv
Fetch OHLCV data from R2
GET
/api/prices/available-symbols
List symbols available in R2
GET
/api/prices/timeframes/{symbol}
List timeframes for a symbol
GET
/api/prices/date-range/{symbol}/{timeframe}
Get available date range
Method
Path
Description
POST
/api/copilot/generate
Generate a strategy canvas from a natural-language prompt
Method
Path
Description
GET
/health
Health check
GET
/docs
Swagger UI
GET
/redoc
ReDoc
Block
Params
Description
price
field: close/open/high/low/volume
Outputs a price series
constant
value: number
Outputs a constant value series
Block
Key Params
Description
sma
period
Simple Moving Average
ema
period
Exponential Moving Average
rsi
period
Relative Strength Index
macd
fast, slow, signal
MACD (line, signal, histogram)
bollinger
period, std_dev
Bollinger Bands (upper, middle, lower)
atr
period
Average True Range
stochastic
k_period, d_period
Stochastic Oscillator (%K, %D)
adx
period
Average Directional Index
Block
Key Params
Description
fvg
min_gap_pips
Fair Value Gap detection
orderBlock
lookback
Order Block detection
bos
lookback
Break of Structure
choch
lookback
Change of Character
liquiditySweep
lookback
Liquidity Sweep detection
premiumDiscount
lookback
Premium/Discount zones
swingHighLow
lookback
Swing High/Low detection
Block
Params
Description
engulfing
—
Engulfing candle
pinBar
—
Pin bar / hammer
Block
Params
Description
greaterThan
threshold
A > B (or A > threshold)
lessThan
threshold
A < B (or A < threshold)
crossAbove
threshold
A crosses above B (or threshold)
crossBelow
threshold
A crosses below B (or threshold)
Block
Description
and
Logical AND of signals
or
Logical OR of signals
not
Invert a signal
Block
Params
Description
buy
—
Open a long trade on signal
sell
—
Open a short trade on signal
stopLoss
pips or price
Set stop loss (pips or fixed price)
takeProfit
pips or price
Set take profit (pips or fixed price)
positionSize
lots
Set position size in lots
Note: Indicator blocks are self-contained — they auto-read the close price from OHLCV when no input is wired.
Populates the block_templates table with all 31 block definitions:
# Via API
curl -X POST https://tradelybox-api.fly.dev/api/blocks/seed
# Or locally
curl -X POST http://localhost:8000/api/blocks/seed
Populates the strategies table with 15 built-in templates:
python scripts/seed_templates.py
Make sure DATABASE_URL is set in your .env before running.
1. Run a Backtest (raw canvas)
curl -X POST https://tradelybox-api.fly.dev/api/backtests/run \
-H " Content-Type: application/json" \
-d ' {
"nodes": [
{
"id": "rsi-1",
"type": "indicator",
"data": { "block_type": "rsi", "params": { "period": 14 } },
"position": { "x": 100, "y": 100 }
},
{
"id": "const-30",
"type": "data_source",
"data": { "block_type": "constant", "params": { "value": 30 } },
"position": { "x": 100, "y": 250 }
},
{
"id": "cross-1",
"type": "comparator",
"data": { "block_type": "crossAbove", "params": {} },
"position": { "x": 350, "y": 175 }
},
{
"id": "buy-1",
"type": "action",
"data": { "block_type": "buy", "params": {} },
"position": { "x": 600, "y": 175 }
}
],
"edges": [
{ "id": "e1", "source": "rsi-1", "target": "cross-1", "sourceHandle": "rsi", "targetHandle": "a" },
{ "id": "e2", "source": "const-30", "target": "cross-1", "sourceHandle": "series", "targetHandle": "b" },
{ "id": "e3", "source": "cross-1", "target": "buy-1", "sourceHandle": "result", "targetHandle": "signal" }
],
"symbol": "EURUSD",
"timeframe": "d1",
"start_date": "2024-08-01",
"end_date": "2025-06-30",
"initial_capital": 10000,
"spread_pips": 1.0,
"default_lot_size": 0.1,
"max_open_trades": 3
}'
curl -X POST https://tradelybox-api.fly.dev/api/strategies \
-H " Content-Type: application/json" \
-d ' {
"name": "RSI Oversold Bounce",
"symbol": "EURUSD",
"timeframe": "h1",
"user_id": 1,
"canvas_data": {
"blocks": [
{ "id": "rsi-1", "type": "indicator", "position": { "x": 100, "y": 100 }, "data": { "block_type": "rsi", "params": { "period": 14 } } },
{ "id": "const-1", "type": "data_source", "position": { "x": 100, "y": 250 }, "data": { "block_type": "constant", "params": { "value": 30 } } },
{ "id": "cross-1", "type": "comparator", "position": { "x": 350, "y": 175 }, "data": { "block_type": "crossAbove", "params": {} } },
{ "id": "buy-1", "type": "action", "position": { "x": 600, "y": 175 }, "data": { "block_type": "buy", "params": {} } }
],
"connections": [
{ "id": "e1", "source": "rsi-1", "target": "cross-1", "sourceHandle": "rsi", "targetHandle": "a" },
{ "id": "e2", "source": "const-1", "target": "cross-1", "sourceHandle": "series", "targetHandle": "b" },
{ "id": "e3", "source": "cross-1", "target": "buy-1", "sourceHandle": "result", "targetHandle": "signal" }
]
}
}'
3. Backtest a Saved Strategy
curl -X POST https://tradelybox-api.fly.dev/api/strategies/1/backtest \
-H " Content-Type: application/json" \
-d ' {
"start_date": "2024-08-01",
"end_date": "2025-06-30",
"initial_capital": 10000,
"spread_pips": 1.5,
"default_lot_size": 0.1,
"max_open_trades": 1
}'
4. AI Copilot — Generate a Strategy
curl -X POST https://tradelybox-api.fly.dev/api/copilot/generate \
-H " Content-Type: application/json" \
-d ' {
"prompt": "Buy when RSI crosses above 30 with a 50 pip stop loss and 100 pip take profit",
"symbol": "EURUSD",
"timeframe": "h1"
}'
curl " https://tradelybox-api.fly.dev/api/prices/ohlcv?symbol=EURUSD&timeframe=d1&start_date=2024-08-01&end_date=2024-12-31"
backtest_api/
├── main.py # FastAPI app entry point
├── requirements.txt # Python dependencies
├── Dockerfile # Docker image (python:3.10-slim)
├── fly.toml # Fly.io deployment config
├── .env # Environment variables (not committed)
│
├── app/
│ ├── database.py # SQLAlchemy engine & session
│ │
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── blocks.py # BlockTemplate (block catalog)
│ │ ├── strategies.py # Strategy (user strategies + templates)
│ │ ├── results.py # BacktestResult (saved results)
│ │ └── user.py # User model (placeholder)
│ │
│ ├── schemas/ # Pydantic request/response schemas
│ │ ├── backtests.py # BacktestRequest, BacktestResponse, metrics
│ │ ├── blocks.py # Block schemas
│ │ ├── strategies.py # StrategyCreate, CanvasData, StrategyBacktestRequest
│ │ └── strategy_templates.py # Template schemas
│ │
│ ├── routers/ # API route handlers
│ │ ├── blocks.py # /api/blocks — seed & list blocks
│ │ ├── strategies.py # /api/strategies — CRUD, canvas, backtest
│ │ ├── backtests.py # /api/backtests — run raw backtests
│ │ ├── results.py # /api/results — result persistence
│ │ ├── prices.py # /api/prices — OHLCV from R2
│ │ └── copilot.py # /api/copilot — AI strategy generation
│ │
│ └── functions/ # Core business logic
│ ├── block_registry.py # 31 block execution functions
│ ├── default_blocks.py # Block catalog definitions (for seeding)
│ └── engine.py # StrategyEngine (graph) + ForexSimulator
│
└── scripts/
├── seed_blocks.py # Seed block catalog
├── seed_templates.py # Seed 15 strategy templates
└── cleanup_database.py # DB cleanup utilities
Backtest Metrics Reference
Every backtest response includes these 28 metrics:
Metric
Description
total_return
Absolute P&L in account currency
total_return_pct
Percentage return
sharpe_ratio
Risk-adjusted return
max_drawdown
Max peak-to-trough drawdown ($)
max_drawdown_pct
Max drawdown as percentage
win_rate
% of winning trades
total_trades
Total closed trades
winning_trades
Number of winners
losing_trades
Number of losers
profit_factor
Gross profit / gross loss
avg_trade_pnl
Average trade P&L ($)
avg_trade_pips
Average trade P&L (pips)
best_trade
Best single trade ($)
worst_trade
Worst single trade ($)
avg_win
Average winning trade ($)
avg_loss
Average losing trade ($)
max_consecutive_wins
Longest winning streak
max_consecutive_losses
Longest losing streak
long_trades
Number of long trades
short_trades
Number of short trades
long_win_rate
Win rate for longs
short_win_rate
Win rate for shorts
sl_exits
Trades closed by stop loss
tp_exits
Trades closed by take profit
signal_exits
Trades closed by opposing signal
initial_capital
Starting capital
final_equity
Ending equity
Private — TRADELYBOX © 2025