Backtesting Binance CCXT Crypto Market Data RealTest

Backtesting Crypto in RealTest: Binance Data, Fees and Funding

Summary

RealTest has no crypto data source and does not need one, because its CSV importer takes exchange exports directly. Yahoo covers the majors free under tickers like BTC-USD, while a universe comes from the exchange through CCXT as CSV. The parts people get wrong are fees, which are a percentage of notional rather than a dollar amount, and funding on perpetuals, which is a real cash flow that never appears in an OHLCV file.

· 7 min read
Backtesting Crypto in RealTest: Binance Data, Fees and Funding
Key findings
  • RealTest imports crypto two ways. Yahoo carries the majors as BTC-USD, ETH-USD and SOL-USD, and exchange history arrives through the CSV importer using either one file per symbol or a single multi-symbol file.
  • A multi-symbol import needs a Symbol column and a CSVFile path, while a per-symbol import uses DataPath with each file named after its symbol. Only Date and Close are strictly required fields.
  • Dates default to month-day-year parsing, so exchange exports that are day first need CSVDateFmt set to DMY, and crypto symbols contain a slash so formula comparisons look like Symbol = $BTC/USDT.
  • Exchange fees are a fraction of notional rather than a fixed dollar amount, so Commission should be written as a formula against FillValue, using the taker rate unless entries genuinely rest on the book.
  • Funding on perpetual futures is a cash flow that never appears in OHLCV data. Importing it as its own symbol in a second CSV block and reading it with Extern makes it available in every formula.
  • Crypto daily bars are a convention rather than a closing auction, almost always the UTC midnight boundary, and mixing sources cut at different boundaries produces an edge that appears and disappears with the universe.
  • Survivorship bias is more severe than in equities because exchanges delist pairs regularly and a dead token simply stops appearing in the export.
  • There is no consolidated tape in crypto, so history should come from the venue you intend to trade on rather than from whichever exchange is easiest to download.

RealTest has no crypto data source. There is no exchange to select in the import dialog, and there will not be one. What it has instead is a CSV importer, which turns out to be enough, because every crypto exchange will hand you history as CSV and the CSV path in RealTest is a first-class citizen rather than a fallback.

There are two routes in, and the right one depends on whether you are testing a handful of majors or an actual universe.

Route one, Yahoo, for the majors

Yahoo carries the large coins under ticker names like BTC-USD, ETH-USD and SOL-USD, and RealTest imports them the same way it imports a stock.

Import:
	DataSource:	Yahoo
	IncludeList:	SPY
	IncludeList:	BTC-USD, ETH-USD, SOL-USD {"InCRYPTO"}
	StartDate:	Earliest
	EndDate:	Latest
	SaveAs:	MainCrypto.rtd

The braces create a named list, so InList("InCRYPTO") is true for those three symbols and you can keep an equity benchmark like SPY in the same file without it entering trades. This route costs nothing and takes a minute, and for a system that trades Bitcoin and Ethereum it is genuinely sufficient. Its limits are the same ones that apply to Yahoo data anywhere, which is a small set of instruments and no way to reach the ones that died.

Route two, exchange CSV, for everything else

For a universe you pull history from the exchange yourself, usually through CCXT, and write it to CSV. RealTest reads either one file per symbol or a single file containing many symbols, and for crypto the single-file form is easier to keep current.

Import:
	DataSource:	CSV
	CSVFields:	Date,Symbol,Open,High,Low,Close,Volume
	CSVFile:	C:\CryptoData\binance_daily.csv
	StartDate:	Earliest
	EndDate:	Latest
	SaveAs:	crypto.rtd

The file needs a Symbol column when you use CSVFile, and the column names in CSVFields have to match the order in your file. If you instead keep one file per instrument, swap CSVFile for DataPath pointing at the folder, and name each file after its symbol. Both forms accept the same field names, of which only Date and Close are strictly required.

Two details save an afternoon. Dates are parsed as month-day-year unless you set CSVDateFmt: DMY, and exchange exports are frequently day first. And crypto symbols contain a slash, so a comparison in a formula looks like Symbol = $BTC/USDT rather than the bare ticker you would use for a stock.

Fees are percentages, so model them as percentages

