Skip to content

Instantly share code, notes, and snippets.

@RobbieClarken
Last active December 29, 2015 19:29
Show Gist options
  • Save RobbieClarken/7717968 to your computer and use it in GitHub Desktop.
Save RobbieClarken/7717968 to your computer and use it in GitHub Desktop.
Fetch CoinJar orders and present statistics
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
from dateutil.parser import parse as parse_date
from collections import namedtuple
import re
import argparse
import getpass
import sys
LOGIN_URL = 'https://secure.coinjar.com/users/sign_in'
HISTORY_URL = 'https://filler.coinjar.com/user/account_history'
Order = namedtuple('Order', ['id', 'exchange_rate', 'fee',
'net_bitcoin_transfer', 'timestamp'])
class LoginError(ValueError):
'''Username or password incorrect.'''
def extract_operations(page_soup):
rows = page_soup.find_all('tr', attrs={'class': 'narration'})
return [tr.td.text for tr in rows]
def fetch_orders(username, password):
session = requests.Session()
session.headers.update({
'user-agent': ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/30.0.1599.101 Safari/537.36')
})
login_page_request = session.get(LOGIN_URL)
login_page = BeautifulSoup(login_page_request.content)
token = login_page.find(attrs={'name': 'authenticity_token'})['value']
data = {
'user[email]': username,
'user[password]': password,
'authenticity_token': token,
'utf8': u'✓',
'commit': 'Sign in'
}
login_request = session.post(LOGIN_URL, data)
if login_request.url == LOGIN_URL:
raise LoginError('Username or password incorrect.')
filler_request = session.get('https://filler.coinjar.com')
history_request = session.get(HISTORY_URL)
history_page = BeautifulSoup(history_request.content)
operations = extract_operations(history_page)
try:
last_page_url = history_page.find(text=u'Last »').parent['href']
except AttributeError:
pass
else:
page_count = int(re.search('page=(\d+)', last_page_url).group(1))
for page in range(2, page_count + 1):
history_url = '{0}?page={1}'.format(HISTORY_URL, page)
history_request = session.get(history_url)
history_page = BeautifulSoup(history_request.content)
operations += extract_operations(history_page)
order_regex = re.compile(
'^ORDER=(?P<id>.*)'
' EXCHANGE_RATE=(?P<exchange_rate>[\d\.]+)'
' FEE=(?P<fee>[\d\.]+)'
' NET_BITCOIN_TRANSFER=(?P<net_bitcoin_transfer>[\d\.]+)'
' TIMESTAMP=(?P<timestamp>[\d\-]+ [\d:]+ (?:UTC|[\+\-]\d+))$'
)
orders = []
for operation in operations:
match = order_regex.match(operation)
if match:
order_dict = match.groupdict()
id = order_dict['id']
exchange_rate = float(order_dict['exchange_rate'])
fee = float(order_dict['fee'])
net_bitcoin_transfer = float(order_dict['net_bitcoin_transfer'])
timestamp = parse_date(order_dict['timestamp'])
orders.append(Order(id, exchange_rate, fee, net_bitcoin_transfer, timestamp))
return orders
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Fetch CoinJar order statistics.')
parser.add_argument('--start', nargs='?', default=None,
help='Only show stats for orders after this date.')
parser.add_argument('--end', nargs='?', default=None,
help='Only show stats for orders before this date.')
parser.add_argument('email', nargs='?', default=None, help='Your CoinJar email.')
args = parser.parse_args()
start = parse_date(args.start) if args.start is not None else None
end = parse_date(args.end) if args.end is not None else None
username = args.email if args.email is not None else raw_input('Email: ')
password = getpass.getpass()
try:
orders = fetch_orders(username, password)
except LoginError:
print 'Username or password incorrect.'
sys.exit(-1)
number_of_orders = 0
cheapest_rate = None
dearest_rate = None
total_invested = 0.
total_bitcoins = 0.
for o in orders:
if start is not None and o.timestamp < start:
continue
if end is not None and o.timestamp > end:
continue
number_of_orders += 1
if cheapest_rate is None or o.exchange_rate < cheapest_rate:
cheapest_rate = o.exchange_rate
if dearest_rate is None or o.exchange_rate > dearest_rate:
dearest_rate = o.exchange_rate
total_invested += (o.net_bitcoin_transfer + o.fee) * o.exchange_rate
total_bitcoins += o.net_bitcoin_transfer
print 'Number of orders: {0}'.format(number_of_orders)
print 'Total invested: ${0}'.format(total_invested)
print u'Bitcoins bought: ฿{0}'.format(total_bitcoins)
print 'Cheapest exchange rate: {0}'.format(cheapest_rate)
print 'Dearest exchange rate: {0}'.format(dearest_rate)
print 'Weighted average exchange rate: {0}'.format(total_invested / total_bitcoins)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment