Outline and Backtest Crypto Algo Buying and selling Methods With Bitfinex Honey Framework Toolkit

Ali Akhtari HackerNoon profile picture

Ali Akhtari

Quant Dev @ Agron Capital | Pupil @ UniBocconi | Legally prohibited from dressed in a fedora | 🏳️‍🌈

github social iconlinkedin social icon

Bitfinex, one of the crucial greatest cryptocurrency virtual exchanges, has greater than 180 open-source repositories in GitHub–from a Tezos JS library to UI sweets. Essentially the most subtle buying and selling toolkit advanced by means of Bitfinex, even though, is Honey Framework with many beneficial applications comparable to bfx-hf-ui, bfx-hf-strategy, bfx-hf-indicators, and bfx-hf-strategy-exec.

On this instructional, we’re going to use the Honey Framework ecosystem to outline and backtest a pattern buying and selling approach on ancient information for the previous 500 days.

Necessities

Let’s set up the libraries we are going to use. First, run the next command to put in Honey Framework libraries.

npm set up bfx-hf-strategy bfx-api-node-models bfx-hf-util bfx-hf-indicators

We’re going to additionally want the next applications to show the trades at the command line.

npm set up cli-desk colours

Ultimately, set up

node-fetch

library as neatly to retrieve the knowledge from Bitfinex API.

Technique

We use a easy pattern buying and selling approach according to the next common sense:

Open brief place if the associated fee is between -1 SD and -2 SD Bollinger Bands® and brief SMA is underneath the lengthy SMA.

Shut brief place if the candle is inexperienced and greater than 75% of its frame crossed above the -1 SD band.

Open lengthy place if the associated fee is between +1 SD and +2 SD bands and the quick easy shifting moderate is above the lengthy easy shifting moderate.

Shut lengthy place if the candle is crimson and greater than 75% of its frame crossed underneath +1 SD band.

The common sense in the back of the tactic is reasonably simple: if the associated fee is between -1 SD and +1 SD bands (No Guy’s Land), we shut our place. If the associated fee is within the sell-zone (between the decrease bands) and the marketplace pattern is bearish (brief SMA is underneath lengthy SMA), we open a brief place. Then again, if the associated fee is between higher bands and the marketplace is bullish, we open an extended place (in different phrases, we handiest industry in route of the entire pattern). Take a look at this newsletter from Investopedia to search out extra details about pattern buying and selling according to Bollinger Bands®.

Code

Let’s get our fingers grimy. First, create

approach.js

that defines a dummy approach.

// approach.js

const { SYMBOLS, TIME_FRAMES } = require("bfx-hf-util");
const { BollingerBands, SMA } = require("bfx-hf-indicators");
const HFS = require("bfx-hf-strategy");

module.exports = ({ image = SYMBOLS.BTC_USD, tf = TIME_FRAMES.ONE_DAY }) =>
  HFS.outline({
    identity: "bbands",
    identify: "bbands",
    image,
    tf,

    alerts: {
      bbands2: new BollingerBands([20, 2]),
      bbands1: new BollingerBands([20, 1]),
      smaShort: new SMA([25]),
      smaLong: new SMA([100]),
    },
  });

Let’s wreck it down. We outline the default image (BTCUSD) and time frame (at some point). Then, we outline the symptoms we are going to use. We want two Bollinger Band® bands, each within the length of 20 days. We give a multiplier of two to the primary (±2 usual deviations) and a multiplier of one to the second (±1 usual deviations). In any case, we upload two SMAs, one in a 25-day length (brief SMA) and the opposite in a 100-day length (lengthy SMA). Take a look at this to discover a checklist of all alerts to be had in Bitfinex Honey Framework.

We will be able to input the marketplace now. The tactic we outlined accepts 5 handler how to replace positions and make trades on each and every match:

  1. onEnter – referred to as when no place is open
  2. onUpdateLong – referred to as when an extended place is open
  3. onUpdateShort – referred to as when a brief place is open
  4. onUpdate – referred to as when any place is open
  5. onPriceUpdate – referred to as on each and every tick

