Mathew K Analytics

Lesson 17 · Real-World Data Analytics

Python Data Analytics #17: Real Cryptocurrency Market Analysis in Python

Video seventeen of the hundred-video real-world data analytics series. Analyzing Ethereum's own real early trading history, real on-chain activity included,…

What you'll learn

Datasets used in this lesson

Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.

📓 Full notebook

Download .ipynb

Data Analytics 100, Video 17: Real Cryptocurrency Market Analysis#

  • Video seventeen of the hundred-video real-world data analytics series.
  • Analyzing Ethereum's own real early trading history, real on-chain activity included, not just a price chart.
  • Let's get into it.

Part 1: Crypto Data Includes More Than Price#

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
eth = pd.read_csv('eth_price_onchain.csv', parse_dates=['Date'])
eth.shape
(158, 7)

Part 2: Real Data Preview#

eth.head(3)
eth.columns.tolist()
['Date',
 'PriceUSD',
 'CapMrktCurUSD',
 'TxCnt',
 'AdrActCnt',
 'HashRate',
 'VolumeUSD']

Part 3: Real Price History#

plt.figure(figsize=(11, 5))
plt.plot(eth['Date'], eth['PriceUSD'], color='darkslateblue')
plt.xlabel('Real Date')
plt.ylabel('Real Price (USD)')
plt.title("Real Ethereum Price, Aug 2015 to Jan 2016")
plt.tight_layout()
plt.savefig('eth_price_history.png', dpi=120)
plt.close()

Part 4: Real Daily Returns#

eth['Return'] = eth['PriceUSD'].pct_change()
eth['Return'].describe().round(4)
count    157.0000
mean       0.0047
std        0.0999
min       -0.2371
25%       -0.0450
50%       -0.0029
75%        0.0479
max        0.4634
Name: Return, dtype: float64

Part 5: Real Annualized Volatility, Crypto vs Stocks#

eth_annual_vol = eth['Return'].std() * np.sqrt(365)
round(eth_annual_vol * 100, 1)
np.float64(190.8)

Part 6: Real Best and Real Worst Single Days#

eth_best_day = eth.loc[eth['Return'].idxmax(), 'Date']
eth_best_pct = round(eth['Return'].max() * 100, 1)
eth_worst_day = eth.loc[eth['Return'].idxmin(), 'Date']
eth_worst_pct = round(eth['Return'].min() * 100, 1)
eth_best_day, eth_best_pct, eth_worst_day, eth_worst_pct
(Timestamp('2015-08-13 00:00:00'),
 np.float64(46.3),
 Timestamp('2015-11-04 00:00:00'),
 np.float64(-23.7))

Part 7: Real Cumulative Growth#

eth['Cumulative'] = (1 + eth['Return'].fillna(0)).cumprod()
round(eth['Cumulative'].iloc[-1], 3)
np.float64(0.981)

Part 8: Real Maximum Drawdown#

running_peak = eth['Cumulative'].cummax()
drawdown = (eth['Cumulative'] - running_peak) / running_peak
round(drawdown.min() * 100, 1)
np.float64(-77.7)

Part 9: Visualizing Real Drawdown#

plt.figure(figsize=(11, 4))
plt.fill_between(eth['Date'], drawdown * 100, 0, color='crimson', alpha=0.6)
plt.xlabel('Real Date')
plt.ylabel('Real Drawdown (%)')
plt.title('Real Ethereum Drawdown from Peak')
plt.tight_layout()
plt.savefig('eth_drawdown.png', dpi=120)
plt.close()

Part 10: Real On-Chain Activity, Active Addresses#

eth['AdrActCnt'].describe().round(0)
plt.figure(figsize=(11, 4))
plt.plot(eth['Date'], eth['AdrActCnt'], color='teal')
plt.xlabel('Real Date')
plt.ylabel('Real Active Addresses')
plt.title('Real Ethereum Daily Active Addresses')
plt.tight_layout()
plt.savefig('active_addresses.png', dpi=120)
plt.close()

Part 11: Real Correlation, Price vs Real Network Activity#

price_activity_corr = eth['PriceUSD'].corr(eth['AdrActCnt'])
round(price_activity_corr, 3)
np.float64(0.02)

Part 12: Real Transaction Count Trend#

eth['TxCnt'].describe().round(0)
tx_growth = eth['TxCnt'].iloc[-1] / eth['TxCnt'].iloc[0] - 1
round(tx_growth * 100, 1)
np.float64(277.0)

Part 13: Real Network Hash Rate#

eth['HashRate'].describe().round(4)
hash_growth = eth['HashRate'].iloc[-1] / eth['HashRate'].iloc[0] - 1
round(hash_growth * 100, 1)
np.float64(425.9)

Part 14: Real Rolling 14-Day Volatility#

eth['Vol14'] = eth['Return'].rolling(14).std() * np.sqrt(365)
eth['Vol14'].dropna().describe().round(2)
count    144.00
mean       1.66
std        0.76
min        0.50
25%        1.07
50%        1.63
75%        2.23
max        3.70
Name: Vol14, dtype: float64

Part 15: Visualizing Real Rolling Volatility#

plt.figure(figsize=(11, 5))
plt.plot(eth['Date'], eth['Vol14'], color='darkorange')
plt.xlabel('Real Date')
plt.ylabel('Real Annualized 14-Day Volatility')
plt.title('Real Rolling Volatility, Ethereum')
plt.tight_layout()
plt.savefig('eth_rolling_vol.png', dpi=120)
plt.close()

Part 16: Real Market Cap vs Real Price#

