Another day, another record. Today, at 17:35 GST+1, Bitcoin crossed U\$33,000 in trading at Coinbase Pro exchange and did not fall sharply down. It took about 4.5 hours to accelerate from a psychological level of U\$30k with more greed among investors rather than fear of bursting Bitcoin (second) bubble around the corner. Greed is good. Gordon Gekko told us so. However, what about the risk?
Those of you who studied my earlier article on Tracking Bitcoin Gains since its 3rd Halving in May 2020 with Python most likely were divided between Bitcoin speculative price to skyrocket by the end of the year and those who left the field staying away and watching arena from the sideline. The level of instability captured Bitcoin in U\$10-12k range for while between August and October, followed by the explosion of strong demand (mainly driven by institutional buying). Being smart enough, it was wise to be long on Bitcoin to cash in the profits now.
Holding long position in Bitcoin bears the risk of price turning southward, suddenly. Two measures of risk, namely, Value-at-Risk (VaR) and Expected Shortfall (ES) are best to quantify the riskiness. No one wants to look at his earned profit melting down in minutes. Yes, in minutes! For cryptocurrencies, a timescales of 1 minute is the same what for trading stocks is the timescale of 1 day. For the latter, we say, the stock closed the day with, say, -5.2% loss. In crypto-trading, one day can turn your investment into seriously painful experience as things happen way to quick! Today delivers a great example:
with a -8.37% decline from the summit of U\$33253.46 reached at 21:00 GST+1 and 22:00. Would you panic or hold tight?
Let’s use Python to analyse the latest bull run of the Bitcoin price since mid-March 2020. We will check whether the use of 1-hour 1% VaR and the corresponding ES can be a consistent estimator of the least probable heavy loss.
# Does It Make Sense to Use 1-Hour 99% VaR and ES for Bitcoin? # (c) 2021 QuantAtRisk.com import ccrypto as cc import numpy as np import pandas as pd import matplotlib.pyplot as plt grey = (.7,.7,.7) # color # fetch Bitcoin close price-series df1 = cc.getCryptoSeries('BTC','USD',freq='h',exch='Coinbase',start_date='2017-01-01') df2 = cc.getCryptoSeries('BTC','USD',freq='h',exch='Coinbase',start_date='2020-03-13') plt.figure(figsize=(12,5)) plt.plot(df1, color=grey) plt.plot(df2, label='2020 BTC Bull Run') plt.grid() plt.ylabel('BTC/USD')
VaR and ES we estimate using the following two functions:
def VaR(ret, sl=.01): return np.quantile(ret, sl, axis=0, interpolation='higher') def ES(ret, sl=.01): var = VaR(ret, sl) return np.mean(ret[ret < var])
with the default significance level set to 1%.
The hourly return vector for the selected Bitcoin time-series we obtain by:
ret = df2.pct_change().dropna().values.flatten() n = ret.shape[0] # 7023 simple returns
where the empirical distribution of hourly returns we can visualised by:
def fitstudent(ret): # Student t best fit (finding: nu) parm = t.fit(ret) nu, mu_t, sig_t = parm nu = np.round(nu) print(nu) return t.pdf(x, nu, mu_t, sig_t) plt.figure(figsize=(12,4)) plt.hist(ret, bins=1000, color='#2c97f1', alpha=0.7, density=1, edgecolor=None) dx = 0.00001 # resolution x = np.arange(-0.4, 0.4, dx) plt.plot(x, fitstudent(ret), color='b', label='Student t PDF') plt.xlim([-0.04, 0.04]) plt.xlabel('Returns') plt.ylabel('Distribution on 1H BTC returns') plt.grid() plt.legend()
where, additionally, the distribution were nicely fit with Student t probability density function (PDF) with 2 degrees-of-freedom:
The distribution represents a complete return distribution for the entire bull run time-series marked in blue in the second chart. This assumes building this empirical distribution as of Jan 2, 2020 with 7023 (hourly) measurements. When the Covid-19’s pullback kicked off in mid-March 2020, a bullish season began. Of course, at the time, no one knew that the Bitcoin would rise so high as U\$30k today, but a lot of speculators put their money into the game creating a steady demand, therefore, the price rising up.
We can simulate the evolution of the empirical distribution of hourly BTC simple returns by the concept of growing window. We start with 30 hourly returns to form the distribution and with every next hour, we will add one more point until we will reach 7023 of them. This can be done in a loop as follows. Please note how the temporary vector is created and two risk measures are computed in each iteration:
outputs = list() # prepare the list to collect the results for i in np.arange(30, n): btc = df2.iloc[0:i] # extending window ret = btc.pct_change().dropna().values.flatten() ret_next_hour = ret[-1] # separate i+1 return ret = ret[0:-1] # trim the vector # calculate both risk measures var = VaR(ret) es = ES(ret) if ret_next_hour >= var: ret_next_hour = 0 outputs.extend([[i, var, es, ret_next_hour]]) outputs = np.array(outputs) pit_ret = out[:,3] # point-in-time hourly return
The last line of code extracts the vector of hourly returns which exceeded estimated 1% VaR. If there was such event, the value has been stored, otherwise replaced with zero.
Let’s visualise all cases when the hourly return exceeded the estimated VaR during 2020 Bitcoin bull run:
plt.figure(figsize=(10,5)) plt.plot(out[:,0], pit_ret, color=grey) plt.plot(out[:,0], out[:,1], label='VaR') plt.plot(out[:,0], out[:,2], label='ES') plt.grid() plt.legend() plt.ylabel('Hourly Returns') plt.xlabel('Number of Hours since 2020-03-13 00:00 GST+1') plt.title('Hours when BTC hourly return exceeded estimated 1% VaR', fontsize=14) plt.savefig("/Users/pawel/Desktop/bitcoin4.png", bbox_inches='tight')
print(len(pit_ret[pit_ret < 0]))
24 cases when VaR was exceeded and only 8 cases when the hourly loss were greater than the anticipated ES:
The Expected Shortfall measure tells you what is, on average, the expected loss if the VaR is exceeded. These eight hourly losses were pretty heavy. From the perspective of the investor sitting at home, the reaction time to close a long position after such event could be significantly delayed. The other situation is for algorithms performing trading BTC on our behalf. They risk engine can implement a presented above simple check and trigger an action ‘close long’.
Is is effective? It depends. As usual, every application of any quantitative risk measure requires proper setup and backtesting before going into model production. Nevertheless, the lesson coming from today’s Bitcoin market and rough Python data analysis indicates that it makes sense to keep both VaR and ES measure being calculated. We have shown, that BTC can slide downhill in an hour, exceeding ES expected value. In the bull run, most probably it will bounce back but in other cases… it can turn into unstoppable avalanche as we witnessed already at the beginning of 2018.
Keep your eyes open! Greed is good but in sane quantities.
3 comments
I am regular reader, how are you everybody? This article posted
at this web site is really fastidious.
Thanks :)