Tournament handlers obtain two parameters,

state

(the tactic context) and

replace

(point-in-time information), they search for industry alternatives and replace

state

if there is a industry to be made.

Input Into the Marketplace

Let’s outline the tactic to go into the marketplace. First, upload

helper.js

to encapsulate the reusable common sense. Outline

getBBands

in it to extract Bollinger Band® bands values from the state.

// helpers.js

const HFS = require("bfx-hf-strategy");

const getBBands = (state) => {
  const indicatorValues = HFS.indicatorValues(state);
  const { bbands1, bbands2 } = indicatorValues;
  const { best: plusOne, backside: minusOne } = bbands1;
  const { best: plusTwo, backside: minusTwo } = bbands2;

  go back {
    plusOne,
    plusTwo,
    minusOne,
    minusTwo,
  };
};

module.exports = {
  getBBands
}
indicatorValues

returns a map of all alerts outlined within the approach. We then extract the Bollinger Bands gadgets from them, which come with 3 values: best, backside, and center. Ultimately, the process returns ±1 and ±2 SD bands.

Outline any other approach to extract uptrend/downtrend information from the state.

// helpers.js

/*
getBBands right here
*/

const checkIfIsUptrend = (state) => {
  const indicatorValues = HFS.indicatorValues(state);
  const { smaShort, smaLong } = indicatorValues;
  const isUpTrend = smaShort > smaLong;
  go back isUpTrend;
};

module.exports = {
  getBBands,
  checkIfIsUptrend,
}

The process merely exams if brief SMA is above lengthy SMA and infers the fashion from it.

Upload

look_for_trade.js

. We’re going to use it to search out industry alternatives.

// look_for_trade.js

const HFS = require("bfx-hf-strategy");
const { getBBands, checkIfIsUptrend } = require("./helpers");

module.exports = async (state = {}, replace = {}) => {
  const { worth, mts: timestamp } = replace;
  const orderParams = {
    mtsCreate: timestamp,
    quantity: 1,
    worth,
  };

  const bands = getBBands(state);

  // between +1 SD and +2 SD from imply, the fashion is up
  const isBuyZone = bands.plusTwo >= worth && worth >= bands.plusOne;
  // between -1 SD and -2 SD from imply, the fashion is down
  const isSellZone = bands.minusTwo <= worth && worth <= bands.minusOne;

  const isUptrend = checkIfIsUptrend(state);

  if (isSellZone && !isUptrend) {
    go back HFS.openShortPositionMarket(state, orderParams);
  }

  if (isBuyZone && isUptrend) {
    go back HFS.openLongPositionMarket(state, orderParams);
  }

  go back state;
};

The process exams if the associated fee is within the industry zone (between +1 and +2 SD or -1 SD and -2 SD bands). If the associated fee is within the promote zone and the fashion is bullish, it opens a brief place, and if the associated fee is within the promote zone and the fashion is bearish, it opens an extended place. If none is correct, it merely returns the former state.

Understand that we use Honey Framework helper purposes to open positions. You’ll to find the checklist of all helper purposes right here. Upload

on_enter.js

to make use of the serve as we simply outlined to care for onEnter occasions.

// on_enter.js

const lookForTrade = require("./look_for_trade");

module.exports = async (state = {}, replace = {}) => {
  newState = look forward to lookForTrade(state, replace);
  go back newState;
};

Now upload the handler to the tactic.

// approach.js

/* different imports */

//  handlers
const on_enter = require("./on_enter");

module.exports = ({ image = SYMBOLS.BTC_USD, tf = TIME_FRAMES.ONE_DAY }) =>
  HFS.outline({

    /*
    different approach homes
    */

    onEnter: on_enter,
  });

Replace Positions

Smartly performed! We now have simply uncovered ourselves to the marketplace. However we will have to upload different handlers to react to marketplace updates whilst we’ve got an open place. Outline any other way in

helpers.js

