Futures Trading with python-binance

A Gentle Introduction

Jack Stephens
Analytics Vidhya
5 min readJul 1, 2021

--

Photo by Executium on Unsplash

Hello friends. Recently, I’ve been attempting to build my own proprietary crypto algorithmic trading software using the python-binance wrapper. A large part of my strategy involves trading Futures (USD(S)-M), for the benefit of applying leverage, going long-short, etc., so I’ve put together this (hopefully) handy little guide based on what I’ve learned about this excellent library (shout out to author Sam McHardy), with a specific focus on futures. Let’s get started!

PLEASE NOTE:

1) I am assuming my dear reader is at least vaguely familiar with the library and therefore understands and possesses Binance API keys (for those unfamiliar, see links below).

2) As Mr McHardy himself disclaims, it is an unofficial library, meaning it’s not supported by Binance the company. Only the actual API links are supported, which may be subject to change every so often. Thus we must use the library at our own risk.

3) Also, and most importantly, please do not infer investment advice in any way from this article! This is very much a ‘how-to’ guide, so please be sensible and think carefully before executing any live trades in the market.

Firstly, we’ll install the library:

# In a terminal, environment (virtual or otherwise) activated
pip install python-binance

Then import it in Python per below & instantiate a client using our API keys:

from binance.client import Clientuser_key = **********************
secret_key = **********************
binance_client = Client(user_key, secret_key)

Market Data

Before diving into the trading side of things, we may first wish to retrieve some market data for the contract we are trading. For this example, let’s keep things simple and select the BTC/USDT perpetual future to work with. If we wish to get the current price of the contract:

binance_client.futures_symbol_ticker(symbol='BTCUSDT')

Outputs:

# {'symbol': 'BTCUSDT', 'price': '48057.72', 'time': 1630312116135}

EDIT: I’d originally quoted the ‘futures_coin_symbol_ticker’ method; transpires the alternative method used above has far greater instrument coverage.

Say we now wish to retrieve OHLCV market data for our contract to perform some data analysis on historical data. We can do so using the below method:

binance_client.futures_historical_klines(
symbol='BTCUSDT',
interval='1d', # can play with this e.g. '1h', '4h', '1w', etc.
start_str='2021-06-01',
end_str='2021-06-30'
)

By default the output will be returned to us in list format, however we can very easily convert it into a pandas DataFrame to make it more fit for analytical purposes:

import pandas as pddf = pd.DataFrame(binance_client.futures_historical_klines(
symbol='BTCUSDT',
interval='1d',
start_str='2021-06-01',
end_str='2021-06-30'
))
df.head()

Outputs:

#               0         1         2   ...          9                  10 11
#0 1622505600000 37244.36 37893.76 ... 291774.994 10673866023.68145 0
#1 1622592000000 36694.37 38232.99 ... 223993.314 8358143926.28754 0
#2 1622678400000 37570.00 39470.00 ... 254932.483 9843247414.77212 0
#3 1622764800000 39247.40 39297.35 ... 345357.923 12774740375.75271 0
#4 1622851200000 36828.03 37900.49 ... 314764.238 11449282806.42592 0
#[5 rows x 12 columns]

As you can see, the data-types in our columns aren’t quite what we’re after (i.e. timestamp instead of date, superfluous columns beyond OHLCV). Therefore we’ll perform a snippet of data wrangling, which pandas makes so easy:

# crop unnecessary columns
df = df.iloc[:, :6]
# ascribe names to columns
df.columns = ['date', 'open', 'high', 'low', 'close', 'volume']
# convert timestamp to date format and ensure ohlcv are all numeric
df['date'] = pd.to_datetime(df['date'], unit='ms')
for col in df.columns[1:]:
df[col] = pd.to_numeric(df[col])
df.head()

Outputs:

#         date      open      high       low     close      volume
#0 2021-06-01 37244.36 37893.76 35500.00 36693.41 590822.540
#1 2021-06-02 36694.37 38232.99 35905.00 37569.99 441719.806
#2 2021-06-03 37570.00 39470.00 37150.15 39247.40 507429.005
#3 2021-06-04 39247.40 39297.35 35552.51 36828.03 700625.866
#4 2021-06-05 36828.03 37900.49 34800.00 35498.62 631028.448

Much better! Right, enough foreplay — let’s dive into the trading.

Trading

The fun part: firstly, let’s ping a test order to see if the server picks it up. If not, then some investigation into account API privileges may be required.

binance_client.create_test_order(
symbol='BTCUSDT',
type='MARKET',
side='BUY',
quantity=0.001
)

If all is well, we should receive an empty dictionary: ‘{}’.

Next, we’ll take a quick glance at the order book before placing a real trade to visualise market depth:

# into a pandas DataFrame for neater output 
df = pd.DataFrame(
binance_client.futures_order_book(symbol='BTCUSDT')
)
print(df[['bids', 'asks']].head())

Outputs:

#bids               asks
#0 [36261.99, 0.005] [36262.22, 0.041]
#1 [36261.98, 0.100] [36262.46, 0.099]
#2 [36261.84, 0.277] [36262.60, 0.066]
#3 [36261.83, 0.005] [36262.62, 0.001]
#4 [36261.79, 0.186] [36262.74, 0.711]

Now, of utmost importance before we place a real futures order is the setting of leverage. We must be very, very careful not to make any mistakes when we determine our leverage, as one small typo could result in us taking on far more risk than we’re willing (or able!) to for a given strategy. This is why, directly before every trade, I always determine my leverage with the below method:

binance_client.futures_change_leverage(symbol='BTCUSDT', leverage=1)

This will ensure that all trades you execute in the terminal session for the specified symbol take on the leverage set above. If you’re more adventurous than I and wish to ramp up the lever, then just ensure you’re fully prepared to take on the additional risk, understand how it works and have enough funds in your margin account to cover any potential losses.

To place a futures limit order:

binance_client.futures_create_order(
symbol='BTCUSDT',
type='LIMIT',
timeInForce='GTC', # Can be changed - see link to API doc below
price=30000, # The price at which you wish to buy/sell, float
side='BUY', # Direction ('BUY' / 'SELL'), string
quantity=0.001 # Number of coins you wish to buy / sell, float
)

To place a futures market order:

binance_client.futures_create_order(
symbol='BTCUSDT',
type='MARKET',
timeInForce='GTC',
side='BUY',
quantity=0.001
)

Et voila! The position should populate in your Binance account view like so (mine was a market order executed at the time of writing):

0.001 BTC/USDT Perpetual - Market Order

If the trade is yet to fill, one may view current outstanding orders very simply:

binance_client.futures_get_open_orders(symbol='BTCUSDT')

Conclusion

Hope this was helpful guys, do feel free to check out full source code on my Github page, plus I’d definitely encourage you to check out and piece together some of the python-binance documentation, as well as the Binance API documentation, as there may likely be other functionality you’re after that I haven’t covered here:

As will always be the case, constructive feedback is more than welcome so do let me know what you think I’ve done right or wrong. Suggestions for future topics are also encouraged, as are any questions or issues, so please don’t hesitate to comment and I’ll endeavour to respond ASAP.

--

--

Jack Stephens
Analytics Vidhya

Interests include theoretical physics, quantitative finance, football, probability, programming... applied mathematics generally!