class Market(object): def __init__(self, currency): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.update_rate = 60 self.fc = FiatConverter() self.fc.update() def get_depth(self): timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: logging.warn("Market: %s order book is expired" % self.name) self.depth = {"asks": [{"price": 0, "amount": 0}], "bids": [{"price": 0, "amount": 0}]} return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: order["price"] = self.fc.convert(order["price"], self.currency, "USD") def ask_update_depth(self): try: self.update_depth() self.convert_to_usd() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) def get_ticker(self): depth = self.get_depth() res = {"ask": 0, "bid": 0} if len(depth["asks"]) > 0 and len(depth["bids"]) > 0: res = {"ask": depth["asks"][0], "bid": depth["bids"][0]} return res ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass
class Market(object): def __init__(self, currency): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.update_rate = 60 self.fc = FiatConverter() self.fc.update() def get_depth(self): timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: logging.warn("Market: %s order book is expired" % self.name) self.depth = { "asks": [{ "price": 0, "amount": 0 }], "bids": [{ "price": 0, "amount": 0 }] } return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: order["price"] = self.fc.convert(order["price"], self.currency, "USD") def ask_update_depth(self): try: self.update_depth() self.convert_to_usd() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) def get_ticker(self): depth = self.get_depth() res = {"ask": 0, "bid": 0} if len(depth["asks"]) > 0 and len(depth["bids"]) > 0: res = {"ask": depth["asks"][0], "bid": depth["bids"][0]} return res ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass
class Market(object): def __init__(self, currency): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.update_rate = 60 self.fc = FiatConverter() self.fc.update() def get_depth(self): timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: logging.warn('Market: %s order book is expired' % self.name) self.depth = { 'asks': [{ 'price': 0, 'amount': 0 }], 'bids': [{ 'price': 0, 'amount': 0 }] } return self.depth def ask_update_depth(self): try: self.update_depth() self.invert() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) def get_ticker(self): depth = self.get_depth() res = {'ask': 0, 'bid': 0} if len(depth['asks']) > 0 and len(depth["bids"]) > 0: res = {'ask': depth['asks'][0], 'bid': depth['bids'][0]} return res def invert(self): if not self.should_invert(): return for ask in self.depth['asks']: ask['amount'] = ask['amount'] * ask['price'] ask['price'] = 1.0 / ask['price'] for bid in self.depth['bids']: bid['amount'] = bid['amount'] * bid['price'] bid['price'] = 1.0 / bid['price'] bids = self.depth['asks'] asks = self.depth['bids'] self.depth['asks'] = asks self.depth['bids'] = bids ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass def should_invert(self): return False
class Market(object): def __init__(self, currency): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.update_rate = 0.5 self.isWebsocket = False self.shouldReportWebsocketTimeout = False if currency == "BTC": self.fiat = False else: self.fiat = True self.fc = FiatConverter() self.fc.update() def get_depth(self): timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: _str = 'Market: %s order book is expired' % self.name logging.warn(_str) send_message(_str) self.depth = { 'asks': [{ 'price': 0, 'amount': 0 }], 'bids': [{ 'price': 0, 'amount': 0 }] } raise Exception('get depth timeout.') return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: order["price"] = self.fc.convert(order["price"], self.currency, "USD") def ask_update_depth(self): try: self.update_depth() if self.fiat: self.convert_to_usd() self.depth_updated = time.time() self.shouldReportWebsocketTimeout = True except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: if not self.isWebsocket: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) else: #don't repeat report if self.shouldReportWebsocketTimeout: logging.error(str(e)) self.shouldReportWebsocketTimeout = False def get_ticker(self): depth = self.get_depth() res = {'ask': 0, 'bid': 0} if len(depth['asks']) > 0 and len(depth["bids"]) > 0: res = {'ask': depth['asks'][0], 'bid': depth['bids'][0]} return res ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass
class Market(object): def __init__(self, currency): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.update_rate = 60 self.fc = FiatConverter() self.fc.update() def get_depth(self): """ @todo Use websocket and reduce the update_rate to realtime, only fall back to RESTful when wss is broken. """ timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: # depth data not updated properly. why? FIXME logging.warn("Market: %s order book is expired" % self.name) self.depth = { "asks": [{ "price": 0, "amount": 0 }], "bids": [{ "price": 0, "amount": 0 }] } return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: order["price"] = self.fc.convert(order["price"], self.currency, "USD") def ask_update_depth(self): try: self.update_depth() self.convert_to_usd() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) def get_ticker(self): depth = self.get_depth() res = {"ask": 0, "bid": 0} if len(depth["asks"]) > 0 and len(depth["bids"]) > 0: res = {"ask": depth["asks"][0], "bid": depth["bids"][0]} return res ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass def _depth_pct(self, pct): bid1 = float(self.depth['bids'][0]['price']) ask1 = float(self.depth['asks'][0]['price']) fair = bid1 * 0.5 + ask1 * 0.5 ceiling, floor = fair * (1 + pct / 100), fair * (1 - pct / 100) bid_sum = 0 for bid in self.depth['bids']: if float(bid['price']) > floor: bid_sum += float(bid['amount']) else: break ask_sum = 0 for ask in self.depth['asks']: if float(ask['price']) < ceiling: ask_sum += float(ask['amount']) else: break def _f(v): return int(v * 100) / 100 return 'pct depth [bid, ask]: [ %s, %s ]' % (_f(bid_sum), _f(ask_sum)) def depth_1pct(self): return self._depth_pct(1) def depth_01pct(self): return self._depth_pct(0.1)
class Market(object): def __init__(self, currency, cryptowatch_code=None): self.name = self.__class__.__name__ self.currency = currency self.cryptowatch_code = cryptowatch_code self.cryptowatch_price = 0 self.depth_updated = 0 self.update_rate = 60 self.fc = FiatConverter() self.fc.update() def get_cryptowatch_price(self): if not self.cryptowatch_code: return url = ('https://api.cryptowat.ch/markets/' + self.name.lower().replace('usd', '').replace('eur', '') + '/' + self.cryptowatch_code + '/price') res = urllib.request.urlopen(url) jsonstr = res.read().decode('utf8') try: price = json.loads(jsonstr) except Exception: logging.error("Cryptowatch %s - Can't parse json: %s" % (self.name, jsonstr)) self.cryptowatch_price = self.fc.convert(price["result"]["price"], self.currency, "USD") def double_ckeck_price(self, price, direction, allowed_percent=None): if self.cryptowatch_price == 0: self.get_cryptowatch_price() allowed_percent = allowed_percent if allowed_percent else 10 if abs(price - self.cryptowatch_price ) > self.cryptowatch_price * allowed_percent / 100: logging.error( "Big diff. @%s depth price(%s) vs Cryptowatch price %f / %f" % (self.name, direction, price, self.cryptowatch_price)) return False return True def get_depth(self): timediff = time.time() - self.depth_updated if timediff > self.update_rate: self.ask_update_depth() timediff = time.time() - self.depth_updated if timediff > config.market_expiration_time: logging.warning('Market: %s order book is expired' % self.name) self.depth = { 'asks': [{ 'price': 0, 'amount': 0 }], 'bids': [{ 'price': 0, 'amount': 0 }] } return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: # self.double_ckeck_price(order["price"], direction, order) # we don't do it here any more order["price"] = self.fc.convert(order["price"], self.currency, "USD") # there are some prices inside the market depth that are ment to de destabilize the market # clear them out def sort_out_market_crush_prices(self): new_depth = {'asks': [], 'bids': []} for direction in ("asks", "bids"): for order in self.depth[direction]: if self.double_ckeck_price(order["price"], direction, 30): new_depth[direction].append(order) if len(new_depth["ask"]) != len(self.depth["ask"]) or len( new_depth["bids"]) != len(self.depth["bids"]): logging.warning( 'Market: %s removed some market crush crush items' % self.name) self.depth = new_depth def ask_update_depth(self): try: self.update_depth() self.convert_to_usd() self.get_cryptowatch_price() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: logging.error("HTTPError, can't update market: %s" % self.name) log_exception(logging.DEBUG) except Exception as e: logging.error("Can't update market: %s - %s" % (self.name, str(e))) log_exception(logging.DEBUG) def get_ticker(self): depth = self.get_depth() res = {'ask': 0, 'bid': 0} if len(depth['asks']) > 0 and len(depth["bids"]) > 0: res = {'ask': depth['asks'][0], 'bid': depth['bids'][0]} return res ## Abstract methods def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass
class MarketBase(object, metaclass=Plugin): """""" def __init__(self, currency, config): self.name = self.__class__.__name__ self.currency = currency self.depth_updated = 0 self.config = config or Configuration() self.update_rate = self.config.default_market_update_rate self.depth = None self.fc = FiatConverter(config) self.fc.update() def set_config(self, config): self.config = config def get_depth(self): time_diff = time.time() - self.depth_updated if time_diff > self.update_rate: self.ask_update_depth() time_diff = time.time() - self.depth_updated if time_diff > self.config.market_expiration_time: LOG.warning('Market: %s order book is expired' % self.name) self.depth = { 'asks': [{ 'price': 0, 'amount': 0 }], 'bids': [{ 'price': 0, 'amount': 0 }] } return self.depth def convert_to_usd(self): if self.currency == "USD": return for direction in ("asks", "bids"): for order in self.depth[direction]: order["price"] = self.fc.convert(order["price"], self.currency, "USD") def ask_update_depth(self): try: self.update_depth() self.convert_to_usd() self.depth_updated = time.time() except (urllib.error.HTTPError, urllib.error.URLError) as e: LOG.exception("HTTPError, can't update market: %s" % self.name) except Exception as e: LOG.exception("Can't update market: %s - %s" % (self.name, str(e))) def get_ticker(self): depth = self.get_depth() res = {'ask': 0, 'bid': 0} if len(depth['asks']) > 0 and len(depth["bids"]) > 0: res = {'ask': depth['asks'][0], 'bid': depth['bids'][0]} return res def update_depth(self): pass def buy(self, price, amount): pass def sell(self, price, amount): pass