to test if 75% or extra of the candle frame crossed the interior bands.

// helpers.js

const HFS = require("bfx-hf-strategy");


/*
 Different strategies
*/

const checkIfShouldClose = (shut, open, bands, place) => {
  const candleBody = Math.abs(shut - open);

  const closeToNoMansLandDist =
    place == "brief" ? shut - bands.minusOne : bands.plusOne - shut;

  // test if 75% of candle frame entered to the No Guy's Land.
  // see: 
  const shouldClose = closeToNoMansLandDist / candleBody >= 0.75;
  go back shouldClose;
};

module.exports = {
  getBBands,
  checkIfIsUptrend,
  checkIfShouldClose,
};
checkIfShouldClose

calculates the candle frame top by means of discovering the space between open and shut values. Then, it exams how a lot of the candle entered the No Guy’s Land. If greater than 75% of the candle frame is in between two internal bands, it closes the location.

It is time to create

on_long.js

.

// on_long.js

const HFS = require("bfx-hf-strategy");
const lookForTrade = require("./look_for_trade");
const { getBBands, checkIfShouldClose } = require("./helpers");

module.exports = async (state = {}, replace = {}) => {
  const { candle, mts: timestamp, worth } = replace;
  const { open, shut } = candle;

  const orderParams = {
    mtsCreate: timestamp,
    quantity: 1,
    worth,
  };

  const bands = getBBands(state);

  const isCandleGreen = open <= shut;
  if (isCandleGreen) go back state;

  const isCloseAbove1Std = bands.plusOne < shut;
  if (isCloseAbove1Std) go back state;

  //  test if 75% of candle frame is underneath 1 std
  const shouldClose = checkIfShouldClose(shut, open, bands, "lengthy");

  if (!shouldClose) go back state;

  let newState = look forward to HFS.closePositionMarket(state, orderParams);

  //  glance if will have to open brief
  newState = look forward to lookForTrade(newState, replace);

  go back newState;
};

The process we simply outlined exams if:

  1. The candle is inexperienced.
  2. The candle is above the No Guy’s Land (i.e., the remaining price is above the +1 SD band).
  3. Not up to 75% of the candle is within the No Guy’s Land.

And if any of those are right kind, it does not contact the location. Differently, it closes the lengthy place the use of

closePositionMarket

helper way after which calls

lookForTrade

to test if a brief place will have to be opened. Now, let’s outline our approach whilst shorting.

// on_short.js

const HFS = require("bfx-hf-strategy");
const lookForTrade = require("./look_for_trade");
const { getBBands, checkIfShouldClose } = require("./helpers");

module.exports = async (state = {}, replace = {}) => {
  const { candle, mts: timestamp, worth } = replace;
  const { open, shut } = candle;

  const orderParams = {
    mtsCreate: timestamp,
    quantity: 1,
    worth,
  };

  const bands = getBBands(state);

  const isCandleRed = open >= shut;
  if (isCandleRed) go back state;

  const isCloseBelowStd = bands.minusOne > shut;
  if (isCloseBelowStd) go back state;

  //  test if 75% of candle frame is underneath 1 std
  const shouldClose = checkIfShouldClose(shut, open, bands, "brief");

  if (!shouldClose) go back state;

  let newState = look forward to HFS.closePositionMarket(state, orderParams);

  //  glance if will have to open lengthy
  newState = look forward to lookForTrade(newState, replace);

  go back newState;
};
on_short.js

exams if:

  1. The candle is crimson.
  2. The candle is underneath the No Guy’s Land (i.e., the remaining price is underneath the -1 SD band).
  3. Not up to 75% of the candle is within the No Guy’s Land.

And if all above are false, it closes the quick place and appears for brand spanking new industry alternatives.

That is it. We now have completed defining the tactic. Upload the brand new match handlers to

approach.js

. Then we will be able to get started checking out the set of rules.

// approach.js

/* different imports */

//  handlers
const on_enter = require("./on_enter");
const on_long = require("./on_long");
const on_short = require("./on_short");

