Table of Contents
Course Introduction
Welcome to the course – More crypto trading bots on Binance, which is an extension of the first course Creating Your First Simple Crypto-Trading Bot with Binance API.
In this course, we will study three more algorithms that you can use for crypto trading and design trading bots with these algorithms using python-binance
API.
We will discuss these three algorithms.
- Simple Moving Average (SMA)
- MACD (Moving average convergence and divergence) based on EMA
- Bollinger bands
Before we begin, I would like to make a small request
- If you don’t know the basics of
binance
andpython-binance
API. - If you want to know how to set up the development environment, set up a
binance
account orbinance-testnet
account. Then, you should please go through the previous course (Creating Your First Simple Crypto-Trading Bot with Binance API) where these are explained in detail. - Please be aware of the following note:
##################### Disclaimer!! ################################### # The bots built here with python should be used only as a learning tool. If you choose # to do real trading on Binance, then you have to build your own criteria # and logic for trading. The author is not responsible for any losses # incurred if you choose to use the code developed as part of the course on Binance. ####################################################################
Another important point:
In the algorithms we discuss, there are multiple buy/sell points to buy/sell crypto. It is up to you as to how to want to write the logic for buying and selling, e.g. In the bots we develop, buying or selling a crypto asset happens at all the buy/sell points using a for loop for each buy and sell point.
There can be multiple ways to implement the buy/sell logic, some are mentioned below
- You can keep separate loops to buy and sell and keep looping until at least one buy and one sell occurs and then break.
- You can choose to buy/sell only for a particular buy/sell signal. i.e. if market price is <= or >= a particular value from the buy/sell list. In this case, no for loop is needed here.
- You can choose to buy/sell, by placing only limit orders and not market orders with the prices from the buy/sell list.
And so on….
Let’s Begin the journey
Now that we are clear on all these things we discussed we can start with our first trading algorithm – SMA. So see you soon in our first algorithm!!
PS: Follow the videos, along with the tutorial to get a better understanding of algorithms!
Simple Moving Average (SMA)
You can check out the full code at the Finxter GitHub repository here.
SMA basics
Let’s start by discussing the basics of Simple Moving Average(SMA) first. The SMA is based on rolling or moving averages. In high school math, you must have learned to take the averages of numbers. The same concept is used to calculate SMA. An example to calculate moving averages for a data set [200, 205, 210, 220, 230, 235, 250, 240, 225, 240]
.
Below are SMA calculations for a period of 3.
1st SMA = (200+205+210)/3 = 205 2nd SMA = (205+210+220)/3 = 211.6 3rd SMA = (210+220+230)/3 = 220 ... and so on.
Similarly, SMA calculations for a period of 5.
1st SMA = (200+205+210+220+230)/5 = 213 2nd SMA = (205+210+220+230+235)/5 = 220 ... and so on.
Hope you now have an idea of how SMA works. Keep rolling one digit at a time while calculating the average or mean. The same concept will be used for the SMA trading strategy. It will involve two SMA’s. In our trading strategy, we will make use of short-term SMA (period of 5) and long-term SMA (period of 15). In general, the long-term SMA will be 3x times the short-term SMA.
SMA crossover
SMA crossover involves the short-term SMA and long-term SMA crossing each other over the closing price of the asset (crypto).
In the above figure, the two SMA’s (5 and 15) plotted against the closing prices of an asset over a period of time. The orange and the green lines cross each other. This is called SMA crossover.
Buy and Sell
The short-term SMA is more sensitive to the closing prices than the long-term SMA because averaging over crypto asset values (such as closing price) for shorter periods gives more proximal to the asset value (closing price) than the longer periods. The SMA crossover hence becomes buying or selling points.
When the orange line (short-term SMA) crosses the green line (long-term SMA) in the upward direction (goes above) – > becomes a buying point.
downward direction (goes beneath) -> becomes a selling point.
See the above figure for a better understanding.
Bot Trading Logic
As we are now clear with the basics of SMA, let’s start coding the bot. As in previous trading bots, we will design the SMA bot step by step.
Step1:
import os from binance.client import Client import pprint import pandas as pd # needs pip install if not installed import numpy as np import matplotlib.pyplot as plt # needs pip install if not installed if __name__ == "__main__": # passkey (saved in bashrc for linux) api_key = os.environ.get('BINANCE_TESTNET_KEY') # secret (saved in bashrc for linux) api_secret = os.environ.get('BINANCE_TESTNET_PASSWORD') client = Client(api_key, api_secret, testnet=True) print("Using Binance TestNet Server") pprint.pprint(client.get_account()) # Change symbol here e.g. BTCUSDT, BNBBTC, ETHUSDT, NEOBTC symbol = 'BNBUSDT' main()
Import the necessary packages (binance client, pandas, NumPy, and Matplotlib). At the start retrieve the Binance testnet API key and password using os.environ.get(). Initialize the Binance client with key, password, and testnet=true (We use only the testnet for the bot).
Any symbol can be used, here we use the ‘BNBUSDT ‘ and trigger main().
Step2:
def get_hourly_dataframe(): ''''valid intervals-1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M request historical candle (or klines) data using timestamp from above interval either every min, hr, day or month starttime = '30 minutes ago UTC' for last 30 mins time e.g. client.get_historical_klines(symbol='ETHUSDTUSDT', '1m', starttime) starttime = '1 Dec, 2017', '1 Jan, 2018' for last month of 2017 e.g. client.get_historical_klines(symbol='BTCUSDT', '1m', "1 Dec, 2017", # "1 Jan, 2018")''' starttime = '1 week ago UTC' # to start for 1 week ago interval = '1h' bars = client.get_historical_klines(symbol, interval, starttime) # Keep only first 5 columns, "date" "open" "high" "low" "close" for line in bars: del line[5:] # 2 dimensional tabular data df = pd.DataFrame(bars, columns=['date', 'open', 'high', 'low', 'close']) return df def sma_trade_logic(): symbol_df = get_hourly_dataframe() def main(): sma_trade_logic()
As a second step, define main(), sma_trade_logic() and get_hourly_dataframe(). We need historical data to start the SMA calculations. The function get_hourly_dataframe() uses the python-binance API get_historical_klines() to get the historical data for the given interval(hourly) and start time(one week ago). Note that the interval and start time can be changed to any valid interval and start time (see comments or python-binance documentation for more details). Finally, use the pandas DataFrame() to generate the data frame for the first five columns(date, open, high, low, and close).
Step3:
Calculate short-term and long-term SMA (for the close values). In this case, we use 5 periods and 15 periods SMA. For the same, use the pandas rolling() and mean() function.
def sma_trade_logic(): symbol_df = get_hourly_dataframe() # calculate 5 moving average using Pandas symbol_df['5sma'] = symbol_df['close'].rolling(5).mean() # calculate 15 moving average using Pandas symbol_df['15sma'] = symbol_df['close'].rolling(15).mean()
This also creates new columns ‘5sma’ and ‘15sma’.
Step4:
Whenever the 5sma > 15sma, it means short-term SMA is above the long-term SMA line. This can be considered as +1, else 0. A new column ‘Signal’ can be formed using the NumPy function where(). The where() function can be thought of as an if-else condition used in python.
# Calculate signal column symbol_df['Signal'] = np.where(symbol_df['5sma'] > symbol_df['15sma'], 1, 0) # NaN is not a number
Step5
At this stage, it would be a good idea to see all the columns output to a text file. We can use the regular file open and write functions to write to a file.
with open('output.txt', 'w') as f: f.write(symbol_df.to_string())
When you run the application, you will see that the output.txt has a date, open, high, low, close, 5sma, 15sma, and Signal columns. You can observe that the date column is in Unix timestamp(ms) and not in a human-readable format. This can be changed to a human-readable format using the Pandas function to_datetime() function.
# To print in human readable date and time (from timestamp) symbol_df.set_index('date', inplace=True) symbol_df.index = pd.to_datetime(symbol_df.index, unit='ms') with open('output.txt', 'w') as f: f.write(symbol_df.to_string())
Step6
Taking the difference of two adjacent values of the ‘Signal’ column we get the buy and sell positions. The positions can be used to get the exact buy and sell point. The position value can be +1 for buy and -1 for sell.
# Calculate position column with diff symbol_df['Position'] = symbol_df['Signal'].diff() symbol_df['Buy'] = np.where(symbol_df['Position'] == 1,symbol_df['close'], np.NaN ) symbol_df['Sell'] = np.where(symbol_df['Position'] == -1,symbol_df['close'], np.NaN )
The ‘Buy’ column is updated to a close value of the crypto asset if the ‘Position’ is 1, otherwise to NaN(Not a number).
The ‘Sell’ column is updated to a close value of the crypto asset if the ‘Position’ is 1, otherwise to NaN(Not a number).
Finally, we have the buy/sell signals as part of SMA.
Step7
We can now visually interpret all the important symbol-related information. This can be done by plotting the graph using matplotlib and making a call to plot_graph() from sma_trade_logic()
def plot_graph(df): df=df.astype(float) df[['close', '5sma','15sma']].plot() plt.xlabel('Date',fontsize=18) plt.ylabel('Close price',fontsize=18) plt.scatter(df.index,df['Buy'], color='purple',label='Buy', marker='^', alpha = 1) # purple = buy plt.scatter(df.index,df['Sell'], color='red',label='Sell', marker='v', alpha = 1) # red = sell plt.show()
Call the above function from sma_trade_logic().
plot_graph(symbol_df) # can comment this line if not needed
Step8
Lastly, trading i.e the actual buying or selling of the crypto must be implemented.
def buy_or_sell(buy_sell_list, df): for index, value in enumerate(buy_sell_list): current_price = client.get_symbol_ticker(symbol =symbol) print(current_price['price']) if value == 1.0: # signal to buy (either compare with current price to buy/sell or use limit order with close price) print(df['Buy'][index]) if current_price['price'] < df['Buy'][index]: print("buy buy buy....") buy_order = client.order_market_buy(symbol=symbol, quantity=2) print(buy_order) elif value == -1.0: # signal to sell if current_price['price'] > df['Sell'][index]: print("sell sell sell....") sell_order = client.order_market_sell(symbol=symbol, quantity=10) print(sell_order) else: print("nothing to do...")
In the above buy_or_sell() a for loop is added to get the current price of the symbol using the get_symbol_ticker() API. The for loop iterates over the buy_sell_list. As the buy_sell_list has either a value of ‘+1.0 ‘ for buy and ‘-1.0’ for sell, place an order on Binance to buy or sell at the market price after comparing with the current price of the symbol.
In the sma_trade_logic(), the ‘Position’ column has +1 and -1. Form a list of this column as it is much easier to iterate over the list (this is optional as you can also iterate directly over the ‘Position’ column using the data frame(df) passed as an argument)
# get the column=Position as a list of items. buy_sell_list = symbol_df['Position'].tolist() buy_or_sell(buy_sell_list, symbol_df)
Wrap Up
In this post, we covered the basics of SMA, the concept of crossover, and successfully designed a bot using the SMA crossover strategy. Running the bot will loop over all the buy and sell points, placing a market buy or sell order. You can always implement your own buy_or_sell() logic with various options as mentioned in the introduction of the course. You can also further enhance the bot by calculating the profit/loss for every buy/sell pair.
Moving Average Convergence Divergence (MACD)
Feel free to check out the full code at the Finxter GitHub repository here.
MACD basics
To understand MACD, firstly it is important to understand Exponential Moving Average (EMA). Mathematically EMA is calculated using
EMA = [CV x Factor] + [EMAprev x (1 - Factor)] where CV = current value of the asset Factor = 2/(N+1), where can be the number of days or period
EMA is also called EWM (Exponential Weighted Moving) average as it assigns weights to all the values due to Factor. In the case of EMA, the latest data point gets the maximum attention, and the oldest data point gets the least attention.
MACD consists of two lines MACD line and the signal line. MACD line is calculated by taking the difference between short-term EMA and long-term EMA. The short-term EMA is usually chosen with a span or period=12 and the long-term EMA is chosen with a span or period=26. The signal line is calculated using the EMA of the MACD line.
MACD = shortEMA - longEMA signal = EMA on MACD with a span or period = 9
Wherever the MACD line crosses the signal line, results in buying or selling points.
If MACD cuts the signal line in the direction (see figure),
- top to the bottom -> selling point
- bottom to the top -> buying point
As the moving average here is converging or diverging from the signal line it is called Moving Average convergence divergence.
Bot Trading Logic
We are now clear with the basics of MACD, let’s start coding the bot. The bot will be designed in steps.
Step1:
import os from binance.client import Client import pprint import pandas as pd # needs pip install import numpy as np import matplotlib.pyplot as plt # needs pip install if __name__ == "__main__": # passkey (saved in bashrc for linux) api_key = os.environ.get('BINANCE_TESTNET_KEY') # secret (saved in bashrc for linux) api_secret = os.environ.get('BINANCE_TESTNET_PASSWORD') client = Client(api_key, api_secret, testnet=True) print("Using Binance TestNet Server") pprint.pprint(client.get_account()) # Change symbol here e.g. BTCUSDT, BNBBTC, ETHUSDT, NEOBTC symbol = 'BNBUSDT' main()
Import the necessary packages (binance client, pandas, NumPy, and Matplotlib). At the start retrieve the Binance testnet API key and password using os.environ.get(). Initialize the Binance client with key, password, and testnet=true (We use only the testnet for the bot).
Any symbol can be used, here we use the ‘BNBUSDT ‘ and trigger main().
Step 2:
def get_data_frame(): # valid intervals - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M # request historical candle (or klines) data using timestamp from above, interval either every min, hr, day or month # starttime = '30 minutes ago UTC' for last 30 mins time # e.g. client.get_historical_klines(symbol='ETHUSDTUSDT', '1m', starttime) # starttime = '1 Dec, 2017', '1 Jan, 2018' for last month of 2017 # e.g. client.get_historical_klines(symbol='BTCUSDT', '1h', "1 Dec, 2017", "1 Jan, 2018") starttime = '1 day ago UTC' interval = '1m' bars = client.get_historical_klines(symbol, interval, starttime) for line in bars: # Keep only first 5 columns, "date" "open" "high" "low" "close" del line[5:] df = pd.DataFrame(bars, columns=['date', 'open', 'high', 'low', 'close']) # 2 dimensional tabular data return df def macd_trade_logic(): symbol_df = get_data_frame() def main(): macd_trade_logic()
As a second step, define main(), macd_trade_logic() and get_data_frame(). We need historical data to start the MACD calculations. The function get_data_frame() uses the python-binance API get_historical_klines() to get the historical data for the given interval(1min) and start time(one day ago). Note that the interval and start time can be changed to any valid interval and start time (see comments or python-binance documentation for more details). Finally, use the pandas DataFrame() to generate the data frame for the first five columns (date, open, high, low, and close).
Step3:
Calculate the short-term and long-term EMA for the close values, MACD, and signal line as we described above.
def macd_trade_logic(): symbol_df = get_data_frame() # calculate short and long EMA mostly using close values shortEMA = symbol_df['close'].ewm(span=12, adjust=False).mean() longEMA = symbol_df['close'].ewm(span=26, adjust=False).mean() # Calculate MACD and signal line MACD = shortEMA - longEMA signal = MACD.ewm(span=9, adjust=False).mean() symbol_df['MACD'] = MACD symbol_df['signal'] = signal
The EMA is calculated using the ewm (exponentially weighted moving) and mean() function of the Pandas data frame. MACD is the difference between short-term and long-term EMA and the signal line is calculated with the EMA of the MACD line.
We also add two more columns,’ MACD’ and ‘signal’.
Step 4:
Whenever the MACD > signal, it means the moving average (EMA in this case) is either converging or diverging from the signal. This can be considered as +1, else 0. A new column ‘Trigger’ can be formed using the NumPy function where(). The np.where() function can be thought of as an if-else condition used in python.
Further, taking the difference of two adjacent values of the ‘Trigger’ column, we get the buy and sell positions. The positions can be used to get the exact buy and sell point. The position value can be +1 for buy and -1 for sell.
symbol_df['Trigger'] = np.where(symbol_df['MACD'] > symbol_df['signal'], 1, 0) symbol_df['Position'] = symbol_df['Trigger'].diff() # Add buy and sell columns symbol_df['Buy'] = np.where(symbol_df['Position'] == 1,symbol_df['close'], np.NaN ) symbol_df['Sell'] = np.where(symbol_df['Position'] == -1,symbol_df['close'], np.NaN )
The ‘Buy’ column is updated to a close value of the crypto asset if the ‘Position’ is 1, otherwise to NaN(Not a number).
The ‘Sell’ column is updated to a close value of the crypto asset if the ‘Position’ is 1, otherwise to NaN(Not a number).
Finally, we have the buy/sell signals as part of MACD.
Step 5:
At this stage, it would be a good idea to see all the columns output to a text file. We can use the regular file open and write functions to write to a file.
with open('output.txt', 'w') as f: f.write(symbol_df.to_string())
When you run the application, you will see that the output.txt has a date, open, high, low, close, Trigger, Position, MACD, and signal, Buy and Sell columns. You can observe that the date column is in Unix timestamp(ms) and not in a human-readable format. This can be changed to a human-readable format using the Pandas function to_datetime() function.
# To print in human-readable date and time (from timestamp) symbol_df.set_index('date', inplace=True) symbol_df.index = pd.to_datetime(symbol_df.index, unit='ms') with open('output.txt', 'w') as f: f.write(symbol_df.to_string())
Step 6:
We can now visually interpret all the important symbol-related information. This can be done by plotting the graph using matplotlib and making a call to plot_graph() from macd_trade_logic()
def plot_graph(df): df=df.astype(float) df[['close', 'MACD','signal']].plot() plt.xlabel('Date',fontsize=18) plt.ylabel('Close price',fontsize=18) x_axis = df.index plt.scatter(df.index,df['Buy'], color='purple',label='Buy', marker='^', alpha = 1) # purple = buy plt.scatter(df.index,df['Sell'], color='red',label='Sell', marker='v', alpha = 1) # red = sell plt.show()
Call the above function from macd_trade_logic().
plot_graph(symbol_df) # can comment this line if not needed
Step 7:
Lastly, trading i.e the actual buying or selling of the crypto must be implemented.
def buy_or_sell(df, buy_sell_list): for index, value in enumerate(buy_sell_list): current_price = client.get_symbol_ticker(symbol =symbol) print(current_price['price']) # Output is in json format, only price needs to be accessed if value == 1.0 : # signal to buy if current_price['price'] < df['Buy'][index]: print("buy buy buy....") buy_order = client.order_market_buy(symbol=symbol, quantity=1) print(buy_order) elif value == -1.0: # signal to sell if current_price['price'] > df['Sell'][index]: print("sell sell sell....") sell_order = client.order_market_sell(symbol=symbol, quantity=1) print(sell_order) else: print("nothing to do...")
In the above buy_or_sell() a for loop is added to get the current price of the symbol using the get_symbol_ticker() API. The for loop iterates over the buy_sell_list. As the buy_sell_list has either a value of ‘+1.0 ‘ for buy and ‘-1.0’ for sell, place an order on Binance to buy or sell at the market price after comparing with the current price of the symbol.
In the macd_trade_logic(), the ‘Position’ column has +1 and -1. Form a list of this column as it is much easier to iterate over the list (this is optional as you can also iterate directly over the ‘Position’ column using the data frame(df) passed as an argument)
# get the column=Position as a list of items. buy_sell_list = symbol_df['Position'].tolist() buy_or_sell( symbol_df, buy_sell_list)
Wrap Up
In this post, we covered the basics of EMA (exponential moving average), the concept of MACD and signal line, and successfully designed a bot using the MACD strategy. Running the bot will loop over all the buy and sell points, placing a market buy or sell order, similar to what we did in SMA. You can always implement your own buy_or_sell() logic based on the needs or requirements for trading. You can also further enhance the bot by calculating the profit/loss for every buy/sell pair.
Bollinger Bands Algorithm
Feel free to check out the full code at the Finxter GitHub repository here.
Bollinger Band Basics
The Bollinger band is comprised of two bands lower and upper which form the boundaries of the tradeable asset such as crypto, stocks, etc. based on the historical prices. The lower and upper boundaries are calculated using Standard Deviation(SD).
Standard Deviation(SD) is a statistical tool that measures the deviation or dispersion of the data from the mean or average.
SD = √ ⎨ ⅀ (x-u)^2⎬ N where u is the mean or average, x is the dataset and N is the number of elements in the dataset.
The upper and lower bands are calculated as
upper band = SMA + 2 x SD lower band = SMA - 2 x SD where SMA is the simple moving average over a period of 20, and SD is the standard deviation
Below is an example representation of the Bollinger band. The middle line is the SMA for a period of 20. The upper and the lower lines are the 2 x standard deviation from the SMA line and form the boundary. An asset such as the crypto or stock values usually lies in between the upper and lower bands. Whenever the asset crosses the upper boundary, it is time to sell, and similarly, when the asset crosses the lower boundary, it is time to buy.
Bot Trading Logic
Let’s start coding the Bollinger band algorithm. As previously followed, we will design it in steps.
Step1:
import os from binance.client import Client import pprint import pandas as pd # needs pip install import numpy as np import matplotlib.pyplot as plt # needs pip install if __name__ == "__main__": # passkey (saved in bashrc for linux) api_key = os.environ.get('BINANCE_TESTNET_KEY') # secret (saved in bashrc for linux) api_secret = os.environ.get('BINANCE_TESTNET_PASSWORD') client = Client(api_key, api_secret, testnet=True) print("Using Binance TestNet Server") pprint.pprint(client.get_account()) # Change symbol here e.g. BTCUSDT, BNBBTC, ETHUSDT, NEOBTC symbol = 'BTCUSDT' main()
Import the necessary packages (binance client, pandas, NumPy, and Matplotlib). At the start retrieve the Binance testnet API key and password using os.environ.get(). Initialize the Binance client with key, password, and testnet=true (We use only the testnet for the bot).
Any symbol can be used, here we use the bitcoin ‘BTCUSDT ‘ and trigger main().
Step2:
def get_data_frame(): # valid intervals - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M # request historical candle (or klines) data using timestamp from above, interval either every min, hr, day or month # starttime = '30 minutes ago UTC' for last 30 mins time # e.g. client.get_historical_klines(symbol='ETHUSDTUSDT', '1m', starttime) # starttime = '1 Dec, 2017', '1 Jan, 2018' for last month of 2017 # e.g. client.get_historical_klines(symbol='BTCUSDT', '1h', "1 Dec, 2017", "1 Jan, 2018") starttime = '1 day ago UTC' # to start for 1 day ago interval = '5m' bars = client.get_historical_klines(symbol, interval, starttime) pprint.pprint(bars) for line in bars: # Keep only first 5 columns, "date" "open" "high" "low" "close" del line[5:] df = pd.DataFrame(bars, columns=['date', 'open', 'high', 'low', 'close']) # 2 dimensional tabular data return df def bollinger_trade_logic(): symbol_df = get_data_frame() def main(): bollinger_trade_logic()
As a second step, define main(), macd_trade_logic() and get_data_frame(). We need historical data to start the Bollinger calculations. The function get_data_frame() uses the python-binance API get_historical_klines() to get the historical data for the given interval(5min) and start time(one day ago). Note that the interval and start time can be changed to any valid interval and start time (see comments or python-binance documentation for more details). Finally, use the pandas DataFrame() to generate the data frame for the first five columns (date, open, high, low, and close).
Step3:
Calculate SMA for a period of 20, Standard deviation(SD), upper and lower band.
def bollinger_trade_logic(): symbol_df = get_data_frame() period = 20 # small time Moving average. calculate 20 moving average using Pandas over close price symbol_df['sma'] = symbol_df['close'].rolling(period).mean() # Get standard deviation symbol_df['std'] = symbol_df['close'].rolling(period).std() # Calculate Upper Bollinger band symbol_df['upper'] = symbol_df['sma'] + (2 * symbol_df['std']) # Calculate Lower Bollinger band symbol_df['lower'] = symbol_df['sma'] - (2 * symbol_df['std'])
The SMA is calculated using rolling() and mean() functions and SD using std() of Pandas data frame. As described, upper and lower are calculated using the mentioned formula above.
Step4:
The buy point is when close values are lesser than lower band values, while the sell point is when close values are greater than the upper band values. To compare the ‘close’, ‘upper’, and ‘lower’ columns, np. where() function can be used. The np. where(), function can be thought of as an if-else condition used in python.
However, directly comparing these columns of Pandas data frame is not possible as some values can be of string type such as NaN (not a number), while others can be of float type. To compare the numeric values we need to convert to a common type such as float.
# prepare buy and sell signals. The lists prepared are still panda data frames with float nos close_list = pd.to_numeric(symbol_df['close'], downcast='float') upper_list = pd.to_numeric(symbol_df['upper'], downcast='float') lower_list = pd.to_numeric(symbol_df['lower'], downcast='float') symbol_df['buy'] = np.where(close_list < lower_list, symbol_df['close'], np.NaN ) symbol_df['sell'] = np.where(close_list > upper_list, symbol_df['close'], np.NaN )
To get a common Pandas data frame type ‘float’, the function to_numeric() can be used.
Step5:
At this stage, it would be a good idea to see all the columns output to a text file. We can use the regular file open and write functions to write to a file.
with open('output.txt', 'w') as f: f.write( symbol_df.to_string() )
When you run the application, you will see that the output.txt has a date, open, high, low, close, upper, lower, buy, and sell columns. You can observe that the date column is in Unix timestamp(ms) and not in a human-readable format. This can be changed to a human-readable format using the Pandas function to_datetime() function.
# To print in human-readable date and time (from timestamp) symbol_df.set_index('date', inplace=True) symbol_df.index = pd.to_datetime(symbol_df.index, unit='ms') with open('output.txt', 'w') as f: f.write(symbol_df.to_string())
Step6:
We can now visually interpret all the important symbol-related information. This can be done by plotting the graph using matplotlib and making a call to plot_graph() from bollinger_trade_logic().
def plot_graph(df): df=df.astype(float) df[['close', 'sma','upper', 'lower']].plot() plt.xlabel('Date',fontsize=18) plt.ylabel('Close price',fontsize=18) x_axis = df.index plt.fill_between(x_axis, df['lower'], df['upper'], color='grey',alpha=0.30) plt.scatter(df.index,df['buy'], color='purple',label='Buy', marker='^', alpha = 1) # purple = buy plt.scatter(df.index,df['sell'], color='red',label='Sell', marker='v', alpha = 1) # red = sell plt.show()
Call the above function from bollinger_trade_logic().
plot_graph(symbol_df) # can comment this line if not needed
Step 7:
Lastly, trading i.e the actual buying or selling of the crypto must be implemented.
def buy_or_sell(df): buy_list = pd.to_numeric(df['buy'], downcast='float') sell_list = pd.to_numeric(df['sell'], downcast='float') for i in range(len(buy_list)): # get current price of the symbol current_price = client.get_symbol_ticker(symbol =symbol) if float(current_price['price']) >= sell_list[i]: # sell order print("sell sell sell...") sell_order = client.order_market_sell(symbol=symbol, quantity=0.01) print(sell_order) elif float(current_price['price']) <= buy_list[i]: # buy order print("buy buy buy...") buy_order = client.order_market_buy(symbol=symbol, quantity=0.001) print(buy_order) else: print("...do nothing...")
Prepare a buy and sell list. Compare with the current market price of the symbol. Accordingly, place a Binance buy/sell order if the price is lesser/greater than the price in the buy/sell list.
The above function can be called from the bollinger_trade_logic() at the end.
buy_or_sell(symbol_df)
Conclusion
We saw what Bollinger bands are and how they can be used for crypto trading. The bot with the Bollinger algorithm was implemented. You can run the application and see the buy/sell profits. The buy_or_sell() logic depends on the user requirements and is not one size fits all. You can always implement the logic which gives you maximum profit during the trade.
Comparison and Conclusion
Comparison
Every algorithm discussed so far has its own merits and demerits. The selection of an algorithm depends on the type of market, volatility, and performance. Let us try to make a short comparison of the algorithms we made use of as part of the crypto courses.
Basic | SMA | Bollinger | MACD | RSI |
Very basic. Used to learn to write your first trade bot | Simplest of momentum indicators | Update version of SMA | Based on EMA | RSI > 70 (overbought) RSI < 30 (oversold) |
No experience needed | Slower to respond to rapid price changes in the market | Visually easy to interpret | Uses MACD and Signal line | Based on the magnitude of recent price changes |
Beginner-friendly | Better in the side market than a trending market | Suitable for trending markets (80% accuracy) | Suitable for side markets | |
Some experience needed | Needs more experience | Needs more experience |
Conclusion
We are now at the end of the crypto course. In this crypto course, we understood the basics behind the three most frequently used trading algorithms in real trading, followed by designing the bot with python. Apart from the algorithms, we designed: RSI, MACD, Bollinger, and SMA, there are many other algorithms such as Time-series momentum strategy, Fibonacci strategy, mean reversal strategy, etc. that can be used for trading. These algorithms need more math skills to understand and design the bots.
In all the trading strategies so far discussed, made use of Binance testnet instead of Binance exchange so that there is no real money involved. As trading involves some financial risk, if you are an experienced trader you can always use the Binance exchange.
In real-life situations as the market is very volatile and unpredictable, many of the times expert traders make use of the combination of various strategies that we discussed so far.
E.g. SMA combined with RSI, MACD combined with RSI.