Skip to content

Instantly share code, notes, and snippets.

@cryptoscopia
Created January 29, 2018 21:44
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cryptoscopia/b62849ade1deb9c36a7131ceaf8d6f41 to your computer and use it in GitHub Desktop.
Save cryptoscopia/b62849ade1deb9c36a7131ceaf8d6f41 to your computer and use it in GitHub Desktop.
Parse Etherscan API transaction lists into a CSV of cumulative incoming, outgoing, and total values
#!/usr/bin/env python
from __future__ import print_function
import argparse
from collections import OrderedDict
from datetime import datetime, timedelta
from decimal import Decimal
import json
parser = argparse.ArgumentParser()
parser.add_argument('incoming', help='JSON transactions from API')
parser.add_argument('outgoing', help='JSON internal transactions from API')
args = parser.parse_args()
# A place to gather the incoming transaction data
data_in = OrderedDict()
with open(args.incoming) as f:
incoming = json.load(f)
assert incoming['message'] == 'OK'
for transaction in incoming['result']:
# Skip invalid and zero-value transactions
if transaction['txreceipt_status'] != '1' \
or transaction['isError'] != '0' \
or transaction['value'] == '0':
continue
# Round the timestamp down to the last 10-minute mark
timestamp = datetime.utcfromtimestamp(int(transaction['timeStamp']))
rounded_minute = timestamp.minute // 10 * 10
timestamp = timestamp.replace(minute=rounded_minute, second=0, microsecond=0)
# Convert value from gwei to ETH
value = Decimal(transaction['value']) / Decimal('1000000000000000000')
# First parsed row, store initial record
if not data_in:
first_timestamp = timestamp
data_in[timestamp] = value
last_timestamp = timestamp
continue
# We've already had a transaction for this 10-minute period, add this one to it
if timestamp in data_in:
data_in[timestamp] += value
last_timestamp = timestamp
continue
# Fill in 10-minute periods without transactions with the total from
# the previous period (probably unnecessary, but avoids gaps)
while last_timestamp + timedelta(minutes=10) < timestamp:
data_in[last_timestamp + timedelta(minutes=10)] = data_in[last_timestamp]
last_timestamp += timedelta(minutes=10)
# And now add the new 10-minute period with the cumulative total
data_in[timestamp] = data_in[last_timestamp] + value
last_timestamp = timestamp
# This is where we'll gather the outgoing transaction data
data_out = OrderedDict()
# Start it off with 0 at the time of the first incoming transaction
data_out[first_timestamp] = Decimal('0.0')
# The reason I keep adding these silly *_timestamp variables is because I can't
# do data_in.keys()[0] or data_in.keys()[-1], and I don't want to keep casting
# them into lists.
last_out_timestamp = first_timestamp
with open(args.outgoing) as f:
outgoing = json.load(f)
assert outgoing['message'] == 'OK'
for transaction in outgoing['result']:
# Skip invalid and zero-value transactions
if transaction['errCode'] != '' \
or transaction['isError'] != '0' \
or transaction['value'] == '0':
continue
# Round the timestamp down to the last 10-minute mark
timestamp = datetime.utcfromtimestamp(int(transaction['timeStamp']))
rounded_minute = timestamp.minute // 10 * 10
timestamp = timestamp.replace(minute=rounded_minute, second=0, microsecond=0)
# Convert value from gwei to ETH
value = Decimal(transaction['value']) / Decimal('1000000000000000000')
# We've already had a transaction for this 10-minute period, add this one to it
if timestamp in data_out:
data_out[timestamp] += value
last_out_timestamp = timestamp
continue
# Fill in 10-minute periods without transactions as we did for incoming
while last_out_timestamp + timedelta(minutes=10) < timestamp:
data_out[last_out_timestamp + timedelta(minutes=10)] = data_out[last_out_timestamp]
last_out_timestamp += timedelta(minutes=10)
# And now add the new 10-minute period with the cumulative total
data_out[timestamp] = data_out[last_out_timestamp] + value
last_out_timestamp = timestamp
# If the outgoing transactions end more than 10 minutes before
# the incoming ones, fill in the empty periods at the end
while last_out_timestamp < last_timestamp:
data_out[last_out_timestamp + timedelta(minutes=10)] = data_out[last_out_timestamp]
last_out_timestamp += timedelta(minutes=10)
# Output our data in CSV format
for k, v in data_in.items():
print('%s,%s,%s,%s' % (k, v, data_out[k], v - data_out[k]))
@cryptoscopia
Copy link
Author

Created for use with PoWH coin: https://etherscan.io/address/0xa7ca36f7273d4d38fc2aec5a454c497f86728a7a

Register on etherscan.io and get an API key first
Fetch transactions with:

curl "http://api.etherscan.io/api?module=account&action=txlist&address=0xa7ca36f7273d4d38fc2aec5a454c497f86728a7a&startblock=0&endblock=99999999&sort=asc&apikey=YOUR_API_KEY" -o transactions.json

Fetch internal (which are outgoing in this case) transactions with:

curl "http://api.etherscan.io/api?module=account&action=txlistinternal&address=0xa7ca36f7273d4d38fc2aec5a454c497f86728a7a&startblock=0&endblock=99999999&sort=asc&apikey=YOUR_API_KEY" -o internal.json

Run:

python powh_graph_api.py transactions.json internal.json > combined.csv

Open combined.csv with your favourite spreadsheet editor (e.g. Google Sheets) and generate graph
It should look something like this:
screen shot 2018-01-30 at 8 37 58 am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment