In [1]:
import os
import pandas as pd
import numpy as np
import datetime

import plotly.graph_objects as go
from plotly.subplots import make_subplots

%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = 'retina'
In [2]:
# try:
#     os.remove("btc.csv")
# except FileNotFoundError:
#     pass
# !wget https://coinmetrics.io/newdata/btc.csv
In [3]:
data = pd.read_csv("btc.csv" ,
                   usecols=['date', 'SplyCur', 'PriceUSD', 'FeeTotNtv', 'IssTotNtv', 'TxTfrValNtv'])

dates = pd.date_range(
    start=np.min(data['date']),
    end='2040-01-01').strftime('%Y-%m-%d')

date_df = pd.DataFrame(dates, columns=['date'])

data = date_df.merge(data, on='date', how='left').reset_index(drop=True)
data.columns.values
Out[3]:
array(['date', 'FeeTotNtv', 'IssTotNtv', 'PriceUSD', 'SplyCur',
       'TxTfrValNtv'], dtype=object)
In [4]:
data['datetime'] = [datetime.datetime.strptime(x, '%Y-%m-%d') for x in data['date']]
data['days_until_halving'] = data['datetime'] - datetime.datetime.strptime('2020-05-12', '%Y-%m-%d')
data['days_until_halving'] = [x.days for x in data['days_until_halving']]
In [5]:
data['IssTotNtvProj'] = [
    issuance if issuance > 0
    else (6.25 * 6 * 24 / (1 * (2 ** (day_number // (365 * 4 + 1)))))
    for issuance, day_number in zip(data['IssTotNtv'], data['days_until_halving'])]

data['extant_supply'] = data['IssTotNtvProj'].cumsum()
In [6]:
data['fee_ratio'] = data['FeeTotNtv'].rolling(28 * 3).mean() / data['SplyCur'].rolling(28 * 3).mean()
data['block_subsidy_ratio'] = data['IssTotNtv'] / data['SplyCur']

data['fee_ratio_volume'] = data['FeeTotNtv'].rolling(28 * 3).mean() / data['TxTfrValNtv'].rolling(28 * 3).mean()
data['block_subsidy_ratio_volume'] = data['IssTotNtv'] / data['TxTfrValNtv']

data['block_subsidy_ratio_proj'] = data['IssTotNtvProj'] / data['extant_supply']
data.loc[data['IssTotNtv'] > 0, 'block_subsidy_ratio_proj'] = None
# chart_utils.two_axis_chart(
#     data.loc[data['date'] > '2010-01-01'], x_series='date',
#     title='Bitcoin Block Reward',
#     y1_series=['fee_ratio', 'block_subsidy_ratio', 'block_subsidy_ratio_proj'], y2_series='extant_supply',
#     y1_series_axis_type='log', y1_series_axis_range=[-10, -2], y1_series_axis_format="1e{n}",
#     y2_series_axis_type='linear', y2_series_axis_range=[0, 25000000], y2_series_axis_format=None
# )
In [7]:
data_subset = data.loc[
    data['date'] >= '2010-01-01'
][['fee_ratio', 'fee_ratio_volume', 'block_subsidy_ratio_volume']].replace([np.inf, -np.inf], np.nan).dropna()

z = np.polyfit(np.log(data_subset.index.array + 1), np.log(data_subset['fee_ratio']), 1)
f = np.poly1d(z)
data['fee_ratio_proj'] = [np.exp(f(np.log(x + 1))) for x in data.index.array]

z = np.polyfit(np.log(data_subset.index.array + 1), np.log(data_subset['fee_ratio_volume']), 1)
f = np.poly1d(z)
data['fee_ratio_volume_proj'] = [np.exp(f(np.log(x + 1))) for x in data.index.array]

z = np.polyfit(np.log(data_subset.index.array + 1), np.log(data_subset['block_subsidy_ratio_volume']), 1)
f = np.poly1d(z)
data['block_subsidy_ratio_volume_proj'] = [np.exp(f(np.log(x + 1))) for x in data.index.array]

data['total_miner_rewards_ratio'] = data['fee_ratio'] + data['block_subsidy_ratio']
data['total_miner_rewards_ratio_volume'] = data['fee_ratio_volume'] + data['block_subsidy_ratio_volume']

data['total_miner_rewards_ratio_proj'] = data['fee_ratio_proj'] + data['block_subsidy_ratio_proj']
data['total_miner_rewards_ratio_volume_proj'] = data['fee_ratio_volume_proj'] + data['block_subsidy_ratio_volume_proj']

data_subset = data_subset = data.loc[
    data['date'] >= '2010-01-01'
]
In [8]:
fig = make_subplots(
    specs=[[{"secondary_y": True}]],
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['fee_ratio'], name='fee_ratio',
               line=dict(color='royalblue')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['fee_ratio_proj'], name='fee_ratio_proj',
               line=dict(color='royalblue', dash='dash')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['block_subsidy_ratio'], name='block_subsidy_ratio',
               line=dict(color='darkgreen')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['block_subsidy_ratio_proj'], name='block_subsidy_ratio_proj',
               line=dict(color='darkgreen', dash='dash')),
    secondary_y=False
)

# Second trace
fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['extant_supply'], name='extant_supply',
               line=dict(color='darkorange')),
    secondary_y=True,
)

fig.update_layout(
    title_text='Bitcoin Block Reward & Fees as Percent of Extant Supply',
    annotations=[
        dict(x=1, y=-0.1,
             text="Chart by: @typerbole; Data: CoinMetrics",
             showarrow=False, xref='paper', yref='paper',
             xanchor='right', yanchor='auto', xshift=0, yshift=0)
    ],
    showlegend=True,
    legend_orientation="h",

)

# Set y-axes titles
fig.update_yaxes(
    title_text='Percent of Extant Supply', secondary_y=False, tickformat=".8%",
    type='log', range=[-10, -2],
    showgrid=False
)
fig.update_yaxes(
    title_text='extant_supply', secondary_y=True, tickformat=None,
    type='linear', range=[0, 21000000],
    showgrid=False
)

fig.show()
In [9]:
fig = make_subplots(
    specs=[[{"secondary_y": True}]],
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['total_miner_rewards_ratio'], name='total_miner_rewards_ratio',
               line=dict(color='royalblue')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['total_miner_rewards_ratio_proj'], name='total_miner_rewards_ratio_proj',
               line=dict(color='royalblue', dash='dash')),
    secondary_y=False
)

# Second trace
fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['extant_supply'], name='extant_supply',
               line=dict(color='darkorange')),
    secondary_y=True,
)

fig.update_layout(
    annotations=[
        dict(x=1, y=-0.1,
             text="Chart by: @typerbole; Data: CoinMetrics",
             showarrow=False, xref='paper', yref='paper',
             xanchor='right', yanchor='auto', xshift=0, yshift=0)
    ],
    showlegend=True,
    legend_orientation="h",
    title_text='Bitcoin Total Miner Rewards as Percent of Extant Supply (Projected)',

)

# Set y-axes titles
fig.update_yaxes(
    title_text='Percent of Extant Supply', secondary_y=False, tickformat=".3%",
    type='log', range=[-5, -1],
    showgrid=False
)
fig.update_yaxes(
    title_text='extant_supply', secondary_y=True, tickformat=None,
    type='linear', range=[0, 21000000],
    showgrid=False
)

fig.show()
In [10]:
fig = make_subplots(
    specs=[[{"secondary_y": True}]],
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['fee_ratio_volume'], name='fee_ratio_volume',
               line=dict(color='royalblue')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['fee_ratio_volume_proj'], name='fee_ratio_volume_proj',
               line=dict(color='royalblue', dash='dash')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['block_subsidy_ratio_volume'], name='block_subsidy_ratio_volume',
               line=dict(color='darkgreen')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['block_subsidy_ratio_volume_proj'], name='block_subsidy_ratio_volume_proj',
               line=dict(color='darkgreen', dash='dash')),
    secondary_y=False
)

# Second trace
fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['extant_supply'], name='extant_supply',
               line=dict(color='darkorange')),
    secondary_y=True,
)

fig.update_layout(
    title_text='Bitcoin Block Reward & Fees as Percent of Transaction Volume',
    annotations=[
        dict(x=1, y=-0.1,
             text="Chart by: @typerbole; Data: CoinMetrics",
             showarrow=False, xref='paper', yref='paper',
             xanchor='right', yanchor='auto', xshift=0, yshift=0)
    ],
    showlegend=True,
    legend_orientation="h",

)

# Set y-axes titles
fig.update_yaxes(
    title_text='Percent of Transaction Volume', secondary_y=False, tickformat=".8%",
    type='log',# range=[-10, -2],
    showgrid=False
)
fig.update_yaxes(
    title_text='extant_supply', secondary_y=True, tickformat=None,
    type='linear', range=[0, 21000000],
    showgrid=False
)

fig.show()
In [11]:
fig = make_subplots(
    specs=[[{"secondary_y": True}]],
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['total_miner_rewards_ratio_volume'], name='total_miner_rewards_ratio_volume',
               line=dict(color='royalblue')),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['total_miner_rewards_ratio_volume_proj'], name='total_miner_rewards_ratio_volume_proj',
               line=dict(color='royalblue', dash='dash')),
    secondary_y=False
)

# Second trace
fig.add_trace(
    go.Scatter(x=data_subset['date'], y=data_subset['extant_supply'], name='extant_supply',
               line=dict(color='darkorange')),
    secondary_y=True,
)

fig.update_layout(
    annotations=[
        dict(x=1, y=-0.1,
             text="Chart by: @typerbole; Data: CoinMetrics",
             showarrow=False, xref='paper', yref='paper',
             xanchor='right', yanchor='auto', xshift=0, yshift=0)
    ],
    showlegend=True,
    legend_orientation="h",
    title_text='Bitcoin Total Miner Rewards as Percent of Transaction Volume',

)

# Set y-axes titles
fig.update_yaxes(
    title_text='Percent of Transaction Volume', secondary_y=False, tickformat=".3%",
    type='log', range=[-5, -1],
    showgrid=False
)
fig.update_yaxes(
    title_text='extant_supply', secondary_y=True, tickformat=None,
    type='linear', range=[0, 21000000],
    showgrid=False
)

fig.show()
In [ ]: