Data·OHLCV Fetching·Intermediate

Blockchain Data Fetcher

Fetch on-chain metrics — hash rate, active addresses, transaction volume — from public blockchain APIs for use as trading signals.

on-chainblockchainbitcoin

Blockchain.info Market Data Acquisition Framework

This notebook defines a standardized protocol for interfacing with the Blockchain.info public REST API to retrieve on-chain metric data for a single chart via a single function call.


1. Dependency Installation

[22]
!pip install requests pandas
Requirement already satisfied: requests in /usr/local/lib/python3.12/dist-packages (2.32.4)
Requirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (2.2.2)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests) (3.4.7)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests) (3.11)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests) (2026.2.25)
Requirement already satisfied: numpy>=1.26.0 in /usr/local/lib/python3.12/dist-packages (from pandas) (2.0.2)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas) (2026.1)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)

2. Library Imports

[23]
import warnings
warnings.filterwarnings("ignore")

import requests
import pandas as pd
from datetime import datetime

Code Logic

  • warnings.filterwarnings("ignore"): Suppresses non-critical runtime warnings to maintain clean output.
  • requests: Handles HTTP communication with the Blockchain.info public REST endpoint.
  • pandas: Provides the DataFrame structure for tabular time-series data.
  • datetime: Supplies datetime objects for date delta computation.

3. Available Chart Types

Blockchain.info exposes the following chart categories via the https://api.blockchain.info/charts/{chart_name} endpoint. Each chart_name value maps directly into the REST path.

3.1 Market Data

| Chart Name | Description | |---| | market-price | Average USD market price across major exchanges | | market-cap | Total USD value of all circulating Bitcoin | | trade-volume | USD value of Bitcoin traded on major exchanges per day | | exchange-volume | Total BTC volume traded on major exchanges per day |

3.2 Blockchain Activity

| Chart Name | Description | |---| | n-transactions | Total number of confirmed transactions per day | | n-unique-addresses | Number of unique addresses used per day | | n-transactions-per-block | Average number of transactions per block | | output-volume | Total BTC output volume per day | | estimated-transaction-volume | Estimated BTC transaction volume per day | | estimated-transaction-volume-usd | Estimated USD transaction volume per day |

3.3 Mining & Network

| Chart Name | Description | |---| | hash-rate | Estimated network hash rate in GH/s | | difficulty | Current mining difficulty target | | miners-revenue | Total miner revenue (block reward + fees) in USD | | transaction-fees | Total BTC paid in transaction fees per day | | transaction-fees-usd | Total USD value of transaction fees per day | | cost-per-transaction | Miner revenue per transaction in USD | | n-orphaned-blocks | Number of orphaned blocks per day |

3.4 Supply & Distribution

| Chart Name | Description | |---| | total-bitcoins | Total number of BTC in circulation | | utxo-count | Number of unspent transaction outputs | | bitcoin-days-destroyed | Measure of BTC economic activity (age × volume) | | average-block-size | Average block size in MB | | blocks-size | Total size of all blocks per day in MB |

[24]
df_fees = fetch_chart("transaction-fees-usd", START_DATE, END_DATE)

print("--- Average Transaction Fee (USD) ---")
display(df_fees.head())
df_fees.info()
--- Average Transaction Fee (USD) ---
timestamp datetime transaction_fees_usd
0 1704067200 2024-01-01 9.397140e+06
1 1704153600 2024-01-02 6.452516e+06
2 1704240000 2024-01-03 6.429705e+06
3 1704326400 2024-01-04 5.546797e+06
4 1704412800 2024-01-05 5.121602e+06
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column                Non-Null Count  Dtype         
---  ------                --------------  -----         
 0   timestamp             8 non-null      int64         
 1   datetime              8 non-null      datetime64[ns]
 2   transaction_fees_usd  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

4. Configuration

[25]
START_DATE = "2024-01-01"    # Format: YYYY-MM-DD
END_DATE   = "2024-01-08"    # Format: YYYY-MM-DD

BASE_URL   = "https://api.blockchain.info/charts/{chart_name}"

Code Logic

  • START_DATE / END_DATE: ISO 8601 date strings defining the retrieval window applied to all fetch calls below.
  • BASE_URL: Public Blockchain.info chart endpoint. No API key is required. The {chart_name} placeholder is resolved at call time.

5. Data Extraction Function

The fetch_chart function performs a single HTTP GET request to the Blockchain.info charts endpoint, maps the response to a standardized schema, and applies precision-safe type casting.

[26]
def fetch_chart(chart_name, start_date, end_date):
    start_dt  = datetime.strptime(start_date, "%Y-%m-%d")
    end_dt    = datetime.strptime(end_date,   "%Y-%m-%d")
    days_diff = (end_dt - start_dt).days

    url    = BASE_URL.format(chart_name=chart_name)
    params = {
        "format":   "json",
        "start":    start_date,
        "timespan": f"{days_diff}days",
        "sampled":  "false",
    }

    response = requests.get(url, params=params, timeout=30)
    response.raise_for_status()

    data = response.json().get("values", [])

    if not data:
        return pd.DataFrame()

    column_name = chart_name.replace("-", "_")

    df = pd.DataFrame({
        "timestamp": [int(d["x"])   for d in data],
        "datetime":  pd.to_datetime([d["x"] for d in data], unit="s"),
        column_name: [float(d["y"]) for d in data],
    })

    df = df.astype({"timestamp": "int64", column_name: "float64"})
    df = df.drop_duplicates("timestamp").sort_values("timestamp", ignore_index=True)

    return df

Code Logic

  • datetime.strptime(...): Parses ISO 8601 date strings into datetime objects for delta computation.
  • (end_dt - start_dt).days: Derives the integer day span required by the timespan parameter.
  • BASE_URL.format(chart_name=chart_name): Resolves the {chart_name} placeholder using the provided chart identifier.
  • "format": "json": Instructs the API to return a structured JSON payload.
  • "start": start_date: Anchors the retrieval window to the specified start date.
  • "timespan": f"{days_diff}days": Defines the window width in days. The API returns all data points within this span in a single response — no pagination required.
  • "sampled": "false": Disables API-side data compression, ensuring all available data points are returned.
  • response.raise_for_status(): Raises an HTTPError on any non-2xx response code, surfacing failures immediately.
  • response.json().get("values", []): Extracts the time-series array from the response envelope; defaults to an empty list if the key is absent.
  • chart_name.replace("-", "_"): Converts the hyphenated chart name to a valid DataFrame column identifier (e.g., market-pricemarket_price).
  • [int(d["x"]) for d in data]: Extracts the Unix second timestamp from each data point dict.
  • [float(d["y"]) for d in data]: Extracts the metric value from each data point dict.
  • pd.to_datetime([...], unit="s"): Derives a human-readable datetime column from Unix second timestamps.
  • .astype({...}): Casts columns to typed numerics required for arithmetic computation.
  • .drop_duplicates("timestamp").sort_values(...): Removes duplicate timestamps and enforces chronological ordering.

6. Execution — One Call Per Chart Type

Each cell below demonstrates a single fetch call for one representative chart from each category defined in Section 3.

6.1 Market Data — Price

[27]
df_price = fetch_chart("market-price", START_DATE, END_DATE)

print("--- Market Price ---")
display(df_price.head())
df_price.info()
--- Market Price ---
timestamp datetime market_price
0 1704067200 2024-01-01 42249.69
1 1704153600 2024-01-02 44176.26
2 1704240000 2024-01-03 44958.98
3 1704326400 2024-01-04 42854.95
4 1704412800 2024-01-05 44190.10
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column        Non-Null Count  Dtype         
---  ------        --------------  -----         
 0   timestamp     8 non-null      int64         
 1   datetime      8 non-null      datetime64[ns]
 2   market_price  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.2 Market Data — Trade Volume

[28]
df_volume = fetch_chart("trade-volume", START_DATE, END_DATE)

print("--- Trade Volume (USD) ---")
display(df_volume.head())
df_volume.info()
--- Trade Volume (USD) ---
timestamp datetime trade_volume
0 1704067200 2024-01-01 1.204915e+08
1 1704153600 2024-01-02 1.914118e+08
2 1704240000 2024-01-03 4.996471e+08
3 1704326400 2024-01-04 5.142611e+08
4 1704412800 2024-01-05 3.149481e+08
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column        Non-Null Count  Dtype         
---  ------        --------------  -----         
 0   timestamp     8 non-null      int64         
 1   datetime      8 non-null      datetime64[ns]
 2   trade_volume  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.3 Blockchain Activity — Confirmed Transactions

[29]
df_txn = fetch_chart("n-transactions", START_DATE, END_DATE)

print("--- Confirmed Transactions Per Day ---")
display(df_txn.head())
df_txn.info()
--- Confirmed Transactions Per Day ---
timestamp datetime n_transactions
0 1704067200 2024-01-01 657752.0
1 1704153600 2024-01-02 367319.0
2 1704240000 2024-01-03 502749.0
3 1704326400 2024-01-04 482557.0
4 1704412800 2024-01-05 420884.0
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   timestamp       8 non-null      int64         
 1   datetime        8 non-null      datetime64[ns]
 2   n_transactions  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.4 Blockchain Activity — Unique Addresses

[30]
df_addr = fetch_chart("n-unique-addresses", START_DATE, END_DATE)

print("--- Unique Active Addresses Per Day ---")
display(df_addr.head())
df_addr.info()
--- Unique Active Addresses Per Day ---
timestamp datetime n_unique_addresses
0 1704067200 2024-01-01 624628.0
1 1704153600 2024-01-02 550846.0
2 1704240000 2024-01-03 677059.0
3 1704326400 2024-01-04 675009.0
4 1704412800 2024-01-05 645934.0
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column              Non-Null Count  Dtype         
---  ------              --------------  -----         
 0   timestamp           8 non-null      int64         
 1   datetime            8 non-null      datetime64[ns]
 2   n_unique_addresses  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.5 Mining & Network — Hash Rate

[31]
df_hash = fetch_chart("hash-rate", START_DATE, END_DATE)

print("--- Network Hash Rate (GH/s) ---")
display(df_hash.head())
df_hash.info()
--- Network Hash Rate (GH/s) ---
timestamp datetime hash_rate
0 1704067200 2024-01-01 5.548140e+08
1 1704153600 2024-01-02 4.689073e+08
2 1704240000 2024-01-03 5.655523e+08
3 1704326400 2024-01-04 6.085056e+08
4 1704412800 2024-01-05 4.939634e+08
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column     Non-Null Count  Dtype         
---  ------     --------------  -----         
 0   timestamp  8 non-null      int64         
 1   datetime   8 non-null      datetime64[ns]
 2   hash_rate  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.6 Mining & Network — Miner Revenue

[32]
df_revenue = fetch_chart("miners-revenue", START_DATE, END_DATE)

print("--- Miner Revenue (USD) ---")
display(df_revenue.head())
df_revenue.info()
--- Miner Revenue (USD) ---
timestamp datetime miners_revenue
0 1704067200 2024-01-01 5.087515e+07
1 1704153600 2024-01-02 4.351777e+07
2 1704240000 2024-01-03 4.994274e+07
3 1704326400 2024-01-04 5.174221e+07
4 1704412800 2024-01-05 4.291799e+07
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 3 columns):
 #   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   timestamp       8 non-null      int64         
 1   datetime        8 non-null      datetime64[ns]
 2   miners_revenue  8 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 324.0 bytes

6.7 Mempool — Unconfirmed Transactions

[33]
df_mempool = fetch_chart("mempool-size", START_DATE, END_DATE)

print("--- Mempool Size (Unconfirmed Transactions) ---")
display(df_mempool.head())
df_mempool.info()
--- Mempool Size (Unconfirmed Transactions) ---
timestamp datetime mempool_size
0 1704067200 2024-01-01 00:00:00 82038643.0
1 1704068100 2024-01-01 00:15:00 83151660.0
2 1704069000 2024-01-01 00:30:00 82448230.0
3 1704069900 2024-01-01 00:45:00 82636299.0
4 1704070800 2024-01-01 01:00:00 82265967.5
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 673 entries, 0 to 672
Data columns (total 3 columns):
 #   Column        Non-Null Count  Dtype         
---  ------        --------------  -----         
 0   timestamp     673 non-null    int64         
 1   datetime      673 non-null    datetime64[ns]
 2   mempool_size  673 non-null    float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 15.9 KB

6.8 Supply — Total BTC in Circulation

[34]
df_supply = fetch_chart("total-bitcoins", START_DATE, END_DATE)

print("--- Total BTC in Circulation ---")
display(df_supply.head())
df_supply.info()
--- Total BTC in Circulation ---
timestamp datetime total_bitcoins
0 1704068978 2024-01-01 00:29:38 19586168.75
1 1704069091 2024-01-01 00:31:31 19586175.00
2 1704070161 2024-01-01 00:49:21 19586181.25
3 1704070760 2024-01-01 00:59:20 19586187.50
4 1704071678 2024-01-01 01:14:38 19586193.75
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1010 entries, 0 to 1009
Data columns (total 3 columns):
 #   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   timestamp       1010 non-null   int64         
 1   datetime        1010 non-null   datetime64[ns]
 2   total_bitcoins  1010 non-null   float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 23.8 KB

6.9 Supply — UTXO Count

[35]
df_utxo = fetch_chart("utxo-count", START_DATE, END_DATE)

print("--- Unspent Transaction Output Count ---")
display(df_utxo.head())
df_utxo.info()
--- Unspent Transaction Output Count ---
timestamp datetime utxo_count
0 1704068978 2024-01-01 00:29:38 154349387.0
1 1704069091 2024-01-01 00:31:31 154348604.0
2 1704070161 2024-01-01 00:49:21 154349266.0
3 1704070760 2024-01-01 00:59:20 154353682.0
4 1704071678 2024-01-01 01:14:38 154355956.0
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1010 entries, 0 to 1009
Data columns (total 3 columns):
 #   Column      Non-Null Count  Dtype         
---  ------      --------------  -----         
 0   timestamp   1010 non-null   int64         
 1   datetime    1010 non-null   datetime64[ns]
 2   utxo_count  1010 non-null   float64       
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 23.8 KB