Bitcoin Logarithmic Trends: Analysis since each halving

stock
Bitcoin’s logarithmic trends track its price movements over time, with each halving event serving as a key point for analysis. Halvings reduce the supply of new Bitcoin, often leading to significant price changes.
Published

Dec 27, 2024

Keywords

Bitcoin

Summary

A plot that shows the logarithmic price of Bitcoin over each halving period.

Code
# Libraries
# ==============================================================================
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import requests

# Get API Data
# ==============================================================================
# Create a df with final year dates
dp = pd.DataFrame({'date': pd.date_range(start='2010-12-31', end='2024-12-31', freq='Y')})
dp['to_ts'] = dp['date'].apply(lambda x: int(pd.to_datetime(x).timestamp()))

# Create an empty list
dataframes = []

# Iterate API with each date
for to_ts in dp['to_ts']:
    # Build an URL with parameters and transform data
    url = f"https://min-api.cryptocompare.com/data/v2/histoday?fsym=BTC&tsym=USD&limit=365&toTs={to_ts}"
    response = requests.get(url)
    data = response.json().get("Data", {}).get("Data", [])
    df = pd.DataFrame([
        {
            "symbol": "BTCUSD",
            "date": pd.to_datetime(entry["time"], unit="s").date(),
            "open": entry["open"],
            "close": entry["close"],
            "low": entry["low"],
            "high": entry["high"],
            "volume": entry["volumeto"]
        }
        for entry in data
    ])
    dataframes.append(df)
# Combine all df into one
btc = pd.concat(dataframes, ignore_index=True)

# DataSet 0 - Halving
#================================================================================
halving = {'halving': [0 , 1, 2, 3, 4],
           'date': ['2009-01-03', '2012-11-28', '2016-07-09', '2020-05-11', '2024-04-20'] 
           }

halving = pd.DataFrame(halving)
halving['date'] = pd.to_datetime(halving['date'])

# DataSet 1 - BTC Price
# ==============================================================================
# Prepare dataset
btc = btc.drop_duplicates()
btc['date'] = pd.to_datetime(btc['date'])
btc['year_month'] = btc['date'].dt.strftime('%Y-%m')
btc = btc.set_index('date')
btc = btc.asfreq('D').ffill()
btc = btc.reset_index()
btc.sort_values(by=['date'], inplace=True)
btc = pd.merge(btc, halving, on='date', how='left')
btc['halving'].fillna(method='ffill', inplace=True)
btc['halving'].fillna(0, inplace=True)
btc['halving'] = btc['halving'].astype(int)
btc['first_close'] = btc.groupby('halving')['close'].transform('first')
btc['increase'] = (btc['close'] - btc['first_close']) / btc['first_close'] * 100
btc['days'] = btc.groupby('halving').cumcount() + 1
btc['closelog'] = np.log10(btc['close'])
btc = btc[btc['halving'] >= 1]
btc['daystotal'] = btc.groupby('symbol').cumcount() + 1

# Graph 1 - SEABORN
# ==============================================================================
# Font Style
plt.rcParams.update({'font.family': 'sans-serif', 'font.sans-serif': ['Open Sans'], 'font.size': 10})

# Colors Background
regions = [
    (0, 500, '#6B8E23'), # Green
    (500, 1000, '#FF4500'), # Red
    (1000, 1500, '#FFA500') # Orange
    ]  

# Colors Palette Lines
lines = {
    0: '#E0E0E0',  # Very Light Grey
    1: '#C0C0C0',  # Light Grey
    2: '#808080',  # Medium Grey
    3: '#404040',  # Dark Grey
    4: '#8B0000'   # Red
}

# Seaborn to plot a graph
sns.set(style="whitegrid", rc={"grid.color": "0.95", "axes.grid.axis": "y"})
plt.figure(figsize=(16, 9))
sns.lineplot(x='days', y='closelog', hue='halving', data=btc, markers=True, palette=lines, linewidth=1)

# Add region colors in the background
for start, end, color in regions:
    plt.axvspan(start, end, color=color, alpha=0.05)

# Title and axis
plt.title('Bitcoin Logarithmic Trends: Analysis Since Each Halving', fontsize=16, fontweight='bold', pad=20)
plt.xlabel('Days',  fontsize=10, fontweight='bold')
plt.ylabel('Log Price', fontsize=10, fontweight='bold')
plt.xlim(0, 1500)
plt.xticks(range(0, 1501, 125), fontsize=9)
plt.tick_params(axis='both', labelsize=8)
plt.yticks(fontsize=9)

# Custom legend
legend = plt.legend(title="Halving", loc='lower right', fontsize=8, title_fontsize='10')
new_title = 'Dates:'
legend.set_title(new_title)
new_labels = ['1st Halving: 2012-11-28 to 2016-07-09', '2nd Halving: 2016-07-09 to 2020-05-11', '3rd Halving: 2020-05-11 to 2024-04-20', '4th Halving: 2024-04-20 to present'] # Adjust the number of labels according to your data
for text, new_label in zip(legend.texts, new_labels):
    text.set_text(new_label)

# Maximo First 750 days
btc1 = btc[(btc['days'] >= 0) & (btc['days'] <= 750)]
for halving, group in btc1.groupby('halving'):
    max_value = group['closelog'].max()
    max_row = group[group['closelog'] == max_value].iloc[0]
    plt.plot(max_row['days'], max_row['closelog'] +0.05, marker='*', color='darkgoldenrod', markersize=5)
    plt.text(max_row['days'], max_row['closelog'] +0.1, f'{max_row["close"]:,.0f} ({max_row["increase"]:,.0f})%', fontsize=7, ha='center', color='darkgoldenrod')

# Min Between 500 and 1000 days
btc2 = btc[(btc['days'] >= 500) & (btc['days'] <= 1000)]
for halving, group in btc2.groupby('halving'):
    min_value = group['closelog'].min()
    min_row = group[group['closelog'] == min_value].iloc[0]
    plt.plot(min_row['days'], min_row['closelog'] - 0.05, marker='v', color='darkred', markersize=5)
    plt.text(min_row['days'], min_row['closelog'] -0.15, f'{min_row["close"]:,.0f} ({min_row["increase"]:,.0f})%', fontsize=7, ha='center', color='darkred')

# Max After 750 days 
btc3 = btc[(btc['days'] >= 750) & (btc['days'] <= 1500)]
for halving, group in btc3.groupby('halving'):
    max_value = group['closelog'].max()
    max_row = group[group['closelog'] == max_value].iloc[0]
    plt.plot(max_row['days'], max_row['closelog'] +0.05, marker='^', color='darkgreen', markersize=5)
    plt.text(max_row['days'], max_row['closelog'] +0.1, f'{max_row["close"]:,.0f} ({max_row["increase"]:,.0f})%', fontsize=7, ha='center', color='darkgreen')

# Custom Last Dots
max_vals = btc.groupby('halving').agg({'closelog': 'last', 'days': 'max'}).reset_index()
for index, row in max_vals.iterrows():
    plt.plot(row['days'], row['closelog'], 'ro', markersize=2)

# Custom Line labels
for halving, group in btc.groupby('halving'):
    last_point = group.iloc[-1]
    x = last_point['days']
    y = last_point['closelog']
    max_days = group['days'].max()
    plt.text(x + 8, y, f'Halving {halving}\n{max_days} days', color=lines[halving], fontsize=8, ha='left', va='center')
    
# Add Year Label
current_year_month = btc['year_month'].max() 
plt.text(1, 1.05, f'{current_year_month}',
    transform=plt.gca().transAxes,
    fontsize=22, ha='right', va='top',
    fontweight='bold', color='#D3D3D3')

# Add Data Source
plt.text(0, -0.065, 'Data Source: CryptoCompare', 
         transform=plt.gca().transAxes, 
         fontsize=8, 
         color='gray')

# Adjust layout
plt.tight_layout()

# Print it!
plt.show()

Back to top