Last time, we introduced perpetual contract funding rate arbitrage (https://www.fmz.com/digest-topic/6381), that is, to make long spot of the same amount by making short of perpetual contract futures, and we can continue to obtain funding rate profit. In the case of a large negative premium, it can also make money and premium, to return profit. In the bull market in August and September, the annualized rate once reached 100%, so it is a relatively popular strategy.

In the low-risk cryptocurrency arbitrage, there is another type of strategy that has not been introduced - the basis return arbitrage. Specific principle:

1.There is a price spread between the futures contract and the spot. The feature of the delivery contract is that it is not settled at the spot price until the delivery date. Therefore, when the delivery date is far away, the delivery of the contract is easily affected by the market sentiment. If the market performs well, more people will be optimistic about the future price, so there will be a positive premium. When there is a sharp drop, there is often a negative premium. But generally speaking, the delivery of the contract will not deviate too much from the spot, and will always return on the delivery day.

2.There are currency-based delivery contracts. For example, Binance has current quarterly and next-quarter delivery contracts. There is a big difference between a crypto-margined delivery contract and a USDT-margined perpetual contract. The crypto-margined settlement uses currency, and the currency price is constantly changing, which will be introduced in detail next.

The code in this article can be run directly, but due to network reasons, the crawling data part requires scientific Internet access, it is best to use your own computer to run, or use Google colab.

Profit & Loss Calculation of Crypto-Margined Contracts

According to Binance documentation, revenue = trading direction × executed volume × contract multiple × (1 / open price - 1 / close price) = position value × (1 / open price - 1 / close price); when you make short, the position value is negative. If you hold 100 BTCUSD delivery contracts, each worth 100USD, and the open price is 10,000USD, then the profit and loss with the price changing is as follows:

Through calculation and analysis, the profits from crypto-margined short or long positions are non-linear and measured by currency profits; if there is loss in making a short position, only lose at most the currency amount of one position, but there is no upper limit on the currency amount earned; if there is profit in making a long position, only make profit of, at most, the currency amount of one position, and there is no upper limit on losses. It seems that it is more cost-effective to make short, but the profit of making short will decrease as the currency price declines, which is not so high calculated in USD. If you calculate the USD profit, the situation is exactly the opposite. You can earn at most one position value by making short, and the loss has no upper limit.

At the same time, when trading crypto-margined contracts, you need to hold currencies originally. If you consider USD as the quote currency, then the total account value = (account currency amount + position value × (1 / open price - 1 / close price)) × spot price. If the value of the position = - currency amount in the account × open price, that is, using one time leverage to make short, and the total account value = currency amount in the account × open price × spot price of close position / close price. Considering that the price of the delivery contract will eventually return to spot price, in the last, the total account value = currency amount in the account × open price. That is to say, the account value will be locked at the open price, and will not change with the current price. According to the analysis, even if the price rises infinitely, the position will not be liquidated. This is the principle of hedging. Making short with one leverage is equivalent to selling your spot currency at the futures price in advance.

If the currency of the futures account is purchased from the spot market, then the total account value = currency amount in the account × (open price - spot buy price), as long as the position is opened, our profit has been fixed, and the current price doesn't matter. The price spread is the profit from arbitrage. This is the principle of futures arbitrage.

Of course, in most cases, we don't have to wait until the delivery date. If the price spread decreases, we can close the position in advance. At this time, the total account value = spot value × (futures-to-spot ratio of the opening period / futures-to-spot ratio of the closing period - 1). As long as the futures and spot price ratio in the opening period is greater than that in the closing period, and can cover the fee, and then there will be profits.

import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

value = 100<em>100 #position value open_price = 10000 #open position price 10000USD long_profit_list = [] short_profit_list = [] long_usdt_profit_list = [] short_usdt_profit_list = [] close_range = range(1000,30000,10) for p in close_range: profit = value</em>(1/open_price-1/p)
long_profit_list.append(profit)
long_usdt_profit_list.append(profit<em>p) short_profit_list.append(-profit) short_usdt_profit_list.append(-profit</em>p)

crypto-margined profit

plt.figure(figsize=(12, 7), dpi=80)
plt.plot(close_range,long_profit_list,label='long');
plt.plot(close_range,short_profit_list);
plt.plot(close_range,[1]<em>len(close_range),'r--'); plt.plot(close_range,[-1]</em>len(close_range),'g--');
plt.ylabel('profit');
plt.xlabel('close price');
plt.grid(True)
plt.annotate('Short profit', xy=(4500, 1.5), xytext=(7000, 2.5),arrowprops=dict(facecolor='black'));
plt.annotate('Long profit', xy=(4500, -1.5), xytext=(7000, -2.5),arrowprops=dict(facecolor='black'));
plt.annotate('Open price', xy=(10000, 0), xytext=(13000, 2.5),arrowprops=dict(facecolor='black'));

profit calculated by USD

plt.figure(figsize=(12, 7), dpi=80)
plt.plot(close_range,long_usdt_profit_list,label='long');
plt.plot(close_range,short_usdt_profit_list);

plt.ylabel('profit');
plt.xlabel('close price');
plt.annotate('Short profit', xy=(5000, 5000), xytext=(7000, 10000),arrowprops=dict(facecolor='black'));
plt.annotate('Long profit', xy=(5000, -5000), xytext=(7000, -10000),arrowprops=dict(facecolor='black'));
plt.grid(True)
Out[101]:

Futures & Spot Arbitrage Procedures

1.Real-time monitoring of the changes in the futures & spot premium. After reaching the set value, the spot currency symbol is bought and immediately transferred to the futures to make short. The value of making short is the spot amount × the open price.
2.Wait for the return of the premium, and after reaching the set value, close the futures position, transfer it to the spot to sell, and gain profit.

Details

1.The premiums on different delivery dates have different meanings. For example, if there is the quarterly premium of 5% and the next-quarter premium of 5% , the quarterly one will definitely be preferred for arbitrage. The corresponding annualized rate needs to be calculated based on the delivery date.
2.The service fee needs to be considered, which involves spot buy and sell as well as futures open and close positions, which in total has 4 trades.
3.Futures and spot trades must be carried out at the same time to lock the premium. In order to avoid market shocks, positions can be reduced in multiple trades.
4.When there is currency in the futures account, you can directly concurrent open position arbitrage without waiting for the transfer. In the same way, the spot currency does not need to be completely transferred to futures, which is convenient for closing positions concurrently.
5.To monitor all trading pairs, whichever has a chance, and which one has a higher premium.
6.The choice of closing positions is very important. You can close positions by levels; you can use 0 premium or a negative premium to close all.

History Premium Changes

Taking the delivery data of Binance as an example; there are 9 trading pairs, namely BTCUSDT, ETHUSDT, ADAUSDT, LINKUSDT, BCHUSDT, DOTUSDT, XRPUSDT, LTCUSDT and BNBUSDT, which can be used for arbitrage trading. Here, ETH is selected to specifically analyze the premium changes between the delivery contract and the spot.

Since the beginning of this year (2021), ETH started from 600U, and rose to a maximum of 4000U in May, then fell to 2000U in June and July, and recently returned to 3500U, which means the market is booming. Consider of the three delivery contracts with expiry dates of 210625, 210924, and 211231. The premium of 210625 remains at 8% for a long time; if start the arbitrage at 10% and close positions at 6% , there are about 4 opportunities in 4 months, and the annualized rate will be over 50%. 210924 has a premium, maximum, over 15%, which has now returned. 211231, which still has a long time before expiry date, has a maximum premium of 5%. It can be seen that as long as you wait patiently, there are many arbitrage opportunities on ETH.

Readers can change the trading pair by themselves; the situation is basically similar; in general, it is a pretty good time zone from January to April this year.

the current trading pair

Info = requests.get('https://dapi.binance.com/dapi/v1/exchangeInfo')
symbols = [s['symbol'] for s in Info.json()['symbols']]
symbols_nq = list(filter(lambda x:x.split('&lt;em>')[-1]=='211231', symbols)) #next quarter contract 
symbols_q = list(filter(lambda x:x.split('&lt;/em>')[-1]=='210924', symbols)) #quarterly contract
symbols_s = [s.split('_')[0]+'T' for s in symbols_nq] #spot trading pair
','.join(symbols_s)
def GetKlines(symbol='BTCUSDT',start='2020-8-10',end='2021-8-10',period='1h',base='fapi',v = 'v1'):
Klines = []
start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))&lt;em>1000 + 8&lt;/em>60&lt;em>60&lt;/em>1000
end_time = int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))&lt;em>1000 + 8&lt;/em>60&lt;em>60&lt;/em>1000
intervel_map = {'m':60&lt;em>1000,'h':60&lt;/em>60&lt;em>1000,'d':24&lt;/em>60&lt;em>60&lt;/em>1000}
while start_time &amp;lt; end_time: mid_time = min(start_time+1000&lt;em>int(period[:-1])&lt;/em>intervel_map[period[-1]],end_time) url = 'https://'+base+'.binance.com/'+base+'/'+v+'/klines?symbol=%s&amp;amp;interval=%s&amp;amp;startTime=%s&amp;amp;endTime=%s&amp;amp;limit=1000'%(symbol,period,start_time,mid_time) res = requests.get(url) res_list = res.json() if type(res_list) == list and len(res_list) > 0:
start_time = res_list[-1][0]
Klines += res_list
elif type(res_list) == list:
start_time = start_time+1000&lt;em>int(period[:-1])&lt;/em>intervel_map[period[-1]]
else:
print(url)
df = pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
df.index = pd.to_datetime(df.time,unit='ms')
return df
symbol = 'ETH'
df_s = GetKlines(symbol=symbol+'USDT',start='2020-12-26',end='2021-9-15',period='1h',base='api',v='v3')
df_nq = GetKlines(symbol=symbol+'USD_211231',start='2021-6-26',end='2021-9-15',period='1h',base='dapi')
df_q = GetKlines(symbol=symbol+'USD_210924',start='2021-3-26',end='2021-9-15',period='1h',base='dapi')
df_lq = GetKlines(symbol=symbol+'USD_210625',start='2020-12-26',end='2021-6-24',period='1h',base='dapi')

spot price

df_s.close.dropna().plot(figsize=(16,6),grid=True);

last quarter contract premium

(100*(df_lq.close-df_s.close)/df_s.close).dropna().plot(figsize=(16,6),grid=True);

quarterly contract premium

(100*(df_q.close-df_s.close)/df_s.close).dropna().plot(figsize=(16,6),grid=True);

next quarter contract premium

(100*(df_nq.close-df_s.close)/df_s.close).dropna().plot(figsize=(16,6),grid=True);

the current trading opportunity

For the contract 210924 is going to expire, here we mainly observe contract 211231, which still has three months to expire.
For now, the basic premium is around 3%, and the highest premium is 5%. We could say the opportunity is not very promising. However, after contract 210924 is expired, a new next quarter contract will be generated, and there will be 6 months to deliver, which means there will still be a lot of opportunities.

df_all = pd.DataFrame(index=pd.date_range(start='2021-6-26', end='2021-9-16', freq='1H'),columns=symbols_s)
for i in range(len(symbols_nq)):
symbol_nq = symbols_nq[i]
symbol_s = symbols_s[i]
df_s = GetKlines(symbol=symbol_s,start='2021-6-26',end='2021-9-16',period='1h',base='api',v='v3')
df_nq = GetKlines(symbol=symbol_nq,start='2021-6-26',end='2021-9-16',period='1h',base='dapi')
df_all[symbol_s] = (100*(df_nq.close-df_s.close)/df_s.close).drop_duplicates()
df_all.dropna().plot(figsize=(16,10),grid=True);

Conclusion

This article mainly introduces making arbitrage trading by using the spread return between the delivery contract and the spot. This type of arbitrage is a common trading practice, with many advantages:

1.Low risk. Since making short position with 1x leverage will not be liquidated, there is no risk even if the premium expands, and it is almost a risk-free arbitrage.
2.High certainty. The price of the delivery contract will always return to the spot. After the arbitrage is completed, it will not be affected by the current price fluctuation.
3.The operation principle is simple, and it can trade with multiple currency symbols, which is suitable for relatively large funds to pursue stable profits.
4.The profit is not low, and sometimes there will be a deep negative premium. If you are lucky and have mastered the rhythm, the profit is very considerable.

Main Risks:
1.If the premium increases for a long time, there will be a floating loss for a long time. At this time, closing positions and leaving the market will result in an actual loss.
2.Platform API failure; single-leg trade.
3.The liquidity of trading contracts is poor, and there are too many strategies of the same type, resulting in excessive slippoint and eroding profits.

Leave a Reply

Your email address will not be published.