1. 基于Web3.py & Ethscan链上分析¶

Author: @shevloader

Date: Sun 08.09.2025

1.1 获取 Transfer 事件日志¶

导入包¶

In [5]:
from web3 import Web3
from eth_utils import to_checksum_address
from eth_utils import to_checksum_address
from eth_abi import decode
import json

常量¶

In [6]:
try:
    with open('config.json', 'r') as file:
        config = json.load(file)
except FileNotFoundError:
    print("The file 'config.json' was not found.")
except json.JSONDecodeError:
    print("Error decoding JSON from the file.")

# 连接 Ethereum 主网节点
RPC_URL = config['RPC_URL']
w3 = Web3(Web3.HTTPProvider(RPC_URL))  # 或用其他 RPC

# ENA 合约地址(checksum 格式)
token_address = to_checksum_address(config['token_address'])

# Transfer 事件 topic
transfer_topic = config['transfer_topic']

获取并解码 Transfer 事件日志¶

In [7]:
# 查询区块范围
latest_block = w3.eth.block_number
from_block = latest_block - 3000  # 最近 3000 个区块

# 获取日志
logs = w3.eth.get_logs({
    'address': token_address,
    'fromBlock': from_block,
    'toBlock': 'latest',
    'topics': [transfer_topic]
})

print(f"抓到 {len(logs)} 条 ENA 的 Transfer 事件")

# 解码日志中的 from / to / value
def parse_transfer_log(log):
    from_address = to_checksum_address("0x" + log['topics'][1].hex()[-40:])
    to_address = to_checksum_address("0x" + log['topics'][2].hex()[-40:])
    value = decode(['uint256'], log['data'])[0]
    return from_address, to_address, value

# 打印前几条示例
for log in logs[:10]:
    from_addr, to_addr, value = parse_transfer_log(log)
    print(f"From: {from_addr} → To: {to_addr} | Amount: {value}")
抓到 5337 条 ENA 的 Transfer 事件
From: 0x6bBB0289DFDa178555dD1ce4AaA8f1BdbFB1bcdE → To: 0x2E1Dee213BA8d7af0934C49a23187BabEACa8764 | Amount: 10222570561101668608
From: 0x2E1Dee213BA8d7af0934C49a23187BabEACa8764 → To: 0xAe4045ffeDdF61D570E6d1fE2D71DED1A2E85a88 | Amount: 10222570561101668608
From: 0xc3Db44ADC1fCdFd5671f555236eae49f4A8EEa18 → To: 0xA69babEF1cA67A37Ffaf7a485DfFF3382056e78C | Amount: 14574256984502285475754
From: 0x0cc9E65F059bDb4d55184981AabD4D085bdFdFE3 → To: 0x6224Bc8d73d7498c2b39C65a340bd66CC69Ade62 | Amount: 0
From: 0xc3Db44ADC1fCdFd5671f555236eae49f4A8EEa18 → To: 0xA69babEF1cA67A37Ffaf7a485DfFF3382056e78C | Amount: 3356441766651113354523
From: 0xb7ef665d4556E61E36B8355d54a28143179646e3 → To: 0x5c28979a5e85DE2BC04221Bba82AD4878FA71CbA | Amount: 35372129573465823671315
From: 0xc3Db44ADC1fCdFd5671f555236eae49f4A8EEa18 → To: 0xA69babEF1cA67A37Ffaf7a485DfFF3382056e78C | Amount: 6419504662179024694881
From: 0xAe4045ffeDdF61D570E6d1fE2D71DED1A2E85a88 → To: 0x74de5d4FCbf63E00296fd95d33236B9794016631 | Amount: 21897788896532434310
From: 0x74de5d4FCbf63E00296fd95d33236B9794016631 → To: 0x74D6f431aafF3a6461adbC8909C75Dee8C1A9d85 | Amount: 21897788896532434310
From: 0xF955C57f9EA9Dc8781965FEaE0b6A2acE2BAD6f3 → To: 0x5e5b99AD5305B760E074415A6a113D2d5E87Ed6C | Amount: 854354991451532638698

1.2 获取top持币者¶

In [8]:
# 导入包
import requests
import pandas as pd

1. Ethscan API 自动版¶

