couteausuis.se thoughts

Meteor Trader : automatic trading using a custom-baked indicator

TLDR; see the gains here : Asteroid Labs Dashboard

Early on in our trading-chart analysis, we devised a simple yet effective indicator that wasn’t available anywhere. After successfully programming it ans testing it manually, it was time to hit the high road and automatate the hole thing.

This project is going to be built using NodeJS and Docker, for portability between my MacBook, RaspberryPi and Vultr instance.

goals

Basically, I want to program to gather data about markets and store it in a database, to keep a history. On demand, it will calculate the pairs’ Meteor Indicator from the (local) historic data, and send it to me using Telegram. Eventually, if it behaves well, I want the trading to be automated (which include : buy, sell orders as well as prices & quantity calculations, further market analysis, and probably losing money).

warmup

As with all exercises, we need some warmup first. In this case, we will query the last 20 candles from Binance, with which we can calculate the Meteor Indicator. Using zoeyg’s binance module, I can easily query market data from Binance using :

binanceRest.klines({
    symbol: symbol,
    interval: interval,
    limit: '100' 
})
.then((data) => {
    console.log(data);
})
.catch((err) => {
    console.error(err);
});

The resulting data contains a bunch of information on the specific candle, and we’ll store it in a MongoDB instance using the appropriate Schema. Now, because I want to query a list of pairs, I wrap it up in a function and call it inside a for loop. For the sake of your hair, watch out for NodeJS asychronicity. The process will not exit if mongoose still has a connection idle, so we need to manage that. I used a decreasing counter in the mongo.save() loop so that if there’s no more data to be saved, it will kill the connection.

feed

Binance has a very robust API and offers a WebSocket stream that we can connect to and receive pushed data. Using the same module, we can easily subscribe to a tickers’ candles stream :

binanceWS.onKline(symbol, interval, (data) => {
    if (data.kline.final == true){ // save only full candles
    var symbol = new Pair({eventType: data.eventType, eventTime: data.eventTime, symbol: data.symbol, interval: interval, currentClose: data.kline.close});
        symbol.save(function (err) {
            if (err) {
                console.log(err);
            }else {
                console.log('Added ' + data.symbol + ' with timestamp '+ data.eventTime + ' interval of '+ interval + ' to DB');
            }
        });  
    }else{} // skip the pushed update
});

Now, Binance’s stream will push updates every second, but I only want to save updates when the candle is closed, so I test if the kline is final.

bot

During the programming of the other two parts, I decided to make a Telegram bot, where I could type queries and it would reply with the current Meteor Indicator and prices for entry and exit, on different intervals. For a simple bot, I use yagop’s node-telegram-bot-api module. It’s very easy to get started, for example with the keyword “/echo”:

bot.onText(/\/echo (.+)/, (msg, match) => {
  // 'msg' is the received Message from Telegram
  // 'match' is the result of executing the regexp above on the text content
  // of the message

  const chatId = msg.chat.id; // User ID
  const resp = match[1]; // the captured "whatever"

  // send back the matched "whatever" to the chat
  bot.sendMessage(chatId, resp);
});

With this, I can use a keyword with multiple options to craft a very specific query. For example, using “/check buy 30m”, the bot will reply with every pair that have a Meteor Indicator suggesting a long position on the 30m interval. Pretty neat!

dockerfile(s)

First off, let’s start with a fresh and current Node image :

FROM node:10.12

RUN apt-get update

ADD / /opt/potency
WORKDIR /opt/potency

RUN npm install
RUN npm update

It is a very simple dockerfile, it only copies the documents to the image, then install all the npm modules. The docker file is the same for warmup, feed and bot. I know that I could combine everything under one container, but I’m not used to that and was a bit rushed so it was faster to use 3 containers.

docker-compose

Remember when I used MongoDB? Yeah, we need a mongo container too! This simple docker-compose file will build and start every container in this order : mongo, warmup, feed and bot.

version: "3"
services:
  warmup:
    build: ./warmup/
    command: node index.js
    depends_on:
      - mongo
  feed:
    build: ./feed/
    command: node index.js
    depends_on:
      - warmup
  bot:
    build: ./bot/
    command: node index.js
    depends_on:
      - feed
  mongo:
    image: mongo
    container_name: mongo
    environment:
      - discovery.type=single-node
    ports:
      - 27017:27017

In only one command, I can start the whole project from any computer/server I have, and scale it easily. Let’s see how successful my trades are with this!