Repository: kennethreitz/coinbin.org Branch: master Commit: bc3232fe5157 Files: 15 Total size: 44.5 KB Directory structure: gitextract_12qrf40r/ ├── .gitignore ├── Pipfile ├── Procfile ├── README.md ├── app.json ├── graph.py ├── predictions.py ├── scraper.py ├── server.py ├── static/ │ ├── LICENSE │ ├── README.md │ ├── latex.css │ └── tufte.css ├── templates/ │ └── index.html └── wallets.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /.envrc ================================================ FILE: Pipfile ================================================ [[source]] url = "https://pypi.python.org/simple" verify_ssl = true [packages] flask = "*" records = "*" "psycopg2" = "*" maya = "*" flask-sslify = "*" pyquery = "*" pandas = "*" "html5lib" = "*" "bs4" = "*" requests = "*" simplejson = "*" flask-cache = "*" flask-common = "*" aiohttp = "<2.0.0" crayons = "*" scikit-learn = "*" scipy = "*" pandas-datareader = "*" numpy = "*" tablib = "==0.12.0" fbprophet = "*" cython = "*" flask-graphql = "*" graphene = "*" "mpld3" = "*" raven = {extras = ["flask"]} "ruamel.ordereddict" = {version="*", markers="python_version < '3.0.0'"} [requires] python_version = "3.6" ================================================ FILE: Procfile ================================================ web: gunicorn server:app -k gaiohttp ================================================ FILE: README.md ================================================ # ₿ Coinbin.org ### The Human–Friendly API Service for Crypto Currency Information. This free web service exists to provide information on "coins". Supports all crypto–currencies. ### Example API Endpoints `$ curl https://coinbin.org/lbc` ```json { "coin": { "name": "LBRY Credits", "rank": "100", "ticker": "lbc", "value": 0.429737, "value.currency": "USD" } } ``` `$ curl https://coinbin.org/lbc/42.01` ```json { "coin": { "exchange_rate": 0.429737, "value": 18.053251369999998, "value.currency": "USD" } } ``` `$ curl https://coinbin.org/lbc/to/sc` ``` { "coin": { "exchange_rate": 61.98696034733942 } } ``` `$ curl https://coinbin.org/lbc/42.01/to/sc` ```json { "coin": { "exchange_rate": 61.98696034733942, "value": 2604.072204191729, "value.coin": "sc" } } ``` `$ curl https://coinbin.org/lbc/history` ```json { "history": [ { "timestamp": "2017-08-24T04:00:55.932092Z", "value": 0.3404, "value.currency": "USD", "when": "today" }, ... ... { "timestamp": "2016-07-12T04:01:09.167162Z", "value": 0.239634, "value.currency": "USD", "when": "Jul 12 2016" } ] } ``` ## More Resources - [Awesome Crypto Currency Tools & Algorithms (Guide)](https://github.com/kennethreitz/awesome-coins) ================================================ FILE: app.json ================================================ { "name": "coinbin.org", "scripts": { }, "env": { "API_KEYS": { "required": true }, "HEROKU_POSTGRESQL_AMBER_URL": { "required": true }, "HEROKU_POSTGRESQL_TEAL_URL": { "required": true }, "SENTRY_DSN": { "required": true }, "WEB_CONCURRENCY": { "required": true } }, "formation": { }, "addons": [ "heroku-postgresql", "heroku-postgresql", "sentry" ], "buildpacks": [ { "url": "heroku/python" } ] } ================================================ FILE: graph.py ================================================ import scraper import graphene def name_to_ticker(name): for coin in scraper.get_coins().values(): if coin['name'].lower() == name.lower(): return coin['ticker'] class Coin(graphene.ObjectType): ticker = graphene.String() name = graphene.String() rank = graphene.Int() usd = graphene.Float() @classmethod def from_coin(klass, c): klass.ticker = c.ticker klass.name = c.name klass.rank = c.rank klass.usd = c.usd return klass class Query(graphene.ObjectType): coin = graphene.Field(Coin, name=graphene.String()) recent_top_coins = graphene.List(Coin) @graphene.resolve_only_args def resolve_coin(self, name=None, ticker=None): if name and not ticker: ticker = name_to_ticker(name) c = Coin.from_coin(scraper.Coin(ticker)) c.name = name return c schema = graphene.Schema(query=Query) ================================================ FILE: predictions.py ================================================ import time import uuid import records import os import maya import numpy as np import pandas as pd # Matplotlib hack. import matplotlib matplotlib.use('agg') import mpld3 from fbprophet import Prophet from scraper import Coin, MWT, convert_to_decimal PERIODS = 30 GRAPH_PERIODS = 365 @MWT(timeout=300) def get_predictions(coin, render=False): """Returns a list of predictions, unless render is True. Otherwise, returns the path of a rendered image. """ c = Coin(coin) q = "SELECT date as ds, value as y from api_coin WHERE name=:coin" db = records.Database() rows = db.query(q, coin=c.name) df = rows.export('df') df['y_orig'] = df['y'] # to save a copy of the original data..you'll see why shortly.  # log-transform y df['y'] = np.log(df['y']) model = Prophet(weekly_seasonality=True, yearly_seasonality=True) model.fit(df) periods = PERIODS if not render else GRAPH_PERIODS future_data = model.make_future_dataframe(periods=periods, freq='d') forecast_data = model.predict(future_data) if render: matplotlib.pyplot.gcf() fig = model.plot(forecast_data, xlabel='Date', ylabel='log($)') return mpld3.fig_to_html(fig) forecast_data_orig = forecast_data # make sure we save the original forecast data forecast_data_orig['yhat'] = np.exp(forecast_data_orig['yhat']) forecast_data_orig['yhat_lower'] = np.exp(forecast_data_orig['yhat_lower']) forecast_data_orig['yhat_upper'] = np.exp(forecast_data_orig['yhat_upper']) df['y_log'] = df['y'] #copy the log-transformed data to another column df['y'] = df['y_orig'] #copy the original data to 'y' # print(forecast_data_orig) d = forecast_data_orig['yhat'].to_dict() predictions = [] for i, k in enumerate(list(d.keys())[-PERIODS:]): w = maya.when(f'{i+1} days from now') predictions.append({ 'when': w.slang_time(), 'timestamp': w.iso8601(), 'usd': convert_to_decimal(d[k]), }) return predictions if __name__ == '__main__': print(get_predictions('btc')) ================================================ FILE: scraper.py ================================================ import pandas import requests import crayons from pyquery import PyQuery as pq import time from collections import OrderedDict from decimal import Decimal url = 'https://coinmarketcap.com/currencies/views/all/' session = requests.Session() class MWT(object): """Memoize With Timeout""" _caches = {} _timeouts = {} def __init__(self, timeout=2): self.timeout = timeout def collect(self): """Clear cache of results which have timed out""" for func in self._caches: cache = {} for key in self._caches[func]: if (time.time() - self._caches[func][key][1]) < self._timeouts[func]: cache[key] = self._caches[func][key] self._caches[func] = cache def __call__(self, f): self.cache = self._caches[f] = {} self._timeouts[f] = self.timeout def func(*args, **kwargs): kw = sorted(kwargs.items()) key = (args, tuple(kw)) try: v = self.cache[key] if (time.time() - v[1]) > self.timeout: raise KeyError except KeyError: v = self.cache[key] = f(*args, **kwargs), time.time() return v[0] func.func_name = f.__name__ return func def convert_to_decimal(f): return Decimal("{0:.8f}".format(f)) class Coin(): """A Coin, unlike Mario's.""" def __init__(self, ticker): self.ticker = ticker self.name = None self.rank = None self._value = None self.update() def update(self): coins = get_coins() print(f'Fetching data on {crayons.cyan(self.ticker)}...') self.name = coins[self.ticker]['name'] self.rank = coins[self.ticker]['rank'] self._usd = coins[self.ticker]['usd'] @property def usd(self): return self._usd @property def btc(self): coins = get_coins() rate = coins['btc']['usd'] return convert_to_decimal(self.usd / rate) def value(self, coin): """Example: BTC -> ETH""" return convert_to_decimal(self.btc / Coin(coin).btc) def __repr__(self): return f'' @MWT(timeout=300) def get_coins(): coins_db = OrderedDict() print(crayons.yellow('Scraping CoinMaketCap...')) r = session.get(url) html = pq(pq(r.content)('table')[0]).html() df = pandas.read_html("{}
".format(html)) df = pandas.concat(df) btc_value = float(df.to_dict()['Price'][0][1:].replace(',', '')) for row in df.itertuples(): rank = int(row[1]) name = ' '.join(row[2].split()[1:]) ticker = row[3].lower() try: usd = float(row[5][1:].replace(',', '')) except ValueError: usd = 0 finally: pass btc = convert_to_decimal(usd / btc_value) coins_db.update({ticker: {'rank': rank, 'name': name, 'ticker': ticker, 'usd': usd, 'btc': btc}}) return coins_db def get_coin(ticker): return Coin(ticker) if __name__ == '__main__': print(get_coins()) ================================================ FILE: server.py ================================================ import os from scraper import get_coins, get_coin, Coin, convert_to_decimal from predictions import get_predictions from graph import schema from flask import Flask, jsonify, render_template, request, send_file from flask_graphql import GraphQLView from flask_cache import Cache from flask_common import Common from flask_sslify import SSLify import crayons import maya import requests import records API_KEYS = os.environ.get('API_KEYS', '').split(':') db = records.Database() pro_db = records.Database(os.environ['HEROKU_POSTGRESQL_TEAL_URL']) app = Flask(__name__) app.debug = 'DEBUG' in os.environ common = Common(app) sslify = SSLify(app) @app.route('/') @common.cache.cached(timeout=60) def hello(): lbc = get_coin('lbc') lbc_42 = get_value_int('lbc', 42.01) lbc_sc = get_exchange('lbc', 'sc') lbc_42_sc = get_exchange_value('lbc', 'sc', 42.01) lbc_forecast = get_forecast('lbc') return render_template('index.html', lbc=lbc, lbc_42=lbc_42, lbc_sc=lbc_sc, lbc_42_sc=lbc_42_sc, coins=get_coins().values(), lbc_forecast=lbc_forecast) @app.route('/coins') def all_coins(): return jsonify(coins=get_coins()) @app.route('/') def get_coin(coin): c = Coin(coin.lower()) return jsonify(coin={ 'name': c.name, 'ticker': c.ticker, 'rank': c.rank, 'usd': c.usd, 'btc': c.btc }) @app.route('//forecast') def get_forecast(coin): return jsonify(forecast=get_predictions(coin.lower())) @app.route('//forecast/graph') def get_forecast_graph(coin): return get_predictions(coin.lower(), render=True) # return send_file(f_name, mimetype='image/png') @app.route('//') def get_value(coin, n): c = Coin(coin.lower()) return jsonify(coin={ 'usd': convert_to_decimal(c.usd * n), 'exchange_rate': c.usd }) @app.route('//') def get_value_int(coin, n): return get_value(coin, n) @app.route('//history') def get_history(coin): c = Coin(coin.lower()) q = "SELECT * from api_coin WHERE name=:coin ORDER BY date desc" if request.args.get('key') in API_KEYS: print(crayons.red('Pro request!')) rows = pro_db.query(q, coin=c.name) else: rows = db.query(q, coin=c.name) return jsonify(history=[ { 'value': r.value, 'value.currency': 'USD', 'timestamp': maya.MayaDT.from_datetime(r.date).subtract(hours=4).iso8601(), 'when': maya.MayaDT.from_datetime(r.date).subtract(hours=4).slang_time() } for r in rows] ) @app.route('//to/') def get_exchange(coin1, coin2): c = Coin(coin1.lower()) return jsonify(coin={ # 'name': c.name, # 'ticker': c.ticker, 'exchange_rate': c.value(coin2.lower()), }) @app.route('///to//') def get_exchange_value(coin1, coin2, n): c = Coin(coin1.lower()) v = c.value(coin2.lower()) n = convert_to_decimal(n) return jsonify(coin={ 'value': convert_to_decimal(v * n), 'value.coin': coin2, 'exchange_rate': v }) @app.route('///to//') def get_exchange_value_int(coin1, coin2, n): return get_exchange_value(coin1.lower(), coin2, n) # GraphQL stuff. app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True)) # app.add_url_rule('/graphql/batch', view_func=GraphQLView.as_view('graphql', schema=schema, batch=True)) if __name__ == '__main__': common.serve() ================================================ FILE: static/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Dave Liepmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: static/README.md ================================================ Tufte CSS ========= Edward Tufte uses a distinctive style in his handouts: simple, with well-set typography, extensive sidenotes, and tight integration of graphics and charts. `tufte-css` brings that style to HTML documents. This project is directly inspired by and based on [Tufte-LaTeX](https://tufte-latex.github.io/tufte-latex/) and the [R Markdown Tufte Handout](http://rmarkdown.rstudio.com/examples/tufte-handout.pdf). Getting Started - The file *index.html* is a self-describing demonstration document that walks through the features of Tufte CSS. The live version at [https://edwardtufte.github.io/tufte-css/](https://edwardtufte.github.io/tufte-css/) is the best overview of the project. To use Tufte CSS, just copy `tufte.css` and the `et-book` font directory to your project and add the following to your HTML doc's head block: ```html ``` All other files in the repository can be ignored, as they are merely used by the demonstration document. Contributing - If you notice something wrong or broken, let us know by opening an issue. **Pull requests are very welcome**. For best results, keep pull requests to one change at a time, and test your fix or new functionality against `index.html` on screens as small as an iPhone 4 and as big as, well, as big as you use normally. (If you don't have a mobile device handy, fake different devices with your browser's developer tools.) See the Issues page, especially [Help Wanted](https://github.com/edwardtufte/tufte-css/labels/help%20wanted), for opportunities to contribute. Keep our style guide in mind: CSS Style Guide - >Every major open-source project has its own style guide: a set of >conventions (sometimes arbitrary) about how to write code for that >project. It is much easier to understand a large codebase when all the >code in it is in a consistent style.
> -- [Google Style Guide](https://github.com/google/styleguide) Tufte CSS aims for clarity, concision, and uniformity. Here's a basic example of our CSS conventions: ```css p { font-size: 1.4rem; line-height: 2rem; margin-top: 1.4rem; margin-bottom: 1.4rem; width: 55%; padding-right: 0; vertical-align: baseline; } @media screen and (max-width: 600px) { p { width: 70%; }} @media screen and (max-width: 400px) { p { width: 90%; }} ``` Notice the single spacing between most syntactic markers, the single blank lines between unrelated blocks, and the absence of line breaks after an open-paren and before end-parens. Notice also that these rules change slightly for media queries. Contributors - - Dave Liepmann (creator, project maintainer, design) - Edward Tufte (editing, direction, design) - [Adam Schwartz](https://github.com/adamschwartz) (ET Book font, descender-clearing link underlines) - [Clay Harmon](https://github.com/edwardtufte/tufte-css/commits/master?author=clayh53) (media queries, rem units) - [Linjie Ding](https://github.com/edwardtufte/tufte-css/commits/master?author=pyrocat101) (italic typeface) - [Stephen A Thomas](https://github.com/edwardtufte/tufte-css/commits/master?author=sathomas) (automagically numbered sidenotes) - [Ben Newman](https://github.com/edwardtufte/tufte-css/pull/9) (sidenote numbering style) - [Kevin Godby](https://github.com/edwardtufte/tufte-css/commits/master?author=godbyk) (booktabs tables) - [James Kolce](https://github.com/edwardtufte/tufte-css/commits/master?author=jameskolce) (sidenote fixes) - [Chris MacKay](https://github.com/crmackay) (sidenote toggling on small screens) - [Paul Rodriguez](https://github.com/edwardtufte/tufte-css/commits/master?author=ruricolist) (sidenote style tweaks) - [Claudiu-Vlad Ursache](https://github.com/edwardtufte/tufte-css/commits/master?author=ursachec) (HTML5 conformity) License - Released under the MIT license. See [LICENSE](https://github.com/edwardtufte/tufte-css/blob/gh-pages/LICENSE). ================================================ FILE: static/latex.css ================================================ .latex-sub, .latex-sup { text-transform: uppercase; font-size: smaller; position: relative; } .latex-sub { top: 0.2rem; margin-left: -0.1667rem; margin-right: -0.125rem; } .latex-sup { top: -0.2rem; margin-left: -0.36rem; margin-right: -0.15rem; text-shadow: none; } .latex::selection, .latex span:not(.latex-sup)::selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe; background: #b4d5fe; } .latex::-moz-selection, .latex span:not(.latex-sup)::-moz-selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe; background: #b4d5fe; } ================================================ FILE: static/tufte.css ================================================ @charset "UTF-8"; /* Import ET Book styles adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */ @font-face { font-family: "et-book"; src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot"); src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg"); font-weight: normal; font-style: normal; } @font-face { font-family: "et-book"; src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot"); src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg"); font-weight: normal; font-style: italic; } @font-face { font-family: "et-book"; src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot"); src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg"); font-weight: bold; font-style: normal; } @font-face { font-family: "et-book-roman-old-style"; src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot"); src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg"); font-weight: normal; font-style: normal; } /* Tufte CSS styles */ html { font-size: 15px; } body { width: 87.5%; margin-left: auto; margin-right: auto; padding-left: 12.5%; font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif; background-color: #fffff8; color: #111; max-width: 1400px; counter-reset: sidenote-counter; } h1 { font-weight: 400; margin-top: 4rem; margin-bottom: 1.5rem; font-size: 3.2rem; line-height: 1; } h2 { font-style: italic; font-weight: 400; margin-top: 2.1rem; margin-bottom: 0; font-size: 2.2rem; line-height: 1; } h3 { font-style: italic; font-weight: 400; font-size: 1.7rem; margin-top: 2rem; margin-bottom: 0; line-height: 1; } hr { display: block; height: 1px; width: 55%; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } p.subtitle { font-style: italic; margin-top: 1rem; margin-bottom: 1rem; font-size: 1.8rem; display: block; line-height: 1; } .numeral { font-family: et-book-roman-old-style; } .danger { color: red; } article { position: relative; padding: 5rem 0rem; } article pre { overflow: auto; } section { padding-top: 1rem; padding-bottom: 1rem; } p, ol, ul { font-size: 1.4rem; } p { line-height: 2rem; margin-top: 1.4rem; margin-bottom: 1.4rem; padding-right: 0; vertical-align: baseline; } /* Chapter Epigraphs */ div.epigraph { margin: 5em 0; } div.epigraph > blockquote { margin-top: 3em; margin-bottom: 3em; } div.epigraph > blockquote, div.epigraph > blockquote > p { font-style: italic; } div.epigraph > blockquote > footer { font-style: normal; } div.epigraph > blockquote > footer > cite { font-style: italic; } /* end chapter epigraphs styles */ blockquote { font-size: 1.4rem; } blockquote p { width: 55%; margin-right: 40px; } blockquote footer { width: 55%; font-size: 1.1rem; text-align: right; } section>ol, section>ul { width: 45%; -webkit-padding-start: 5%; -webkit-padding-end: 5%; } li { padding: 0.5rem 0; } figure { padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; max-width: 55%; -webkit-margin-start: 0; -webkit-margin-end: 0; margin: 0 0 3em 0; } figcaption { float: right; clear: right; margin-top: 0; margin-bottom: 0; font-size: 1.1rem; line-height: 1.6; vertical-align: baseline; position: relative; max-width: 40%; } figure.fullwidth figcaption { margin-right: 24%; } /* Links: replicate underline that clears descenders */ a:link, a:visited { color: inherit; } a:link { text-decoration: none; background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#333, #333); background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(#333, #333); -webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px; -moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px; background-size: 0.05em 1px, 0.05em 1px, 1px 1px; background-repeat: no-repeat, no-repeat, repeat-x; text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8; background-position: 0% 93%, 100% 93%, 0% 93%; } @media screen and (-webkit-min-device-pixel-ratio: 0) { a:link { background-position-y: 87%, 87%, 87%; } } a:link::selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe; background: #b4d5fe; } a:link::-moz-selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe; background: #b4d5fe; } /* Sidenotes, margin notes, figures, captions */ img { max-width: 100%; } .sidenote, .marginnote { float: right; clear: right; margin-right: -60%; width: 50%; margin-top: 0; margin-bottom: 0; font-size: 1.1rem; line-height: 1.3; vertical-align: baseline; position: relative; } .sidenote-number { counter-increment: sidenote-counter; } .sidenote-number:after, .sidenote:before { content: counter(sidenote-counter) " "; font-family: et-book-roman-old-style; position: relative; vertical-align: baseline; } .sidenote-number:after { content: counter(sidenote-counter); font-size: 1rem; top: -0.5rem; left: 0.1rem; } .sidenote:before { content: counter(sidenote-counter) " "; top: -0.5rem; } blockquote .sidenote, blockquote .marginnote { margin-right: -82%; min-width: 59%; text-align: left; } p, footer, table { width: 55%; } div.fullwidth, table.fullwidth { width: 100%; } div.table-wrapper { overflow-x: auto; font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif; } .sans { font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif; letter-spacing: .03em; } code { font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1.0rem; line-height: 1.42; } .sans > code { font-size: 1.2rem; } h1 > code, h2 > code, h3 > code { font-size: 0.80em; } .marginnote > code, .sidenote > code { font-size: 1rem; } pre.code { font-size: 0.9rem; width: 52.5%; margin-left: 2.5%; overflow-x: auto; } pre.code.fullwidth { width: 90%; } .fullwidth { max-width: 90%; clear:both; } span.newthought { font-variant: small-caps; font-size: 1.2em; } input.margin-toggle { display: none; } label.sidenote-number { display: inline; } label.margin-toggle:not(.sidenote-number) { display: none; } @media (max-width: 760px) { body { width: 84%; padding-left: 8%; padding-right: 8%; } p, footer { width: 100%; } pre.code { width: 97%; } section > ol { width: 90%; } section > ul { width: 90%; } figure { max-width: 90%; } figcaption, figure.fullwidth figcaption { margin-right: 0%; max-width: none; } blockquote { margin-left: 1.5em; margin-right: 0em; } blockquote p, blockquote footer { width: 100%; } label.margin-toggle:not(.sidenote-number) { display: inline; } .sidenote, .marginnote { display: none; } .margin-toggle:checked + .sidenote, .margin-toggle:checked + .marginnote { display: block; float: left; left: 1rem; clear: both; width: 95%; margin: 1rem 2.5%; vertical-align: baseline; position: relative; } label { cursor: pointer; } div.table-wrapper, table { width: 85%; } img { width: 100%; } } ================================================ FILE: templates/index.html ================================================ Coinbin.org: A Human–Friendly API Service for Crypto Currency Information

₿ Coinbin.org

A Human–Friendly API Service for Crypto Currency Information.

This service provides machine (and human) friendly JSON data for all known crypto–currencies. All {{ coins|length }} active & known coins are supported.

Historical data, exchange rates, conversion ratios, and value conversion endpoints are all available, free of charge. Data is refreshed every five minutes.

There is no rate limit. There never will be.

Example API Endpoints

$ curl https://coinbin.org/lbc
{{ lbc.data.decode('utf-8') }}
      

$ curl https://coinbin.org/lbc/42.01
{{ lbc_42.data.decode('utf-8') }}
      

$ curl https://coinbin.org/lbc/to/sc
{{ lbc_sc.data.decode('utf-8') }}
      

$ curl https://coinbin.org/lbc/42.01/to/sc
{{ lbc_42_sc.data.decode('utf-8') }} 

$ curl https://coinbin.org/lbc/history
{
  "history": [
    {
      "timestamp": "2017-08-24T04:00:55.932092Z",
      "value": 0.3404,
      "value.currency": "USD",
      "when": "today"
    }, ...

... {
      "timestamp": "2016-07-12T04:01:09.167162Z",
      "value": 0.239634,
      "value.currency": "USD",
      "when": "Jul 12 2016"
    }
  ]
}

This endpoint returns up to four years of daily USD data, on any given coin.

Pro Version

We're collecting historical data, moving forwardWe may backfill our historical data as well, if customers interest is high., every ten minutes (instead of daily). If you'd like access to this data, send us an email. We accept payment in coins.

Experimental (e.g. fun) Endpoints

Prediction of BTC Price (using machine learning)

 

Note — This information is presented for informational purposes only, and is not recommended for making actual trading decisions.

$ curl https://coinbin.org/btc/forecast
{{ lbc_forecast.data.decode('utf-8') }} 

Full List of Supported Coins (Ordered by Rank)

$ curl https://coinbin.org/coins
{
  "coins": [{% for coin in coins %}
    "{{ coin['ticker'] }}":
      {{ coin|tojson }},{% endfor %}
  ]
}
      

More Resources

================================================ FILE: wallets.py ================================================ wallets = { 'btc': '1PYZH8SCXQF7c2qgpsQ8kDgKixXeYvVsKv', 'ltc': 'LXPtxt68njDdTBdu1ZvHUbARhHsPm9T3Zq', 'doge': 'DRDjoTo3zg64QHpq3xgrVVJnerLAvVzMbc', 'vtc': 'VvNd9XoYKavHagE6VkLNPeAazFmpgMZgQ5', 'ppc': 'PMQWpq15QxT4dR6h6NrvrJMNtehcmRVxYW', 'ftc': '6zDLXZmoNBdz87ZMvtK2JF7C3NRuKu2nVr', 'rdd': 'RudBYrzAQeYmDXHhMXs7hPsYJc7n1C7Trt', 'dash': 'XvtKBmKUhiEPQyEgNxvSRt9hyHBCN8Mia7', 'pot': 'PTjS6cpqGoUUbEKyUWMqHk92ymvXMi84Ti', 'blk': 'BKNihHBXHy24q7wWM6A45xnDWTvcKrcmXN', 'emc2': 'EbMSP6TnLgfiJEnL1SUf4N8tjSHsY2L8zA', 'xmy': 'MQPjf1pCpKQDVabTXe3do4JTQ9A81oJyHp', 'aur': 'AVdVKHAvQij7QWmZ8p8P3qArK1eunrUukK', 'gld': 'E6UVrbrd4VnvspMuDqDw7FfMhGAqj26dZE', 'fair': 'fVkBYTPiQpcWCmFGSTtxhug2yW2nDZw6x7', 'slr': '8WUGQdSjo6XikocLF54KfHfBJ2HQqwtE3t', 'ptc': 'LJ7NefEUuJ9DC8qneEW2541p5iJzxNMqyQ', 'grs': 'FZg2ceLVCRFaV48C1BViKd1ersC9pxcHeb', 'nlg': 'GTEBkz4H73YJgTNhAVtwvwZwUgTsEezVjR', 'xwc': 'WXiGQuL7YNhDj93GMdRWJK3gdPMJfQWB8e', 'mona': 'MSE8zn8b7tdHnCL45em7nes5BtTQfPuSwc', 'enrg': 'eBzzqNtRCsxYLDyKkBT4CSiu2c6hFK8N5X', 'rby': 'RRcRzBTcz8HhfNncH9rbKM1hppwMB4EpPj', 'thc': 'HMemWrgjEfmgutjkM7C2zMqgpj97SJtW7g', 'erc': 'EWeL8eYZRJJZnMFrwMvhidxJsXDcfsELgL', 'vrc': 'VUmKQQdfVdsNfSzGtWZddWnv1gD1VuYPSa', 'cure': 'BE1rrjqnMPXnLbsTXdbhe13wuRRN1q5qTy', 'cloak': 'BtMtdrXRWBw6YMfSsxtkBiRP1wYeFH2Xrk', 'bsd': 'iPcwLWBxp2BYfDCyGYbvHbjRCzGL7rjE2U', 'start': 'sdvC9GSopsBmJ8VtVmNxKf1xwcGtY9bzwz', 'kore': 'K8iJwoL5ojPWw2kjhnWJrNwm1rsoWewErb', 'trust': 'TUFooWK6jqDYHKUggZyREvPAeK6nhSYHAX', 'nav': 'NUBRSjHJ8h52bqF2d2U4iXzEF3v6fgskw4', 'xst': 'S6L8FQGNLhpGEhcZzt4YMYNHq1H98QKkmK', 'btcd': 'RCJPmNM6BaNBTiomfJ83c2hEjMpnLjFghe', 'via': 'Vcd9Be6s1NePuci1LvC16K21kBytYmRf1t', 'uno': 'uZsGhq6VfNpYPUtNqg9fdushmsuc6B9GMA', 'pink': '2EjF3ACSNJqudSKZaEeSHvkGqVFg4JtUSA', 'ioc': 'iZmhHdNtPGfEVwswTkaLEDEuxrHQFDGD77', 'cann': 'CemM7gxYYJK9weV6Ed8sw4B7fvPQgY8hfW', 'sys': 'SUNH2SNQqaZvxqqPvuQcBVNdZshPRq2ZTv', 'neos': 'NTM232LiTUz8tgXmAWg8TxbrKtcAkDW9Mr', 'dgb': 'DA2eLVocFESdqVETtgVLP6k1m319o4g4Yq', 'excl': 'EPdycUjUzcYvFFGvTPC8z9NriZ8EgxLL7P', 'dope': 'D6NTRES89hzLNYx55AEuqWuAs8rUsR3sVc', 'block': 'Ba3yDhGLkiqN28YXoMYgBPuSjKht4a2ZGK', 'aby': 'AMbFZwYzjMJHtjJL3fHti2k2JtpfqrX7Ud', 'byc': 'BGD2TfaNbN6wq6CZXHMG9fSEWdniVZhJzn', 'blitz': 'oWZsQvU3T9FU25FdmRnAousz5CpzXjd6Eg', 'bay': 'BFDi3ZSZorDPX17iYrmhRFRSQK5DniqG4v', 'spr': 'SYeuSdejAg8jbhrC6pYmwMMPn99egVmyaP', 'vtr': 'xr14J4LzdL4jYfRNpP5WdPjtq5dC2YNXiZA27ZayWqC87o4B4UwibZFWr6U5B3B3T7gdjfCqsN5c3btYhFSzBCf2fDL9Bvj1LAPqYQ', 'game': 'GMn4k4jXVDjVbSMCWabNguczwADkQxnnRu', 'nxs': '2RQbTTGVYJB1qkghsoZunueS71EPfc6KfCbhJqXveLJFCCK4U35', 'bitb': '2UjoiH7RmYhvdzJRGXAt5SVeP1iw9MP3Ka', 'xvg': 'DAtQMkVj14Vs4jUww8EcnurUGz1c92pBV9', 'geo': 'GR7Zj1EsHWc7M3KU5BDhTCSx4y9QR9nEEo', 'flo': 'FMSEzFyS9dWhb69ch72VF1ETePnXnb2qxY', 'nbt': 'BBijzpMJo92pT4dp1NxwGXY1kBJGxz1QJr', 'grc': 'S1t5Jr2WwxZSeSNn8p5RkAAycHa2ZraShi', 'mue': '7bSsG2TBa4645qitQsfBPj9Gp7ZW8QTa87', 'xvc': 'VpYaBkNXNCtYg3HTP7onhdvhTqtvGBwBCo', 'clam': 'xVJ7ySQNPfN3XKmAykTYapuZzZun23xsr5', 'dmd': 'dGRJXSHNiF9SoAatLeuoKYxmCbKJ8aXkga', 'gam': 'GSqe2k3G2EQQy3QNPwGyyyW33m7eEr6Df6', 'sphr': 'BPpGQCDR63NcN6Po9Lvo2D8nqQbhpiSHcE', 'ok': 'PGuDs5iu3sEaeAr1kMnMSwNCwJW2xUMTwA', 'snrg': 'SYkCDBer4Kap91ftY4cdDfrjnTh3nRvNqk', 'pkb': 'PLvXxUE6NrJqvoP1imR8sS23hDCmXoWcxz', 'cpc': 'CYWUbfBTAVW9H4zAPRe6yckWWBVRXaznT1', 'eth': '0xcf4c939ccae5c0ecc8b63505cce1513e5ef0d567', 'gcr': 'GRxryTQ43RET8xfzm38L42wYchim9H3cHf', 'tx': 'TixtGQBFrzfFH5Z1ouKjM4UDGqkKXcyw8p', 'exp': '0xbc4ee321e752cdd8ca54e4405de71c5f4f5b5f24', 'infx': 'iBJzRkcQk6coYUE4UFFDzvfi8Y1URMzyyA', 'omni': '15rebjRT6mESSbHU9yyLTh8oADdC4x4RWg', 'usdt': '1Ne3DYc5tJSAjS3rwqDt3GSN1FYMrHLPWr', 'amp': '13f3KoRoFD5iJw1zdQBw5Hum5EYRs9pB3x', 'agrs': '16EPWtBErUnT6fEsKmJfB4gxnJx5qndMCJ', 'bta': 'BJD3NHuuiibB85FrxYULSHTgJmye25PRKF', 'club': 'Ce9MJXxjasVSbVPntihwote3SjMbfqnvDJ', 'vox': 'VV5QjvbWFC9rvWtLyxMvsJDT1FFk9jgbWa', 'emc': 'EgPN6YhGXqgTL7np3UtAM2UReMs7eWVD8K', 'fct': 'FA3EuMt78kTLHdJsfS65r15xE4acVRtARBfUnKTqfMmGUyTzcNtP', 'maid': '1gUbRQjyQX2uJkezY8WY7KSEGGEmD9Zme', 'egc': 'EZYWa2KKhzUstJnTZG1SA8zp7stiyrt2Up', 'sls': 'SZVpV5LtN9WXdafou3BoHsacDhMcmCjUzr', 'rads': 'XcML29TJXQihsV5JmphEVbTPcS6xPkcZFj', 'dcr': 'DsUcYM48ZravjWaLCoeAxYQvTcNigqYaQVf', 'safex': '1jTMyxf2iP9NxNzMDAZVhQVQskj7zvDj9', 'pivx': 'DU6uyNH7E5VPse3hh4RZr4A12VQtM2E3Ue', 'meme': 'PCXXZ3NKQUMA26GsX5cjozE48yvM5uUnrR', '2give': 'GpG7ygLvdd3GKsbAUvPRZbMR8GtXa7JizS', 'lsk': '3548326455915242856L', 'pdc': '12ZeM7mrPnZBM5rZWXh9QpNbe6eSTykxCr', 'dgd': '0x7e7cec0a54cbda02b44e6c24a298b2d89b8f3c31', 'brk': 'brfTVJS9JGtNX8prmKQBaQtWbtj1b1WJB7X', 'waves': '3P6H2V28Zzs9qX3U86Rs5hzTFkcCJrbDJEm', 'lbc': 'bVQKmE9tkLHxkjnu97SSe8eQHT9q4c69Zb', 'brx': 'bxVriVBdAZ1jXkKFvBAA3zQkS819kZFqWVd', 'etc': '0xb52c0534da8d758943e8604916b6be70071bc6d3', 'strat': 'Sf8iKKeaAFRX772JA5TWXDwZMJZkJNwmSZ', 'unb': '13izqwELn1jTt1j7umfoJKUPRUBBPmwpHv', 'ebst': 'e91xYCEFKh2J2VogvUraooeCFUUcCbrUnM', 'vrm': 'VXYWrM5h6YE7pU1zPjFpXYcGVoYnLAETyK', 'xaur': '0x1253295779080ec136551724a27143e4470073a2', 'seq': 'Se8Eg7u1k6izqAW3nmKAwuBewiJu1G2fbD', 'sngls': '0x6f4f433ff62347998785e4ed30f3048a2281fd98', 'rep': '0x16169642de5a4c43a5f3bcbc5eea36ca767ecc4d', 'shift': '3548326455915242856S', 'xzc': 'a3vmJpgzqDu4Yg6FPt9uj27m3sBAbMwtRs', 'neo': 'AG2dY41SYEMmZLLy5dS1gNwHkWEAshE3ft', 'zec': 't1fnCgLKXy7Q1ovFD5obWcH1Vmpp6ivVhJu', 'zcl': 't1bHV2hFD8mVoVH2S7KVSfAmdTX615xXGgy', 'iop': 'pEP4niYzA8eiPUfCcy5pnPxoETu7zx6n4G', 'ubq': '0x98b3ffb0a988308304b32077ba31e5b300be1567', 'hkg': '0x1567685a30ee1d1ace1f1e6291b727b1e2ca5eea', 'sib': 'Sicrwdsg9mVMCACVJJq23RfqSXiNfH7H2f', 'ion': 'ia2ts12ZrprJ9GjsuJChY1HmzeFnwy6k5x', 'lmc': 'LZFKYiQRjX3zLaBRMTzF6kaRReoAqsTGgX', 'qwark': '0xe4f1f6665f68489f6ff512194553918df13a1ae6', 'crw': '12rCC2LwBBuue46KELC9zE9H75Tq9ff492', 'swt': '0xaef9799c36cc1459d7876b56383a4a2107bc4b66', 'time': '0x1ddcfde92c5c82f5fc919b69478ce65db5446483', 'mln': '0x8c1d250c58133ff94b224390c3137d8dc4bf02bc', 'tks': '3PESLYrs1s5sNYGBHD8bZnqWvB3pW3BMcWd', 'ark': 'AJrDLieoPW46gg3XRANt3J8emDFdQPDUmq', 'music': '0x9248334cf30082b5e301bef6fa29642c3170e2e4', 'incnt': '3PEuNUJZpE4mjqhHZDCmisGabd4g1qzAeve', 'gbyte': 'RYLB7TCEBR4WK3ZEBMGOSLHOPU2COVMZ', 'gnt': '0x7da2d058575c81a0b5658878a3b3efed0de142d4', 'nxc': '0x06e1d5c1e7dded4b9e32f45845e1d352c0cf8bc5', 'edg': '0xdc8e6d7de95fb75774f2b3be2d03efd29d9242e8', 'lgd': '0xce7591232523f66b14189c4cec4679e3ab7b3d8e', 'trst': '0xa60ff29d26d373a88afbe74f6dbcab3aeca677e6', 'wings': '0xb4466e1575882d28388820a719516d1dff412961', 'rlc': '0xab916ef71e19c56c98de93d0dba99469b1283db1', 'bcc': '1LVojXegSH5EhrNQncWfxg7ErVh4N9HCAL', 'qtum': '0x1646d7c096047756ab0b1cb636cf5dd5d36959d2', 'part': 'Ph9oGH1vwtsFTHmAwYh3iS9J1vcVhoLXFk', 'cvc': '0x584827cad4a2cb47582ebd5a5ee6e4fd5ea63255', 'omg': '0xef24cccdad02b96e8bd3c68757c1aab5547ecda7', 'adx': '0x36f8b284fa87405389e672d74898d0bf2930a5d9', 'storj': '0x05feda4008e2d9253bc339332a29a5a862c8c5d2', 'mtl': '0x7b610ddc59fd76c1e8a23ff69904e5d4898bbf78', 'pay': '0x3a957df561559587b43eb77b4266c8f0063ec948', 'fun': '0xd9a996f367802920aa7bb5bce48de183f45eeb54', 'adt': '0x7853d58160a73d538e89278bb036d2b80e00c351', 'mco': '0xf3959d90b9b880ee29e62f1210a37fe9b54ce0c1', 'snt': '0x3f6526ddd2e452ca6f93033653f0f39ace19f71e', 'nmr': '0xcb83ccdd55939de0653b455d7aebf21982357320', 'bnt': '0x3363f5a728901533511427d27f3151fe9df152a0', 'cfi': '0xa27c5edf5d5ca32a3f3926f7d46d4dcbea43241d', 'myst': '0x9dfe066e10215254e7e62c86a30fd0aea1884be3', 'ptoy': '0x5bc546675be2ea8b3a56eab0161e7f8c6615930a', 'crb': '0x3e12bb90fffebdab71dffca9557a81587d32862f', 'qrl': '0x7e4b07296fc5a54031ca133b98546d350c0cd293', '1st': '0x919865c75dd7949fb061e7a2102290b79e4d9150', 'bat': '0x04db9cf3de9183f8e5d5b7609c5793e4448c9bf6', 'sc': '6197b45062c2d75d8d94d7c7fe4a6530cc6fe6422e0edd9f285d237646b2392541c03005947d', 'zen': 'znmGXVrq1UcF3r59C8V75t6zqFkmqMzC4YY', 'ant': '0xd54c9c210d286e5bae0e5f59ca8817e9dc2378de', 'hmq': '0x0c3a58dc40e933b2031d0cbfe08cf0738f55a17d', 'tkn': '0x5a020b51b748b21274078e42b10a7eb3988e89e1', 'apx': '0x2c4588d7d92700966fc6101af9b1af4181ab5358', 'lun': '0x12c38554537d9677aef623cf7bd9b9460d51045b', 'gup': '0xf4b6b5fce73e455e93f80190b7f7e5999864a3de', 'gno': '0x8e2118d168713e639b624851958cc5fa46ebce2a', 'rlc': '0xab916ef71e19c56c98de93d0dba99469b1283db1' }