Back test your trading strategies with Bitfinex Terminal & Honey Framework
The Honey Framework provides easy ways to create and back test trading strategies. Today we’ll take a look at how to back test your trading strategies Bitfinex Terminal data and Node.js. Bitfinex Terminal was released with the needs of algo traders in mind – a fast, reliable way to sync and share historical data. We take a trading strategy, EMA Crossover, and test it against historical candle data.
We will be running our back test on 5 minute candles based on BTCUSD trading data. Just like in a blockchain, this data is stored in a Merkle Tree and can be cryptographically verified. The data is shared over a peer-to-peer (P2P) network and can be streamed live. That means the back test can be run while we get the data and resume the downloads after the connection is reset for us. All these features make Terminal an attractive choice for sharing trading data and trading signals.
Bitfinex Terminal supports Dazaar Cards, which is an easy way to access the data streams. Each data stream has a unique ID, which is cryptographically verified, similar to a Bitcoin address. The Dazaar card contains a description of the content and the stream ID. Imagine it is a torrent file, but for encrypted, real-time data streams.
To get started, we install the required dependencies:
npm install dazaar hyperbee bitfinex-terminal-key-encoding bfx-hf-util bfx-hf-backtest bfx-hf-strategy bitfinex-terminal-terms-of-use
We also need to create a file; let’s say
backtest.js. We can now start writing our code.
To see the results of our console back test, we need to enable debug output:
process.env.DEBUG = process.env.DEBUG || 'bfx:*'
const dazaar = require('dazaar') const swarm = require('dazaar/swarm') const Hyperbee = require('hyperbee') const keyEncoding = require('bitfinex-terminal-key-encoding') const HFBT = require('bfx-hf-backtest') const SYMBOLS, TIME_FRAMES = require('bfx-hf-util') const EMAStrategy = require('bfx-hf-strategy/examples/ema_cross') const terms = require('bitfinex-terminal-terms-of-use')
We also define a small helper function to give us the time of exactly 24 hours in the past:
const get24HoursAgo = (date) => const res = date.getTime() - (1 * 86400 * 1000) return new Date(res)
For back testing, we need to define the market we are testing and pass it on to the EMA strategy:
const market = symbol: SYMBOLS.BTC_USD, tf: TIME_FRAMES.FIVE_MINUTES const strat = EMAStrategy(market)
Then we can initialize Dazaar:
const dmarket = dazaar('dbs/terminal-backtest')
With the above command Dazaar will create a local database in
dbs/terminal-backtest. All of our data is stored in this folder, so if you want to start over, you can easily delete it.
As the next step, we download the Dazaar Card for BTCUSD from https://raw.githubusercontent.com/bitfinexcom/bitfinex-terminal/master/cards/bitfinex.terminal.btcusd.candles.json and load it:
const card = require('./bitfinex.terminal.btcusd.candles.json')
Dazaar also supports paid feeds, for example for selling trading signals of a successful strategy, but the Bitfinex Terminal data is free. Our map is loaded in Dazaar. We turn on sparse mode, with sparse mode set, it only downloads the data requested from us. We also load the terms of service we needed above, after reading and confirming them:
const buyer = dmarket.buy(card, sparse: true, terms )
If we wanted to download a full copy of all the candles in the background, we would set
Once the data is ready, Dazaar will create a
feed event. After that airs, we can set up Hyperbee on top of the Dazaar feed. Hyperbee provides us with a B-Tree structure for easy querying of the data. For Terminal, we use a special key encryption module, which makes querying the data easier. We have already loaded the key encryption module with
const keyEncoding = require('bitfinex-terminal-key-encoding'). Once the Hyperbee database is set up, we can make a call
runTest and work with the database:
buyer.on('feed', function () console.log('got feed') const db = new Hyperbee(buyer.feed, keyEncoding, valueEncoding: 'json' ) runTest(db) )
The last part of our back test is the actual testing. For that we have to define the function
async function runTest (db)
Within the position
runTest we need to define the time frame we want to use for our test. For the start of the timeframe, we’ll use the helper function we created at the beginning of our tutorial. The value for
to points to the current time:
const from = get24HoursAgo(new Date()) const to = new Date()
We set the deadlines together with our strategy and the market
HFBT.execStream. It returns a function named
exec and a function called
const exec, onEnd = await HFBT.execStream(strat, market, from, to )
exec is applied to every element of the stream, but first we need to start the stream. We will run our test
5m candles. To get all the data within that 24 hour timeframe, we use our variables
to in the respective fields
lte (less than equal) and
gte (greater than equal):
const stream = db.createReadStream( gte: candle: TIME_FRAMES.FIVE_MINUTES, timestamp: from , lte: candle: TIME_FRAMES.FIVE_MINUTES, timestamp: to )
Using an Async Iterator we call the exec with each item and store the result in
let btState for await (const data of stream) const key, value = data btState = await exec(key, value)
Then when the iterator no longer gives us results, we call the function
onEnd, which will print our results to the console:
Here’s the whole feature
async function runTest (db) const from = get24HoursAgo(new Date()) const to = new Date() const exec, onEnd = await HFBT.execStream(strat, market, from, to ) const stream = db.createReadStream( gte: candle: TIME_FRAMES.FIVE_MINUTES, timestamp: from , lte: candle: TIME_FRAMES.FIVE_MINUTES, timestamp: to ) let btState for await (const data of stream) const key, value = data btState = await exec(key, value) await onEnd(btState)
After finishing the position
runTest, we’re almost done. To start everything, we have to go online:
Now if we run our file, we will get the result printed on the console:
As you can see, with this strategy we would have made a loss in the period from 9/6/2020, 3:18:58 PM to 9/7/2020, 3:18:58 PM, when this article was written.
In this article, we took a look at how back-testing a Honey Framework trading strategy works with Bitfinex Terminal. We were able to back-test less than 70 lines of code with an easy and reliable way to sync large amounts of data. Everything ran on top of Dazaar, which can also be used to sell trading signals. One of our next articles will cover exactly that topic, so stay tuned!