mod bitcoin: multiple exchange support (#353)

* mod bitcoin: add 'volume_percent'

* mod bitcoin: Fix exception on url opening (#304)

Calling user_open as a 'Python callback' raises an exception because
this function doesn't expects 'self'.
Wrote a wrapper function as a 'Member callback' to filter it out.

* mod bitcoin: add specific exchange support

* mod bitcoin: add request age attribute

* mod bitcoin: refactor

* mod bitcoin: btc volume divisor

* bitcoin: Deal with diffrent locales

* Fixing PEP8

* mod bitcoin: Updated docs
This commit is contained in:
Maximiliano 2016-04-07 23:20:37 +02:00 committed by enkore
parent c93bfe16b6
commit c0cdfae1f8

View File

@ -1,10 +1,27 @@
import urllib.request
import json
import time
from datetime import datetime
from i3pystatus import IntervalModule
from i3pystatus.core.util import internet, require, user_open
import locale
import threading
from contextlib import contextmanager
LOCALE_LOCK = threading.Lock()
@contextmanager
def setlocale(name):
# To deal with locales only in this module and keep it thread save
with LOCALE_LOCK:
saved = locale.setlocale(locale.LC_ALL)
try:
yield locale.setlocale(locale.LC_ALL, name)
finally:
locale.setlocale(locale.LC_ALL, saved)
class Bitcoin(IntervalModule):
@ -12,8 +29,10 @@ class Bitcoin(IntervalModule):
This module fetches and displays current Bitcoin market prices and
optionally monitors transactions to and from a list of user-specified
wallet addresses. Market data is pulled from the BitcoinAverage Price
Index API <https://bitcoinaverage.com> while transaction data is pulled
from blockchain.info <https://blockchain.info/api/blockchain_api>.
Index API <https://bitcoinaverage.com> and it is possible to specify
the exchange to be monitored.
Transaction data is pulled from blockchain.info
<https://blockchain.info/api/blockchain_api>.
.. rubric:: Available formatters
@ -22,6 +41,9 @@ class Bitcoin(IntervalModule):
* {bid_price}
* {daily_average}
* {volume}
* {volume_thousend}
* {volume_percent}
* {age}
* {status}
* {last_tx_type}
* {last_tx_addr}
@ -37,6 +59,7 @@ class Bitcoin(IntervalModule):
("currency", "Base fiat currency used for pricing."),
("wallet_addresses", "List of wallet address(es) to monitor."),
("color", "Standard color"),
("exchange", "Get ticker from a custom exchange instead"),
("colorize", "Enable color change on price increase/decrease"),
("color_up", "Color for price increases"),
("color_down", "Color for price decreases"),
@ -46,6 +69,7 @@ class Bitcoin(IntervalModule):
)
format = "{symbol} {status}{last_price}"
currency = "USD"
exchange = None
symbol = "฿"
wallet_addresses = ""
color = "#FFFFFF"
@ -59,14 +83,39 @@ class Bitcoin(IntervalModule):
}
on_leftclick = "electrum"
on_rightclick = [user_open, "https://bitcoinaverage.com/"]
on_rightclick = ["open_something", "https://bitcoinaverage.com/"]
_price_prev = 0
def _get_age(self, bitcoinaverage_timestamp):
with setlocale('C'): # Deal with locales (months name differ)
# Assume format is always utc, to avoid import pytz
utc_tstamp = datetime.strptime(
bitcoinaverage_timestamp.split(', ')[1],
u'%d %b %Y %H:%M:%S -0000')
diff = datetime.utcnow() - utc_tstamp
return int(diff.total_seconds())
def _query_api(self, api_url):
url = "{}{}".format(api_url, self.currency.upper())
response = urllib.request.urlopen(url).read().decode("utf-8")
return json.loads(response)
def _fetch_price_data(self):
api = "https://api.bitcoinaverage.com/ticker/global/"
url = "{}{}".format(api, self.currency.upper())
return json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
if self.exchange is None:
api_url = "https://api.bitcoinaverage.com/ticker/global/"
return self._query_api(api_url)
else:
api_url = "https://api.bitcoinaverage.com/exchanges/"
ret = self._query_api(api_url)
exchange = ret[self.exchange.lower()]
# Adapt values to global ticker format
exchange['ask'] = exchange['rates']['ask']
exchange['bid'] = exchange['rates']['bid']
exchange['last'] = exchange['rates']['last']
exchange['24h_avg'] = None
exchange['timestamp'] = ret['timestamp']
return exchange
def _fetch_blockchain_data(self):
api = "https://blockchain.info/multiaddr?active="
@ -77,6 +126,7 @@ class Bitcoin(IntervalModule):
@require(internet)
def run(self):
price_data = self._fetch_price_data()
fdict = {
"symbol": self.symbol,
"daily_average": price_data["24h_avg"],
@ -84,6 +134,9 @@ class Bitcoin(IntervalModule):
"bid_price": price_data["bid"],
"last_price": price_data["last"],
"volume": price_data["volume_btc"],
"volume_thousend": price_data["volume_btc"] / 1000,
"volume_percent": price_data["volume_percent"],
"age": self._get_age(price_data['timestamp'])
}
if self._price_prev and fdict["last_price"] > self._price_prev:
@ -125,3 +178,9 @@ class Bitcoin(IntervalModule):
"full_text": self.format.format(**fdict),
"color": color,
}
def open_something(self, url_or_command):
"""
Wrapper function, to pass the arguments to user_open
"""
user_open(url_or_command)