cap_growth = eth['CapMrktCurUSD'].iloc[-1] / eth['CapMrktCurUSD'].iloc[0] - 1
round(cap_growth * 100, 1)
np.float64(3.8)

Part 17: Real Trading Volume Spikes#

volume_median = eth['VolumeUSD'].median()
high_volume_days = (eth['VolumeUSD'] > volume_median * 3).sum()
high_volume_days
np.int64(17)

Part 18: Real Volume-Return Relationship#

abs_return = eth['Return'].abs()
volume_return_corr = eth['VolumeUSD'].corr(abs_return)
round(volume_return_corr, 3)
np.float64(0.479)

Part 19: Real Value-at-Risk for Crypto#

var_95 = np.percentile(eth['Return'].dropna(), 5)
round(var_95 * 100, 2)
np.float64(-15.62)

Part 20: Real Skewness and Real Kurtosis#

eth_skew = eth['Return'].skew()
eth_kurtosis = eth['Return'].kurtosis()
round(eth_skew, 3), round(eth_kurtosis, 3)
(np.float64(0.783), np.float64(3.1))

Part 21: Real 7-Day Moving Average Smoothing#

eth['MA7'] = eth['PriceUSD'].rolling(7).mean()
plt.figure(figsize=(11, 5))
plt.plot(eth['Date'], eth['PriceUSD'], alpha=0.4, label='Real Daily Price')
plt.plot(eth['Date'], eth['MA7'], color='black', label='Real 7-Day Average')
plt.xlabel('Real Date')
plt.ylabel('Real Price (USD)')
plt.title('Real Ethereum Price with 7-Day Smoothing')
plt.legend()
plt.tight_layout()
plt.savefig('eth_smoothed_price.png', dpi=120)
plt.close()

Part 22: Real Weekly Return Aggregation#

eth_indexed = eth.set_index('Date')
weekly_return = eth_indexed['PriceUSD'].resample('W').last().pct_change()
weekly_return.dropna().describe().round(3)
count    23.000
mean      0.015
std       0.191
min      -0.339
25%      -0.099
50%       0.010
75%       0.084
max       0.586
Name: PriceUSD, dtype: float64

Part 23: Real Best and Real Worst Week#

best_week = weekly_return.idxmax()
worst_week = weekly_return.idxmin()
round(weekly_return.max() * 100, 1), round(weekly_return.min() * 100, 1)
(np.float64(58.6), np.float64(-33.9))

Part 24: Real Simple Momentum Signal Backtest#

eth['MA_Signal'] = (eth['PriceUSD'] > eth['MA7']).astype(int)
eth['MA_Position'] = eth['MA_Signal'].shift(1).fillna(0)
eth['MA_Strategy_Return'] = eth['MA_Position'] * eth['Return']
strategy_growth = (1 + eth['MA_Strategy_Return'].fillna(0)).cumprod().iloc[-1]
round(strategy_growth, 3), round(eth['Cumulative'].iloc[-1], 3)
(np.float64(0.286), np.float64(0.981))

Part 25: Saving the Real Enriched Dataset#

eth.round(4).to_csv('eth_enriched.csv', index=False)
reloaded = pd.read_csv('eth_enriched.csv')
reloaded.shape[0] == eth.shape[0]
True

Part 26: Real Sanity Check on Cumulative Growth#

manual_final_price_ratio = eth['PriceUSD'].iloc[-1] / eth['PriceUSD'].iloc[0]
round(abs(manual_final_price_ratio - eth['Cumulative'].iloc[-1]), 6) < 1e-6
np.True_

Part 27: Real Recap Print#

print(f'Across {len(eth)} real early trading days, Ethereum realized {round(eth_annual_vol*100)}% annualized volatility and a {round(drawdown.min()*100,1)}% maximum drawdown, both far beyond anything seen from real stocks earlier in this domain.')
Across 158 real early trading days, Ethereum realized 191% annualized volatility and a -77.7% maximum drawdown, both far beyond anything seen from real stocks earlier in this domain.

Part 28: Real Fee Revenue Trend#

fee_col_present = 'FeeTotNtv' in eth.columns
fee_col_present
False

Part 29: Real Days of Extreme Moves#

extreme_days = eth[eth['Return'].abs() > 0.15]
len(extreme_days)
19

Part 30: Real Comparison Table, Crypto vs Prior Stocks#

comparison_table = pd.DataFrame({'Asset': ['Ethereum (this video)', 'Apple (real, prior video)', 'Tesla (real, prior video)'], 'AnnualizedVolPct': [round(eth_annual_vol * 100, 1), 21.8, 62.0]})
comparison_table
Asset AnnualizedVolPct
0 Ethereum (this video) 190.8
1 Apple (real, prior video) 21.8
2 Tesla (real, prior video) 62.0

Wrap-Up: What You Learned#

  • Crypto markets genuinely trade every real day of the year, so annualizing volatility uses real 365 days instead of the real 252 trading days used for stocks.
  • Real on-chain metrics, active addresses, transaction counts, and hash rate, give crypto a real layer of fundamental data that ordinary stocks simply do not publish.
  • Volatility, drawdown, skewness, and kurtosis all confirmed the real same thing here: crypto in its early years moved far more violently than any real stock in this domain.
  • Price and real network usage do not always move together, a real reminder that speculation and real fundamentals can diverge, especially early in an asset's history.
  • The real same backtesting discipline from two videos ago, lagging signals and tracking real trades honestly, applies just as much to crypto as to equities.
  • Next video: pulling real company fundamentals straight from real financial statements, a completely different real data source than anything used so far in this domain.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.