Ejemplo n.º 1
0
	def refresh_iexc_index():
		try:
			stockSymbols = get_symbols(token=os.environ["IEXC_KEY"])
			for index, stock in stockSymbols.iterrows():
				if stock["exchange"] not in TickerParserServer.exchanges:
					TickerParserServer.exchanges[stock["exchange"]] = Exchange(stock["exchange"])
				tickerId = stock["symbol"] if stock["iexId"] is None else stock["iexId"]
				TickerParserServer.iexcStocksIndex[stock["symbol"]] = {"id": tickerId, "name": stock["name"], "base": stock["symbol"], "quote": stock["currency"], "exchange": stock["exchange"]}
				TickerParserServer.exchanges[stock["exchange"]].properties.symbols.append(stock["symbol"])
			
			forexSymbols = requests.get("https://cloud.iexapis.com/stable/ref-data/fx/symbols?token={}".format(os.environ["IEXC_KEY"])).json()
			derivedCurrencies = set()
			for pair in forexSymbols["pairs"]:
				derivedCurrencies.add(pair["fromCurrency"])
				derivedCurrencies.add(pair["toCurrency"])
				TickerParserServer.iexcForexIndex[pair["symbol"]] = {"id": pair["symbol"], "name": pair["symbol"], "base": pair["fromCurrency"], "quote": pair["toCurrency"], "reversed": False}
				TickerParserServer.iexcForexIndex[pair["toCurrency"] + pair["fromCurrency"]] = {"id": pair["symbol"], "name": pair["toCurrency"] + pair["fromCurrency"], "base": pair["toCurrency"], "quote": pair["fromCurrency"], "reversed": True}
			for fromCurrency in derivedCurrencies:
				for toCurrency in derivedCurrencies:
					symbol = fromCurrency + toCurrency
					if fromCurrency != toCurrency and symbol not in TickerParserServer.iexcForexIndex:
						TickerParserServer.iexcForexIndex[symbol] = {"id": symbol, "name": symbol, "base": fromCurrency, "quote": toCurrency, "reversed": False}

			otcSymbols = requests.get("https://cloud.iexapis.com/stable/ref-data/otc/symbols?token={}".format(os.environ["IEXC_KEY"])).json()
			for stock in otcSymbols:
				if stock["exchange"] not in TickerParserServer.exchanges:
					TickerParserServer.exchanges[stock["exchange"]] = Exchange(stock["exchange"])
				tickerId = stock["symbol"] if stock["iexId"] is None else stock["iexId"]
				TickerParserServer.iexcOtcIndex[stock["symbol"]] = {"id": tickerId, "name": stock["name"], "base": stock["symbol"], "quote": stock["currency"], "exchange": stock["exchange"]}

		except Exception:
			print(traceback.format_exc())
Ejemplo n.º 2
0
    def request_ccxt_depth(self, request):
        ticker = request.get_ticker()
        exchange = request.get_exchange()

        imageStyle = request.get_image_style()
        forceMode = "force" in imageStyle and request.authorId == 361916376069439490
        uploadMode = "upload" in imageStyle and request.authorId == 361916376069439490

        try:
            if exchange is None: return None, None
            exchange = Exchange(exchange.id, "crypto")

            try:
                depthData = exchange.properties.fetch_order_book(ticker.symbol)
                bestBid = depthData["bids"][0]
                bestAsk = depthData["asks"][0]
                lastPrice = (bestBid[0] + bestAsk[0]) / 2
            except:
                return None, None

            imageData = self.generate_depth_image(depthData, bestBid, bestAsk,
                                                  lastPrice)
            if uploadMode:
                bucket.blob("uploads/{}.png".format(int(
                    time.time() * 1000))).upload_from_string(
                        base64.decodebytes(imageData))

            return imageData, None
        except Exception:
            print(traceback.format_exc())
            if os.environ["PRODUCTION_MODE"]:
                self.logging.report_exception(user=ticker.id)
            return None, None
Ejemplo n.º 3
0
    def _request_forex(cls, request, ticker):
        exchange = Exchange.from_dict(ticker.get("exchange"))

        try:
            if exchange is not None: return [{}, ""]
            rawData = get(
                "https://cloud.iexapis.com/stable/fx/latest?symbols={}&token={}"
                .format(ticker.get("id"), environ["IEXC_KEY"])).json()
            if rawData is None or type(rawData) is not list or len(
                    rawData) == 0:
                return [{}, ""]
        except:
            return [{}, ""]

        price = rawData[0]["rate"]
        if price is None: return [{}, ""]
        if ticker.get("isReversed"): price = 1 / price

        payload = {
            "quotePrice": "{:,.5f} {}".format(price, ticker.get("quote")),
            "title": ticker.get("name"),
            "thumbnailUrl": static_storage.icon,
            "messageColor": "deep purple",
            "sourceText": "Data provided by IEX Cloud",
            "platform": "IEXC",
            "raw": {
                "quotePrice": [price],
                "timestamp": time()
            }
        }
        return [payload, ""]
Ejemplo n.º 4
0
    def request_candles(cls, request):
        ticker = request.get("ticker")
        exchange = Exchange.from_dict(ticker.get("exchange"))

        if exchange is None: return [{}, ""]

        try:
            rawData = exchange.properties.fetch_ohlcv(ticker.get("symbol"),
                                                      timeframe="1m",
                                                      limit=3)
            if len(rawData
                   ) == 0 or rawData[-1][4] is None or rawData[0][1] is None:
                return [{}, ""]
        except:
            return [{}, ""]

        payload = {
            "candles": [],
            "title": ticker.get("name"),
            "sourceText": "Data from {}".format(exchange.name),
            "platform": "CCXT"
        }

        for e in rawData:
            timestamp = e[0] / 1000
            if ticker.get("isReversed"):
                payload["candles"].append(
                    [timestamp, 1 / e[1], 1 / e[2], 1 / e[3], 1 / e[4]])
            else:
                payload["candles"].append([timestamp, e[1], e[2], e[3], e[4]])

        return [payload, ""]