module.exports = ({ image = SYMBOLS.BTC_USD, tf = TIME_FRAMES.ONE_DAY }) =>
  HFS.outline({
    /* 
      Different approach homes
    */

    onEnter: on_enter,
    onUpdateLong: on_long,
    onUpdateShort: on_short,
  });

Check on Historic Information

Upload

get_data.js

to retrieve ancient information from Bitfinex API.

// get_data.js

"use strict";

const fetch = require("node-fetch");
const url = "https://api-pub.bitfinex.com/v2/";

const get_500_days = () => {
  let date = new Date();

  const finish = date.getTime();

  date.setDate(date.getDate() - 500);
  const get started = date.getTime();

  go back { get started, finish };
};

module.exports = async serve as getData({ image, tf }) {
  check out {
    const { get started, finish } = get_500_days();

    const pathParams = `candles/industry:${tf}:${image}/hist`;
    const queryParams = `get started=${get started}&finish=${finish}&restrict=500`;

    const req = look forward to fetch(`${url}/${pathParams}?${queryParams}`);
    const reaction = look forward to req.json();
    go back reaction;
  } catch (err) {
    console.log(err);
  }
};
getData

fetches OHLC information of the previous 500 days, given a logo and a time frame. You’ll regulate the parameters to satisfy your wishes. In finding extra details about Bitfinex API’s public endpoint for candle information right here.

Upload

exec.js

to outline the execution common sense.

// exec.js

procedure.env.DEBUG = "*";

const { Candle } = require("bfx-api-node-models");
const { SYMBOLS, TIME_FRAMES } = require("bfx-hf-util");
const logTrades = require("bfx-hf-strategy/lib/debug/log_trades");
const HFS = require("bfx-hf-strategy");
const getData = require("./get_data");
const BBandsStrategy = require("./approach");

const marketplace = {
  image: SYMBOLS.BTC_USD,
  tf: TIME_FRAMES.ONE_DAY,
};

const getCandles = async () => {
  const rawCandleData = look forward to getData(marketplace);

  // connect marketplace information
  const candles = rawCandleData
    .kind((a, b) => a[0] - b[0])
    .map((candle) => ({
      ...new Candle(candle).toJS(),
      ...marketplace,
    }));

  go back candles;
};

const run = async () => {
  const candles = look forward to getCandles();

  let strategyState = BBandsStrategy(marketplace);

  for (let i = 0; i < candles.duration; i += 1) {
    strategyState = look forward to HFS.onCandle(strategyState, candles[i]);
  }

  logTrades(strategyState);
};

check out {
  run();
} catch (e) {
  console.error(e);
}
getCandles

way retrieves the knowledge and attaches marketplace knowledge to them. All over reside execution, we might obtain information from more than one assets for various symbols and other timeframes, thus, it is essential to glue this data to uncooked information.

Then,

run

will get candle information and the tactic and passes them to

onCandle

helper way that orchestrates related approach match handlers for the brand new worth motion information. Ultimately,

run

logs the effects the use of

logTrades

serve as.

Let’s take a look at the set of rules. Open the command line within the challenge’s listing and run the next command.

The end result can be one thing like this:

You’ll discover a checklist of all positions at the side of the quantity, worth, rate, and benefit/loss determine of each and every one. On the backside, normal details about the tactic is logged. The bot has made 37 trades, opened 19 positions, and received 3960.91$. You’ll regulate

log_trades.js

helper serve as and alter the way it presentations the effects.

That is it! We now have outlined and backtested a easy buying and selling approach the use of Bitfinex Honey Framework toolkit. The instance items of code within the article are to be had right here.

Ali Akhtari HackerNoon profile picture
by means of Ali Akhtari @aliakh.Quant Dev @ Agron Capital | Pupil @ UniBocconi | Legally prohibited from dressed in a fedora | 🏳️‍🌈

Learn my tales

Similar Tales

L O A D I N G
. . . feedback & extra!

Leave a Comment