Stock backtests use a dollar commission with a minimum. Crypto exchanges charge a fraction of notional and split it by whether you took liquidity or provided it. RealTest expresses that directly, because Commission is a formula rather than a number, and FillValue is the dollar size of the position at entry.

Parameters:
	MakerFee:	0.0002	// limit orders that rest on the book
	TakerFee:	0.0005	// market orders that cross the spread

Strategy:	CryptoMR
	Commission:	TakerFee * FillValue

Set those two values to your own fee tier rather than the example, and use the taker rate unless your entries genuinely rest as limit orders. Getting this wrong is not a rounding error in a strategy that turns over daily. A system taking two hundred round trips a year at market pays a fifth of a percent every time it moves, which compounds into a difference that decides whether the edge exists.

Funding rates, which most backtests just ignore

If you are testing perpetual futures rather than spot, funding is a real cash flow that arrives several times a day and can be larger than your edge in a crowded trade. It is not in the OHLCV file, so it has to come in separately, and the way RealTest handles this is neat. Import the funding history as its own symbol in a second CSV, then read it from any formula with Extern.

Import:
	DataSource:	CSV
	CSVFields:	Date,Symbol,Open,High,Low,Close,Volume
	CSVFile:	C:\CryptoData\binance_daily.csv

	DataSource:	CSV
	CSVFields:	Date,Symbol,Close
	CSVFile:	C:\CryptoData\daily_funding_rates.csv
	SaveAs:	crypto.rtd

Data:
	FundingRate:	Extern($FUNDING_RATE, C)

Multiple DataSource blocks combine into one data file, so the funding series ends up alongside the price series and Extern pulls its value on each bar regardless of which instrument the formula is currently evaluating. From there you can charge it against a position, filter entries when funding is extreme, or simply plot it to see how much of a backtested return was really a funding subsidy.

What crypto breaks that stocks do not

The day has no natural end

Equities have a closing auction. Crypto does not, so a daily bar is a convention someone chose, almost always the UTC midnight boundary. That is fine as long as every file in your universe uses the same convention. Mixing an exchange export cut at UTC with a source cut at New York time produces bars that disagree by hours, which shows up as an edge that appears and disappears depending on which symbols are in the test.

Dead coins are the norm, not the exception

Survivorship bias is worse here than in equities. Exchanges delist pairs regularly, and a token that stops trading simply stops appearing in the export. Build a universe from the pairs Binance lists today and backtest it over five years and you have selected for the tokens that survived a period in which most did not. The fix is the same as it is for stocks, which is to keep the delisted pairs in your CSV rather than rebuilding the list each time you download. If you are new to why that matters, it is the second of the five backtesting mistakes that fake an edge.

There is no consolidated tape

A stock has one official closing price. A coin has as many prices as there are venues, and they differ enough to matter for a strategy trading small moves. Whatever exchange you intend to trade on is the exchange your history should come from, and testing on Binance data while executing on Coinbase introduces a gap that no cost assumption models.

Spot and perpetual are different instruments

They track each other and they are not the same thing. Perpetuals carry funding, allow leverage, and can dislocate from spot exactly when your strategy is most exposed. A backtest built on spot candles that is then traded on perps is testing something adjacent to what you are doing.

How to start

Pull one symbol first, BTC/USDT daily, and import it alone. Check the first and last bar and the row count before writing a strategy, since a truncated download looks identical to a working one until the results make no sense. Then add the rest of the universe, and only after that add funding.

Keep the download and the import as separate steps you can run independently. The download is slow and rate-limited, the import takes seconds, and mixing them means waiting for the exchange every time you want to change a field mapping.

If you would rather not write the downloader, our Python code to download crypto data from Binance with CCXT produces files in the shape the import above expects, and the free crypto CSV data for spot and futures lets you skip the download entirely for a first test.

Once the data is in, the question becomes what to test. If you would rather read than download, the SetupAlpha Substack is where the longer research goes, including the academic papers behind several of these systems. It is free and the archive is large enough to keep you busy.

Key terms

