@@ -5,15 +5,16 @@ A python based trading bot for Binance, which relies heavily on backtesting.
5
5
![ CryptoBot components] ( ./cryptobot.jpg )
6
6
7
7
1 . [ Overview] ( #overview )
8
+ 2 . [ History] ( #history )
8
9
* [ 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 )
17
18
* [ PAIRING] ( #pairing )
18
19
* [ INITIAL_INVESTMENT] ( #initial_investment )
19
20
* [ RE_INVEST_PERCENTAGE] ( #re_invest_percentage )
@@ -54,12 +55,145 @@ A python based trading bot for Binance, which relies heavily on backtesting.
54
55
* [ max_profit_on_clean_wins] ( #max_profit_on_clean_wins )
55
56
* [ number_of_clean_wins] ( #number_of_clean_wins )
56
57
* [ 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
+
59
61
60
62
## Overview
61
63
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?
63
197
64
198
There are multiple tool or services in this repo, for example:
65
199
@@ -122,8 +256,6 @@ You can choose to build your own strategy and place it on the
122
256
This bot currently provides different strategies:
123
257
124
258
* [ * BuyDropSellRecoveryStrategy* ] ( ./strategies/BuyDropSellRecoveryStrategy.py )
125
- * [ * BuyDropSellRecoveryStrategyWhenBTCisDown* ] ( ./strategies/BuyDropSellRecoveryStrategyWhenBTCisDown.py )
126
- * [ * BuyDropSellRecoveryStrategyWhenBTCisUp* ] ( ./strategies/BuyDropSellRecoveryStrategyWhenBTCisUp.py )
127
259
* [ * BuyMoonSellRecoveryStrategy* ] ( ./strategies/BuyMoonSellRecoveryStrategy.py )
128
260
* [ * BuyOnGrowthTrendAfterDropStrategy* ] ( ./strategies/BuyOnGrowthTrendAfterDropStrategy.py )
129
261
* [ * BuyOnRecoveryAfterDropDuringGrowthTrendStrategy* ] ( ./strategies/BuyOnRecoveryAfterDropDuringGrowthTrendStrategy.py )
@@ -204,7 +336,7 @@ TICKERS:
204
336
In order to test the different 'profiles' for different coins, we would then
205
337
run this bot in backtesting mode.
206
338
207
- There are 3 modes of execution: live, testnet, backtesting
339
+ There are 4 modes of execution: logmode, live, testnet, backtesting
208
340
209
341
## Discord
210
342
@@ -251,6 +383,8 @@ Place your new *my_newly_named_config.yaml* file into the *configs/* folder.
251
383
See the [ example
252
384
secrets.yaml] ( https://github.com/Azulinho/cryptobot/blob/master/examples/secrets.yaml ) file
253
385
386
+ Note that you don't need valid credentials for backtesting, or logmode.
387
+
254
388
``` yaml
255
389
ACCESS_KEY : " ACCESS_KEY"
256
390
SECRET_KEY : " SECRET_KEY"
0 commit comments