Ejemplo n.º 5
0
	def _request_depth(cls, request, ticker):
		exchange = Exchange.from_dict(ticker.get("exchange"))

		preferences = request.get("preferences")
		forceMode = {"id": "force", "value": "force"} in preferences
		uploadMode = {"id": "upload", "value": "upload"} in preferences

		if exchange is None: return [{}, ""]

		try:
			depthData = exchange.properties.fetch_order_book(ticker.get("symbol"))
			bestBid = depthData["bids"][0]
			bestAsk = depthData["asks"][0]
			lastPrice = (bestBid[0] + bestAsk[0]) / 2
		except:
			return [{}, ""]

		imageBuffer = BytesIO()
		chartImage = Image.new("RGBA", (1600, 1200))
		chartImage.paste(CCXT._generate_depth_image(depthData, bestBid, bestAsk, lastPrice))
		chartImage = Image.alpha_composite(chartImage, CCXT.chartOverlay["normal"])
		chartImage.save(imageBuffer, format="png")
		imageData = b64encode(imageBuffer.getvalue())
		imageBuffer.close()
		# if uploadMode:
		# 	bucket.blob("uploads/{}.png".format(int(time() * 1000))).upload_from_string(decodebytes(imageData))

		payload = {
			"data": imageData.decode(),
			"platform": "CCXT"
		}

		return [payload, ""]
Ejemplo n.º 6
0
	def request_ccxt_candles(self, request):
		ticker = request.get_ticker()
		exchange = request.get_exchange()

		try:
			if exchange is None: return None, None
			exchange = Exchange(exchange.id, "crypto")

			try:
				rawData = exchange.properties.fetch_ohlcv(ticker.symbol, timeframe="1m", limit=3)
				if len(rawData) == 0 or rawData[-1][4] is None or rawData[0][1] is None: return None, None
			except:
				return None, None

			payload = {
				"candles": [],
				"title": ticker.name,
				"baseTicker": "USD" if ticker.base in CandleProcessor.stableCoinTickers else ticker.base,
				"quoteTicker": "USD" if ticker.quote in CandleProcessor.stableCoinTickers else ticker.quote,
				"sourceText": "on {}".format(exchange.name),
				"platform": "CCXT"
			}

			for e in rawData:
				timestamp = e[0] / 1000
				if ticker.isReversed:
					payload["candles"].append([timestamp, 1 / e[1], 1 / e[2], 1 / e[3], 1 / e[4]])
				else:
					payload["candles"].append([timestamp, e[1], e[2], e[3], e[4]])

			return payload, None
		except Exception:
			print(traceback.format_exc())
			if os.environ["PRODUCTION_MODE"]: self.logging.report_exception(user=ticker.id)
			return None, None
Ejemplo n.º 7
0
	def refresh_ccxt_index(self):
		difference = set(ccxt.exchanges).symmetric_difference(supported.ccxtExchanges)
		newExchanges = []
		newSupportedExchanges = []
		unsupportedCryptoExchanges = []
		for e in difference:
			try:
				ex = getattr(ccxt, e)()
			except:
				unsupportedCryptoExchanges.append(e)
				continue
			if e not in supported.ccxtExchanges:
				if ex.has['fetchOHLCV'] != False and ex.has['fetchOrderBook'] != False and ex.timeframes is not None and len(ex.timeframes) != 0: newSupportedExchanges.append(e)
				else: newExchanges.append(e)
		if len(newSupportedExchanges) != 0: print("New supported CCXT exchanges: {}".format(newSupportedExchanges))
		if len(newExchanges) != 0: print("New partially unsupported CCXT exchanges: {}".format(newExchanges))
		if len(unsupportedCryptoExchanges) != 0: print("New deprecated CCXT exchanges: {}".format(unsupportedCryptoExchanges))

		completedTasks = set()
		sortedIndexReference = {}

		for platform in supported.cryptoExchanges:
			if platform not in sortedIndexReference: sortedIndexReference[platform] = {}
			for exchange in supported.cryptoExchanges[platform]:
				if exchange not in completedTasks:
					if exchange not in self.exchanges: self.exchanges[exchange] = Exchange(exchange, "crypto" if exchange in ccxt.exchanges else "traditional")
					try: self.exchanges[exchange].properties.load_markets()
					except: continue
					completedTasks.add(exchange)

				for symbol in self.exchanges[exchange].properties.symbols:
					if '.' not in symbol and (self.exchanges[exchange].properties.markets[symbol].get("active") is None or self.exchanges[exchange].properties.markets[symbol].get("active")):
						base = self.exchanges[exchange].properties.markets[symbol]["base"]
						quote = self.exchanges[exchange].properties.markets[symbol]["quote"]
						marketPair = symbol.split("/")

						if base != marketPair[0] or quote != marketPair[-1]:
							if marketPair[0] != marketPair[-1]: base, quote = marketPair[0], marketPair[-1]
							else: continue

						isIdentifiable = quote in self.coinGeckoIndex and self.coinGeckoIndex[quote]["market_cap_rank"] is not None

						if base not in sortedIndexReference[platform]:
							sortedIndexReference[platform][base] = {}
						if quote not in sortedIndexReference[platform][base]:
							if isIdentifiable:
								sortedIndexReference[platform][base][quote] = self.coinGeckoIndex[quote]["market_cap_rank"]
							else:
								sortedIndexReference[platform][base][quote] = MAXSIZE

		for platform in sortedIndexReference:
			self.ccxtIndex[platform] = {}
			for base in sortedIndexReference[platform]:
				if base not in self.ccxtIndex[platform]: self.ccxtIndex[platform][base] = []
				self.ccxtIndex[platform][base] = sorted(sortedIndexReference[platform][base].keys(), key=lambda quote: sortedIndexReference[platform][base][quote])
				try: self.ccxtIndex[platform][base].insert(0, self.ccxtIndex[platform][base].pop(self.ccxtIndex[platform][base].index("USDT")))
				except: pass
				try: self.ccxtIndex[platform][base].insert(0, self.ccxtIndex[platform][base].pop(self.ccxtIndex[platform][base].index("USD")))
				except: pass
