Trading, without the emotion.
The recommended way to run this repository is as a provided Docker application.
Tradebot is the repository of a trading bot for Binance exchange.
It is composed of different applications :
binance-cli: a tool allowing some manipulations (placing orders) and queries (balance, ...) from the command line.dogebot: the application to launch the trading bot. Several bots might be provided.naivebot: a proof of concept, simply placing an order, and placing the reverse order (with some marging for earnings) upon completion.productionbot: the current bot used on the production exchange.
initial-fragments: populate a database withSellfragments following the provided configuration. This is essential when first deploying aproductionbot, since it only place orders for corresponding fragments.tests: unit, integration, regression testing using Catch2 framework.tradelist: present a list of all the exchange's trades corresponding to a filled order.
The applications are implemented upon the following libraries:
binance: implementation of the Binance REST Api.trademath: general mathematics functions and classes that can be applied to trading.websocket: a simple websocket library on top of Boost::Beast. (Should be moved out of this repo as it is generic.)tradebot: relies on all the libraries above to provide the features required to implement a trading bot. It notably provides theTraderclass, which is a high-level interface to interract with an exchange's REST Api and its websocket streams (currently only targeted at Binance).
It also contains Python3 code to provide statistics of a running bot.
The main script is updatesheets.py, exporting the content of a database
to a Google Sheet spreadsheet.
ProductionBot realizes the original intent of this repository.
Functionally, it listens to the market stream for the latest trades, takes the current rate from there, and check in the database if any fragment could be satisfied:
Sellfragments with a target rate under the current rate.Buyfragments with a target rate above the current rate.
It then place limit FOK order(s) for the matching fragments (a separate order per side, per target rate).
Upon an order completion, the registered Spawner will be called upon each Fragment
composing the order, to spawn counter-fragments.
Note: Limit FOK has been chosen because it is guaranteed to either fill or not execute at all, while allowing to set a limit.
Care has been taken so operation can be resumed in event of a crash, and that no irrecoverable state should be lost. (taking a few lessons from crash-only software).
Further details regarding the implementations can be found in design.md.
Access to Binance API must be authorized via an API key and a secret.
They should be provided to the application via a JSON file containing:
{
"server": "production", // or "test"
"apikey": "your_api_key",
"secretkey": "your_secret_key"
}
The tokens are obtained via the web application: https://www.binance.com/en/my/settings/api-management
The restrictions should be edited to add Enable Spot & Margin Trading.
To use the testnet, API key and secret should be obtained from https://testnet.binance.vision/. (As of this writing, it seems mandatory to log-in with Github).
There is a docker application (multi-container docker compose). It automatically starts both:
productionbot(viatradebotapplication).- A container periodically running
updatesheet.py.
It also contains some utilities, to be called explicitly via docker-compose run:
binance-cliinitial-fragments
Note: They should be called via the .sh wrapper in the container working directory,
as they forward configurations and secrets to the utilities.
Note: Explicitly building the images is not required for deployments, as docker compose will take care of it when running.
However, the command to build tradebot would be.
docker build -t adnn/tradebot .
The one command to build containers and run the application:
docker-compose up --build
By default, the application expects the following files and folder to exist from the host working directory:
./secrets/binance.json: The credentials to access Binance API./secrets/googlesheet-tokens.json: The user authorization for Google Sheet API access./configs/dogebot.json: The tradebot configuration./configs/updatesheet.env:python/updatesheet.pyconfiguration./logs/: Folder where the bot will write its logs.
It mounts the corresponding folders at the root of the container.
Note: In the host environment, it is possible to create symlinks from a specific file (secret, config) to the generic name expected by the container. This is convenient so several configs can coexist in the repo.
The expected path to the files above can be changed via environment variables that must be
set in the shell executing docker-compose up:
- BINANCE_SECRETS_FILE (default:
/secrets/binance.json) - DOGEBOT_CONFIG (default:
/configs/dogebot.json) - GOOGLE_TOKEN_FILE (default:
/secrets/googlesheet-tokens.json) - UPDATESHEET_CONFIG (default:
/configs/updatesheet.env)
Important: This is convenient to change the filename part of the path, to match the filename on the host. If the dirname is changed, or if the folders are not named as expected on the host, new mounts will also have to be provided.
The location where the container will write the bot logs on the host can be change via environment variable:
- BOT_LOG_FOLDER (default:
./logs)
Export the environment variables defined in Customization points in the calling shell if their value should be overriden.
-
Gather secrets:
- Binance exchange API authorization should be placed in
./secrets/binance.json. - Google Sheet API authorization should be placed in
./secrets/googlesheet-tokens.json.
- Binance exchange API authorization should be placed in
-
Provide the configuration for the services
- For the Cpp trader, see the existing files in
./configsfor examples. The production config should be placed in (or symlinked to)./configs/dogebot.json. - For the python exporter, pace a file
./configs/updatesheet.envwith content:
SPREADSHEET_ID=some_spreadsheet_id - For the Cpp trader, see the existing files in
-
The first time the application is deployed on a docker host, a new volume with an empty database is created. The database should be populated with initial fragments. The fragments will be spawned based following the Cpp trader configuration provided above.
docker-compose run tradebot ./initial-fragments.sh -
Then, launch the long-running stack.
docker-compose up -d [--build #force build even if images already exist]
- C++17 compiler
- git
- Conan (
pip3 install conan) - CMake optional
For Linux or macOS
git clone --branch develop --recurse https://github.com/KoolChain/tradebot.git
cd tradebot
mkdir build && cd build
conan install --build missing -s build_type=Debug -o tradebot:build_tests=True ../conan
conan build -sf .. ../conan
The test network credentials should be provided as CMake variables (done once at build folder level):
# Still from build/ folder
cmake -DBINANCE_TESTNET_APIKEY=${apikey} -DBINANCE_TESTNET_SECRETKEY=${secret} ..
# Build again, for example
conan build -sf .. ../conan
From build/ folder
src/apps/tests/tests
- Move
websocketlibrary to a more generic repository. - Implement placing order with fixed quote quantity (currently only fixed base is implemented).
- This would notably be beneficial for buy counter-fragments: currently
productionbotdecides how much quote should be re-invested in the buy counter-fragment, then have to convert it to the base amount at expected target rate. This might lead to missed opportunities in base space, if the order executes at a lower rate than target (currently providing "leftover quote" that was not invested to reach the fixed buy base amount, instead of spending the exact amount of quote and provide more base when the rate is lower).
- This would notably be beneficial for buy counter-fragments: currently
- Clean bot shutdown. In particular, have it shutdown when Docker is stopping the container.
- Record more information when spawning counter-fragments:
- Currently, when spawning counter-fragments, only the spawning
Orderis recorded. Maybe there could be an additional table recording the spawningFragments and the corresponding proportion (relative to the counter-fragment total). Note that counter-fragments have potentially several spawningFragments. (see spawning relation)
- Currently, when spawning counter-fragments, only the spawning
- Ability to compose an order with fragments of different target rates.
- This would allow to satisfy at once all beneficial fragments, instead of placing one order per rate.
- It would not be possible anymore to have the
fragmentsRateonOrder. - This requires the above features of augmenting the spawning relation records when spawning (because the parent order would not allow to get the spawning fragment rate anymore).
- Investigate the cause for HTTP response with status 0
- Is it related to cpr lib? Because it is using the system's Curl?
- Should the application retry the query in this situation?
- Better handle order cancellation on the exchange:
- Is it possible to specify the canceled client id?
- In the user stream report,
cvsCfield.