CCXT
An open-source library that provides a common interface to many crypto exchange APIs, commonly used to pull historical candles and write them to CSV.
Maker Fee
The fee charged when an order rests on the book and provides liquidity. Usually lower than the taker fee.
Taker Fee
The fee charged when an order crosses the spread and removes liquidity. The correct assumption for any strategy sending market orders.
Funding Rate
A periodic payment between long and short holders of a perpetual futures contract that keeps its price tethered to spot. A real cash flow that never appears in price data.
Perpetual Futures
A futures contract with no expiry, held in line with spot through funding payments rather than through settlement.
FillValue
A RealTest position property holding the dollar value of a position at entry, which is what percentage-based exchange fees are calculated against.
CSVFile Import
The RealTest import form that reads many symbols from one CSV file, requiring a Symbol column, as opposed to DataPath which reads one file per symbol from a folder.
Consolidated Tape
A single official record of trades across venues, which equities have and crypto does not, so each exchange carries its own prices.

Frequently asked questions

Does RealTest support crypto data?

Yes, though not through a dedicated crypto data source. RealTest imports crypto either from Yahoo, which carries the majors under tickers such as BTC-USD, or from CSV files exported from an exchange. The CSV path is a full feature rather than a fallback, so a universe of exchange pairs imports as cleanly as stocks do.

How do you import Binance data into RealTest?

Export the history to CSV, usually via CCXT, then use an Import section with DataSource set to CSV, a CSVFields line matching your column order, and CSVFile pointing at the file. A multi-symbol file needs a Symbol column. RealTest writes the result to a data file that your strategies then read.

Should you use one CSV per symbol or one file for everything?

For crypto the single multi-symbol file is usually easier to keep current, since one refresh updates the whole universe. Use CSVFile for that form and DataPath for the folder form, where each file has to be named after its symbol.

Why does my crypto CSV import produce wrong dates?

Because RealTest parses dates as month-day-year by default and most exchange exports are day first. Adding CSVDateFmt set to DMY fixes it. The symptom is usually a data file that imports without error but contains far fewer bars than expected.

How do you model crypto trading fees in RealTest?

As a percentage of position value rather than a dollar amount. Commission is a formula, and FillValue holds the dollar size of the position at entry, so a taker fee is written as your rate multiplied by FillValue. Use the taker rate unless your entries genuinely rest as limit orders.

What is the difference between maker and taker fees?

A maker order rests on the order book and adds liquidity, usually at a lower fee. A taker order crosses the spread and removes liquidity, at a higher one. A backtest that assumes maker fees while the live strategy sends market orders understates costs on every single trade.

How do you include funding rates in a crypto backtest?

Import the funding history as its own symbol in a second CSV block within the same Import section, then read it in a formula with Extern. Because multiple data source blocks combine into one data file, the funding series sits alongside the prices and is available on every bar regardless of which instrument is being evaluated.

Do funding rates actually matter to a backtest?

On perpetual futures, often more than the entry rule. Funding is charged several times a day and in a crowded trade it can exceed the edge being harvested. A backtest that ignores it can show a profitable system that is really collecting a funding subsidy, or paying one.

Where does the crypto trading day start?

Wherever the data provider decided, since there is no closing auction. Almost every exchange export uses the UTC midnight boundary. What matters is that every file in a universe uses the same one, because mixing boundaries shifts bars by hours and quietly changes which signals fire.

Is survivorship bias a problem in crypto backtests?

More than in equities. Exchanges delist pairs frequently and a token that stops trading simply stops appearing in downloads. Building a universe from the pairs listed today and testing it over several years selects for the tokens that survived a period in which most did not.

Can you backtest on one exchange and trade on another?

You can, and it introduces a gap no cost assumption models. Crypto has no consolidated tape, so each venue has its own prices, and the differences are large enough to matter for strategies trading small moves. History should come from the venue you intend to trade.

Is spot data good enough for testing a perpetual futures strategy?

No. Spot and perpetuals track each other without being the same instrument. Perps carry funding, allow leverage and can dislocate from spot at exactly the moments a strategy is most exposed, so a spot backtest describes something adjacent to what you would actually be trading.

Related strategies

Python Code to Download Crypto Data (Binance + CCXT)
The downloader that produces files in the shape the import in this article expects, so the CSV mapping works on the first attempt.
View →
Crypto CSV Data (Spot + Futures)
Ready CSV history for spot and futures, which skips the download entirely for a first test.
View →
← Back to Learn

#1 RealTest Backtests

Supercharge Your Trading Now

Reduce drawdown, build diversification, or speed up your development time.

Browse RealTest Strategies