Ejemplo n.º 8
0
	def request_ccxt_quote(self, request):
		ticker = request.get_ticker()
		exchange = request.get_exchange()

		try:
			if exchange is None: return None, None
			exchange = Exchange(exchange.id)

			tf, limitTimestamp, candleOffset = Utils.get_highest_supported_timeframe(exchange.properties, datetime.datetime.now().astimezone(pytz.utc))
			try:
				rawData = exchange.properties.fetch_ohlcv(ticker.symbol, timeframe=tf.lower(), since=limitTimestamp, limit=300)
				if len(rawData) == 0 or rawData[-1][4] is None or rawData[0][1] is None: return None, None
			except:
				print(traceback.format_exc())
				return None, None

			price = [rawData[-1][4], rawData[0][1]] if len(rawData) < candleOffset else [rawData[-1][4], rawData[-candleOffset][1]]
			if ticker.isReversed: price = [1 / price[0], 1 / price[1]]
			volume = None if price[0] is None else sum([candle[5] for candle in rawData if int(candle[0] / 1000) >= int(exchange.properties.milliseconds() / 1000) - 86400]) / (price[0] if exchange.id in ["bitmex", "binancefutures"] else 1)
			priceChange = 0 if tf == "1m" or price[1] == 0 else (price[0] / price[1]) * 100 - 100

			payload = {
				"quotePrice": "{:,.8f}".format(price[0]) if ticker.isReversed else Utils.format_price(exchange.properties, ticker.symbol, price[0]),
				"quoteVolume": volume,
				"quoteConvertedPrice": "≈ ${:,.6f}".format(price[0] * self.lastBitcoinQuote["quotePrice"][0]) if ticker.quote == "BTC" else None,
				"quoteConvertedVolume": "≈ ${:,.4f}".format(volume * self.lastBitcoinQuote["quotePrice"][0]) if ticker.quote == "BTC" else None,
				"title": ticker.name,
				"baseTicker": "USD" if ticker.base in QuoteProcessor.stableCoinTickers else ticker.base,
				"quoteTicker": "USD" if ticker.quote in QuoteProcessor.stableCoinTickers else ticker.quote,
				"change": priceChange,
				"thumbnailUrl": TickerParser.get_coingecko_image(ticker.base),
				"messageColor": "amber" if priceChange == 0 else ("green" if priceChange > 0 else "red"),
				"sourceText": "on {}".format(exchange.name),
				"platform": "CCXT",
				"raw": {
					"quotePrice": [price[0]] if tf == "1m" else price[:1],
					"quoteVolume": volume,
					"ticker": ticker,
					"exchange": exchange,
					"timestamp": time.time()
				}
			}
			return payload, None
		except Exception:
			print(traceback.format_exc())
			if os.environ["PRODUCTION_MODE"]: self.logging.report_exception()
			return None, None
Ejemplo n.º 9
0
    def _request_depth(cls, request, ticker):
        exchange = Exchange.from_dict(ticker.get("exchange"))

        preferences = request.get("preferences")
        forceMode = {"id": "force", "value": "force"} in preferences
        uploadMode = {"id": "upload", "value": "upload"} in preferences

        try:
            stock = Stock(ticker.get("symbol"), token=environ["IEXC_KEY"])
            depthData = stock.get_book()[ticker.get("symbol")]
            rawData = stock.get_quote().loc[ticker.get("symbol")]
            if ticker.get("quote") is None and exchange is not None:
                return [
                    {},
                    "Orderbook visualization for `{}` is not available on {}.".
                    format(ticker.get("name"), exchange.get("name"))
                ]
            lastPrice = (depthData["bids"][0]["price"] +
                         depthData["asks"][0]["price"]) / 2
            depthData = {
                "bids": [[e.get("price"), e.get("size")]
                         for e in depthData["bids"]
                         if e.get("price") >= lastPrice * 0.75],
                "asks": [[e.get("price"), e.get("size")]
                         for e in depthData["asks"]
                         if e.get("price") <= lastPrice * 1.25]
            }
            bestBid = depthData["bids"][0]
            bestAsk = depthData["asks"][0]
        except:
            return [{}, ""]

        imageBuffer = BytesIO()
        chartImage = Image.new("RGBA", (1600, 1200))
        chartImage.paste(
            IEXC._generate_depth_image(depthData, bestBid, bestAsk, lastPrice))
        chartImage = Image.alpha_composite(chartImage,
                                           IEXC.chartOverlay["normal"])
        chartImage.save(imageBuffer, format="png")
        imageData = b64encode(imageBuffer.getvalue())
        imageBuffer.close()
        # if uploadMode:
        # 	bucket.blob("uploads/{}.png".format(int(time() * 1000))).upload_from_string(decodebytes(imageData))

        payload = {"data": imageData.decode(), "platform": "IEXC"}

        return [payload, ""]
Ejemplo n.º 10
0
	def request_candles(cls, request):
		ticker = request.get("ticker")
		exchange = Exchange.from_dict(ticker.get("exchange"))

		try:
			stock = Stock(ticker.get("id"), token=environ["IEXC_KEY"])
			rawData = stock.get_intraday_prices(chartLast=3)
			if len(rawData) == 0: return [{}, ""]
			if ticker.get("quote") is None and exchange is not None: return [{}, "Price for `{}` is not available on {}.".format(ticker.get("name"), exchange.get("name"))]
		except:
			return [{}, ""]

		payload = {
			"candles": [],
			"title": ticker.get("name"),
			"sourceText": "Data provided by IEX Cloud",
			"platform": "IEXC"
		}

		for index, e in rawData.iterrows():
			parsedDatetime = None
			try: parsedDatetime = datetime.strptime(index, "%Y-%m-%d %I:%M %p")
			except: pass
			try: parsedDatetime = datetime.strptime(index, "%Y-%m-%d %I %p")
			except: pass
			try: parsedDatetime = datetime.strptime(index, "%Y-%m-%d None")
			except: pass

			if parsedDatetime is None:
				raise Exception("timestamp formatting mismatch: {}".format(index))

			timestamp = timezone('US/Eastern').localize(parsedDatetime, is_dst=None).timestamp()

			if ticker.get("isReversed"):
				if "marketClose" in e:
					payload["candles"].append([timestamp, 1 / e.marketOpen, 1 / e.marketHigh, 1 / e.marketLow, 1 / e.marketClose])
				else:
					payload["candles"].append([timestamp, 1 / e.open, 1 / e.high, 1 / e.low, 1 / e.close])
			else:
				if "marketClose" in e:
					payload["candles"].append([timestamp, e.marketOpen, e.marketHigh, e.marketLow, e.marketClose])
				else:
					payload["candles"].append([timestamp, e.open, e.high, e.low, e.close])

		return [payload, ""]
Ejemplo n.º 11
0
	def _request_quote(cls, request, ticker):
		exchange = Exchange.from_dict(ticker.get("exchange"))

		if exchange is None: return [{}, ""]

		tf, limitTimestamp, candleOffset = CCXT.get_highest_supported_timeframe(exchange.properties, datetime.now().astimezone(utc))
		try:
			rawData = exchange.properties.fetch_ohlcv(ticker.get("symbol"), timeframe=tf.lower(), since=limitTimestamp, limit=300)
			if len(rawData) == 0 or rawData[-1][4] is None or rawData[0][1] is None: return [{}, ""]
		except:
			return [{}, ""]

		price = [rawData[-1][4], rawData[0][1]] if len(rawData) < candleOffset else [rawData[-1][4], rawData[-candleOffset][1]]
		if ticker.get("isReversed"): price = [1 / price[0], 1 / price[1]]
		volume = None if price[0] is None else sum([candle[5] for candle in rawData if int(candle[0] / 1000) >= int(exchange.properties.milliseconds() / 1000) - 86400]) / (price[0] if exchange.id == "bitmex" else 1)
		priceChange = 0 if tf == "1m" or price[1] == 0 else (price[0] / price[1]) * 100 - 100
		coinThumbnail = static_storage.icon if ticker.get("image") is None else ticker.get("image")

		base = "USD" if ticker.get("base") in AbstractProvider.stableCoinTickers else ticker.get("base")
		quote = "USD" if ticker.get("quote") in AbstractProvider.stableCoinTickers else ticker.get("quote")
		payload = {
			"quotePrice": "{:,.10f}".format(price[0]).rstrip('0').rstrip('.') + " " + quote,
			"quoteVolume": "{:,.4f}".format(volume).rstrip('0').rstrip('.') + " " + base,
			"title": ticker.get("name"),
			"change": "{:+.2f} %".format(priceChange),
			"thumbnailUrl": coinThumbnail,
			"messageColor": "amber" if priceChange == 0 else ("green" if priceChange > 0 else "red"),
			"sourceText": "Data from {}".format(exchange.name),
			"platform": CCXT.name,
			"raw": {
				"quotePrice": [price[0]] if tf == "1m" else price[:1],
				"quoteVolume": [volume],
				"timestamp": time()
			}
		}
		if ticker.get("quote") == "BTC":
			payload["quoteConvertedPrice"] = "≈ ${:,.6f}".format(price[0] * CoinGecko.lastBitcoinQuote)
			payload["quoteConvertedVolume"] = "≈ ${:,.4f}".format(volume * CoinGecko.lastBitcoinQuote)

		return [payload, ""]
Ejemplo n.º 12
0
    def request_ccxt_depth(self, request):
        ticker = request.get_ticker()
        exchange = request.get_exchange()

        try:
            if exchange is None: return None, None
            exchange = Exchange(exchange.id)

            try:
                depthData = exchange.properties.fetch_order_book(ticker.symbol)
                bestBid = depthData["bids"][0]
                bestAsk = depthData["asks"][0]
                lastPrice = (bestBid[0] + bestAsk[0]) / 2
            except:
                return None, None

            imageData = self.generate_depth_image(depthData, bestBid, bestAsk,
                                                  lastPrice)

            return imageData, None
        except Exception:
            print(traceback.format_exc())
            if os.environ["PRODUCTION_MODE"]: self.logging.report_exception()
            return None, None
