Overview
Backtest results chart how a strategy would have performed versus holding Bitcoin over the same window. They appear on the strategy card and stats page after you upload a file on My Strategies. This is a historical simulation, not a promise of future results.
A normal spreadsheet will not upload
Excel, Numbers, and Google Sheets CSVs of trades or equity will be rejected. The file must be an SFGterminal results export (or a JSON pack that matches it). If you built your own CSV on a Mac, it almost always fails because it is missing the # section: markers.
- Accepted files: .csv or .json, UTF-8, comma-separated, under 2 MB.
- CSV must contain # section: meta and # section: daily. members and trades are optional.
- Line endings can be LF (Mac/Linux) or CRLF (Windows). Do not use semicolon-delimited CSV.
- Download the sample files, confirm they upload, then replace the numbers with your backtest.
Sample files
Download a sample, drop it on your strategy in My Strategies to confirm the uploader works, then replace the numbers with your backtest.
How to upload
- 1
Open My Strategies
Go to My Strategies and find the strategy you own. Followers cannot upload a backtest onto someone else’s strategy.
- 2
Open Backtest results
Click the upload / chart icon on the strategy card, or drop the file onto the card. The dialog says SFGterminal CSV or JSON.
- 3
Drop the file
Use the SFGterminal export if you have one. Otherwise start from the sample CSV on this page. A successful upload charts growth versus Bitcoin immediately.
Studio backtests
Strategies built in Alerts Studio can save a Studio backtest as their backtest results without a file. File upload is for publishers who already have an SFGterminal (or matching) export.
CSV layout
The CSV is a single text file split into labeled sections. Comment lines start with #. Empty lines are ignored. Extra columns in members, trades, and daily are ignored, so an SFGterminal export with more fields still works.
- Start each block with a line like # section: meta (lowercase name after the colon).
- The next line is the header row for that section.
- Required sections: meta, daily. Optional: members, trades.
- Dates are YYYY-MM-DD. Percentages are numbers (50 means +50%, -10 means −10%). Do not include a % sign.
# SFGterminal results export
# section: meta
key,value
fund,Example Strategy
slug,example-strategy
leverage,2
start,2025-10-28
end,2025-10-30
out_of_sample_only,true
fee_bps_per_side,5
days,3
cagr_pct,100
max_drawdown_pct,-10
sharpe,2
total_return_pct,50
trades,2
win_pct,50
avg_win_pts,3
avg_loss_pts,-1
profit_factor,2
bench:BTC:cagr_pct,-20
bench:BTC:max_drawdown_pct,-30
bench:BTC:sharpe,-0.5
bench:BTC:total_return_pct,-25
# section: members
symbol,weight_pct,trades,wins,win_pct,pnl_pts,max_dd_pts,position_now
BTC,50,1,1,100,10,-5,flat
ETH,50,1,0,0,-2,-4,long
# section: trades
n,symbol,side,entry_date,exit_date,net_pnl_pts,days_held,status
1,BTC,short,2025-10-28,2025-10-29,9.9,1,closed
2,ETH,long,2025-10-29,,-2.1,1,open
# section: daily
date,equity,bench_btc_rebased_100
2025-10-28,100,100
2025-10-29,110,90
2025-10-30,150,80meta section
Header is key,value. Each following row is one field. Bitcoin comparison stats are required because the chart is strategy versus holding BTC.
| Key | Required | Notes |
|---|---|---|
| fund | Yes | Strategy title shown on the chart |
| slug | No | URL-safe id. If omitted, we slugify fund |
| start | Yes | Period start, YYYY-MM-DD |
| end | Yes | Period end, YYYY-MM-DD |
| days | Yes | Number of days in the window |
| leverage | Yes | Leverage used in the simulation |
| fee_bps_per_side | Yes | Fee in basis points per side |
| out_of_sample_only | No | true or false. Defaults to false |
| total_return_pct | Yes | Strategy total return % |
| cagr_pct | Yes | Strategy CAGR % |
| max_drawdown_pct | Yes | Strategy max drawdown % (usually negative) |
| sharpe | Yes | Strategy Sharpe |
| trades | Yes | Trade count |
| win_pct | Yes | Win rate % (50 = 50%) |
| profit_factor | Yes | Gross profit / gross loss |
| avg_win_pts | Yes | Average winning trade, points |
| avg_loss_pts | Yes | Average losing trade, points (usually negative) |
| bench:BTC:total_return_pct | Yes | BTC buy-and-hold total return % |
| bench:BTC:cagr_pct | Yes | BTC CAGR % |
| bench:BTC:max_drawdown_pct | Yes | BTC max drawdown % |
| bench:BTC:sharpe | Yes | BTC Sharpe |
| bench:EW basket (daily rebalanced):total_return_pct | No | If this key is present, the matching cagr_pct, max_drawdown_pct, and sharpe keys for the same prefix are also required |
daily section
One row per calendar day. This is the growth chart. At least two rows are needed for a usable chart.
| Column | Required | Notes |
|---|---|---|
| date | Yes | YYYY-MM-DD |
| equity | Yes | Strategy equity, typically rebased so the first day is ~100 |
| bench_btc_rebased_100 | No | BTC buy-and-hold equity, same rebase |
| bench_ew_basket_daily_rebalanced__rebased_100 | No | Equal-weight basket equity, same rebase. Two underscores before rebased_100 |
Rebase
Start equity near 100 so +50% total return ends near 150. BTC and basket columns should use the same start value so the overlay is comparable.
members and trades
Both sections are optional. Include them if you want per-coin weights and a trade list on the past-results view. You can omit the whole section; do not send a header with empty required cells.
| members column | Required |
|---|---|
| symbol | Yes |
| weight_pct | Yes |
| trades | Yes |
| wins | Yes |
| win_pct | Yes |
| pnl_pts | Yes |
| max_dd_pts | Yes |
| position_now | Yes — e.g. long, short, flat |
| trades column | Required |
|---|---|
| n | Yes — 1-based trade number |
| symbol | Yes |
| side | Yes — long or short |
| entry_date | Yes — YYYY-MM-DD |
| exit_date | No — leave blank for open trades |
| net_pnl_pts | Yes |
| days_held | Yes |
| status | Yes — closed or open |
JSON alternative
If you already have a results pack in JSON, upload that instead. The object must include slug, title, a strategy series (return, CAGR, max drawdown, Sharpe, plus trades), a holdBitcoin series, and an equity array with at least two { date, strategy } points. Optional fields: holdBasket, members, trades, walkForward.
- Date strings: YYYY-MM-DD.
- Open trades: set exitDate to null.
- Equity dates must be strings, strategy values must be numbers.
- File must start with { or use a .json name.
Mac CSV troubleshooting
If a CSV “didn’t take” on a Mac, it was almost certainly a generic export, not this schema.
- Do not upload .xlsx, .numbers, or .xls — save as CSV.
- Use comma separators. Some Excel locales default to semicolon; those files fail.
- Save as UTF-8 CSV. Numbers: File → Export To → CSV.
- Open the file in a text editor and confirm you can see # section: meta and # section: daily as their own lines.
- If Excel wrapped the section line in quotes it still works. If it stripped the # lines, the upload is rejected.
- Try the sample CSV first. If the sample uploads and yours does not, your headers or required keys are the problem.