In [10]:
# Ethscan Pro 版本
def fetch_token_holders():
    API_KEY = config['API_KEY']
    # API_KEY = 'FH5I3X12Q1SMVEC5TAKXNBS15BHJT97RE6'
    # token_address = '0x57e114B691Db790C35207b2e685D4A43181e6061'
    
    url = f'https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress={token_address}&page=1&offset=20&apikey={API_KEY}'
    
    response = requests.get(url)
    data = response.json()
    
    if data['status'] == '1':
        holders = data['result']
        df = pd.DataFrame(holders)
        df['TokenHolderAddress'] = df['TokenHolderAddress'].apply(lambda x: x.lower())
        df['TokenHolderQuantity'] = df['TokenHolderQuantity'].astype(float) / 1e18  # 假设 18位精度
        df = df.sort_values(by='TokenHolderQuantity', ascending=False)
        print(df[['TokenHolderAddress', 'TokenHolderQuantity']])
    else:
        print("API 请求失败:", data.get('message'))

2. Etherscan 手动获取版¶

In [11]:
# 半手动方法
# https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061#balances 
# Download
In [12]:
# 读取数据
df = pd.read_csv("export-token-0x57e114B691Db790C35207b2e685D4A43181e6061.csv")

# 清洗列名
df.columns = [c.strip().lower() for c in df.columns]

# 转换百分比为 float
df['percentage'] = df['percentage'].str.replace('%', '').astype(float)

# 可选:处理 address_nametag 为空的情况
df['address_nametag'] = df['address_nametag'].fillna('Unknown')

df
Out[12]:
rank address address_nametag quantity percentage value
0 1 0xc4e512313dd1ce0795f88ec5229778edf1fdf79b Unknown 2,677,535,328.19 17.8502 $1,551,503,200.99
1 2 0xcfc40d4eca21f60d329f1e6b9b3d6069eaa20bbc Unknown 1,332,635,764.34 8.8842 $772,198,458.92
2 3 0x2146aa5807d96e6b2922a149cee870f17347f1d0 Unknown 1,330,997,641.527777777777777795 8.8733 $771,249,245.38
3 4 0x1dc55d87c4143cc1829989d7ff8d580549ac0901 Unknown 1,231,887,037.76 8.2126 $713,819,407.80
4 5 0xb2af973905f05bc82bf97486b6ab883598d98298 Unknown 1,155,682,571.43 7.7046 $669,662,577.38
5 6 0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9 Ethena: sENA Token 990,038,451.157461025792590031 6.6003 $573,679,760.60
6 7 0xf977814e90da44bfa03b6295a0616a897441acec Binance: Hot Wallet 20 886,381,042 5.9092 $513,615,267.55
7 8 0x54b8c65f0635fd91c8729dd3269c630d9aed54e5 Unknown 681,913,729.671612340621111223 4.5461 $395,136,274.49
8 9 0x877b3d5c681c8890d19dbf450306caa3c3d4bba6 Unknown 375,000,000 2.5000 $217,294,500.00
9 10 0x41c7d5db1bb11a30196f4e9873b2ce417b9cba39 Unknown 350,000,000 2.3333 $202,808,200.00
10 11 0xdedc15fa923d4e147875c63c0a97f85f178dfe96 Unknown 165,700,649 1.1047 $96,015,572.46
11 12 0x70f58622158d7e609ae5839c4ad0d477f468863f Unknown 160,000,002 1.0667 $92,712,321.16
12 13 0xf0465df588906d820f831970262bdcca0f2b3e2d Unknown 147,494,251.68 0.9833 $85,465,839.12
13 14 0xa9cf4aa55c675badb68519e3cfa8f4be942e6d11 Unknown 135,999,992 0.9067 $78,805,467.36
14 15 0xb829e684df8e31b402a4d4aedf3bbc18a52e7589 Unknown 120,000,002 0.8000 $69,534,241.16
15 16 0x0c36fda877d41671b14fb4e7655798965237c7d0 Unknown 117,831,472.376023660931652455 0.7855 $68,277,682.33
16 17 0x3c716d252b53891753de883894ff29a9ebee0f54 Unknown 115,949,958.74598124 0.7730 $67,187,435.50
17 18 0x28c6c06298d514db089934071355e5743bf21d60 Binance 14 108,447,417.7916789024486268 0.7230 $62,840,073.13
18 19 0x70167b76543c4a12b49b2f2b70cbf04d99345786 Unknown 94,774,852.414706237138572049 0.6318 $54,917,477.78
19 20 0x3cd9c4942467c859224325b41aeb3a4d2b84c541 Unknown 85,989,160.0994 0.5733 $49,826,590.80
20 21 0x4655b6a10c83d6beff1dc7116436cfd8b4f8d48a Unknown 74,711,475.724211944786442383 0.4981 $43,291,714.03
21 22 0xc882b111a75c0c657fc507c04fbfcd2cc984f071 Gate.io 5 73,185,531.28345142700488998 0.4879 $42,407,502.47
22 23 0x205188a68430e94f80a512038329030c556b50ff Unknown 63,475,389.541521787215571173 0.4232 $36,780,941.42
23 24 0x6a5e25fbaf575876f2905eaa11143cbfa29bd443 Unknown 61,347,841.6678125 0.4090 $35,548,129.55
24 25 0x8af2833f3aa3933a58c07e6244f9c35580f4611d Unknown 60,631,881.78 0.4042 $35,133,265.16
25 26 0xbef89f2cc3c1fa89d1929d10c2421caea3d793cc Unknown 57,023,825.605400165677028386 0.3802 $33,042,569.79
26 27 0xab2eedf5cf6e534b3ab8e2a71f7457228138c1b3 Unknown 47,639,720.16 0.3176 $27,604,931.13
27 28 0x1157a2076b9bb22a85cc2c162f20fab3898f4101 FalconX: 0x115...101 47,210,608.782906584223017985 0.3147 $27,356,281.68
28 29 0xc31cb05ead558ed3426ec1143320540a542c9fcc Unknown 46,824,823.470011 0.3122 $27,132,737.61
29 30 0xf7e9a266ee1145f6302d2cd67b1d2ba6ca400207 Unknown 43,750,000.999992621527777776 0.2917 $25,351,025.58
30 31 0x22af984f13dfb5c80145e3f9ee1050ae5a5fb651 Kraken: Cold Wallet 38,190,824.4829 0.2546 $22,129,749.63
31 32 0x9b0c45d46d386cedd98873168c36efd0dcba8d46 Revolut 3 32,266,483.019 0.2151 $18,696,878.12
32 33 0x4693dcf3851100c60351282dc05f9efa3b776fc8 Unknown 31,279,815.08 0.2085 $18,125,151.41
33 34 0xffa8db7b38579e6a2d14f9b347a9ace4d044cd54 Unknown 27,995,950.2561075748818648 0.1866 $16,222,309.37
34 35 0xf608291ed68a5ab477a4eacf5781060936970a6e Unknown 27,600,000 0.1840 $15,992,875.20
35 36 0x43684d03d81d3a4c70da68febdd61029d426f042 Unknown 27,343,446.2245874 0.1823 $15,844,214.60
36 37 0xc06f25517e906b7f9b4dec3c7889503bb00b3370 Kraken: Cold Wallet 2 27,210,454.37509 0.1814 $15,767,152.21
37 38 0xfab03b7d0ea9190368bfbf8f0ede5db721188f76 Unknown 25,312,500 0.1688 $14,667,378.75
38 39 0xf31a5763b52f67846c38c2eea22b075f66f4ea10 Unknown 25,312,500 0.1688 $14,667,378.75
39 40 0x1ea1097699deb7d634155bc5a046d1abbfdde487 Unknown 25,312,500 0.1688 $14,667,378.75
40 41 0xa055f4c2092dee7432e0699f582ef44d97b7c5eb Unknown 25,312,500 0.1688 $14,667,378.75
41 42 0x8ab4e48fb3ab5febba57b9f5b152c459b0303780 Unknown 25,312,500 0.1688 $14,667,378.75
42 43 0x454da665c949390bb755cb147c471d3c3098276f Unknown 25,312,500 0.1688 $14,667,378.75
43 44 0x86c74258b818b4e25516f4cdbefd41c031dbd9ab Unknown 25,312,500 0.1688 $14,667,378.75
44 45 0x5c8a4d04a7daffe58e6d00adb78281ce29f7e295 Unknown 25,312,500 0.1688 $14,667,378.75
45 46 0x02bda4efec1b116a563c6d05a60f617f9eda7df4 Unknown 25,000,000 0.1667 $14,486,300.00
46 47 0x629e44441c6001e63483803202c579dba0722b2f Unknown 24,390,243.9 0.1626 $14,132,975.61
47 48 0x90c74dfe1ff09789cbdaa4514d80b8d8043ccf51 Unknown 23,819,597.76 0.1588 $13,802,313.56
48 49 0xdfd5293d8e347dfe59e90efd55b2956a1343963d Binance 16 22,337,182.09399579 0.1489 $12,943,324.84
49 50 0xd322e4c49b3cb0d0c15e8a956f44ea56ccdfb97a Unknown 21,875,000 0.1458 $12,675,512.50
In [13]:
# top 50 持币地址
df['address']
Out[13]:
0     0xc4e512313dd1ce0795f88ec5229778edf1fdf79b
1     0xcfc40d4eca21f60d329f1e6b9b3d6069eaa20bbc
2     0x2146aa5807d96e6b2922a149cee870f17347f1d0
3     0x1dc55d87c4143cc1829989d7ff8d580549ac0901
4     0xb2af973905f05bc82bf97486b6ab883598d98298
5     0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9
6     0xf977814e90da44bfa03b6295a0616a897441acec
7     0x54b8c65f0635fd91c8729dd3269c630d9aed54e5
8     0x877b3d5c681c8890d19dbf450306caa3c3d4bba6
9     0x41c7d5db1bb11a30196f4e9873b2ce417b9cba39
10    0xdedc15fa923d4e147875c63c0a97f85f178dfe96
11    0x70f58622158d7e609ae5839c4ad0d477f468863f
12    0xf0465df588906d820f831970262bdcca0f2b3e2d
13    0xa9cf4aa55c675badb68519e3cfa8f4be942e6d11
14    0xb829e684df8e31b402a4d4aedf3bbc18a52e7589
15    0x0c36fda877d41671b14fb4e7655798965237c7d0
16    0x3c716d252b53891753de883894ff29a9ebee0f54
17    0x28c6c06298d514db089934071355e5743bf21d60
18    0x70167b76543c4a12b49b2f2b70cbf04d99345786
19    0x3cd9c4942467c859224325b41aeb3a4d2b84c541
20    0x4655b6a10c83d6beff1dc7116436cfd8b4f8d48a
21    0xc882b111a75c0c657fc507c04fbfcd2cc984f071
22    0x205188a68430e94f80a512038329030c556b50ff
23    0x6a5e25fbaf575876f2905eaa11143cbfa29bd443
24    0x8af2833f3aa3933a58c07e6244f9c35580f4611d
25    0xbef89f2cc3c1fa89d1929d10c2421caea3d793cc
26    0xab2eedf5cf6e534b3ab8e2a71f7457228138c1b3
27    0x1157a2076b9bb22a85cc2c162f20fab3898f4101
28    0xc31cb05ead558ed3426ec1143320540a542c9fcc
29    0xf7e9a266ee1145f6302d2cd67b1d2ba6ca400207
30    0x22af984f13dfb5c80145e3f9ee1050ae5a5fb651
31    0x9b0c45d46d386cedd98873168c36efd0dcba8d46
32    0x4693dcf3851100c60351282dc05f9efa3b776fc8
33    0xffa8db7b38579e6a2d14f9b347a9ace4d044cd54
34    0xf608291ed68a5ab477a4eacf5781060936970a6e
35    0x43684d03d81d3a4c70da68febdd61029d426f042
36    0xc06f25517e906b7f9b4dec3c7889503bb00b3370
37    0xfab03b7d0ea9190368bfbf8f0ede5db721188f76
38    0xf31a5763b52f67846c38c2eea22b075f66f4ea10
39    0x1ea1097699deb7d634155bc5a046d1abbfdde487
40    0xa055f4c2092dee7432e0699f582ef44d97b7c5eb
41    0x8ab4e48fb3ab5febba57b9f5b152c459b0303780
42    0x454da665c949390bb755cb147c471d3c3098276f
43    0x86c74258b818b4e25516f4cdbefd41c031dbd9ab
44    0x5c8a4d04a7daffe58e6d00adb78281ce29f7e295
45    0x02bda4efec1b116a563c6d05a60f617f9eda7df4
46    0x629e44441c6001e63483803202c579dba0722b2f
47    0x90c74dfe1ff09789cbdaa4514d80b8d8043ccf51
48    0xdfd5293d8e347dfe59e90efd55b2956a1343963d
49    0xd322e4c49b3cb0d0c15e8a956f44ea56ccdfb97a
Name: address, dtype: object
In [14]:
import matplotlib.pyplot as plt

top10 = df.head(10)

# 柱状图
plt.figure(figsize=(10, 6))
plt.barh(top10['address'], top10['percentage'])
plt.xlabel("Proportion of token holdings (%)")
plt.title("Pic 1. ENA top 10 address persent(bar chart)")
plt.gca().invert_yaxis()
plt.tight_layout()
plt.show()

# 饼图
plt.figure(figsize=(8, 8))
plt.pie(top10['percentage'], labels=top10['address_nametag'], autopct='%1.1f%%')
plt.title("Pic 2. ENA top 10 address persent(pie chart)")
plt.tight_layout()
plt.show()
No description has been provided for this image
No description has been provided for this image

2. 基于santiment 链上分析¶

2.1 导入包¶

In [16]:
import requests
import datetime
import pandas as pd
import matplotlib.pyplot as plt
import time

2.2 常量¶

In [17]:
# Santiment API Token
santiment_API = config["santiment_API"]
API_TOKEN = santiment_API
API_KEY = santiment_API
HEADERS = {'Authorization': f'Apikey {API_TOKEN}'}

# 分析代币标识(slug)
ASSET = 'ethena'  # ENA 的 slug 在 Santiment 中为 'ethena'

# 时间范围
START_DATE = '2024-07-01'
END_DATE = '2025-08-01'
INTERVAL = '1d'