Ejemplo n.º 13
0
	def request_lld(cls, request):
		ticker = request.get("ticker")
		exchange = Exchange.from_dict(ticker.get("exchange"))
		preferences = request.get("preferences")
		action = [e.get("value") for e in preferences if e.get("id") == "lld"]
		if len(action) == 0: return [{}, ""]
		action = action[0]

		if action == "funding":
			if exchange.id in ["bitmex"]:
				try: rawData = exchange.properties.public_get_instrument({"symbol": ticker.get("id")})[0]
				except: return [{}, "Requested funding data for `{}` is not available.".format(ticker.get("name"))]

				if rawData["fundingTimestamp"] is not None:
					fundingDate = datetime.strptime(rawData["fundingTimestamp"], "%Y-%m-%dT%H:%M:00.000Z").replace(tzinfo=utc)
				else:
					fundingDate = datetime.now().replace(tzinfo=utc)
				indicativeFundingTimestamp = datetime.timestamp(fundingDate) + 28800
				indicativeFundingDate = datetime.utcfromtimestamp(indicativeFundingTimestamp).replace(tzinfo=utc)
				deltaFunding = fundingDate - datetime.now().astimezone(utc)
				deltaIndicative = indicativeFundingDate - datetime.now().astimezone(utc)

				hours1, seconds1 = divmod(deltaFunding.days * 86400 + deltaFunding.seconds, 3600)
				minutes1 = int(seconds1 / 60)
				hoursFunding = "{:d} {} ".format(hours1, "hours" if hours1 > 1 else "hour") if hours1 > 0 else ""
				minutesFunding = "{:d} {}".format(minutes1 if hours1 > 0 or minutes1 > 0 else seconds1, "{}".format("minute" if minutes1 == 1 else "minutes") if hours1 > 0 or minutes1 > 0 else ("second" if seconds1 == 1 else "seconds"))
				deltaFundingText = "{}{}".format(hoursFunding, minutesFunding)

				hours2, seconds2 = divmod(deltaIndicative.days * 86400 + deltaIndicative.seconds, 3600)
				minutes2 = int(seconds2 / 60)
				hoursIndicative = "{:d} {} ".format(hours2, "hours" if hours2 > 1 else "hour") if hours2 > 0 else ""
				minutesIndicative = "{:d} {}".format(minutes2 if hours2 > 0 or minutes2 > 0 else seconds2, "{}".format("minute" if minutes2 == 1 else "minutes") if hours2 > 0 or minutes2 > 0 else ("second" if seconds2 == 1 else "seconds"))
				deltaIndicativeText = "{}{}".format(hoursIndicative, minutesIndicative)

				fundingRate = float(rawData["fundingRate"]) * 100
				predictedFundingRate = float(rawData["indicativeFundingRate"]) * 100
				averageFundingRate = (fundingRate + predictedFundingRate) / 2

				coinThumbnail = static_storage.icon if ticker.get("image") is None else ticker.get("image")

				payload = {
					"quotePrice": "Funding Rate: {:+.4f} %".format(fundingRate),
					"quoteConvertedPrice": "Predicted Rate: {:+.4f} % *(in {})*".format(predictedFundingRate, deltaIndicativeText),
					"title": ticker.get("name"),
					"change": "in {}".format(deltaFundingText),
					"thumbnailUrl": coinThumbnail,
					"messageColor": "yellow" if averageFundingRate == 0.01 else ("light green" if averageFundingRate < 0.01 else "deep orange"),
					"sourceText": "Funding on {}".format(exchange.name),
					"platform": CCXT.name,
					"raw": {
						"quotePrice": [fundingRate, predictedFundingRate],
						"timestamp": time()
					}
				}
				return [payload, ""]
			return [{}, "Funding data is only available on BitMEX."]
		elif action == "oi":
			if exchange.id in ["bitmex"]:
				try: rawData = exchange.properties.public_get_instrument({"symbol": ticker.get("id")})[0]
				except: return [{}, "Requested open interest data for `{}` is not available.".format(ticker.get("name"))]

				coinThumbnail = static_storage.icon if ticker.get("image") is None else ticker.get("image")

				payload = {
					"quotePrice": "Open interest: {:,.0f} contracts".format(float(rawData["openInterest"])),
					"quoteConvertedPrice": "Open value: {:,.4f} XBT".format(float(rawData["openValue"]) / 100000000),
					"title": ticker.get("name"),
					"thumbnailUrl": coinThumbnail,
					"messageColor": "deep purple",
					"sourceText": "Open interest on {}".format(exchange.name),
					"platform": CCXT.name,
					"raw": {
						"quotePrice": [float(rawData["openInterest"]), float(rawData["openValue"]) / 100000000],
						"timestamp": time()
					}
				}
				return [payload, ""]
			return [{}, "Open interest and open value data is only available on BitMEX."]
		elif action == "ls":
			if exchange.id in ["bitfinex2"]:
				try:
					longs = exchange.properties.publicGetStats1KeySizeSymbolLongLast({"key": "pos.size", "size": "1m", "symbol": "t{}".format(ticker.get("id")), "side": "long", "section": "last"})
					shorts = exchange.properties.publicGetStats1KeySizeSymbolShortLast({"key": "pos.size", "size": "1m", "symbol": "t{}".format(ticker.get("id")), "side": "long", "section": "last"})
					ratio = longs[1] / (longs[1] + shorts[1]) * 100
				except:
					return [{}, ""]

				coinThumbnail = static_storage.icon if ticker.get("image") is None else ticker.get("image")

				payload = {
					"quotePrice": "{:.1f} % longs / {:.1f} % shorts".format(ratio, 100 - ratio),
					"title": ticker.get("name"),
					"change": "in {}".format(deltaFundingText),
					"thumbnailUrl": coinThumbnail,
					"messageColor": "deep purple",
					"sourceText": "Longs/shorts on {}".format(exchange.name),
					"platform": CCXT.name,
					"raw": {
						"quotePrice": [longs[1], shorts[1]],
						"timestamp": time()
					}
				}
				return [payload, ""]
			return [{}, "Longs and shorts data is only available on Bitfinex."]
		elif action == "dom":
			try: rawData = CoinGecko.connection.get_global()
			except: return [{}, "Requested dominance data for `{}` is not available.".format(ticker.get("name"))]
			if ticker.get("base").lower() not in rawData["market_cap_percentage"]: return [{}, "Dominance for {} does not exist.".format(ticker.get("base"))]
			coinDominance = rawData["market_cap_percentage"][ticker.get("base").lower()]

			coinThumbnail = static_storage.icon if ticker.get("image") is None else ticker.get("image")

			payload = {
				"quotePrice": "{} dominance: {:,.2f} %".format(ticker.get("base"), coinDominance),
				"title": "Market Dominance",
				"thumbnailUrl": coinThumbnail,
				"messageColor": "deep purple",
				"sourceText": "Market information from CoinGecko",
				"platform": CCXT.name,
				"raw": {
					"quotePrice": [coinDominance],
					"timestamp": time()
				}
			}
			return [payload, ""]
		else:
			return [{}, ""]
Ejemplo n.º 14
0
    def _request_stocks(cls, request, ticker):
        exchange = Exchange.from_dict(ticker.get("exchange"))

        try:
            stock = Stock(ticker.get("symbol"), token=environ["IEXC_KEY"])
            rawData = stock.get_quote().loc[ticker.get("symbol")]
            if ticker.get("quote") is None and exchange is not None:
                return [{}, "Price for `{}` is not available on {}.".format(
                    ticker.get("name"), exchange.get("name"))]
            if rawData is None or (rawData["latestPrice"] is None
                                   and rawData["delayedPrice"] is None):
                return [{}, ""]
        except:
            return [{}, ""]

        try:
            coinThumbnail = stock.get_logo().loc[ticker.get("symbol")]["url"]
        except:
            coinThumbnail = static_storage.icon

        latestPrice = rawData["delayedPrice"] if rawData[
            "latestPrice"] is None else rawData["latestPrice"]
        price = float(
            latestPrice if "isUSMarketOpen" not in rawData
            or rawData["isUSMarketOpen"] or "extendedPrice" not in rawData
            or rawData["extendedPrice"] is None else rawData["extendedPrice"])
        if ticker.get("isReversed"): price = 1 / price
        priceChange = (
            (1 / float(rawData["change"]) if ticker.get("isReversed")
             and float(rawData["change"]) != 0 else float(rawData["change"])) /
            price * 100
        ) if "change" in rawData and rawData["change"] is not None else 0

        payload = {
            "quotePrice":
            "{:,.10f}".format(price).rstrip('0').rstrip('.') +
            ("" if ticker.get("isReversed") else
             (" USD" if ticker.get("quote") is None else
              (" " + ticker.get("quote")))),
            "title":
            ticker.get("name"),
            "change":
            "{:+.2f} %".format(priceChange),
            "thumbnailUrl":
            coinThumbnail,
            "messageColor":
            "amber" if priceChange == 0 else
            ("green" if priceChange > 0 else "red"),
            "sourceText":
            "Data provided by IEX Cloud",
            "platform":
            "IEXC",
            "raw": {
                "quotePrice": [price],
                "timestamp": time()
            }
        }

        if "latestVolume" in rawData:
            volume = float(rawData["latestVolume"])
            payload["quoteVolume"] = "{:,.4f}".format(volume).rstrip(
                '0').rstrip('.') + " " + ticker.get("base")
            payload["raw"]["quoteVolume"] = [volume]

        return [payload, ""]
Ejemplo n.º 15
0
	def refresh_iexc_index(self):
		try:
			def get_url(url):
				while True:
					try:
						return get(url).json()
					except:
						print(format_exc())
						sleep(10)


			iexcExchanges = set()
			exchanges = get_url("https://cloud.iexapis.com/stable/ref-data/market/us/exchanges?token={}".format(environ["IEXC_KEY"]))
			suffixMap = {}

			for exchange in exchanges:
				if exchange["refId"] == "": continue
				exchangeId = exchange["refId"]
				iexcExchanges.add(exchangeId.lower())
				self.exchanges[exchangeId.lower()] = Exchange(exchangeId, "traditional", exchange["longName"], region="us")
			exchanges = get_url("https://cloud.iexapis.com/stable/ref-data/exchanges?token={}".format(environ["IEXC_KEY"]))
			for exchange in exchanges:
				exchangeId = exchange["exchange"].replace("Euronext Euronext", "Euronext")
				if exchangeId.lower() in iexcExchanges: continue
				iexcExchanges.add(exchangeId.lower())
				self.exchanges[exchangeId.lower()] = Exchange(exchangeId, "traditional", exchange["description"], region=exchange["region"])
				suffixMap[exchangeId.lower()] = exchange["exchangeSuffix"]

			difference = set(iexcExchanges).symmetric_difference(supported.iexcExchanges)
			newSupportedExchanges = []
			unsupportedCryptoExchanges = []
			for exchangeId in difference:
				if exchangeId not in supported.iexcExchanges:
					newSupportedExchanges.append(exchangeId)
				else:
					unsupportedCryptoExchanges.append(exchangeId)
			if len(newSupportedExchanges) != 0: print("New supported IEXC exchanges: {}".format(newSupportedExchanges))
			if len(unsupportedCryptoExchanges) != 0: print("New deprecated IEXC exchanges: {}".format(unsupportedCryptoExchanges))

			for exchangeId in supported.traditionalExchanges["IEXC"]:
				symbols = get_url("https://cloud.iexapis.com/stable/ref-data/exchange/{}/symbols?token={}".format(self.exchanges[exchangeId].id, environ["IEXC_KEY"]))
				if len(symbols) == 0: print("No symbols found on {}".format(exchangeId))
				for symbol in symbols:
					suffix = suffixMap.get(exchangeId, "")
					tickerId = symbol["symbol"]
					if tickerId not in self.iexcStocksIndex:
						self.iexcStocksIndex[tickerId] = {"id": tickerId.removesuffix(suffix), "name": symbol["name"], "base": tickerId.removesuffix(suffix), "quote": symbol["currency"]}
					self.exchanges[exchangeId].properties.symbols.append(tickerId)

			forexSymbols = get_url("https://cloud.iexapis.com/stable/ref-data/fx/symbols?token={}".format(environ["IEXC_KEY"]))
			derivedCurrencies = set()
			for pair in forexSymbols["pairs"]:
				derivedCurrencies.add(pair["fromCurrency"])
				derivedCurrencies.add(pair["toCurrency"])
				self.iexcForexIndex[pair["symbol"]] = {"id": pair["symbol"], "name": pair["symbol"], "base": pair["fromCurrency"], "quote": pair["toCurrency"], "reversed": False}
				self.iexcForexIndex[pair["toCurrency"] + pair["fromCurrency"]] = {"id": pair["symbol"], "name": pair["toCurrency"] + pair["fromCurrency"], "base": pair["toCurrency"], "quote": pair["fromCurrency"], "reversed": True}
			for fromCurrency in derivedCurrencies:
				for toCurrency in derivedCurrencies:
					symbol = fromCurrency + toCurrency
					if fromCurrency != toCurrency and symbol not in self.iexcForexIndex:
						self.iexcForexIndex[symbol] = {"id": symbol, "name": symbol, "base": fromCurrency, "quote": toCurrency, "reversed": False}

		except Exception:
			print(format_exc())
Ejemplo n.º 16
0
	def request_depth_visualization(self, request):
		ticker = request.get_ticker()
		exchange = request.get_exchange()

		try:
			if exchange is None: return None, "Data for {} isn't available.".format(ticker.name)
			exchange = Exchange(exchange.id)

			try:
				depthData = exchange.properties.fetch_order_book(ticker.symbol)
				bestBid = depthData["bids"][0]
				bestAsk = depthData["asks"][0]
				lastPrice = (bestBid[0] + bestAsk[0]) / 2
			except:
				return None, None

			bidTotal = 0
			xBids = [bestBid[0]]
			yBids = [0]
			for bid in depthData['bids']:
				if len(xBids) < 10 or bid[0] > lastPrice * 0.9:
					bidTotal += bid[1]
					xBids.append(bid[0])
					yBids.append(bidTotal)

			askTotal = 0
			xAsks = [bestAsk[0]]
			yAsks = [0]
			for ask in depthData['asks']:
				if len(xAsks) < 10 or ask[0] < lastPrice * 1.1:
					askTotal += ask[1]
					xAsks.append(ask[0])
					yAsks.append(askTotal)

			fig = plt.figure(facecolor="#131722")
			ax = fig.add_subplot(1, 1, 1)
			ax.tick_params(color="#787878", labelcolor="#D9D9D9")
			ax.step(xBids, yBids, where="post", color="#27A59A")
			ax.step(xAsks, yAsks, where="post", color="#EF534F")
			ax.fill_between(xBids, yBids, 0, facecolor="#27A59A", interpolate=True, step="post", alpha=0.33, zorder=2)
			ax.fill_between(xAsks, yAsks, 0, facecolor="#EF534F", interpolate=True, step="post", alpha=0.33, zorder=2)
			plt.axvline(x=lastPrice, color="#758696", linestyle="--")

			ax.set_facecolor("#131722")
			for spine in ax.spines.values():
				spine.set_edgecolor("#787878")
			ax.autoscale(enable=True, axis="both", tight=True)

			def on_draw(event):
				bboxes = []
				for label in ax.get_yticklabels():
					bbox = label.get_window_extent()
					bboxi = bbox.transformed(fig.transFigure.inverted())
					bboxes.append(bboxi)

				bbox = mtransforms.Bbox.union(bboxes)
				if fig.subplotpars.left < bbox.width:
					fig.subplots_adjust(left=1.1 * bbox.width)
					fig.canvas.draw()
				return False

			ax.yaxis.set_major_formatter(tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
			plt.setp(ax.get_xticklabels(), rotation=45, horizontalalignment='right')
			lastPriceLabel = bestAsk[0] if bestAsk[1] >= bestBid[1] else bestBid[0]
			xLabels = list(plt.xticks()[0][1:])
			yLabels = list(plt.yticks()[0][1:])
			for label in xLabels:
				plt.axvline(x=label, color="#363C4F", linewidth=1, zorder=1)
			for label in yLabels:
				plt.axhline(y=label, color="#363C4F", linewidth=1, zorder=1)
			diffLabels = 1 - xLabels[0] / xLabels[1]
			bottomBound, topBound = lastPriceLabel * (1 - diffLabels * (1/4)), lastPriceLabel * (1 + diffLabels * (1/4))
			xLabels = [l for l in xLabels if not (bottomBound <= l <= topBound)]

			plt.xticks(xLabels + [lastPriceLabel])
			plt.yticks(yLabels)
			ax.set_xlim([xBids[-1], xAsks[-1]])
			ax.set_ylim([0, max(bidTotal, askTotal)])

			fig.canvas.mpl_connect("draw_event", on_draw)
			plt.tight_layout()

			rawImageData = BytesIO()
			plt.savefig(rawImageData, format="png", edgecolor="none")
			rawImageData.seek(0)

			imageBuffer = BytesIO()
			chartImage = Image.new("RGBA", (1600, 1200))
			chartImage.paste(Image.open(rawImageData))
			chartImage = Image.alpha_composite(chartImage, self.imageOverlays["Alpha depth"])
			chartImage.save(imageBuffer, format="png")
			imageData = base64.b64encode(imageBuffer.getvalue())
			imageBuffer.close()

			return imageData, None
		except Exception:
			print(traceback.format_exc())
			if os.environ["PRODUCTION_MODE"]: self.logging.report_exception()
			return None, None
Ejemplo n.º 17
0
    def request_lld_quote(self, request):
        ticker = request.get_ticker()
        exchange = request.get_exchange()
        filters = request.get_filters()
        action = request.find_parameter_in_list("lld", filters)

        try:
            if exchange is not None: exchange = Exchange(exchange.id, "crypto")

            if action == "funding":
                if exchange.id in ["bitmex"]:
                    try:
                        rawData = exchange.properties.public_get_instrument(
                            {"symbol": ticker.id})[0]
                    except:
                        return None, "Requested funding data for `{}` is not available.".format(
                            ticker.name)

                    if rawData["fundingTimestamp"] is not None:
                        fundingDate = datetime.datetime.strptime(
                            rawData["fundingTimestamp"],
                            "%Y-%m-%dT%H:%M:00.000Z").replace(tzinfo=pytz.utc)
                    else:
                        fundingDate = datetime.datetime.now().replace(
                            tzinfo=pytz.utc)
                    indicativeFundingTimestamp = datetime.datetime.timestamp(
                        fundingDate) + 28800
                    indicativeFundingDate = datetime.datetime.utcfromtimestamp(
                        indicativeFundingTimestamp).replace(tzinfo=pytz.utc)
                    deltaFunding = fundingDate - datetime.datetime.now(
                    ).astimezone(pytz.utc)
                    deltaIndicative = indicativeFundingDate - datetime.datetime.now(
                    ).astimezone(pytz.utc)

                    hours1, seconds1 = divmod(
                        deltaFunding.days * 86400 + deltaFunding.seconds, 3600)
                    minutes1 = int(seconds1 / 60)
                    hoursFunding = "{:d} {} ".format(
                        hours1, "hours"
                        if hours1 > 1 else "hour") if hours1 > 0 else ""
                    minutesFunding = "{:d} {}".format(
                        minutes1 if hours1 > 0 or minutes1 > 0 else seconds1,
                        "{}".format("minute" if minutes1 == 1 else "minutes")
                        if hours1 > 0 or minutes1 > 0 else
                        ("second" if seconds1 == 1 else "seconds"))
                    deltaFundingText = "{}{}".format(hoursFunding,
                                                     minutesFunding)

                    hours2, seconds2 = divmod(
                        deltaIndicative.days * 86400 + deltaIndicative.seconds,
                        3600)
                    minutes2 = int(seconds2 / 60)
                    hoursIndicative = "{:d} {} ".format(
                        hours2, "hours"
                        if hours2 > 1 else "hour") if hours2 > 0 else ""
                    minutesIndicative = "{:d} {}".format(
                        minutes2 if hours2 > 0 or minutes2 > 0 else seconds2,
                        "{}".format("minute" if minutes2 == 1 else "minutes")
                        if hours2 > 0 or minutes2 > 0 else
                        ("second" if seconds2 == 1 else "seconds"))
                    deltaIndicativeText = "{}{}".format(
                        hoursIndicative, minutesIndicative)

                    fundingRate = float(rawData["fundingRate"]) * 100
                    predictedFundingRate = float(
                        rawData["indicativeFundingRate"]) * 100
                    averageFundingRate = (fundingRate +
                                          predictedFundingRate) / 2

                    payload = {
                        "quotePrice":
                        "Funding Rate: {:+.4f} % *(in {})*\nPredicted Rate: {:+.4f} % *(in {})*"
                        .format(fundingRate, deltaFundingText,
                                predictedFundingRate, deltaIndicativeText),
                        "title":
                        ticker.name,
                        "baseTicker":
                        ticker.base,
                        "quoteTicker":
                        ticker.quote,
                        "thumbnailUrl":
                        TickerParser.get_coingecko_image(ticker.base),
                        "messageColor":
                        "yellow" if averageFundingRate == 0.01 else
                        ("light green"
                         if averageFundingRate < 0.01 else "deep orange"),
                        "sourceText":
                        "Contract details on {}".format(exchange.name),
                        "platform":
                        "LLD",
                        "raw": {
                            "quotePrice": [fundingRate, predictedFundingRate],
                            "ticker": ticker,
                            "exchange": exchange,
                            "timestamp": time.time()
                        }
                    }
                    return payload, None
                return None, "Funding data is only available on BitMEX."
            elif action == "oi":
                if exchange.id in ["bitmex"]:
                    try:
                        rawData = exchange.properties.public_get_instrument(
                            {"symbol": ticker.id})[0]
                    except:
                        return None, "Requested open interest data for `{}` is not available.".format(
                            ticker.name)

                    payload = {
                        "quotePrice":
                        "Open interest: {:,.0f} {}\nOpen value: {:,.4f} XBT".
                        format(float(rawData["openInterest"]),
                               "USD" if ticker.id == "XBTUSD" else "contracts",
                               float(rawData["openValue"]) / 100000000),
                        "title":
                        ticker.name,
                        "baseTicker":
                        ticker.base,
                        "quoteTicker":
                        ticker.quote,
                        "thumbnailUrl":
                        TickerParser.get_coingecko_image(ticker.base),
                        "messageColor":
                        "deep purple",
                        "sourceText":
                        "Contract details on {}".format(exchange.name),
                        "platform":
                        "LLD",
                        "raw": {
                            "quotePrice": [
                                float(rawData["openInterest"]),
                                float(rawData["openValue"]) / 100000000
                            ],
                            "ticker":
                            ticker,
                            "exchange":
                            exchange,
                            "timestamp":
                            time.time()
                        }
                    }
                    return payload, None
                return None, "Open interest and open value data is only available on BitMEX."
            elif action == "ls":
                if exchange.id in ["bitfinex2"]:
                    try:
                        longs = exchange.properties.publicGetStats1KeySizeSymbolLongLast(
                            {
                                "key": "pos.size",
                                "size": "1m",
                                "symbol": "t{}".format(ticker.id),
                                "side": "long",
                                "section": "last"
                            })
                        shorts = exchange.properties.publicGetStats1KeySizeSymbolShortLast(
                            {
                                "key": "pos.size",
                                "size": "1m",
                                "symbol": "t{}".format(ticker.id),
                                "side": "long",
                                "section": "last"
                            })
                        ratio = longs[1] / (longs[1] + shorts[1]) * 100
                    except:
                        return None, None

                    payload = {
                        "quotePrice":
                        "{:.1f} % longs / {:.1f} % shorts".format(
                            ratio, 100 - ratio),
                        "title":
                        "{} longs/shorts ratio".format(ticker.name),
                        "baseTicker":
                        ticker.base,
                        "quoteTicker":
                        ticker.quote,
                        "thumbnailUrl":
                        TickerParser.get_coingecko_image(ticker.base),
                        "messageColor":
                        "deep purple",
                        "sourceText":
                        "Data on {}".format(exchange.name),
                        "platform":
                        "LLD",
                        "raw": {
                            "quotePrice": [longs[1], shorts[1]],
                            "ticker": ticker,
                            "exchange": exchange,
                            "timestamp": time.time()
                        }
                    }
                    return payload, None
                return None, "Longs and shorts data is only available on Bitfinex."
            elif action == "sl":
                if exchange.id in ["bitfinex2"]:
                    try:
                        longs = exchange.properties.publicGetStats1KeySizeSymbolLongLast(
                            {
                                "key": "pos.size",
                                "size": "1m",
                                "symbol": "t{}".format(ticker.id),
                                "side": "short",
                                "section": "last"
                            })
                        shorts = exchange.properties.publicGetStats1KeySizeSymbolShortLast(
                            {
                                "key": "pos.size",
                                "size": "1m",
                                "symbol": "t{}".format(ticker.id),
                                "side": "short",
                                "section": "last"
                            })
                        ratio = shorts[1] / (longs[1] + shorts[1]) * 100
                    except:
                        return None, None

                    payload = {
                        "quotePrice":
                        "{:.1f} % shorts / {:.1f} % longs".format(
                            ratio, 100 - ratio),
                        "title":
                        "{} shorts/longs ratio".format(ticker.name),
                        "baseTicker":
                        ticker.base,
                        "quoteTicker":
                        ticker.quote,
                        "thumbnailUrl":
                        TickerParser.get_coingecko_image(ticker.base),
                        "messageColor":
                        "deep purple",
                        "sourceText":
                        "Data on {}".format(exchange.name),
                        "platform":
                        "LLD",
                        "raw": {
                            "quotePrice": [longs[1], shorts[1]],
                            "ticker": ticker,
                            "exchange": exchange,
                            "timestamp": time.time()
                        }
                    }
                    return payload, None
                return None, "Longs and shorts data is only available on Bitfinex."
            elif action == "dom":
                try:
                    rawData = self.coinGecko.get_global()
                except:
                    return None, "Requested dominance data for `{}` is not available.".format(
                        ticker.name)
                if ticker.base.lower() not in rawData["market_cap_percentage"]:
                    return None, "Dominance for {} does not exist.".format(
                        ticker.base)
                coinDominance = rawData["market_cap_percentage"][
                    ticker.base.lower()]

                payload = {
                    "quotePrice":
                    "{} dominance: {:,.2f} %".format(ticker.base,
                                                     coinDominance),
                    "title":
                    "Market Dominance",
                    "baseTicker":
                    ticker.base,
                    "quoteTicker":
                    ticker.quote,
                    "thumbnailUrl":
                    TickerParser.get_coingecko_image(ticker.base),
                    "messageColor":
                    "deep purple",
                    "sourceText":
                    "Market information from CoinGecko",
                    "platform":
                    "LLD",
                    "raw": {
                        "quotePrice": coinDominance,
                        "ticker": ticker,
                        "timestamp": time.time()
                    }
                }
                return payload, None
            else:
                return None, None
        except Exception:
            print(traceback.format_exc())
            if os.environ["PRODUCTION_MODE"]:
                self.logging.report_exception(user=ticker.id)
            return None, None