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:
parent
c93bfe16b6
commit
c0cdfae1f8
@ -1,10 +1,27 @@
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
import json
|
import json
|
||||||
import time
|
from datetime import datetime
|
||||||
|
|
||||||
from i3pystatus import IntervalModule
|
from i3pystatus import IntervalModule
|
||||||
from i3pystatus.core.util import internet, require, user_open
|
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):
|
class Bitcoin(IntervalModule):
|
||||||
|
|
||||||
@ -12,8 +29,10 @@ class Bitcoin(IntervalModule):
|
|||||||
This module fetches and displays current Bitcoin market prices and
|
This module fetches and displays current Bitcoin market prices and
|
||||||
optionally monitors transactions to and from a list of user-specified
|
optionally monitors transactions to and from a list of user-specified
|
||||||
wallet addresses. Market data is pulled from the BitcoinAverage Price
|
wallet addresses. Market data is pulled from the BitcoinAverage Price
|
||||||
Index API <https://bitcoinaverage.com> while transaction data is pulled
|
Index API <https://bitcoinaverage.com> and it is possible to specify
|
||||||
from blockchain.info <https://blockchain.info/api/blockchain_api>.
|
the exchange to be monitored.
|
||||||
|
Transaction data is pulled from blockchain.info
|
||||||
|
<https://blockchain.info/api/blockchain_api>.
|
||||||
|
|
||||||
.. rubric:: Available formatters
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
@ -22,6 +41,9 @@ class Bitcoin(IntervalModule):
|
|||||||
* {bid_price}
|
* {bid_price}
|
||||||
* {daily_average}
|
* {daily_average}
|
||||||
* {volume}
|
* {volume}
|
||||||
|
* {volume_thousend}
|
||||||
|
* {volume_percent}
|
||||||
|
* {age}
|
||||||
* {status}
|
* {status}
|
||||||
* {last_tx_type}
|
* {last_tx_type}
|
||||||
* {last_tx_addr}
|
* {last_tx_addr}
|
||||||
@ -37,6 +59,7 @@ class Bitcoin(IntervalModule):
|
|||||||
("currency", "Base fiat currency used for pricing."),
|
("currency", "Base fiat currency used for pricing."),
|
||||||
("wallet_addresses", "List of wallet address(es) to monitor."),
|
("wallet_addresses", "List of wallet address(es) to monitor."),
|
||||||
("color", "Standard color"),
|
("color", "Standard color"),
|
||||||
|
("exchange", "Get ticker from a custom exchange instead"),
|
||||||
("colorize", "Enable color change on price increase/decrease"),
|
("colorize", "Enable color change on price increase/decrease"),
|
||||||
("color_up", "Color for price increases"),
|
("color_up", "Color for price increases"),
|
||||||
("color_down", "Color for price decreases"),
|
("color_down", "Color for price decreases"),
|
||||||
@ -46,6 +69,7 @@ class Bitcoin(IntervalModule):
|
|||||||
)
|
)
|
||||||
format = "{symbol} {status}{last_price}"
|
format = "{symbol} {status}{last_price}"
|
||||||
currency = "USD"
|
currency = "USD"
|
||||||
|
exchange = None
|
||||||
symbol = "฿"
|
symbol = "฿"
|
||||||
wallet_addresses = ""
|
wallet_addresses = ""
|
||||||
color = "#FFFFFF"
|
color = "#FFFFFF"
|
||||||
@ -59,14 +83,39 @@ class Bitcoin(IntervalModule):
|
|||||||
}
|
}
|
||||||
|
|
||||||
on_leftclick = "electrum"
|
on_leftclick = "electrum"
|
||||||
on_rightclick = [user_open, "https://bitcoinaverage.com/"]
|
on_rightclick = ["open_something", "https://bitcoinaverage.com/"]
|
||||||
|
|
||||||
_price_prev = 0
|
_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):
|
def _fetch_price_data(self):
|
||||||
api = "https://api.bitcoinaverage.com/ticker/global/"
|
if self.exchange is None:
|
||||||
url = "{}{}".format(api, self.currency.upper())
|
api_url = "https://api.bitcoinaverage.com/ticker/global/"
|
||||||
return json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
|
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):
|
def _fetch_blockchain_data(self):
|
||||||
api = "https://blockchain.info/multiaddr?active="
|
api = "https://blockchain.info/multiaddr?active="
|
||||||
@ -77,6 +126,7 @@ class Bitcoin(IntervalModule):
|
|||||||
@require(internet)
|
@require(internet)
|
||||||
def run(self):
|
def run(self):
|
||||||
price_data = self._fetch_price_data()
|
price_data = self._fetch_price_data()
|
||||||
|
|
||||||
fdict = {
|
fdict = {
|
||||||
"symbol": self.symbol,
|
"symbol": self.symbol,
|
||||||
"daily_average": price_data["24h_avg"],
|
"daily_average": price_data["24h_avg"],
|
||||||
@ -84,6 +134,9 @@ class Bitcoin(IntervalModule):
|
|||||||
"bid_price": price_data["bid"],
|
"bid_price": price_data["bid"],
|
||||||
"last_price": price_data["last"],
|
"last_price": price_data["last"],
|
||||||
"volume": price_data["volume_btc"],
|
"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:
|
if self._price_prev and fdict["last_price"] > self._price_prev:
|
||||||
@ -125,3 +178,9 @@ class Bitcoin(IntervalModule):
|
|||||||
"full_text": self.format.format(**fdict),
|
"full_text": self.format.format(**fdict),
|
||||||
"color": color,
|
"color": color,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def open_something(self, url_or_command):
|
||||||
|
"""
|
||||||
|
Wrapper function, to pass the arguments to user_open
|
||||||
|
"""
|
||||||
|
user_open(url_or_command)
|
||||||
|
Loading…
Reference in New Issue
Block a user