2.3 函数定义:获取活跃地址数¶

In [18]:
# 获取活跃地址数
def get_active_addresses(asset, from_date, to_date, interval='1d'):
    url = f"https://api.santiment.net/graphql"
    query = """
    {
      getMetric(metric: "active_addresses_24h") {
        timeseriesData(
          slug: "%s"
          from: "%sT00:00:00Z"
          to: "%sT00:00:00Z"
          interval: "%s"
        ) {
          datetime
          value
        }
      }
    }
    """ % (asset, from_date, to_date, interval)
    
    response = requests.post(url, json={'query': query}, headers=HEADERS)
    data = response.json()
    timeseries = data['data']['getMetric']['timeseriesData']
    df = pd.DataFrame(timeseries)
    df['datetime'] = pd.to_datetime(df['datetime'])
    df.set_index('datetime', inplace=True)
    return df

2.4 函数定义:获取 Exchange 流入量¶

In [19]:
# 获取 Exchange 流入量
def get_exchange_inflow(asset, from_date, to_date, interval='1d'):
    url = f"https://api.santiment.net/graphql"
    query = """
    {
      getMetric(metric: "exchange_inflow") {
        timeseriesData(
          slug: "%s"
          from: "%sT00:00:00Z"
          to: "%sT00:00:00Z"
          interval: "%s"
        ) {
          datetime
          value
        }
      }
    }
    """ % (asset, from_date, to_date, interval)
    
    response = requests.post(url, json={'query': query}, headers=HEADERS)
    data = response.json()
    timeseries = data['data']['getMetric']['timeseriesData']
    df = pd.DataFrame(timeseries)
    df['datetime'] = pd.to_datetime(df['datetime'])
    df.set_index('datetime', inplace=True)
    return df

2.5 *fetch & save price data 无需每次执行¶

In [20]:
# 获取数据并保存
active_df = get_active_addresses(ASSET, START_DATE, END_DATE)
# 保存数据到本地
active_df.to_pickle("active_data.pkl")

time.sleep(2)

inflow_df = get_exchange_inflow(ASSET, START_DATE, END_DATE)
inflow_df.to_pickle("exchange_inflow_data.pkl")

2.6 活跃地址与CEX流入数据分析¶

In [21]:
# 读取数据
active_df = pd.read_pickle("active_data.pkl")
inflow_df = pd.read_pickle("exchange_inflow_data.pkl")

fig, ax1 = plt.subplots(figsize=(12, 6))
ax1.plot(active_df.index, active_df['value'], color='orange', label="Active Addresses (24h)")
ax1.set_ylabel("Active Addresses (24h)", color='orange')
ax1.tick_params(axis='y', labelcolor='orange')

ax2 = ax1.twinx()
ax2.plot(inflow_df.index, inflow_df['value'], color='blue', label="Exchange Inflow")
ax2.set_ylabel("Exchange Inflow", color='blue')
ax2.tick_params(axis='y', labelcolor='blue')

plt.title(f"Pic 1. ENA active address & CEX inflow")
plt.show()
No description has been provided for this image

2.7 函数定义: 获取 ENA 价格时间序列¶

In [22]:
# 获取 ENA 价格时间序列
def get_price_via_graphql(slug, from_date, to_date, interval="1d"):
    url = "https://api.santiment.net/graphql"
    headers = {
        "Authorization": f"Apikey {API_KEY}",
        "Content-Type": "application/json"
    }

    query = f"""
    {{
      getMetric(metric: "price_usd") {{
        timeseriesData(
          slug: "{slug}",
          from: "{from_date}T00:00:00Z",
          to: "{to_date}T00:00:00Z",
          interval: "{interval}"
        ) {{
          datetime
          value
        }}
      }}
    }}
    """

    # Request Data
    resp = requests.post(url, json={"query": query}, headers=headers)  
    data = resp.json()

    ts = data['data']['getMetric']['timeseriesData']
    df = pd.DataFrame(ts)
    df['datetime'] = pd.to_datetime(df['datetime'])
    df.set_index('datetime', inplace=True)
    df.rename(columns={'value': 'price_usd'}, inplace=True)
    return df

2.8 *fetch & save price data 无需每次执行¶

In [23]:
# fetch & save price data 无需每次执行
price_df = get_price_via_graphql("ethena", START_DATE, END_DATE)

# 保存数据到本地
price_df.to_pickle("ethena_price_data.pkl")

2.9 活跃地址与ENA价格关联分析¶

In [24]:
# 读取数据
price_df = pd.read_pickle("ethena_price_data.pkl")

fig, ax1 = plt.subplots(figsize=(12, 6))
ax1.plot(price_df.index, price_df['price_usd'], color='orange', label="ENA Price")
ax1.set_ylabel("Price USD", color='orange')
ax1.tick_params(axis='y', labelcolor='orange')

ax2 = ax1.twinx()
ax2.plot(active_df.index, active_df['value'], color='blue', label="active address")
ax2.set_ylabel("active address", color='blue')
ax2.tick_params(axis='y', labelcolor='blue')

plt.title("Pic 2. ENA Price vs active address")
plt.show()
No description has been provided for this image

2.10 函数定义:获取交易所 流入|流出 数据¶

In [25]:
def get_exchange_flow(slug, from_date, to_date, flow_type):
    url = "https://api.santiment.net/graphql"
    headers = {
        "Authorization": f"Apikey {API_KEY}",
        "Content-Type": "application/json"
    }
    query = f"""
    {{
      getMetric(metric: "{flow_type}") {{
        timeseriesData(
          slug: "{slug}",
          from: "{from_date}T00:00:00Z",
          to: "{to_date}T00:00:00Z",
          interval: "1d"
        ) {{
          datetime
          value
        }}
      }}
    }}
    """
    resp = requests.post(url, json={"query": query}, headers=headers)
    data = resp.json()
    ts = data['data']['getMetric']['timeseriesData']
    df = pd.DataFrame(ts)
    df['datetime'] = pd.to_datetime(df['datetime'])
    df.set_index('datetime', inplace=True)
    return df

2.11 *fetch & save CEX in&out flow data 无需每次执行¶

In [26]:
time.sleep(2)
inflow_df = get_exchange_flow("ethena", START_DATE, END_DATE, "exchange_inflow")
# 保存数据到本地
inflow_df.to_pickle("exchange_inflow_data.pkl")  
time.sleep(2)

outflow_df = get_exchange_flow("ethena", START_DATE, END_DATE, "exchange_outflow")
# 保存数据到本地
outflow_df.to_pickle("exchange_outflow_data.pkl")  
time.sleep(2)

2.12 ENA price & exchange_inflow_data analysis¶

In [27]:
# 1. 读取pickle文件
inflow_df = pd.read_pickle('exchange_inflow_data.pkl')

# 2. 查看数据结构
print(inflow_df.head())
print(inflow_df.columns)

# 假设DataFrame有datetime索引和'value'列(Santiment的GraphQL结果一般是这样)
# 如果不是datetime索引,需要转化
if not isinstance(inflow_df.index, pd.DatetimeIndex):
    inflow_df['datetime'] = pd.to_datetime(inflow_df['datetime'])
    inflow_df.set_index('datetime', inplace=True)

# 3. 绘制交易所流入时间序列图
plt.figure(figsize=(14,6))
plt.plot(inflow_df.index, inflow_df['value'], label='Exchange Inflow')
plt.title('ENA Token Exchange Inflow Over Time')
plt.xlabel('Date')
plt.ylabel('Token Amount')
plt.legend()
plt.grid(True)
plt.show()

