Repository: anfederico/cryptoview Branch: master Commit: b889ae2a22be Files: 12 Total size: 20.5 KB Directory structure: gitextract_6bbm8dlf/ ├── Procfile ├── README.md ├── app.py ├── requirements.txt ├── runtime.txt ├── scripts/ │ ├── __init__.py │ ├── apis.py │ ├── models.py │ └── mongio.py ├── static/ │ └── js/ │ └── helpers.js ├── templates/ │ └── index.html └── updaters.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: Procfile ================================================ web: gunicorn app:app --log-file=- ================================================ FILE: README.md ================================================ ## Deprecated This project is no longer maintained. ================================================ FILE: app.py ================================================ from flask import Flask, redirect, url_for, render_template, request import threading import signal import json import os import time # Locals from scripts import mongio, apis, settings app = Flask(__name__) # ======== Tasks =========================================================== # def refresh_positions(exchanges): E = [] for exchange in exchanges: e = getattr(apis, exchange.title()) key = getattr(settings, '{0}_key'.format(exchange)) secret = getattr(settings, '{0}_secret'.format(exchange)) try: passphrase = getattr(settings, '{0}_passphrase'.format(exchange)) E.append(e(key, secret, passphrase).get_balances()) except AttributeError: E.append(e(key, secret).get_balances()) return sum(E).positions() # ======== Routing =========================================================== # @app.route('/', methods=['GET']) def index(): if 'positions' not in mongio.db.collection_names(): mongio.db.create_collection('positions') mongio.save(settings.mongo_portfolio, 'positions', []) mongio.save(settings.mongo_portfolio, 'equity', {'btc':{}, 'usd':{}}) positions = mongio.load(settings.mongo_portfolio, 'positions') equity = mongio.load(settings.mongo_portfolio, 'equity') return render_template('index.html', p=positions, e=equity) @app.route('/refresh', methods=['POST']) def refresh(): positions = refresh_positions(settings.exchanges) mongio.save(settings.mongo_portfolio, 'positions', positions) positions = mongio.load(settings.mongo_portfolio, 'positions') return json.dumps({'success': True, 'positions': positions}) # ======== Main ============================================================== # if __name__ == "__main__": app.run() ================================================ FILE: requirements.txt ================================================ Flask gunicorn pymongo pandas requests datetime schedule ================================================ FILE: runtime.txt ================================================ python-3.6.0 ================================================ FILE: scripts/__init__.py ================================================ ================================================ FILE: scripts/apis.py ================================================ import sys import time import hmac import hashlib import urllib import requests import json import base64 # Local Files sys.path.append("..") from scripts import models class Gemini: def __init__(self, api_key, api_secret): self.api_key = api_key self.api_secret = api_secret def raw_balances(self): url = "https://api.gemini.com/v1/balances" nonce = int(time.time() * 1000) message_json = json.dumps({"request": "/v1/balances", "nonce": nonce}) message = base64.b64encode(message_json.encode()) signature = hmac.new(self.api_secret.encode(), message, hashlib.sha384).hexdigest() headers = {'Content-Type': "text/plain", 'Content-Length': "0", 'X-GEMINI-APIKEY': self.api_key, 'X-GEMINI-PAYLOAD': message, 'X-GEMINI-SIGNATURE': signature, 'Cache-Control': "no-cache"} response = requests.request("POST", url, headers=headers) return response.json() def get_balances(self): E = models.Exchange('Gemini') raw = self.raw_balances() for t in raw: balance = float(t['available']) if balance > 0: ticker = t['currency'] try: price = requests.get('https://api.gemini.com/v1/pubticker/{0}'.format(ticker + 'btc')).json()['last'] E.tokens.append(models.Token(ticker, balance, 'Gemini', price=price)) except KeyError: E.tokens.append(models.Token(ticker, balance, 'Gemini')) return E class Binance: def __init__(self, api_key, api_secret): self.api_key = api_key self.api_secret = api_secret def raw_balances(self): session = requests.session() session.headers.update({'Accept': 'application/json','User-Agent': 'binance/python','X-MBX-APIKEY': self.api_key}) kwargs = {'params': {'timestamp': int(time.time()*1000)}} query_string = urllib.parse.urlencode(kwargs['params']) apisign = hmac.new(self.api_secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest() kwargs['params']['signature'] = apisign response = getattr(session, 'get')('https://api.binance.com/api/v3/account', timeout=10, **kwargs) return response.json()['balances'] def get_balances(self): E = models.Exchange('Binance') prices = requests.get('https://api.binance.com//api/v1/ticker/allPrices').json() prices = {i['symbol']: i['price'] for i in prices} raw = self.raw_balances() for t in raw: balance = float(t['free']) if balance > 0: ticker = t['asset'] try: price = prices['{0}BTC'.format(ticker)] E.tokens.append(models.Token(ticker, balance, 'Binance', price=price)) except KeyError: E.tokens.append(models.Token(ticker, balance, 'Binance')) return E class Bittrex: def __init__(self, api_key, api_secret): self.api_key = api_key self.api_secret = api_secret def raw_balances(self): nonce = str(int(time.time()*1000)) query_string = 'https://bittrex.com/api/v1.1/account/getbalances?' query_string += 'apikey=' + self.api_key + "&nonce=" + nonce + '&' apisign = hmac.new(self.api_secret.encode(), query_string.encode(), hashlib.sha512).hexdigest() response = requests.get(query_string, headers={"apisign": apisign}) return response.json()['result'] def get_balances(self): E = models.Exchange('Bittrex') prices = requests.get('https://bittrex.com/api/v1.1/public/getmarketsummaries').json()['result'] prices = {i['MarketName']: i['Last'] for i in prices} raw = self.raw_balances() for t in raw: balance = float(t['Available']) if balance > 0: ticker = t['Currency'] try: price = prices['BTC-{0}'.format(ticker)] E.tokens.append(models.Token(ticker, balance, 'Bittrex', price=price)) except KeyError: E.tokens.append(models.Token(ticker, balance, 'Bittrex')) return E class Poloniex: def __init__(self, api_key, api_secret): self.api_key = api_key self.api_secret = api_secret def raw_balances(self): args = {'command': 'returnCompleteBalances'} args['nonce'] = int(time.time()*1000000) data = urllib.parse.urlencode(args) sign = hmac.new(self.api_secret.encode('utf-8'), data.encode('utf-8'), hashlib.sha512) response = requests.post('https://poloniex.com/tradingApi', data=args, headers={'Sign': sign.hexdigest(), 'Key': self.api_key}, timeout=10) return response.json() def get_balances(self): E = models.Exchange('Poloniex') raw = self.raw_balances() for t in raw: balance = float(raw[t]['available']) if balance > 0: value = float(raw[t]['btcValue']) ticker = t try: E.tokens.append(models.Token(ticker, balance, 'Poloniex', value=value)) except KeyError: E.tokens.append(models.Token(ticker, balance, 'Poloniex')) return E class Gdax: def __init__(self, api_key, api_secret, api_passphrase): self.api_key = api_key self.api_secret = api_secret self.api_passphrase = api_passphrase def raw_balances(self): timestamp = str(time.time()) message = timestamp+'GET/accounts/' message = message.encode('ascii') hmac_key = base64.b64decode(self.api_secret) signature = hmac.new(hmac_key, message, hashlib.sha256) signature_b64 = base64.b64encode(signature.digest()) response = requests.get('https://api.gdax.com/accounts/', headers={ 'Content-Type': 'Application/JSON', 'CB-ACCESS-SIGN': signature_b64, 'CB-ACCESS-TIMESTAMP': timestamp, 'CB-ACCESS-KEY': self.api_key, 'CB-ACCESS-PASSPHRASE': self.api_passphrase}) return response.json() def get_balances(self): E = models.Exchange('Gdax') raw = self.raw_balances() for t in raw: balance = float(t['available']) if balance > 0: ticker = t['currency'] try: price = requests.get('https://api.gdax.com/products/{0}-BTC/ticker'.format(ticker)).json()['price'] E.tokens.append(models.Token(ticker, balance, 'Gdax', price=price)) except KeyError: E.tokens.append(models.Token(ticker, balance, 'Gdax')) return E ================================================ FILE: scripts/models.py ================================================ import requests import copy def get_performances(): data = requests.get('https://api.coinmarketcap.com/v1/ticker/').json() p = {} for ticker in data: t = dict(ticker) p[t['symbol']] = {'daily': t['percent_change_24h'], 'weekly': t['percent_change_7d']} return p class Exchange: def __init__(self, name): self.name = name self.tokens = [] def __str__(self): string = "Exchange: {0}\n".format(self.name) for token in self.tokens: string += "{0} {1} = {2} BTC\n".format(token.balance, token.name, token.value) return string def __add__(self, other): new = copy.deepcopy(self) new.name += "/"+other.name for t1 in new.tokens: for t2 in other.tokens: if t1 == t2: t1 += t2 new.tokens += [t for t in other.tokens if t not in new.tokens] return new def __radd__(self, other): if other is int(0): return self else: return self.__add__(other) def positions(self): p = get_performances() self.tokens.sort(key=lambda t: t.value, reverse=True) total_btc = sum([token.value for token in self.tokens]) positions = [] for token in self.tokens: # Ignore dust if token.value < 0.001: continue try: positions.append({'Token' : token.name, 'Balance' : round(token.balance, 2), 'Value' : round(token.value, 5), 'Allocation' : round(100*token.value/total_btc, 3), 'Daily' : p[token.name]['daily'], 'Weekly' : p[token.name]['weekly'], 'Exchanges' : "/".join(token.exchanges)}) except KeyError as e: positions.append({'Token' : token.name, 'Balance' : round(token.balance, 2), 'Value' : round(token.value, 5), 'Allocation' : round(100*token.value/total_btc, 3), 'Daily' : '--', 'Weekly' : '--', 'Exchanges' : "/".join(token.exchanges)}) return positions class Token: def __init__(self, name, balance, exchange, value=None, price=None): self.name = name.upper() self.balance = float(balance) self.exchanges = [exchange] if name == "BTC": self.value = float(balance) return if name == "USD" or name == "USDT": self.value = 0 return try: self.value = float(value) except TypeError: try: self.value = float(price)*float(balance) except TypeError: self.value = 0 def __str__(self): return "{0} {1} = {2} BTC".format(self.balance, self.name, self.value) def __eq__(self, other): return self.name == other.name def __add__(self, other): self.balance += other.balance self.value += other.value self.exchanges += other.exchanges return self ================================================ FILE: scripts/mongio.py ================================================ import pymongo import json import sys # Local Files sys.path.append("..") from scripts import settings client = pymongo.MongoClient(settings.mongo_server, settings.mongo_id) db = client[settings.mongo_client] db.authenticate(settings.mongo_user, settings.mongo_pass) def save(account, datatype, data): d = db.positions.find_one({'account': account}) if d is not None: d[datatype] = json.dumps(data) db.positions.save(d) else: db.positions.insert_one({'account': account, datatype: json.dumps(data)}) def load(account, datatype): d = db.positions.find_one({'account': account}) return json.loads(d[datatype]) ================================================ FILE: static/js/helpers.js ================================================ var rancol = function () { return function (bg) { var hue = Math.floor(Math.random() * 360); var hsl = 'hsl('+hue+', 90%, 70%)'; // 100 87.5 function checkHex(v) { return 1 === v.length ? '0'+v : v; } var data, r, g, b, a, cnv = document.createElement('canvas'), ctx = cnv.getContext('2d'), alpha = /a\(/.test(hsl), output = {}; return cnv.width = cnv.height = 1, bg && (ctx.fillStyle = bg, ctx.fillRect(0, 0, 1, 1)), ctx.fillStyle = hsl, ctx.fillRect(0, 0, 1, 1), data = ctx.getImageData(0, 0, 1, 1).data, r = data[0], g = data[1], b = data[2], a = (data[3] / 255).toFixed(2), output.hex = '#'+checkHex(r.toString(16))+checkHex(g.toString(16))+checkHex(b.toString(16)), output.hex; }; }(); function colorize(n) { var colors = [] for (var i = 0; i < n; i++ ){ colors.push(rancol()) } return colors } ================================================ FILE: templates/index.html ================================================ cryptoview



{% raw %} {% endraw %} ================================================ FILE: updaters.py ================================================ import requests import datetime import schedule import time # Local Files from scripts import mongio, settings def get_btc_price(): btc = requests.get('https://api.coinmarketcap.com/v1/ticker/bitcoin/').json() return float(btc[0]['price_usd']) def update_equity(): now = datetime.datetime.now().strftime("%Y-%m-%d") print('{0} | Updating equity'.format(now)) positions = mongio.load(settings.mongo_portfolio, 'positions') btc = sum([p['Value'] for p in positions]) usd = btc*get_btc_price() equity = mongio.load(settings.mongo_portfolio, 'equity') equity['btc'][now] = round(btc, 3) equity['usd'][now] = round(usd, 3) mongio.save(settings.mongo_portfolio, 'equity', equity) if __name__ == "__main__": print('Starting scheduler...') schedule.every(15).minutes.do(update_equity) while True: schedule.run_pending() time.sleep(1)