Skip to content

Commit ddfa133

Browse files
committed
added history to README
1 parent 18a3b74 commit ddfa133

File tree

1 file changed

+148
-14
lines changed

1 file changed

+148
-14
lines changed

README.md

Lines changed: 148 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ A python based trading bot for Binance, which relies heavily on backtesting.
55
![CryptoBot components](./cryptobot.jpg)
66

77
1. [Overview](#overview)
8+
2. [History](#history)
89
* [How does it work](#how-does-it-work)
9-
2. [Discord](#discord)
10-
3. [Getting started](#getting-started)
11-
4. [Usage](#usage)
12-
5. [Automated Backtesting](#automated-backtesting)
13-
6. [Prove automated-backtesting results](#prove-automated-backtesting-results)
14-
7. [config-endpoint-service](#config-endpoint-service)
15-
8. [Control Flags](#control-flags)
16-
9. [Config settings](#config-settings)
10+
3. [Discord](#discord)
11+
4. [Getting started](#getting-started)
12+
5. [Usage](#usage)
13+
6. [Automated Backtesting](#automated-backtesting)
14+
7. [Prove automated-backtesting results](#prove-automated-backtesting-results)
15+
8. [config-endpoint-service](#config-endpoint-service)
16+
9. [Control Flags](#control-flags)
17+
10. [Config settings](#config-settings)
1718
* [PAIRING](#pairing)
1819
* [INITIAL_INVESTMENT](#initial_investment)
1920
* [RE_INVEST_PERCENTAGE](#re_invest_percentage)
@@ -54,12 +55,145 @@ A python based trading bot for Binance, which relies heavily on backtesting.
5455
* [max_profit_on_clean_wins](#max_profit_on_clean_wins)
5556
* [number_of_clean_wins](#number_of_clean_wins)
5657
* [greed](#greed)
57-
10. [Bot command center](#bot-command-center)
58-
11. [Development/New features](#development/new-features)
58+
11. [Bot command center](#bot-command-center)
59+
12. [Development/New features](#development/new-features)
60+
5961

6062
## Overview
6163

62-
A cryptobot designed to work across different trends of the market.
64+
CryptoBot is a python based bot which relies heavily on automation and
65+
backtesting to work across different trends of the market.
66+
67+
## History
68+
69+
I built this bot due to my own negative experience in other opensource bots that
70+
lacked backtesting support and which had farly convoluted codebases, with no
71+
tests making them hard to extend or modify with the features I wanted.
72+
73+
Essentially, I was looking for a bot where I could consume binance data and run
74+
backtesting using different strategies. My initial goal was for a
75+
bot that would buy a particular coin when that coin price went down by x% and
76+
then sell it when the coin price raised by %y.
77+
78+
I added new functionality as I felt I need it, for example the bot started
79+
by using a mode *logmode* which would save the current price for all the coins
80+
with a 1s or less granularity. By having prices logged over a number of days I
81+
could run backtesting strategies and identify the best options over the past days
82+
in detail.
83+
As the time to backtest increased with the number of logs, I added options to
84+
consume price information from the logs every N seconds. For example only
85+
consuming the price records entries price records every 60 seconds or so.
86+
This allowed me to have a quick glance of how a particular backtesting strategy
87+
would behave on a number of available price logs for the last N days.
88+
I could then pick the best strategy and reduce the interval back to 1 second to
89+
understand how that strategy would behave in a *normal* trade day.
90+
91+
Several rounds of refactoring and profiling the code improved the execution time,
92+
down from minutes to around 30 seconds per daily log.
93+
94+
As saving daily logs through the *logmode* forced to have to run the bot for a
95+
number of days before I could get any useful data to backtest, I looked into
96+
automating the download of klines from binance using the minimum 1min interval
97+
and saving them into the price log format consumed by the bot.
98+
With this new tool I could now download price log files going back until 2017 from
99+
binance and run backtesting since the beggining of time.
100+
101+
At this point, backtesting was time consuming and tricky to identify the best
102+
crypto tokens to backtest as well as what parameters to apply to each one
103+
of those tokens. A mix of luck, looking at market charts and identifying
104+
patterns allowed me to fit a set of parameters onto a coin and backtesting it
105+
so that the bot would return a sane profit. And as long the market conditions
106+
remained the same, the bot would return a profit while trading in live mode.
107+
108+
Might be worth pointing out now, that the bot has a few modes of operation,
109+
backtesting, live, testnet, logmode.
110+
111+
At this point I started looking on how I could automate the tasks of finding
112+
the best options for each coin over a period of time.
113+
This lead me to simply automate the same tasks I was running manually which were to
114+
run backtesting multiple times with different parameters and log those returns.
115+
Eventually I added code to strip out any coins that didn't provide a minimum
116+
amount of profit and filtering the best configs for each
117+
one of those tokens automatically, ending with a single optimized config for a
118+
number of crypto tokens.
119+
120+
As I had access to a good chunk of CPU, I refactored the automated backtesting
121+
code to consume all my available CPU cores.
122+
This of course caused the run to start hitting binance API limits.
123+
To avoid those I started added proxies, retrying API calls to binance to avoid
124+
hitting those rate limits and failed backtesting sessions.
125+
For example when the bot finds a coin for the first time in a price log, it
126+
would call binance to retrieve all its klines data from the last 60 min on a
127+
1min interval, last 24 hours on a 1h interval and the last 1000 days on a daily
128+
interval. Additionally for every trade I needed to find the precision to use for
129+
each token. All this data needed to be saved locally as I would be requesting it
130+
multiple times over and over. This new service klines-caching-service that would
131+
deal with interacting with binance for me.
132+
133+
With access to enough CPU and a set of good strategies, I could achieve results
134+
where I would invest $100 in 2017 and the bot would return in an optimized
135+
config just above a million.
136+
Of course this is not representative of how well the bot would behave in live
137+
and that for the amounts involved there would never be enough liquidity in the
138+
market. So I would always took these results with a very large grain of salt.
139+
140+
This lead me to another question, on how could I improve my confidence on the
141+
results provided by these automated backtesting runs ?
142+
143+
I thought of a couple of things, first I would discard any coins on a particular
144+
run that finished the runs with a stop-loss or a stale, or sill holding that
145+
coin in the wallet at the end of the run. And focus the results on getting the
146+
config for a coin that returned not the maximum profit but the highest number of
147+
trades without any losses. This essentially meant that the bot instead of buying
148+
a coin when it dropped in price by 10%, it would instead buy that coin when it
149+
dropped in price by 40%.
150+
This resulted in some side optimizations in backtesting, for example I would
151+
quit backtesting a coin early as soon as I hit a STALE or a STOP LOSS.
152+
153+
The remaining piece was to automate the automated backtesting, instead of
154+
running the backtesting over the last 300 days or so. I refactored the
155+
automated backtesting script into pretending that we were running in live mode.
156+
Essentially I would give a start date, like 2021-01-01 tell the bot to backtest
157+
300 days and then run in pretend *live* mode for 30 days, before repeating this
158+
process from the 2021-02-01 all the end until 2022-12-31.
159+
The feedback was that I could see how a particular set of strategies would
160+
behave in different markets and how well the automated-backtesting would adapt
161+
to those changing markets. Essentially I could simulate what the bot looked to
162+
return in a live scenario by using backtesting data against new price logs that
163+
hadn't been backtested yet.
164+
165+
I could now identify strategies that could return lower consistent returns
166+
insted of higher profits in highly volatile runs that would trigger my anxiety
167+
response if I were to be trading that strategy live.
168+
169+
I called this new automated-backtesting, prove-backtesting.
170+
171+
Around this time I added a new price log service that would serve the price
172+
logs to the backtesting bots. This resulted in removing all the IO I was
173+
experiencing while running 48-96 concurrent bots and saved my SSDs from total
174+
destruction. As part of the donwload klines script, I optimized the download of
175+
klines so that I could have daily price log files for each coin.
176+
This would allow the bot to backtesting a single coin in under a second, even
177+
for a large number of price log files.
178+
179+
As of today, I can backtest around 300 days of logs for 48-96 coins in just a
180+
few seconds on an old dual Xeon for those less permisive configs.
181+
182+
Possibly the final piece was how to collect the optimized backtesting configs I got
183+
from my prove or automated-backtesting runs and feed them to my live bots.
184+
For this I updated the bot to poll a http endpoint for a new set of configs and refresh
185+
itself as soon a new config was available.
186+
I called this the config-endpoint-service, and essentially its a service that
187+
runs a prove-backtesting session (nightly or so) and when it finishes makes that
188+
optimized config available to the live bot on a http endpoint.
189+
190+
With all these changes the original bot is now a collection of services
191+
and is mostly hands-free.
192+
193+
194+
# What tools
195+
196+
So what tools do we have?
63197

64198
There are multiple tool or services in this repo, for example:
65199

@@ -122,8 +256,6 @@ You can choose to build your own strategy and place it on the
122256
This bot currently provides different strategies:
123257

124258
* [*BuyDropSellRecoveryStrategy*](./strategies/BuyDropSellRecoveryStrategy.py)
125-
* [*BuyDropSellRecoveryStrategyWhenBTCisDown*](./strategies/BuyDropSellRecoveryStrategyWhenBTCisDown.py)
126-
* [*BuyDropSellRecoveryStrategyWhenBTCisUp*](./strategies/BuyDropSellRecoveryStrategyWhenBTCisUp.py)
127259
* [*BuyMoonSellRecoveryStrategy*](./strategies/BuyMoonSellRecoveryStrategy.py)
128260
* [*BuyOnGrowthTrendAfterDropStrategy*](./strategies/BuyOnGrowthTrendAfterDropStrategy.py)
129261
* [*BuyOnRecoveryAfterDropDuringGrowthTrendStrategy*](./strategies/BuyOnRecoveryAfterDropDuringGrowthTrendStrategy.py)
@@ -204,7 +336,7 @@ TICKERS:
204336
In order to test the different 'profiles' for different coins, we would then
205337
run this bot in backtesting mode.
206338
207-
There are 3 modes of execution: live, testnet, backtesting
339+
There are 4 modes of execution: logmode, live, testnet, backtesting
208340
209341
## Discord
210342
@@ -251,6 +383,8 @@ Place your new *my_newly_named_config.yaml* file into the *configs/* folder.
251383
See the [example
252384
secrets.yaml](https://github.com/Azulinho/cryptobot/blob/master/examples/secrets.yaml) file
253385

386+
Note that you don't need valid credentials for backtesting, or logmode.
387+
254388
```yaml
255389
ACCESS_KEY: "ACCESS_KEY"
256390
SECRET_KEY: "SECRET_KEY"

0 commit comments

Comments
 (0)