Browse Source

exchange rates: enforce https APIs. store exchanges list in json file.

283
ThomasV 8 years ago
parent
commit
13b16e9d4f
  1. 4
      gui/kivy/uix/dialogs/fx_dialog.py
  2. 7
      gui/qt/main_window.py
  3. 104
      lib/exchange_rate.py

4
gui/kivy/uix/dialogs/fx_dialog.py

@ -94,7 +94,7 @@ class FxDialog(Factory.Popup):
Clock.schedule_once(lambda dt: self.add_currencies())
def add_exchanges(self):
exchanges = sorted(self.fx.exchanges_by_ccy.get(self.fx.get_currency())) if self.fx.is_enabled() else []
exchanges = sorted(self.fx.get_exchanges_by_ccy(self.fx.get_currency(), True)) if self.fx.is_enabled() else []
mx = self.fx.exchange.name() if self.fx.is_enabled() else ''
ex = self.ids.exchanges
ex.values = exchanges
@ -107,7 +107,7 @@ class FxDialog(Factory.Popup):
self.fx.set_exchange(text)
def add_currencies(self):
currencies = sorted(self.fx.exchanges_by_ccy.keys()) if self.fx else []
currencies = sorted(self.fx.get_currencies()) if self.fx else []
my_ccy = self.fx.get_currency() if self.fx.is_enabled() else ''
self.ids.ccy.values = currencies
self.ids.ccy.text = my_ccy

7
gui/qt/main_window.py

@ -2578,7 +2578,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
ex_combo = QComboBox()
def update_currencies():
currencies = sorted(self.fx.exchanges_by_ccy.keys())
currencies = sorted(self.fx.get_currencies())
ccy_combo.clear()
ccy_combo.addItems([_('None')] + currencies)
if self.fx.is_enabled():
@ -2596,7 +2596,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
c = self.fx.get_currency()
exchanges = self.fx.get_exchanges_by_ccy(c, h)
else:
exchanges = self.fx.exchanges.keys()
exchanges = self.fx.get_exchanges_by_ccy('USD', False)
ex_combo.clear()
ex_combo.addItems(sorted(exchanges))
ex_combo.setCurrentIndex(ex_combo.findText(self.fx.config_exchange()))
@ -2613,11 +2613,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def on_exchange(idx):
exchange = str(ex_combo.currentText())
if self.fx.is_enabled() and exchange != self.fx.exchange.name():
if self.fx.is_enabled() and exchange and exchange != self.fx.exchange.name():
self.fx.set_exchange(exchange)
def on_history(checked):
self.fx.set_history_config(checked)
update_exchanges()
self.history_list.refresh_headers()
if self.fx.is_enabled() and checked:
# reset timeout to get historical rates

104
lib/exchange_rate.py