# 4. 简单统计分析示例:计算每日流入均值、峰值等
mean_inflow = inflow_df['value'].mean()
max_inflow = inflow_df['value'].max()
print(f"Average daily inflow: {mean_inflow:.2f}")
print(f"Maximum daily inflow: {max_inflow:.2f}")

# 5. 进阶:和价格数据对比(假设你有price_df)
# 合并两个DataFrame
# price_df已经有datetime索引和'price_usd'列
combined_df = inflow_df.join(price_df['price_usd'], how='inner')

fig, ax1 = plt.subplots(figsize=(14,6))

color = 'tab:blue'
ax1.set_xlabel('Date')
ax1.set_ylabel('Exchange Inflow', color=color)
ax1.plot(combined_df.index, combined_df['value'], color=color)
ax1.tick_params(axis='y', labelcolor=color)

ax2 = ax1.twinx()
color = 'tab:orange'
ax2.set_ylabel('Price USD', color=color)
ax2.plot(combined_df.index, combined_df['price_usd'], color=color)
ax2.tick_params(axis='y', labelcolor=color)

plt.title('ENA Exchange Inflow vs Price')
plt.show()
                                  value
datetime                               
2024-08-11 00:00:00+00:00  2.142636e+06
2024-08-12 00:00:00+00:00  1.005877e+07
2024-08-13 00:00:00+00:00  1.026039e+07
2024-08-14 00:00:00+00:00  3.340458e+06
2024-08-15 00:00:00+00:00  7.058729e+06
Index(['value'], dtype='object')
No description has been provided for this image
Average daily inflow: 22927086.33
Maximum daily inflow: 202353475.26
No description has been provided for this image

2.13 ENA Price & analysis exchange_outflow_data¶

In [28]:
# 1. 读取pickle文件
outflow_df = pd.read_pickle('exchange_outflow_data.pkl')

# 2. 查看数据结构
print(outflow_df.head())
print(outflow_df.columns)

# 假设DataFrame有datetime索引和'value'列(Santiment的GraphQL结果一般是这样)
# 如果不是datetime索引,需要转化
if not isinstance(outflow_df.index, pd.DatetimeIndex):
    outflow_df['datetime'] = pd.to_datetime(outflow_df['datetime'])
    outflow_df.set_index('datetime', inplace=True)

# 3. 绘制交易所流入时间序列图
plt.figure(figsize=(14,6))
plt.plot(outflow_df.index, outflow_df['value'], label='Exchange Outflow')
plt.title('ENA Token Exchange Outflow Over Time')
plt.xlabel('Date')
plt.ylabel('Token Amount')
plt.legend()
plt.grid(True)
plt.show()

# 4. 简单统计分析示例:计算每日流入均值、峰值等
mean_outflow = outflow_df['value'].mean()
max_outflow = outflow_df['value'].max()
print(f"Average daily outflow: {mean_outflow:.2f}")
print(f"Maximum daily outflow: {max_outflow:.2f}")

# 5. 进阶:和价格数据对比(假设你有price_df)
# 合并两个DataFrame
# price_df已经有datetime索引和'price_usd'列
combined_df = outflow_df.join(price_df['price_usd'], how='inner')

fig, ax1 = plt.subplots(figsize=(14,6))

color = 'tab:blue'
ax1.set_xlabel('Date')
ax1.set_ylabel('Exchange Outflow', color=color)
ax1.plot(combined_df.index, combined_df['value'], color=color)
ax1.tick_params(axis='y', labelcolor=color)

ax2 = ax1.twinx()
color = 'tab:orange'
ax2.set_ylabel('Price USD', color=color)
ax2.plot(combined_df.index, combined_df['price_usd'], color=color)
ax2.tick_params(axis='y', labelcolor=color)

plt.title('ENA Exchange Outflow vs Price')
plt.show()
                                  value
datetime                               
2024-08-11 00:00:00+00:00  2.281849e+06
2024-08-12 00:00:00+00:00  2.047038e+07
2024-08-13 00:00:00+00:00  9.898722e+06
2024-08-14 00:00:00+00:00  4.945018e+06
2024-08-15 00:00:00+00:00  5.945851e+06
Index(['value'], dtype='object')
No description has been provided for this image
Average daily outflow: 19693605.60
Maximum daily outflow: 287706783.95
No description has been provided for this image
In [ ]: