Skip to content
import pandas as pd
import numpy as np
from datetime import datetime

import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.stattools import adfuller
from statsmodels.stats.diagnostic import acorr_ljungbox
from scipy.stats import shapiro

Data Collection

Daily data: CSV

# Load the CSV file from the 'csv data' folder
btc_daily = pd.read_csv('CSV Data/btc_data_daily.csv')

# Display the first few rows of the dataframe to verify loading
btc_daily.head()

Hourly data: CSV

# Read the data from CSV into a DataFrame
minute_data = pd.read_csv('CSV Data/btcusd_1-min_data.csv')

# Convert the 'Timestamp' column to datetime format
minute_data['Timestamp'] = pd.to_datetime(minute_data['Timestamp'], unit='s')

# Filter minute_data for timestamps at the full hour
hour_data = minute_data[minute_data['Timestamp'].dt.minute == 0]

# Display the first few rows of the DataFrame to verify the data
hour_data.head()
hour_data['Timestamp'] = pd.to_datetime(hour_data['Timestamp'])
hour_data[hour_data['Timestamp'] > pd.to_datetime('2024-11-04')]

Data cleaning

btc_daily.dtypes
# Rename columns to avoid confusion
btc_daily = btc_daily.rename(columns={'Price': 'Close', 'Start': 'Date'})

# Convert the relevant columns to float, if necessary
#btc_daily['Close'] = btc_daily['Close'].str.replace(',', '').astype(float)
#btc_daily['Open'] = btc_daily['Open'].str.replace(',', '').astype(float)
#btc_daily['High'] = btc_daily['High'].str.replace(',', '').astype(float)
#btc_daily['Low'] = btc_daily['Low'].str.replace(',', '').astype(float)
#btc_daily['Vol.'] = btc_daily['Vol.'].str.replace('K', 'e3').str.replace('M', 'e6').str.replace('B', 'e9').str.replace(',', '').astype(float)
#btc_daily['Change %'] = btc_daily['Change %'].str.replace('%', '').astype(float)
# Convert the 'Date' column to a datetime object for easier manipulation and analysis.
btc_daily['Date'] = pd.to_datetime(btc_daily['Date'])

# Calculate the range of each day's price as the difference between 'High' and 'Low' columns,
# and store it in a new column named 'Range'.
btc_daily['Range'] = btc_daily['High'] - btc_daily['Low'] 

# Sort the DataFrame by the 'Date' column in ascending order and reset the index.
# The drop=True parameter prevents the old index from being added as a new column.
btc_daily = btc_daily.sort_values('Date').reset_index(drop=True)

# Drop the 'End' column from the DataFrame as it's no longer needed for the analysis.
btc_daily = btc_daily.drop('End', axis=1)

# Display the resulting DataFrame.
btc_daily
btc_daily.isna().any()

Exploring Changes in Bitcoin Prices

# Calculate the 28-day moving average of Range
btc_daily['Range_MA'] = btc_daily['Range'].rolling(window=7).mean()

# Create the plot with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])

# Add the 7-day moving average of Range (green line with alpha 0.5)
fig.add_trace(
    go.Scatter(
        x=btc_daily['Date'], 
        y=btc_daily['Range_MA'], 
        mode='lines', 
        name='7-Day MA of Range',
        line=dict(color='#03EF62', width=2),  # Set the line color to green
        opacity=0.3
    ),
    secondary_y=True
)

# Add the BTC daily close prices (white line)
fig.add_trace(
    go.Scatter(
        x=btc_daily['Date'], 
        y=btc_daily['Close'], 
        mode='lines', 
        name='BTC Close Price',
        line=dict(color='#FF931E')  # Set the line color to white
    ),
    secondary_y=False
)


# Update layout with adjusted font sizes
fig.update_layout(
    title='Bitcoin Daily Close Prices with 7-Day Moving Average of Range',
    title_font=dict(size=24),
    xaxis=dict(
        title='Date',
        title_font=dict(size=16),
        tickfont=dict(size=14),
        gridcolor="rgba(33, 49, 71, 0.5)"
    ),
    yaxis=dict(
        title='Close Price (USD)',
        title_font=dict(size=16),
        tickfont=dict(size=14),
        gridcolor="rgba(33, 49, 71, 0.5)"
    ),
    yaxis2=dict(
        title='7-Day MA of Range',
        title_font=dict(size=16),
        tickfont=dict(size=14),
        gridcolor="rgba(33, 49, 71, 0.5)"
    ),
    legend=dict(
        font=dict(size=16, color='white')
    ),
    showlegend=True,
    plot_bgcolor='#05192D',
    paper_bgcolor='#05192D',
    font=dict(color='white'),
    width=1200,
    height=675
)

fig.show()