@ -30,19 +30,15 @@ class ExchangeBase(PrintError):
self.on_quotes = on_quotes
self.on_history = on_history
def protocol(self):
return "https"
def get_json(self, site, get_string):
url = "".join([self.protocol(), '://', site, get_string])
response = requests.request('GET', url,
headers={'User-Agent' : 'Electrum'})
# APIs must have https
url = ''.join(['https://', site, get_string])
response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'})
return response.json()
def get_csv(self, site, get_string):
url = "".join([self.protocol(), '://', site, get_string])
response = requests.request('GET', url,
headers={'User-Agent' : 'Electrum'})
url = ''.join(['https://', site, get_string])
response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'})
reader = csv.DictReader(response.content.split('\n'))
return list(reader)
@ -86,6 +82,10 @@ class ExchangeBase(PrintError):
def historical_rate(self, ccy, d_t):
return self.history.get(ccy, {}).get(d_t.strftime('%Y-%m-%d'))
def get_currencies(self):
rates = self.get_rates('')
return [str(a) for (a, b) in rates.iteritems() if b is not None]
class BitcoinAverage(ExchangeBase):
def get_rates(self, ccy):
@ -105,15 +105,13 @@ class BitcoinAverage(ExchangeBase):
for h in history])
class BitcoinVenezuela(ExchangeBase):
def get_rates(self, ccy):
json = self.get_json('api.bitcoinvenezuela.com', '/')
rates = [(r, json['BTC'][r]) for r in json['BTC']
if json['BTC'][r] is not None] # Giving NULL for LTC
return dict(rates)
def protocol(self):
return "http"
def history_ccys(self):
return ['ARS', 'EUR', 'USD', 'VEF']
@ -122,26 +120,17 @@ class BitcoinVenezuela(ExchangeBase):
"/historical/index.php?coin=BTC")[ccy +'_BTC']
class BTCParalelo(ExchangeBase):
def get_rates(self, ccy):
json = self.get_json('btcparalelo.com', '/api/price')
return {'VEF': Decimal(json['price'])}
def protocol(self):
return "http"
class Bitso(ExchangeBase):
def get_rates(self, ccy):
json = self.get_json('api.bitso.com', '/v2/ticker')
return {'MXN': Decimal(json['last'])}
def protocol(self):
return "http"
class Bitcurex(ExchangeBase):
def get_rates(self, ccy):
json = self.get_json('pln.bitcurex.com', '/data/ticker.json')
pln_price = json['last']
return {'PLN': Decimal(pln_price)}
class Bitmarket(ExchangeBase):
def get_rates(self, ccy):
@ -254,17 +243,13 @@ class Winkdex(ExchangeBase):
for h in history])
class MercadoBitcoin(ExchangeBase):
def get_rates(self,ccy):
json = requests.get('http://api.bitvalor.com/v1/ticker.json').json()
def get_rates(self, ccy):
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])}
def history_ccys(self):
return ['BRL']
class Bitcointoyou(ExchangeBase):
def get_rates(self,ccy):
json = self.get_json('bitcointoyou.com',
"/API/ticker.aspx")
def get_rates(self, ccy):
json = self.get_json('bitcointoyou.com', "/API/ticker.aspx")
return {'BRL': Decimal(json['ticker']['last'])}
def history_ccys(self):
@ -272,24 +257,18 @@ class Bitcointoyou(ExchangeBase):
class Bitvalor(ExchangeBase):
def get_rates(self,ccy):
json = requests.get('http://api.bitvalor.com/v1/ticker.json').json()
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['total']['last'])}
def history_ccys(self):
return ['BRL']
class Foxbit(ExchangeBase):
def get_rates(self,ccy):
json = requests.get('http://api.bitvalor.com/v1/ticker.json').json()
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['exchanges']['FOX']['last'])}
def history_ccys(self):
return ['BRL']
class NegocieCoins(ExchangeBase):
def get_rates(self,ccy):
json = requests.get('http://api.bitvalor.com/v1/ticker.json').json()
json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['exchanges']['NEG']['last'])}
def history_ccys(self):
@ -304,17 +283,39 @@ def dictinvert(d):
keys.append(k)
return inv
def get_exchanges():
def get_exchanges_and_currencies():
import os, json
path = os.path.join(os.path.dirname(__file__), 'currencies.json')
try:
return json.loads(open(path, 'r').read())
except:
pass
d = {}
is_exchange = lambda obj: (inspect.isclass(obj)
and issubclass(obj, ExchangeBase)
and obj != ExchangeBase)
return dict(inspect.getmembers(sys.modules[__name__], is_exchange))
exchanges = dict(inspect.getmembers(sys.modules[__name__], is_exchange))
for name, klass in exchanges.items():
exchange = klass(None, None)
try:
d[name] = exchange.get_currencies()
except:
continue
with open(path, 'w') as f:
f.write(json.dumps(d, indent=4, sort_keys=True))
return d
CURRENCIES = get_exchanges_and_currencies()
def get_exchanges_by_ccy():
"return only the exchanges that have history rates (which is hardcoded)"
def get_exchanges_by_ccy(history=True):
if not history:
return dictinvert(CURRENCIES)
d = {}
exchanges = get_exchanges()
for name, klass in exchanges.items():
exchanges = CURRENCIES.keys()
for name in exchanges:
klass = globals()[name]
exchange = klass(None, None)
d[name] = exchange.history_ccys()
return dictinvert(d)
@ -330,12 +331,15 @@ class FxThread(ThreadJob):
self.history_used_spot = False
self.ccy_combo = None
self.hist_checkbox = None
self.exchanges = get_exchanges()
self.exchanges_by_ccy = get_exchanges_by_ccy()
self.set_exchange(self.config_exchange())
def get_currencies(self):
d = get_exchanges_by_ccy(False)
return sorted(d.keys())
def get_exchanges_by_ccy(self, ccy, h):
return self.exchanges_by_ccy.get(ccy, [])
d = get_exchanges_by_ccy(h)
return d.get(ccy, [])
def ccy_amount_str(self, amount, commas):
prec = CCY_PRECISIONS.get(self.ccy, 2)
@ -380,12 +384,10 @@ class FxThread(ThreadJob):
self.on_quotes()
def set_exchange(self, name):
class_ = self.exchanges.get(name) or self.exchanges.values()[0]
name = class_.__name__
class_ = globals()[name]
self.print_error("using exchange", name)
if self.config_exchange() != name:
self.config.set_key('use_exchange', name, True)
self.exchange = class_(self.on_quotes, self.on_history)
# A new exchange means new fx quotes, initially empty. Force
# a quote refresh

Loading…
Cancel
Save