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()) Clock.schedule_once(lambda dt: self.add_currencies())
def add_exchanges(self): 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 '' mx = self.fx.exchange.name() if self.fx.is_enabled() else ''
ex = self.ids.exchanges ex = self.ids.exchanges
ex.values = exchanges ex.values = exchanges
@ -107,7 +107,7 @@ class FxDialog(Factory.Popup):
self.fx.set_exchange(text) self.fx.set_exchange(text)
def add_currencies(self): 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 '' my_ccy = self.fx.get_currency() if self.fx.is_enabled() else ''
self.ids.ccy.values = currencies self.ids.ccy.values = currencies
self.ids.ccy.text = my_ccy self.ids.ccy.text = my_ccy

7
gui/qt/main_window.py

@ -2578,7 +2578,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
ex_combo = QComboBox() ex_combo = QComboBox()
def update_currencies(): def update_currencies():
currencies = sorted(self.fx.exchanges_by_ccy.keys()) currencies = sorted(self.fx.get_currencies())
ccy_combo.clear() ccy_combo.clear()
ccy_combo.addItems([_('None')] + currencies) ccy_combo.addItems([_('None')] + currencies)
if self.fx.is_enabled(): if self.fx.is_enabled():
@ -2596,7 +2596,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
c = self.fx.get_currency() c = self.fx.get_currency()
exchanges = self.fx.get_exchanges_by_ccy(c, h) exchanges = self.fx.get_exchanges_by_ccy(c, h)
else: else:
exchanges = self.fx.exchanges.keys() exchanges = self.fx.get_exchanges_by_ccy('USD', False)
ex_combo.clear() ex_combo.clear()
ex_combo.addItems(sorted(exchanges)) ex_combo.addItems(sorted(exchanges))
ex_combo.setCurrentIndex(ex_combo.findText(self.fx.config_exchange())) ex_combo.setCurrentIndex(ex_combo.findText(self.fx.config_exchange()))
@ -2613,11 +2613,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def on_exchange(idx): def on_exchange(idx):
exchange = str(ex_combo.currentText()) 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) self.fx.set_exchange(exchange)
def on_history(checked): def on_history(checked):
self.fx.set_history_config(checked) self.fx.set_history_config(checked)
update_exchanges()
self.history_list.refresh_headers() self.history_list.refresh_headers()
if self.fx.is_enabled() and checked: if self.fx.is_enabled() and checked:
# reset timeout to get historical rates # 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_quotes = on_quotes
self.on_history = on_history self.on_history = on_history
def protocol(self):
return "https"
def get_json(self, site, get_string): def get_json(self, site, get_string):
url = "".join([self.protocol(), '://', site, get_string]) # APIs must have https
response = requests.request('GET', url, url = ''.join(['https://', site, get_string])
headers={'User-Agent' : 'Electrum'}) response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'})
return response.json() return response.json()
def get_csv(self, site, get_string): def get_csv(self, site, get_string):
url = "".join([self.protocol(), '://', site, get_string]) url = ''.join(['https://', site, get_string])
response = requests.request('GET', url, response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'})
headers={'User-Agent' : 'Electrum'})
reader = csv.DictReader(response.content.split('\n')) reader = csv.DictReader(response.content.split('\n'))
return list(reader) return list(reader)
@ -86,6 +82,10 @@ class ExchangeBase(PrintError):
def historical_rate(self, ccy, d_t): def historical_rate(self, ccy, d_t):
return self.history.get(ccy, {}).get(d_t.strftime('%Y-%m-%d')) 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): class BitcoinAverage(ExchangeBase):
def get_rates(self, ccy): def get_rates(self, ccy):
@ -105,15 +105,13 @@ class BitcoinAverage(ExchangeBase):
for h in history]) for h in history])
class BitcoinVenezuela(ExchangeBase): class BitcoinVenezuela(ExchangeBase):
def get_rates(self, ccy): def get_rates(self, ccy):
json = self.get_json('api.bitcoinvenezuela.com', '/') json = self.get_json('api.bitcoinvenezuela.com', '/')
rates = [(r, json['BTC'][r]) for r in json['BTC'] rates = [(r, json['BTC'][r]) for r in json['BTC']
if json['BTC'][r] is not None] # Giving NULL for LTC if json['BTC'][r] is not None] # Giving NULL for LTC
return dict(rates) return dict(rates)
def protocol(self):
return "http"
def history_ccys(self): def history_ccys(self):
return ['ARS', 'EUR', 'USD', 'VEF'] return ['ARS', 'EUR', 'USD', 'VEF']
@ -122,26 +120,17 @@ class BitcoinVenezuela(ExchangeBase):
"/historical/index.php?coin=BTC")[ccy +'_BTC'] "/historical/index.php?coin=BTC")[ccy +'_BTC']
class BTCParalelo(ExchangeBase): class BTCParalelo(ExchangeBase):
def get_rates(self, ccy): def get_rates(self, ccy):
json = self.get_json('btcparalelo.com', '/api/price') json = self.get_json('btcparalelo.com', '/api/price')
return {'VEF': Decimal(json['price'])} return {'VEF': Decimal(json['price'])}
def protocol(self):
return "http"
class Bitso(ExchangeBase): class Bitso(ExchangeBase):
def get_rates(self, ccy): def get_rates(self, ccy):
json = self.get_json('api.bitso.com', '/v2/ticker') json = self.get_json('api.bitso.com', '/v2/ticker')
return {'MXN': Decimal(json['last'])} 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): class Bitmarket(ExchangeBase):
def get_rates(self, ccy): def get_rates(self, ccy):
@ -254,17 +243,13 @@ class Winkdex(ExchangeBase):
for h in history]) for h in history])
class MercadoBitcoin(ExchangeBase): class MercadoBitcoin(ExchangeBase):
def get_rates(self,ccy): 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']['MBT']['last'])} return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])}
def history_ccys(self):
return ['BRL']
class Bitcointoyou(ExchangeBase): class Bitcointoyou(ExchangeBase):
def get_rates(self,ccy): def get_rates(self, ccy):
json = self.get_json('bitcointoyou.com', json = self.get_json('bitcointoyou.com', "/API/ticker.aspx")
"/API/ticker.aspx")
return {'BRL': Decimal(json['ticker']['last'])} return {'BRL': Decimal(json['ticker']['last'])}
def history_ccys(self): def history_ccys(self):
@ -272,24 +257,18 @@ class Bitcointoyou(ExchangeBase):
class Bitvalor(ExchangeBase): class Bitvalor(ExchangeBase):
def get_rates(self,ccy): 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'])} return {'BRL': Decimal(json['ticker_1h']['total']['last'])}
def history_ccys(self):
return ['BRL']
class Foxbit(ExchangeBase): class Foxbit(ExchangeBase):
def get_rates(self,ccy): 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'])} return {'BRL': Decimal(json['ticker_1h']['exchanges']['FOX']['last'])}
def history_ccys(self):
return ['BRL']
class NegocieCoins(ExchangeBase): class NegocieCoins(ExchangeBase):
def get_rates(self,ccy): 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'])} return {'BRL': Decimal(json['ticker_1h']['exchanges']['NEG']['last'])}
def history_ccys(self): def history_ccys(self):
@ -304,17 +283,39 @@ def dictinvert(d):
keys.append(k) keys.append(k)
return inv 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) is_exchange = lambda obj: (inspect.isclass(obj)
and issubclass(obj, ExchangeBase) and issubclass(obj, ExchangeBase)
and 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(): def get_exchanges_by_ccy(history=True):
"return only the exchanges that have history rates (which is hardcoded)" if not history:
return dictinvert(CURRENCIES)
d = {} d = {}
exchanges = get_exchanges() exchanges = CURRENCIES.keys()
for name, klass in exchanges.items(): for name in exchanges:
klass = globals()[name]
exchange = klass(None, None) exchange = klass(None, None)
d[name] = exchange.history_ccys() d[name] = exchange.history_ccys()
return dictinvert(d) return dictinvert(d)
@ -330,12 +331,15 @@ class FxThread(ThreadJob):
self.history_used_spot = False self.history_used_spot = False
self.ccy_combo = None self.ccy_combo = None
self.hist_checkbox = None self.hist_checkbox = None
self.exchanges = get_exchanges()
self.exchanges_by_ccy = get_exchanges_by_ccy()
self.set_exchange(self.config_exchange()) 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): 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): def ccy_amount_str(self, amount, commas):
prec = CCY_PRECISIONS.get(self.ccy, 2) prec = CCY_PRECISIONS.get(self.ccy, 2)
@ -380,12 +384,10 @@ class FxThread(ThreadJob):
self.on_quotes() self.on_quotes()
def set_exchange(self, name): def set_exchange(self, name):
class_ = self.exchanges.get(name) or self.exchanges.values()[0] class_ = globals()[name]
name = class_.__name__
self.print_error("using exchange", name) self.print_error("using exchange", name)
if self.config_exchange() != name: if self.config_exchange() != name:
self.config.set_key('use_exchange', name, True) self.config.set_key('use_exchange', name, True)
self.exchange = class_(self.on_quotes, self.on_history) self.exchange = class_(self.on_quotes, self.on_history)
# A new exchange means new fx quotes, initially empty. Force # A new exchange means new fx quotes, initially empty. Force
# a quote refresh # a quote refresh

Loading…
Cancel
Save