# Simple Moving Average (SMA) – Python Binance API for Crypto Trading

Rate this post

A simple moving average (SMA) is calculated by summing over a fixed number of last prices, say `k`, and dividing this by the number of prices `k`. Depending on the selection k, you can obtain short-term or long-term SMAs. Short-term SMAs respond quickly whereas long-term SMAs respond slowly to changes in the prices.

You can check out the full code at the Finxter GitHub repository here.

## Intro

Before we begin, I would like to make a small request

• If you don’t know the basics of `binance` and `python-binance` API.
• If you want to know how to set up the development environment, set up a `binance` account or `binance-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

1.  You can keep separate loops to buy and sell and keep looping until at least one buy and one sell occurs and then break.
2.  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.
3.  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 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.

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.

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.

Step 1:

```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)
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_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

symbol_df = get_hourly_dataframe()

def main():
```

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).

Step 3:

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`’.

Step 4:

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
```

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, 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())
```

Step 6

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.

Step 7

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['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):
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)

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.

## 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.

## Full Code

Here’s the code of the crypto-trading bot for copy&paste:

```# Author : Yogesh K for finxter.com
# SMA(simple moving average) using python-binance

import os
from binance.client import Client
from binance import ThreadedWebsocketManager # This import can be removed. not needed
import pprint
import datetime      # This import can be removed, not needed
import pandas as pd     # needs pip install
import numpy as np
import matplotlib.pyplot as plt   # needs pip install

def get_hourly_dataframe(): # we want hourly data and for past 1 week.
# 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 week ago UTC'  # to start for 1 week ago
interval = '1h'
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 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['Sell'], color='red',label='Sell',  marker='v', alpha = 1)  # red = sell

plt.show()

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 (either compare with current price to buy/sell or use limit order with close price)
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...")

symbol_df = get_hourly_dataframe()

# small time Moving average. calculate 5 moving average using Pandas over close price
symbol_df['5sma'] = symbol_df['close'].rolling(5).mean()
# long time moving average. calculate 15 moving average using Pandas
symbol_df['15sma'] = symbol_df['close'].rolling(15).mean()

# 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')

# Calculate signal column
symbol_df['Signal'] = np.where(symbol_df['5sma'] > symbol_df['15sma'], 1, 0)
# 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 )

with open('output.txt', 'w') as f:
f.write(
symbol_df.to_string()
)

#plot_graph(symbol_df)

# get the column=Position as a list of items.

def main():

if __name__ == "__main__":

api_key = os.environ.get('BINANCE_TESTNET_KEY')     # passkey (saved in bashrc for linux)
api_secret = os.environ.get('BINANCE_TESTNET_PASSWORD')  # secret (saved in bashrc for linux)

client = Client(api_key, api_secret, testnet=True)
print("Using Binance TestNet Server")

pprint.pprint(client.get_account())

symbol = 'BNBUSDT'   # Change symbol here e.g. BTCUSDT, BNBBTC, ETHUSDT, NEOBTC
main()```

## Where to Go From Here

Cryptocurrency trading is a highly sought-after skill in the 21st century. Freelancers who excel in crypto trading are paid up to \$300 per hour. If you want to learn the ins and outs of trading, check out our full course on the Finxter Computer Science academy: