Back to Help & Support

Help & Support

Backtest file format

Upload an SFGterminal results CSV (or matching JSON) on My Strategies to chart a strategy versus holding Bitcoin. A plain trades spreadsheet will not work.

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. 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. 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. 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,80

meta section

Header is key,value. Each following row is one field. Bitcoin comparison stats are required because the chart is strategy versus holding BTC.

KeyRequiredNotes
fundYesStrategy title shown on the chart
slugNoURL-safe id. If omitted, we slugify fund
startYesPeriod start, YYYY-MM-DD
endYesPeriod end, YYYY-MM-DD
daysYesNumber of days in the window
leverageYesLeverage used in the simulation
fee_bps_per_sideYesFee in basis points per side
out_of_sample_onlyNotrue or false. Defaults to false
total_return_pctYesStrategy total return %
cagr_pctYesStrategy CAGR %
max_drawdown_pctYesStrategy max drawdown % (usually negative)
sharpeYesStrategy Sharpe
tradesYesTrade count
win_pctYesWin rate % (50 = 50%)
profit_factorYesGross profit / gross loss
avg_win_ptsYesAverage winning trade, points
avg_loss_ptsYesAverage losing trade, points (usually negative)
bench:BTC:total_return_pctYesBTC buy-and-hold total return %
bench:BTC:cagr_pctYesBTC CAGR %
bench:BTC:max_drawdown_pctYesBTC max drawdown %
bench:BTC:sharpeYesBTC Sharpe
bench:EW basket (daily rebalanced):total_return_pctNoIf 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.

ColumnRequiredNotes
dateYesYYYY-MM-DD
equityYesStrategy equity, typically rebased so the first day is ~100
bench_btc_rebased_100NoBTC buy-and-hold equity, same rebase
bench_ew_basket_daily_rebalanced__rebased_100NoEqual-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 columnRequired
symbolYes
weight_pctYes
tradesYes
winsYes
win_pctYes
pnl_ptsYes
max_dd_ptsYes
position_nowYes — e.g. long, short, flat
trades columnRequired
nYes — 1-based trade number
symbolYes
sideYes — long or short
entry_dateYes — YYYY-MM-DD
exit_dateNo — leave blank for open trades
net_pnl_ptsYes
days_heldYes
statusYes — 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.