#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# File: unicorn_fy/unicorn_fy.py
#
# Part of ‘UnicornFy’
# Project website: https://github.com/oliver-zehentleitner/unicorn-fy
# Github: https://github.com/oliver-zehentleitner/unicorn-fy
# Documentation: https://oliver-zehentleitner.github.io/unicorn-fy
# PyPI: https://pypi.org/project/unicorn-fy
#
# License: MIT
# https://github.com/oliver-zehentleitner/unicorn-fy/blob/master/LICENSE
#
# Author: Oliver Zehentleitner
#
# Copyright (c) 2019-2026, Oliver Zehentleitner (https://about.me/oliver-zehentleitner)
#
# All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
from typing import Optional
import cython
import logging
import platform
import requests
import time
import orjson as json
__app_name__: str = "unicorn-fy"
__version__: str = "0.17.2.dev"
__logger__: logging.getLogger = logging.getLogger("unicorn_fy")
logger = __logger__
[docs]
class UnicornFy(object):
"""
Unify received data from crypto exchanges
Supported exchanges:
- Binance.com
- Binance-com-futures
- Binance-com-coin_futures
- Binance-com-margin
- Binance-com-isolated_margin
- Binance.us
- trBinance.com
- Binance.org
"""
def __init__(self, debug=False):
self.last_update_check_github = {
"timestamp": time.time(),
"status": {"tag_name": None},
}
self.name = __app_name__
self.version = __version__
if debug is True:
logger.info(
f"New instance of {__app_name__}_{__version__}-{'compiled' if cython.compiled else 'source'} "
f"on {str(platform.system())} {str(platform.release())} started ..."
)
def __enter__(self):
logger.debug(f"Entering with-context of UnicornFy() ...")
return self
def __exit__(self, exc_type, exc_value, error_traceback):
logger.debug(f"Leaving with-context of UnicornFy() ...")
if exc_type:
logger.critical(
f"An exception occurred: {exc_type} - {exc_value} - {error_traceback}"
)
[docs]
@staticmethod
def binance_com_websocket(stream_data_json):
"""
unicorn_fy binance.com raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_websocket(
stream_data_json, exchange="binance.com", show_deprecated_warning=False
)
[docs]
@staticmethod
def binance_com_margin_websocket(stream_data_json):
"""
unicorn_fy binance.com-margin raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_websocket(
stream_data_json,
exchange="binance.com-margin",
show_deprecated_warning=False,
)
[docs]
@staticmethod
def binance_com_isolated_margin_websocket(stream_data_json):
"""
unicorn_fy binance.com-isolated_margin raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_websocket(
stream_data_json,
exchange="binance.com-isolated_margin",
show_deprecated_warning=False,
)
[docs]
@staticmethod
def binance_com_futures_websocket(stream_data_json):
"""
unicorn_fy binance.com-futures raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_futures_websocket(
stream_data_json,
exchange="binance.com-futures",
show_deprecated_warning=False,
)
[docs]
@staticmethod
def binance_com_coin_futures_websocket(stream_data_json):
"""
unicorn_fy binance.com-coin_futures raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_futures_websocket(
stream_data_json,
exchange="binance.com-coin_futures",
show_deprecated_warning=False,
)
[docs]
@staticmethod
def binance_us_websocket(stream_data_json):
"""
unicorn_fy binance.us (US) raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_websocket(
stream_data_json, exchange="binance.us", show_deprecated_warning=False
)
[docs]
@staticmethod
def trbinance_com_websocket(stream_data_json):
"""
unicorn_fy trbinance.com (TR) raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:return: dict
"""
return UnicornFy.binance_websocket(
stream_data_json, exchange="trbinance.com", show_deprecated_warning=False
)
[docs]
@staticmethod
def binance_websocket(
stream_data_json, exchange="binance", show_deprecated_warning=True
):
"""
unicorn_fy binance.com raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:param exchange: Exchange endpoint.
:type exchange: str
:param show_deprecated_warning: Show or hide warning
:type show_deprecated_warning: bool
:return: dict
"""
unicorn_fied_data = {}
logger.debug("UnicornFy->binance_websocket(" + str(stream_data_json) + ")")
if show_deprecated_warning is True:
logger.warning(
"Using `UnicornFy.binance_websocket()` is deprecated, use "
"`UnicornFy.binance_com_websocket()` instead!"
)
if UnicornFy.is_json(stream_data_json) is False:
return stream_data_json
stream_data = json.loads(stream_data_json)
try:
if stream_data[0]["e"] == "24hrMiniTicker":
stream_data = {"data": {"e": "24hrMiniTicker"}, "items": stream_data}
elif stream_data[0]["e"] == "24hrTicker":
stream_data = {"data": {"e": "24hrTicker"}, "items": stream_data}
except KeyError:
pass
try:
if "!ticker@arr" in stream_data["stream"]:
stream_data = {
"data": {"e": "24hrTicker"},
"items": stream_data["data"],
}
elif "!miniTicker@arr" in stream_data["stream"]:
stream_data = {
"data": {"e": "24hrMiniTicker"},
"items": stream_data["data"],
}
except KeyError:
pass
try:
if "event" in stream_data and "subscriptionId" in stream_data:
# WS API userData envelope: {"subscriptionId": 0, "event": {"e": "executionReport", ...}}
# Unwrap to standard format so the rest of the normalisation pipeline works unchanged.
stream_data = {"data": stream_data["event"]}
except (KeyError, TypeError):
pass
try:
if "e" in stream_data and "data" not in stream_data:
stream_data = {"data": stream_data}
except TypeError:
pass
try:
if stream_data["stream"].find("@depth5") != -1:
stream_data["data"]["e"] = "depth"
stream_data["data"]["depth_level"] = 5
elif stream_data["stream"].find("@depth10") != -1:
stream_data["data"]["e"] = "depth"
stream_data["data"]["depth_level"] = 10
elif stream_data["stream"].find("@depth20") != -1:
stream_data["data"]["e"] = "depth"
stream_data["data"]["depth_level"] = 20
elif "@bookTicker" in stream_data["stream"]:
stream_data["data"]["e"] = "bookTicker"
except KeyError:
pass
try:
# return if already unicorn_fied
if stream_data["unicorn_fied"]:
return stream_data
except KeyError:
pass
try:
if stream_data["result"] is None:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
else:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
except KeyError:
pass
try:
if stream_data["error"]:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
except KeyError:
pass
if stream_data["data"]["e"] == "aggTrade":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"aggregate_trade_id": stream_data["data"]["a"],
"price": stream_data["data"]["p"],
"quantity": stream_data["data"]["q"],
"first_trade_id": stream_data["data"]["f"],
"last_trade_id": stream_data["data"]["l"],
"trade_time": stream_data["data"]["T"],
"is_market_maker": stream_data["data"]["m"],
"ignore": stream_data["data"]["M"],
}
elif stream_data["data"]["e"] == "listStatus":
objects = []
for item in stream_data["data"]["O"]:
objects.append(
{
"symbol": item["s"],
"order_id": item["i"],
"client_order_id": item["c"],
}
)
unicorn_fied_data = {
"stream_type": stream_data["data"]["s"].lower() + "@listStatus",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"order_list_id": stream_data["data"]["g"],
"contingency_type": stream_data["data"]["c"],
"list_status_type": stream_data["data"]["l"],
"list_order_status": stream_data["data"]["L"],
"list_reject_reason": stream_data["data"]["r"],
"list_client_order_id": stream_data["data"]["C"],
"transaction_time": stream_data["data"]["T"],
"objects": objects,
}
elif stream_data["data"]["e"] == "trade":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"trade_id": stream_data["data"]["t"],
"price": stream_data["data"]["p"],
"quantity": stream_data["data"]["q"],
"buyer_order_id": stream_data["data"]["b"],
"seller_order_id": stream_data["data"]["a"],
"trade_time": stream_data["data"]["T"],
"is_market_maker": stream_data["data"]["m"],
"ignore": stream_data["data"]["M"],
}
elif stream_data["data"]["e"] == "bookTicker":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"order_book_update_id": stream_data["data"]["u"],
"symbol": stream_data["data"]["s"],
"best_bid_price": stream_data["data"]["b"],
"best_bid_quantity": stream_data["data"]["B"],
"best_ask_price": stream_data["data"]["a"],
"best_ask_quantity": stream_data["data"]["A"],
"event_type": stream_data["data"]["e"],
}
elif stream_data["data"]["e"] == "kline":
stream_data["data"] = UnicornFy.set_to_false_if_not_exist(
stream_data["data"], "f"
)
stream_data["data"] = UnicornFy.set_to_false_if_not_exist(
stream_data["data"], "L"
)
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"kline": {
"kline_start_time": stream_data["data"]["k"]["t"],
"kline_close_time": stream_data["data"]["k"]["T"],
"symbol": stream_data["data"]["k"]["s"],
"interval": stream_data["data"]["k"]["i"],
"first_trade_id": stream_data["data"]["f"],
"last_trade_id": stream_data["data"]["L"],
"open_price": stream_data["data"]["k"]["o"],
"close_price": stream_data["data"]["k"]["c"],
"high_price": stream_data["data"]["k"]["h"],
"low_price": stream_data["data"]["k"]["l"],
"base_volume": stream_data["data"]["k"]["v"],
"number_of_trades": stream_data["data"]["k"]["n"],
"is_closed": stream_data["data"]["k"]["x"],
"quote": stream_data["data"]["k"]["q"],
"taker_by_base_asset_volume": stream_data["data"]["k"]["V"],
"taker_by_quote_asset_volume": stream_data["data"]["k"]["Q"],
"ignore": stream_data["data"]["k"]["B"],
},
}
elif stream_data["data"]["e"] == "24hrMiniTicker":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!miniTicker@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"symbol": item["s"],
"close_price": item["c"],
"open_price": item["o"],
"high_price": item["h"],
"low_price": item["l"],
"taker_by_base_asset_volume": item["v"],
"taker_by_quote_asset_volume": item["q"],
}
unicorn_fied_data["data"].append(data)
except KeyError:
try:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"close_price": stream_data["data"]["c"],
"open_price": stream_data["data"]["o"],
"high_price": stream_data["data"]["h"],
"low_price": stream_data["data"]["l"],
"taker_by_base_asset_volume": stream_data["data"]["v"],
"taker_by_quote_asset_volume": stream_data["data"]["q"],
}
unicorn_fied_data["data"].append(data)
except KeyError as error_msg:
logger.critical(
f"UnicornFy->binance_com_futures_websocket({str(stream_data)}) - "
f"error: {str(error_msg)}"
)
print(str(stream_data))
elif stream_data["data"]["e"] == "24hrTicker":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!ticker@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"symbol": item["s"],
"price_change": item["p"],
"price_change_percent": item["P"],
"weighted_average_price": item["w"],
"trade_before_24h_window": item["x"],
"last_price": item["c"],
"last_quantity": item["Q"],
"best_bid_price": item["b"],
"best_bid_quantity": item["B"],
"best_ask_price": item["a"],
"best_ask_quantity": item["A"],
"open_price": item["o"],
"high_price": item["h"],
"low_price": item["l"],
"total_traded_base_asset_volume": item["v"],
"total_traded_quote_asset_volume": item["q"],
"statistics_open_time": item["O"],
"statistics_close_time": item["C"],
"first_trade_id": item["F"],
"last_trade_id": item["L"],
"total_nr_of_trades": item["n"],
}
unicorn_fied_data["data"].append(data)
except KeyError:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"price_change": stream_data["data"]["p"],
"price_change_percent": stream_data["data"]["P"],
"weighted_average_price": stream_data["data"]["w"],
"trade_before_24h_window": stream_data["data"]["x"],
"last_price": stream_data["data"]["c"],
"last_quantity": stream_data["data"]["Q"],
"best_bid_price": stream_data["data"]["b"],
"best_bid_quantity": stream_data["data"]["B"],
"best_ask_price": stream_data["data"]["a"],
"best_ask_quantity": stream_data["data"]["A"],
"open_price": stream_data["data"]["o"],
"high_price": stream_data["data"]["h"],
"low_price": stream_data["data"]["l"],
"total_traded_base_asset_volume": stream_data["data"]["v"],
"total_traded_quote_asset_volume": stream_data["data"]["q"],
"statistics_open_time": stream_data["data"]["O"],
"statistics_close_time": stream_data["data"]["C"],
"first_trade_id": stream_data["data"]["F"],
"last_trade_id": stream_data["data"]["L"],
"total_nr_of_trades": stream_data["data"]["n"],
}
unicorn_fied_data["data"].append(data)
elif stream_data["data"]["e"] == "depth":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"symbol": stream_data["stream"][
: stream_data["stream"].find("@")
].upper(),
"last_update_id": stream_data["data"]["lastUpdateId"],
"bids": stream_data["data"]["bids"],
"asks": stream_data["data"]["asks"],
}
elif stream_data["data"]["e"] == "depthUpdate":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"first_update_id_in_event": stream_data["data"]["U"],
"final_update_id_in_event": stream_data["data"]["u"],
"bids": stream_data["data"]["b"],
"asks": stream_data["data"]["a"],
}
elif stream_data["data"]["e"] == "outboundAccountInfo":
unicorn_fied_data = {
"stream_type": "!userData@arr",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"maker_commission_rate": stream_data["data"]["m"],
"taker_commission_rate": stream_data["data"]["t"],
"buyer_commission_rate": stream_data["data"]["b"],
"seller_commission_rate": stream_data["data"]["s"],
"can_trade": stream_data["data"]["T"],
"can_withdraw": stream_data["data"]["W"],
"can_deposit": stream_data["data"]["D"],
"balances": [],
"account_permissions": stream_data["data"]["P"],
}
for item in stream_data["data"]["B"]:
new_item = {"asset": item["a"], "free": item["f"], "locked": item["l"]}
unicorn_fied_data["balances"] += [new_item]
elif stream_data["data"]["e"] == "outboundAccountPosition":
unicorn_fied_data = {
"stream_type": "!userData@arr",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"last_update_time": stream_data["data"]["u"],
"balances": [],
}
for item in stream_data["data"]["B"]:
new_item = {"asset": item["a"], "free": item["f"], "locked": item["l"]}
unicorn_fied_data["balances"] += [new_item]
elif stream_data["data"]["e"] == "balanceUpdate":
unicorn_fied_data = {
"stream_type": "!userData@arr",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"asset": stream_data["data"]["a"],
"balance_delta": stream_data["data"]["d"],
"clear_time": stream_data["data"]["T"],
}
elif stream_data["data"]["e"] == "executionReport":
unicorn_fied_data = {
"stream_type": "!userData@arr",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"client_order_id": stream_data["data"]["c"],
"side": stream_data["data"]["S"],
"order_type": stream_data["data"]["o"],
"time_in_force": stream_data["data"]["f"],
"order_quantity": stream_data["data"]["q"],
"order_price": stream_data["data"]["p"],
"stop_price": stream_data["data"]["P"],
"iceberg_quantity": stream_data["data"]["F"],
"ignore_g": stream_data["data"]["g"],
"original_client_order_id": stream_data["data"]["C"],
"current_execution_type": stream_data["data"]["x"],
"current_order_status": stream_data["data"]["X"],
"order_reject_reason": stream_data["data"]["r"],
"order_id": stream_data["data"]["i"],
"last_executed_quantity": stream_data["data"]["l"],
"cumulative_filled_quantity": stream_data["data"]["z"],
"last_executed_price": stream_data["data"]["L"],
"commission_amount": stream_data["data"]["n"],
"commission_asset": stream_data["data"]["N"],
"transaction_time": stream_data["data"]["T"],
"trade_id": stream_data["data"]["t"],
"ignore_I": stream_data["data"]["I"],
"is_order_working": stream_data["data"]["w"],
"is_trade_maker_side": stream_data["data"]["m"],
"ignore_M": stream_data["data"]["M"],
"order_creation_time": stream_data["data"]["O"],
"cumulative_quote_asset_transacted_quantity": stream_data["data"]["Z"],
"last_quote_asset_transacted_quantity": stream_data["data"]["Y"],
}
unicorn_fied_version = [exchange, UnicornFy.get_version()]
unicorn_fied_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
"UnicornFy->binance_com_futures_websocket(" + str(unicorn_fied_data) + ")"
)
return unicorn_fied_data
[docs]
@staticmethod
def binance_futures_websocket(
stream_data_json, exchange="binance.com-futures", show_deprecated_warning=False
):
"""
unicorn_fy binance.com-futures raw_stream_data
:param stream_data_json: The received raw stream data from the Binance websocket
:type stream_data_json: json
:param exchange: Exchange endpoint.
:type exchange: str
:param show_deprecated_warning: Show or hide warning
:type show_deprecated_warning: bool
:return: dict
"""
unicorn_fied_data = {}
logger.debug(
"UnicornFy->binance_futures_websocket(" + str(stream_data_json) + ")"
)
if show_deprecated_warning is True:
pass
if UnicornFy.is_json(stream_data_json) is False:
return stream_data_json
stream_data = json.loads(stream_data_json)
try:
if stream_data[0]["e"] in [
"24hrMiniTicker",
"24hrTicker",
"markPriceUpdate",
"indexPriceUpdate",
]:
stream_data = {"data": {"e": stream_data[0]["e"]}, "items": stream_data}
except KeyError:
pass
try:
if "!ticker@arr" in stream_data["stream"]:
stream_data = {
"data": {"e": "24hrTicker"},
"items": stream_data["data"],
}
elif "!miniTicker@arr" in stream_data["stream"]:
stream_data = {
"data": {"e": "24hrMiniTicker"},
"items": stream_data["data"],
}
elif "!markPriceUpdate@arr" in stream_data["stream"]:
stream_data = {
"data": {"e": "markPriceUpdate"},
"items": stream_data["data"],
}
except KeyError:
pass
try:
if "e" in stream_data and "data" not in stream_data:
stream_data = {"data": stream_data}
except TypeError:
pass
try:
if stream_data["stream"].find("@depth5") != -1:
stream_data["data"]["depth_level"] = 5
elif stream_data["stream"].find("@depth10") != -1:
stream_data["data"]["depth_level"] = 10
elif stream_data["stream"].find("@depth20") != -1:
stream_data["data"]["depth_level"] = 20
elif "@bookTicker" in stream_data["stream"]:
stream_data["data"]["e"] = "bookTicker"
except KeyError:
pass
try:
# return if already unicorn_fied
if stream_data["unicorn_fied"]:
return stream_data
except KeyError:
pass
try:
if stream_data["result"] is None:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_futures_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
else:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_futures_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
except KeyError:
pass
try:
if stream_data["error"]:
unicorn_fied_version = [exchange, UnicornFy.get_version()]
stream_data["unicorn_fied"] = unicorn_fied_version
logger.debug(
f"UnicornFy->binance_futures_websocket({str(stream_data)}, {str(exchange)}"
)
return stream_data
except KeyError:
pass
try:
if stream_data["data"]["e"] == "aggTrade":
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"aggregate_trade_id": stream_data["data"]["a"],
"price": stream_data["data"]["p"],
"quantity": stream_data["data"]["q"],
"first_trade_id": stream_data["data"]["f"],
"last_trade_id": stream_data["data"]["l"],
"trade_time": stream_data["data"]["T"],
"is_market_maker": stream_data["data"]["m"],
}
elif (
stream_data["data"]["e"] == "kline"
or stream_data["data"]["e"] == "continuous_kline"
):
stream_data["data"] = UnicornFy.set_to_false_if_not_exist(
stream_data["data"], "f"
)
stream_data["data"] = UnicornFy.set_to_false_if_not_exist(
stream_data["data"], "L"
)
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"kline": {
"kline_start_time": stream_data["data"]["k"]["t"],
"kline_close_time": stream_data["data"]["k"]["T"],
"interval": stream_data["data"]["k"]["i"],
"first_trade_id": stream_data["data"]["f"],
"last_trade_id": stream_data["data"]["L"],
"open_price": stream_data["data"]["k"]["o"],
"close_price": stream_data["data"]["k"]["c"],
"high_price": stream_data["data"]["k"]["h"],
"low_price": stream_data["data"]["k"]["l"],
"base_volume": stream_data["data"]["k"]["v"],
"number_of_trades": stream_data["data"]["k"]["n"],
"is_closed": stream_data["data"]["k"]["x"],
"quote": stream_data["data"]["k"]["q"],
"taker_by_base_asset_volume": stream_data["data"]["k"]["V"],
"taker_by_quote_asset_volume": stream_data["data"]["k"]["Q"],
},
}
try:
unicorn_fied_data["symbol"] = stream_data["data"]["s"]
unicorn_fied_data["kline"]["symbol"] = stream_data["data"]["k"]["s"]
except KeyError:
unicorn_fied_data["pair"] = stream_data["data"]["ps"]
unicorn_fied_data["contract_type"] = stream_data["data"]["ct"]
elif (
stream_data["data"]["e"] == "indexPrice_kline"
or stream_data["data"]["e"] == "markPrice_kline"
):
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"pair": stream_data["data"]["ps"],
"kline": {
"kline_start_time": stream_data["data"]["k"]["t"],
"kline_close_time": stream_data["data"]["k"]["T"],
"interval": stream_data["data"]["k"]["i"],
"open_price": stream_data["data"]["k"]["o"],
"close_price": stream_data["data"]["k"]["c"],
"high_price": stream_data["data"]["k"]["h"],
"low_price": stream_data["data"]["k"]["l"],
"number_of_basic_data": stream_data["data"]["k"]["n"],
"is_closed": stream_data["data"]["k"]["x"],
},
}
if stream_data["data"]["e"] == "markPrice_kline":
unicorn_fied_data["kline"]["symbol"] = stream_data["data"]["k"]["s"]
elif stream_data["data"]["e"] == "bookTicker":
unicorn_fied_data = {
"stream_type": "bookTicker",
"order_book_update_id": stream_data["data"]["u"],
"symbol": stream_data["data"]["s"],
"best_bid_price": stream_data["data"]["b"],
"best_bid_quantity": stream_data["data"]["B"],
"best_ask_price": stream_data["data"]["a"],
"best_ask_quantity": stream_data["data"]["A"],
"event_type": stream_data["data"]["e"],
}
if "ps" in stream_data["data"]:
unicorn_fied_data["pair"] = stream_data["data"]["ps"]
elif stream_data["data"]["e"] == "indexPriceUpdate":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!indexPrice@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"pair": item["i"],
"index_price": item["p"],
}
unicorn_fied_data["data"].append(data)
except KeyError:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"pair": stream_data["data"]["i"],
"index_price": stream_data["data"]["p"],
}
unicorn_fied_data["data"].append(data)
elif stream_data["data"]["e"] == "markPriceUpdate":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!markPrice@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"symbol": item["s"],
"mark_price": item["p"],
"estimated_settle_price": item["P"],
"funding_rate": item["r"],
"next_funding_time": item["T"],
}
if "i" in item:
data["index_price"] = item["i"]
unicorn_fied_data["data"].append(data)
except KeyError:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"mark_price": stream_data["data"]["p"],
"estimated_settle_price": stream_data["data"]["P"],
"funding_rate": stream_data["data"]["r"],
"next_funding_time": stream_data["data"]["T"],
}
if "i" in stream_data["data"]:
data["index_price"] = stream_data["data"]["i"]
unicorn_fied_data["data"].append(data)
elif stream_data["data"]["e"] == "forceOrder":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#liquidation-order-streams
ex:
{
"e":"forceOrder", // Event Type
"E":1568014460893, // Event Time
"o":{
"s":"BTCUSDT", // Symbol
"S":"SELL", // Side
"o":"LIMIT", // Order Type
"f":"IOC", // Time in Force
"q":"0.014", // Original Quantity
"p":"9910", // Price
"ap":"9910", // Average Price
"X":"FILLED", // Order Status
"l":"0.014", // Order Last Filled Quantity
"z":"0.014", // Order Filled Accumulated Quantity
"T":1568014460893, // Order Trade Time
}
}
"""
unicorn_fied_data = {
"stream_type": "forceOrder",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["o"]["s"],
"side": stream_data["data"]["o"]["S"],
"order_type": stream_data["data"]["o"]["o"],
"time_in_force": stream_data["data"]["o"]["f"],
"original_quantity": stream_data["data"]["o"]["q"],
"price": stream_data["data"]["o"]["p"],
"avg_price": stream_data["data"]["o"]["ap"],
"order_status": stream_data["data"]["o"]["X"],
"last_executed_quantity": stream_data["data"]["o"]["l"],
"cumulative_filled_quantity": stream_data["data"]["o"]["z"],
"transaction_time": stream_data["data"]["o"]["T"],
}
if "ps" in stream_data["data"]["o"]:
unicorn_fied_data["pair"] = stream_data["data"]["o"]["ps"]
elif stream_data["data"]["e"] == "compositeIndex":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#composite-index-symbol-information-streams
ex:
{
"e":"compositeIndex", // Event type
"E":1602310596000, // Event time
"s":"DEFIUSDT", // Symbol
"p":"554.41604065", // Price
"C":"baseAsset",
"c":[ // Composition
{
"b":"BAL", // Base asset
"q":"USDT", // Quote asset
"w":"1.04884844", // Weight in quantity
"W":"0.01457800", // Weight in percentage
"i":"24.33521021" // Index price
},
{
"b":"BAND",
"q":"USDT" ,
"w":"3.53782729",
"W":"0.03935200",
"i":"7.26420084"
}
]
}
"""
unicorn_fied_data = {
"stream_type": "compositeIndex",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"price": stream_data["data"]["p"],
"composition": [],
}
for item in stream_data["data"]["c"]:
data = {
"base_asset": item["b"],
"quote_asset": item["q"],
"weight_quantity": item["w"],
"weight_percentage": item["W"],
"index_price": item["i"],
}
unicorn_fied_data["composition"].append(data)
elif stream_data["data"]["e"] == "24hrMiniTicker":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!miniTicker@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"symbol": item["s"],
"close_price": item["c"],
"open_price": item["o"],
"high_price": item["h"],
"low_price": item["l"],
"total_traded_base_asset_volume": item["v"],
"total_traded_quote_asset_volume": item["q"],
}
if "ps" in item:
data["pair"] = item["ps"]
unicorn_fied_data["data"].append(data)
except KeyError:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"close_price": stream_data["data"]["c"],
"open_price": stream_data["data"]["o"],
"high_price": stream_data["data"]["h"],
"low_price": stream_data["data"]["l"],
"total_traded_base_asset_volume": stream_data["data"]["v"],
"total_traded_quote_asset_volume": stream_data["data"]["q"],
}
if "ps" in stream_data["data"]:
data["pair"] = stream_data["data"]["ps"]
unicorn_fied_data["data"].append(data)
elif stream_data["data"]["e"] == "24hrTicker":
try:
if stream_data["stream"]:
pass
except KeyError:
stream_data["stream"] = "!ticker@arr"
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"data": [],
}
try:
for item in stream_data["items"]:
data = {
"stream_type": stream_data["stream"],
"event_type": item["e"],
"event_time": item["E"],
"symbol": item["s"],
"price_change": item["p"],
"price_change_percent": item["P"],
"weighted_average_price": item["w"],
"last_price": item["c"],
"last_quantity": item["Q"],
"open_price": item["o"],
"high_price": item["h"],
"low_price": item["l"],
"total_traded_base_asset_volume": item["v"],
"total_traded_quote_asset_volume": item["q"],
"statistics_open_time": item["O"],
"statistics_close_time": item["C"],
"first_trade_id": item["F"],
"last_trade_id": item["L"],
"total_nr_of_trades": item["n"],
}
if "ps" in item:
data["pair"] = item["ps"]
unicorn_fied_data["data"].append(data)
except KeyError:
data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["s"],
"price_change": stream_data["data"]["p"],
"price_change_percent": stream_data["data"]["P"],
"weighted_average_price": stream_data["data"]["w"],
"last_price": stream_data["data"]["c"],
"last_quantity": stream_data["data"]["Q"],
"open_price": stream_data["data"]["o"],
"high_price": stream_data["data"]["h"],
"low_price": stream_data["data"]["l"],
"total_traded_base_asset_volume": stream_data["data"]["v"],
"total_traded_quote_asset_volume": stream_data["data"]["q"],
"statistics_open_time": stream_data["data"]["O"],
"statistics_close_time": stream_data["data"]["C"],
"first_trade_id": stream_data["data"]["F"],
"last_trade_id": stream_data["data"]["L"],
"total_nr_of_trades": stream_data["data"]["n"],
}
if "ps" in stream_data["data"]:
data["pair"] = stream_data["data"]["ps"]
unicorn_fied_data["data"].append(data)
elif stream_data["data"]["e"] == "depthUpdate":
stream_data["data"] = UnicornFy.set_to_false_if_not_exist(
stream_data["data"], "depth_level"
)
unicorn_fied_data = {
"stream_type": stream_data["stream"],
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"transaction_time": stream_data["data"]["T"],
"symbol": stream_data["data"]["s"],
"depth_level": stream_data["data"]["depth_level"],
"first_update_id_in_event": stream_data["data"]["U"],
"final_update_id_in_event": stream_data["data"]["u"],
"final_update_id_in_previous_event": stream_data["data"]["pu"],
"asks": stream_data["data"]["a"],
"bids": stream_data["data"]["b"],
}
if "ps" in stream_data["data"]:
unicorn_fied_data["pair"] = stream_data["data"]["ps"]
elif stream_data["data"]["e"] == "ORDER_TRADE_UPDATE":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#event-order-update
ex:
{
"e":"ORDER_TRADE_UPDATE", // Event Type
"E":1568879465651, // Event Time
"T":1568879465650, // Transaction Time
"o":{
"s":"BTCUSDT", // Symbol
"c":"TEST", // Client Order Id
// special client order id:
// starts with "autoclose-": liquidation order
// "adl_autoclose": ADL auto close order
"S":"SELL", // Side
"o":"TRAILING_STOP_MARKET", // Order Type
"f":"GTC", // Time in Force
"q":"0.001", // Original Quantity
"p":"0", // Original Price
"ap":"0", // Average Price
"sp":"7103.04", // Stop Price. Please ignore with TRAILING_STOP_MARKET order
"x":"NEW", // Execution Type
"X":"NEW", // Order Status
"i":8886774, // Order Id
"l":"0", // Order Last Filled Quantity
"z":"0", // Order Filled Accumulated Quantity
"L":"0", // Last Filled Price
"N":"USDT", // Commission Asset, will not push if no commission
"n":"0", // Commission, will not push if no commission
"T":1568879465651, // Order Trade Time
"t":0, // Trade Id
"b":"0", // Bids Notional
"a":"9.91", // Ask Notional
"m":false, // Is this trade the maker side?
"R":false, // Is this reduce only
"wt":"CONTRACT_PRICE", // Stop Price Working Type
"ot":"TRAILING_STOP_MARKET", // Original Order Type
"ps":"LONG", // Position Side
"cp":false, // If Close-All, pushed with conditional order
"AP":"7476.89", // Activation Price, only puhed with TRAILING_STOP_MARKET order
"cr":"5.0", // Callback Rate, only puhed with TRAILING_STOP_MARKET order
"rp":"0" // Realized Profit of the trade
}
}
"""
unicorn_fied_data = {
"stream_type": "ORDER_TRADE_UPDATE",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["o"]["s"], # Symbol
"client_order_id": stream_data["data"]["o"]["c"], # Client Order Id
"side": stream_data["data"]["o"]["S"], # Side
"order_type": stream_data["data"]["o"]["o"], # Order Type
"time_in_force": stream_data["data"]["o"]["f"], # Time in Force
"order_quantity": stream_data["data"]["o"][
"q"
], # Original Quantity
"order_price": stream_data["data"]["o"]["p"], # Original Price
"order_avg_price": stream_data["data"]["o"]["ap"], # Average Price
"order_stop_price": stream_data["data"]["o"]["sp"], # Stop Price.
"current_execution_type": stream_data["data"]["o"][
"x"
], # Execution Type
"current_order_status": stream_data["data"]["o"][
"X"
], # Order Status
"order_id": stream_data["data"]["o"]["i"], # Order Id
"last_executed_quantity": stream_data["data"]["o"]["l"],
"cumulative_filled_quantity": stream_data["data"]["o"]["z"],
"last_executed_price": stream_data["data"]["o"][
"L"
], # Last Filled Price
"transaction_time": stream_data["data"]["o"][
"T"
], # Order Trade Time
"trade_id": stream_data["data"]["o"]["t"], # Trade Id
"net_pay": stream_data["data"]["o"]["b"], # Ask Notional
"net_selling_order_value": stream_data["data"]["o"][
"a"
], # Ask Notional
"is_trade_maker_side": stream_data["data"]["o"]["m"],
"reduce_only": stream_data["data"]["o"]["R"], # Is this reduce only
"trigger_price_type": stream_data["data"]["o"][
"wt"
], # Stop Price Working Type
"order_price_type": stream_data["data"]["o"][
"ot"
], # Original Order Type
"position_side": stream_data["data"]["o"]["ps"],
"order_realized_profit": stream_data["data"]["o"]["rp"],
} # Realized Profit
if "i" in stream_data["data"]:
unicorn_fied_data["account_alias"] = stream_data["data"]["i"]
if "ma" in stream_data["data"]["o"]:
unicorn_fied_data["margin_asset"] = stream_data["data"]["o"]["ma"]
if "N" in stream_data["data"]["o"]:
unicorn_fied_data["commission_asset"] = stream_data["data"]["o"][
"N"
]
if "n" in stream_data["data"]["o"]:
unicorn_fied_data["commission"] = stream_data["data"]["o"]["n"]
if "cp" in stream_data["data"]["o"]:
unicorn_fied_data["close_all"] = stream_data["data"]["o"]["cp"]
if "AP" in stream_data["data"]["o"]:
unicorn_fied_data["activation_price"] = stream_data["data"]["o"][
"AP"
]
if "cr" in stream_data["data"]["o"]:
unicorn_fied_data["callback_rate"] = stream_data["data"]["o"]["cr"]
elif stream_data["data"]["e"] == "ACCOUNT_UPDATE":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#event-balance-and-position-update
ex:
{
"e": "ACCOUNT_UPDATE", // Event Type
"E": 1564745798939, // Event Time
"T": 1564745798938 , // Transaction
"a": // Update Data
{
"m":"ORDER", // Event reason type
"B":[ // Balances
{
"a":"USDT", // Asset
"wb":"122624.12345678", // Wallet Balance
"cw":"100.12345678" // Cross Wallet Balance
},
{
"a":"BNB",
"wb":"1.00000000",
"cw":"0.00000000"
}
],
"P":[
{
"s":"BTCUSDT", // Symbol
"pa":"0", // Position Amount
"ep":"0.00000", // Entry Price
"cr":"200", // (Pre-fee) Accumulated Realized
"up":"0", // Unrealized PnL
"mt":"isolated", // Margin Type
"iw":"0.00000000", // Isolated Wallet (if isolated position)
"ps":"BOTH" // Position Side
},
{
"s":"BTCUSDT",
"pa":"20",
"ep":"6563.66500",
"cr":"0",
"up":"2850.21200",
"mt":"isolated",
"iw":"13200.70726908",
"ps":"LONG"
},
{
"s":"BTCUSDT",
"pa":"-10",
"ep":"6563.86000",
"cr":"-45.04000000",
"up":"-1423.15600",
"mt":"isolated",
"iw":"6570.42511771",
"ps":"SHORT"
}
]
}
}
"""
unicorn_fied_data = {
"stream_type": "ACCOUNT_UPDATE",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"transaction": stream_data["data"]["T"],
"event_reason": stream_data["data"]["a"]["m"],
"balances": [],
"positions": [],
}
if "i" in stream_data["data"]:
unicorn_fied_data["account_alias"] = stream_data["data"]["i"]
for balance in stream_data["data"]["a"]["B"]:
data = {
"asset": balance["a"],
"wallet_balance": balance["wb"],
"cross_wallet_balance": balance["cw"],
}
if "bc" in balance:
data["balance_change"] = balance["bc"]
unicorn_fied_data["balances"].append(data)
for position in stream_data["data"]["a"]["P"]:
unicorn_fied_data["positions"].append(
{
"symbol": position["s"],
"position_amount": position["pa"],
"entry_price": position["ep"],
"accumulated_realized": position["cr"],
"upnl": position["up"],
"margin_type": position["mt"],
"isolated_wallet": position["iw"],
"position_side": position["ps"],
}
)
elif stream_data["data"]["e"] == "MARGIN_CALL":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#event-margin-call
ex: {
"e":"MARGIN_CALL", // Event Type
"E":1587727187525, // Event Time
"cw":"3.16812045", // Cross Wallet Balance. Only pushed with crossed position margin call
"p":[ // Position(s) of Margin Call
{
"s":"ETHUSDT", // Symbol
"ps":"LONG", // Position Side
"pa":"1.327", // Position Amount
"mt":"CROSSED", // Margin Type
"iw":"0", // Isolated Wallet (if isolated position)
"mp":"187.17127", // Mark Price
"up":"-1.166074", // Unrealized PnL
"mm":"1m,n.614445" // Maintenance Margin Required
}
]
}
"""
unicorn_fied_data = {
"stream_type": "MARGIN_CALL",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"positions": [],
}
if "i" in stream_data["data"]:
unicorn_fied_data["account_alias"] = stream_data["data"]["i"]
if "cw" in stream_data["data"]:
unicorn_fied_data["cross_wallet"] = stream_data["data"]["cw"]
for position in stream_data["data"]["p"]:
data = {
"symbol": position["s"],
"side": position["ps"],
"amount": position["pa"],
"type": position["mt"],
"price": position["mp"],
"pnl": position["up"],
"margin": position["mm"],
}
if "iw" in position:
unicorn_fied_data["isolated_wallet"] = position["iw"]
unicorn_fied_data["positions"].append(data)
elif stream_data["data"]["e"] == "ACCOUNT_CONFIG_UPDATE":
"""
url: https://binance-docs.github.io/apidocs/futures/en/#event-order-update
ex:
{
"e":"ACCOUNT_CONFIG_UPDATE", // Event Type
"E":1611646737479, // Event Time
"T":1611646737476, // Transaction Time
"ac":{
"s":"BTCUSDT", // symbol
"l":25 // leverage
}
}
or:
{
"e":"ACCOUNT_CONFIG_UPDATE", // Event Type
"E":1611646737479, // Event Time
"T":1611646737476, // Transaction Time
"ai":{ // User's Account Configuration
"j":true // Multi-Assets Mode
}
}
"""
if "ac" in stream_data["data"]:
unicorn_fied_data = {
"stream_type": "ACCOUNT_CONFIG_UPDATE",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"symbol": stream_data["data"]["ac"]["s"],
"leverage": stream_data["data"]["ac"]["l"],
}
else:
unicorn_fied_data = {
"stream_type": "ACCOUNT_CONFIG_UPDATE",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"multi_assets_mode": stream_data["data"]["ai"]["j"],
}
elif stream_data["data"]["e"] == "TRADE_LITE":
unicorn_fied_data = {
"stream_type": "TRADE_LITE",
"event_type": stream_data["data"]["e"],
"event_time": stream_data["data"]["E"],
"transaction_time": stream_data["data"]["T"],
"symbol": stream_data["data"]["s"],
"client_order_id": stream_data["data"]["c"],
"side": stream_data["data"]["S"],
"order_quantity": stream_data["data"]["q"],
"order_price": stream_data["data"]["p"],
"last_executed_quantity": stream_data["data"]["l"],
"last_executed_price": stream_data["data"]["L"],
"trade_id": stream_data["data"]["t"],
"order_id": stream_data["data"]["i"],
"is_trade_maker_side": stream_data["data"]["m"],
}
except TypeError as error_msg:
logger.critical(
f"UnicornFy->binance_futures_websocket({str(unicorn_fied_data)}) - "
f"error: {str(error_msg)} - Variable: {stream_data['data']}"
)
except KeyError as error_msg:
logger.critical(
f"UnicornFy->binance_futures_websocket({str(unicorn_fied_data)}) - "
f"error: {str(error_msg)} - Variable: {stream_data['data']}"
)
unicorn_fied_version = [exchange, UnicornFy.get_version()]
try:
unicorn_fied_data["unicorn_fied"] = unicorn_fied_version
except TypeError as error_msg:
logger.critical(
f"UnicornFy->binance_futures_websocket({str(unicorn_fied_data)}) - "
f"error: {str(error_msg)} - Variable: {stream_data['data']}"
)
logger.debug(
"UnicornFy->binance_futures_websocket(" + str(unicorn_fied_data) + ")"
)
return unicorn_fied_data
[docs]
@staticmethod
def get_latest_release_info():
"""
Get infos about the latest available release
:return: dict or False
"""
try:
respond = requests.get(
"https://api.github.com/repos/oliver-zehentleitner/unicorn-fy/releases/latest"
)
return respond.json()
except Exception:
return False
[docs]
def get_latest_version(self) -> Optional[str]:
"""
Get the version of the latest available release (cache time 1 hour)
:return: str or False
"""
# Do a fresh request if status is not a dict, has no tag_name, or last timestamp is older 1 hour
if (
not isinstance(self.last_update_check_github["status"], dict)
or self.last_update_check_github["status"].get("tag_name") is None
or (self.last_update_check_github["timestamp"] + (60 * 60) < time.time())
):
self.last_update_check_github["status"] = self.get_latest_release_info()
if (
isinstance(self.last_update_check_github["status"], dict)
and self.last_update_check_github["status"]
):
try:
return self.last_update_check_github["status"]["tag_name"]
except KeyError:
return "unknown"
else:
return "unknown"
[docs]
@staticmethod
def get_version():
"""
Get the package/module version
:return: str
"""
return __version__
[docs]
@staticmethod
def is_json(data):
"""
Is the string in json format?
:param data: the data to verify
:type data: str
:return: True or False
:rtype: bool
"""
try:
json.loads(data)
except ValueError:
return False
except TypeError:
return False
return True
[docs]
def is_update_available(self):
"""
Is a new release of this package available?
:return: bool
"""
installed_version = self.get_version()
latest_version = self.get_latest_version()
if ".dev" in installed_version:
installed_version = installed_version[:-4]
if latest_version == installed_version:
return False
elif latest_version == "unknown":
return False
else:
return True
[docs]
@staticmethod
def set_to_false_if_not_exist(value, key):
"""
some vars are non existent if they would be empty, so we create the missing vars with default values
:param value: default value
:type value: str
:param key: the key name
:type key: str
:return: final value
:rtype: str
"""
try:
if value[key]:
return value
except KeyError:
value[key] = False
return value
except IndexError:
value[key] = False
return value