DEV Community

Cover image for How to build a crypto bot with Python 3 and the Binance API (part 1)
Nicolas Bonnici
Nicolas Bonnici

Posted on • Edited on

How to build a crypto bot with Python 3 and the Binance API (part 1)

The first point about trading crypto currencies or any asset is to have a goal and a strategy to achieve. Here i'am not writing about trading strategy but just build a simple yet functional crypto trader bot to apply your strategy. Trade with caution this serie of post is just more like an automated crypto trading bot framework.

We'll use python 3.9 (3.9.2) to first create the project file structure.

/exchanges
/strategies
/models

Here "exchanges" folder store the exchanges API wrappers, strategies your strategies and models the business object we gonna use.

The models

We'll defined several business objects for this projects, such like price, currency or order for instance. First let's begin with the Price one to use it on the strategy we'll create just after.

Before we write a common abstract layer forour business object.

./models/model.py

from datetime import datetime


class AbstractModel:
    created: datetime

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

Enter fullscreen mode Exit fullscreen mode

Then our first Price class.

./models/price

from models.model import AbstractModel


class Price(AbstractModel):
    pair: str = ''
    exchange: str = ''
    current: float = 0
    lowest: float = 0
    highest: float = 0
    currency: str = ''
    asset: str = ''

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.pair = self.get_pair()

    def get_pair(self):
        return self.currency + '_' + self.asset
Enter fullscreen mode Exit fullscreen mode

The strategy part

Here if the biggest part of this system, the strategy will be responsible to run your own trading logic and to do so, there's two way, a classic using an interval then run API calls to external exchanges API or even internal webhooks and route and a real time event based one using WebSocket.

To do so we'll first create an abstract strategy class that our strategies will extend.

./strategies/strategy.py

import json
import threading
import time
from datetime import datetime
from decouple import config
from models.price import Price


class Strategy(object):
    price: Price

    def __init__(self, exchange, interval=60, *args, **kwargs):
        self._timer = None
        self.interval = interval
        self.args = args
        self.kwargs = kwargs
        self.is_running = False
        self.next_call = time.time()
        self.portfolio = {}
        self.exchange = exchange
        # Load account portfolio for pair at load
        self.get_portfolio()

    def _run(self):
        self.is_running = False
        self.start()
        self.run(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            print(datetime.now())
            if self._timer is None:
                self.next_call = time.time()
            else:
                self.next_call += self.interval

            self._timer = threading.Timer(self.next_call - time.time(), self._run)
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False

    def get_portfolio(self):
        self.portfolio = {'currency': self.exchange.get_asset_balance(self.exchange.currency),
                          'asset': self.exchange.get_asset_balance(self.exchange.asset)}

    def get_price(self):
        try:
            self.price = self.exchange.symbol_ticker()
        except Exception as e:
            pass

...

Enter fullscreen mode Exit fullscreen mode

Here our strategy abstract layer constructor signature need an Exchange instance, we'll do this part later writing of first wrapper using the Binance API.

We define without any extra library a simple yet functional infinite interval runner, note that this every run will launch the next call on another thread but in fact your strategy will use never no more than two threads, one main and the current run iteration if you strategy take a lot of external call or heavy computation. Each thread consume 0.3% of RAM and 0 or 0.1 CPU usage, this also involve the Strategy to fetch ticker and orders, then store price and order related data on an another internal API.

Yet the interval run precision can drift a little bit on microseconds, but will be stable at seconds level.

Here a simple usage of that layer, a strategy that basically print your exchange account portfolio and the exchange price. We got method to also retrieve a symbol ticker from an external exchange we gonna connect later, and also a method to retrieve your current portfolio available on connected exchange.

./strategies/watcher.py

from exchanges.exchange import Exchange
from strategies.strategy import Strategy


class Watcher(Strategy):
    def __init__(self, exchange: Exchange, timeout=60, *args, **kwargs):
        super().__init__(exchange, timeout, *args, **kwargs)

    def run(self):
        self.get_price()
        print('*******************************')
        print('Exchange: ', self.exchange.name)
        print('Pair: ', self.exchange.get_symbol())
        print('Available: ', self.portfolio['currency'] + ' ' + self.exchange.currency)
        print('Available: ', self.portfolio['asset'] + ' ' + self.exchange.asset)
        print('Price: ', self.price.current)
Enter fullscreen mode Exit fullscreen mode

In the next parts we gonna connect our first Exchange Binance by coding a simple wrapper using the official Binance API https://github.com/binance/binance-spot-api-docs and Python requests library https://pypi.org/project/requests/. Then code our missing business objects order and currency to store respectively the order you send to exchanges and the currencies we'll manipulate fiat or cryptocurrencies then put all those different pieces together.

Thank for reading, stay tuned for the next part.

Top comments (10)

Collapse
 
blahdeblah profile image
blahdeBlah

binance.py has this...
.
.
.
from binance.client import Client
.
.
.
self.client = Client(self.apiKey, self.apiSecret)
.
.
.

Can you please explain where this Client object comes from? It appears to be self-referential, but I don't understand how that can be.

Collapse
 
blahdeblah profile image
blahdeBlah

nm I think I got it. It's an imbiguously-named reference to a Binance API component.

Collapse
 
curiouspaul1 profile image
Curious Paul • Edited

Hi can u please explain the significance of the attributes I underlined in the image below. They're part of the Strategy class in your code, I need to know what each one does and why it is important to the class.

Also please can you explain what the start() method does exactly I don't seem to understand the back and forths going on with the if else blocks there, please give more context if you can

Collapse
 
blahdeblah profile image
blahdeBlah

What's going on in the very first code block?

No, seriously. Self-taught -- trader-turned-programmer asking.

Collapse
 
nicolasbonnici profile image
Nicolas Bonnici

Hey there, this an abstract layer that all entities inherit. You Can use it to put all the common code among all your business objects.

Collapse
 
blahdeblah profile image
blahdeBlah

Thx. Basically saves from having to re-write similar objects?

Collapse
 
kellymweu profile image
kellymweu

hello, have the code from part 1 to part 3 in order. but I keep getting an error that says import "models.model could not be resolved pylance(reportmissingimports).....this error appears anywhere where the code calls for an import. I am using vscode. thank you

Collapse
 
nicolasbonnici profile image
Nicolas Bonnici

Hey there check your Python version iOS 3.9 then directly grab the Source code from Github. Hope it ll help.

Collapse
 
guillerbr profile image
Guiller

Hi is there any github for this project? we can help to develop. We can disclose to other people help. You can do it?

Collapse
 
nicolasbonnici profile image
Nicolas Bonnici

Yes there is, i will share it in the next part still WIP. github.com/nicolasbonnici/cryptobot