Детальная информация по торговым парам с биржи Bybit в приложении Flet Python

GetCoder.ru
Изображение статьи

Создание пользовательского интерфейса для отображения детальной информация по торговым парам с биржи Bybit в приложении Flet Python.

В продолжении статьи Приложение на Flet Python для отображения актуальных цен с биржи Bybit мы добавили возможность более детального просмотра информации по торговым парам. Теперь при нажатии на торговую пару открывается сцена с информацией по каждой торговой паре, которая также обновляется в режиме реального времени.
  • Последняя цена
  • Самая высокая цена за 24 часа
  • Самая низкая цена за 24 часа
  • Процентное изменение рыночной цены
  • Объем за 24 часа
  • Оборот за 24 часа

Код

  • copy
# -*- coding: utf-8 -*- import flet as ft import time, websocket, json, threading, requests, re from functools import partial sybolsList = {} class bybit(): def __init__(self): try: self.mTickers = {} self.ticker_socket = {} self.start() except Exception as e: print(e) # Данные от сокета def on_message(self, _wsa, wsData, prm): varData = json.loads(wsData) if 'op' in varData: if varData['op'] == 'subscribe' and varData['success'] == False: mPairs = re.findall(r'\[([^]]*)\]', varData['ret_msg']) for elem in mPairs: del(self.ticker_socket[prm['key']]['listPair'][elem]) if len(self.ticker_socket[prm['key']]['listPair']) == 0: self.ticker_socket[prm['key']]['exit'] = 'true' self.ticker_socket[prm['key']]['status'] = 'off' _wsa.close() else: self.mTickers[varData['data']['symbol']] = varData['data'] # Отлов ошибок/выключения сокета def on_close(self, _wsa, wsData, prm): _wsa.close() self.ticker_socket[prm['key']]['status'] = 'off' # Открытие соединения def on_open(self, _wsa, prm): try: args = list(self.ticker_socket[prm['key']]['listPair'].values()) _wsa.send(json.dumps({"op": "subscribe", "args": args})) except Exception as e: _wsa.close() # Запуск сокета def runWebSockPl(self, key): while True: try: wss = 'wss://stream.bybit.com/v5/public/spot' wsa = websocket.WebSocketApp(wss, on_open = partial(self.on_open, prm={'key': key}), on_message = partial(self.on_message, prm={'key': key}), on_error = partial(self.on_close, prm={'key': key}), on_close = partial(self.on_close, prm={'key': key})) self.ticker_socket[key]['connect'] = wsa self.ticker_socket[key]['status'] = 'on' print(u'Установлено соединение Web Socket ключ '+key) wsa.run_forever() if self.ticker_socket[key]['exit'] == 'true': break raise Exception('Exit') except Exception as e: print(u'Разрыв соединения Web Socket ключ '+key) self.ticker_socket[key]['status'] = 'off' time.sleep(10) def start(self): response = requests.get("https://api.bybit.com/v5/market/instruments-info?category=spot") data = response.json() i = 1 listPair = {} for elem in data['result']['list']: listPair['tickers.'+elem['symbol']] = 'tickers.'+elem['symbol'] if len(listPair) >= 10: key = str(i) self.ticker_socket[key] = {'connect': '', 'status': 'off', 'exit': 'false', 'listPair': listPair} listPair = {} ws = threading.Thread(target=self.runWebSockPl, kwargs={'key': key}, daemon=True) ws.start() i = i + 1 if len(listPair) > 0: key = str(i) self.ticker_socket[key] = {'connect': '', 'status': 'off', 'exit': 'false', 'listPair': listPair} ws = threading.Thread(target=self.runWebSockPl, kwargs={'key': key}, daemon=True) ws.start() def main(page: ft.Page): # Обновление торговых пар def update_data_pair(): while True: time.sleep(1) for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].bgcolor = None det_title_con.bgcolor = None for keyElem, dataElem in bb.mTickers.items(): if keyElem in sybolsList: if mPage['detailed']['container'].visible == True: if det_title.value == keyElem: det_lastPrice.value = dataElem['lastPrice'] det_highPrice24h.value = dataElem['highPrice24h'] det_lowPrice24h.value = dataElem['lowPrice24h'] det_prevPrice24h.value = dataElem['prevPrice24h'] det_volume24h.value = dataElem['volume24h'] det_turnover24h.value = dataElem['turnover24h'] if float(dataElem['lastPrice']) > float(sybolsList[keyElem]['lastPrice']): det_title_con.bgcolor = ft.colors.GREEN_700 if float(dataElem['lastPrice']) < float(sybolsList[keyElem]['lastPrice']): det_title_con.bgcolor = ft.colors.RED sybolsList[keyElem]['text'].value = keyElem+' '+str(dataElem['lastPrice']) if float(dataElem['lastPrice']) > float(sybolsList[keyElem]['lastPrice']): sybolsList[keyElem]['container'].bgcolor = ft.colors.GREEN_700 if float(dataElem['lastPrice']) < float(sybolsList[keyElem]['lastPrice']): sybolsList[keyElem]['container'].bgcolor = ft.colors.RED sybolsList[keyElem]['lastPrice'] = float(dataElem['lastPrice']) page.update() # Нижнее меню def bottom_menu(e): if e.control.selected_index == 0: mPage['main']['container'].visible = True mPage['detailed']['container'].visible = False formSearch.visible = True page.update() # Детальная информация def detailed_open(symbol): if symbol in bb.mTickers: det_title.value = symbol det_lastPrice.value = bb.mTickers[symbol]['lastPrice'] det_highPrice24h.value = bb.mTickers[symbol]['highPrice24h'] det_lowPrice24h.value = bb.mTickers[symbol]['lowPrice24h'] det_prevPrice24h.value = bb.mTickers[symbol]['prevPrice24h'] det_volume24h.value = bb.mTickers[symbol]['volume24h'] det_turnover24h.value = bb.mTickers[symbol]['turnover24h'] mPage['detailed']['container'].visible = True mPage['main']['container'].visible = False formSearch.visible = False page.update() # Филтрация списка def filter_proccess(e): serchVar = search.value.upper() for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].visible = False if serchVar in keyElem: sybolsList[keyElem]['container'].visible = True page.update() # Отмена фильтрации def clear_filter(e): search.value = '' for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].visible = True page.update() # Генерация главной страницы def main_page(): response = requests.get("https://api.bybit.com/v5/market/instruments-info?category=spot") data = response.json() lastPrice = 0.00000000 rv = ft.ResponsiveRow([]) for elem in data['result']['list']: var_text = ft.Text(elem['symbol']+' '+str(lastPrice)) var_elem = ft.Container( ft.CupertinoButton( content=var_text, opacity_on_click=0.3, on_click=lambda e, symbol=elem['symbol']: detailed_open(symbol), color="black" ), padding=5, col={"sm": 6, "md": 4, "xl": 2}, border = ft.border.all(1, ft.colors.PRIMARY) ) sybolsList[elem['symbol']] = {'container': var_elem, 'text': var_text, 'lastPrice': lastPrice} rv.controls.append(var_elem) mPage['main']['container'].controls.append(rv) page.update() # Деальная информация det_title = ft.Text("--/--", size = 50, weight = ft.FontWeight.BOLD) det_title_con = ft.Container(det_title,padding = 10, alignment=ft.alignment.center, border = ft.border.all(1, ft.colors.PRIMARY)) det_lastPrice = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_highPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_lowPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_prevPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_volume24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_turnover24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) mPage = { 'main': {'container': ft.ListView(expand = 1, spacing = 10, padding = 10)}, 'detailed': {'container': ft.ResponsiveRow([ det_title_con, ft.Row([ft.Text("Последняя цена: ", size = 20), det_lastPrice]), ft.Row([ft.Text("Самая высокая цена за 24 часа: ", size = 20), det_highPrice24h]), ft.Row([ft.Text("Самая низкая цена за 24 часа: ", size = 20), det_lowPrice24h]), ft.Row([ft.Text("Процентное изменение рыночной цены: ", size = 20), det_prevPrice24h]), ft.Row([ft.Text("Объем за 24 часа: ", size = 20), det_volume24h]), ft.Row([ft.Text("Оборот за 24 часа: ", size = 20), det_turnover24h]) ])} } mPage['main']['container'].visible = True mPage['detailed']['container'].visible = False # Фильтр search = ft.TextField(label="Поиск", on_change=filter_proccess) searchContainer = ft.Container(search ,padding=10) btnFilter = ft.IconButton(ft.icons.FILTER_ALT_OFF, icon_size=30,tooltip = "Отмена фильтра", on_click = clear_filter) formSearch = ft.Row([searchContainer, btnFilter]) # Верхнее меню page.appbar = ft.AppBar( title=ft.Text("Bybit - торговые пары"), center_title=False, bgcolor=ft.colors.SURFACE_VARIANT, actions=[formSearch], ) # Нижнее меню page.navigation_bar = ft.CupertinoNavigationBar( bgcolor=ft.colors.SURFACE_VARIANT, #color="black", on_change=lambda e: bottom_menu(e), destinations=[ft.NavigationBarDestination(icon=ft.icons.HOME_ROUNDED, label="Main")] ) page.add(mPage['main']['container'], mPage['detailed']['container']) # Генерация главной страницы ws = threading.Thread(target = main_page, daemon=True) ws.start() # Запуск ws bb = bybit() # Запуск обновления торговых пар ws = threading.Thread(target = update_data_pair, daemon=True) ws.start() ft.app(target=main)
Исходный код

Заключение

В этом примере мы продемонстрировали, как можно реализовать несколько сцен в Python Flet. Также было показано, как можно обновлять элементы сцены в режиме реального времени.

  • 13.08.2024
  • 27
  • 0

Детальная информация по торговым парам с биржи Bybit в приложении Flet Python

В продолжении статьи Приложение на Flet Python для отображения актуальных цен с биржи Bybit мы добавили возможность более детального просмотра информации по торговым парам. Теперь при нажатии на торговую пару открывается сцена с информацией по каждой торговой паре, которая также обновляется в режиме реального времени.
  • Последняя цена
  • Самая высокая цена за 24 часа
  • Самая низкая цена за 24 часа
  • Процентное изменение рыночной цены
  • Объем за 24 часа
  • Оборот за 24 часа

Код

  • copy
# -*- coding: utf-8 -*- import flet as ft import time, websocket, json, threading, requests, re from functools import partial sybolsList = {} class bybit(): def __init__(self): try: self.mTickers = {} self.ticker_socket = {} self.start() except Exception as e: print(e) # Данные от сокета def on_message(self, _wsa, wsData, prm): varData = json.loads(wsData) if 'op' in varData: if varData['op'] == 'subscribe' and varData['success'] == False: mPairs = re.findall(r'\[([^]]*)\]', varData['ret_msg']) for elem in mPairs: del(self.ticker_socket[prm['key']]['listPair'][elem]) if len(self.ticker_socket[prm['key']]['listPair']) == 0: self.ticker_socket[prm['key']]['exit'] = 'true' self.ticker_socket[prm['key']]['status'] = 'off' _wsa.close() else: self.mTickers[varData['data']['symbol']] = varData['data'] # Отлов ошибок/выключения сокета def on_close(self, _wsa, wsData, prm): _wsa.close() self.ticker_socket[prm['key']]['status'] = 'off' # Открытие соединения def on_open(self, _wsa, prm): try: args = list(self.ticker_socket[prm['key']]['listPair'].values()) _wsa.send(json.dumps({"op": "subscribe", "args": args})) except Exception as e: _wsa.close() # Запуск сокета def runWebSockPl(self, key): while True: try: wss = 'wss://stream.bybit.com/v5/public/spot' wsa = websocket.WebSocketApp(wss, on_open = partial(self.on_open, prm={'key': key}), on_message = partial(self.on_message, prm={'key': key}), on_error = partial(self.on_close, prm={'key': key}), on_close = partial(self.on_close, prm={'key': key})) self.ticker_socket[key]['connect'] = wsa self.ticker_socket[key]['status'] = 'on' print(u'Установлено соединение Web Socket ключ '+key) wsa.run_forever() if self.ticker_socket[key]['exit'] == 'true': break raise Exception('Exit') except Exception as e: print(u'Разрыв соединения Web Socket ключ '+key) self.ticker_socket[key]['status'] = 'off' time.sleep(10) def start(self): response = requests.get("https://api.bybit.com/v5/market/instruments-info?category=spot") data = response.json() i = 1 listPair = {} for elem in data['result']['list']: listPair['tickers.'+elem['symbol']] = 'tickers.'+elem['symbol'] if len(listPair) >= 10: key = str(i) self.ticker_socket[key] = {'connect': '', 'status': 'off', 'exit': 'false', 'listPair': listPair} listPair = {} ws = threading.Thread(target=self.runWebSockPl, kwargs={'key': key}, daemon=True) ws.start() i = i + 1 if len(listPair) > 0: key = str(i) self.ticker_socket[key] = {'connect': '', 'status': 'off', 'exit': 'false', 'listPair': listPair} ws = threading.Thread(target=self.runWebSockPl, kwargs={'key': key}, daemon=True) ws.start() def main(page: ft.Page): # Обновление торговых пар def update_data_pair(): while True: time.sleep(1) for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].bgcolor = None det_title_con.bgcolor = None for keyElem, dataElem in bb.mTickers.items(): if keyElem in sybolsList: if mPage['detailed']['container'].visible == True: if det_title.value == keyElem: det_lastPrice.value = dataElem['lastPrice'] det_highPrice24h.value = dataElem['highPrice24h'] det_lowPrice24h.value = dataElem['lowPrice24h'] det_prevPrice24h.value = dataElem['prevPrice24h'] det_volume24h.value = dataElem['volume24h'] det_turnover24h.value = dataElem['turnover24h'] if float(dataElem['lastPrice']) > float(sybolsList[keyElem]['lastPrice']): det_title_con.bgcolor = ft.colors.GREEN_700 if float(dataElem['lastPrice']) < float(sybolsList[keyElem]['lastPrice']): det_title_con.bgcolor = ft.colors.RED sybolsList[keyElem]['text'].value = keyElem+' '+str(dataElem['lastPrice']) if float(dataElem['lastPrice']) > float(sybolsList[keyElem]['lastPrice']): sybolsList[keyElem]['container'].bgcolor = ft.colors.GREEN_700 if float(dataElem['lastPrice']) < float(sybolsList[keyElem]['lastPrice']): sybolsList[keyElem]['container'].bgcolor = ft.colors.RED sybolsList[keyElem]['lastPrice'] = float(dataElem['lastPrice']) page.update() # Нижнее меню def bottom_menu(e): if e.control.selected_index == 0: mPage['main']['container'].visible = True mPage['detailed']['container'].visible = False formSearch.visible = True page.update() # Детальная информация def detailed_open(symbol): if symbol in bb.mTickers: det_title.value = symbol det_lastPrice.value = bb.mTickers[symbol]['lastPrice'] det_highPrice24h.value = bb.mTickers[symbol]['highPrice24h'] det_lowPrice24h.value = bb.mTickers[symbol]['lowPrice24h'] det_prevPrice24h.value = bb.mTickers[symbol]['prevPrice24h'] det_volume24h.value = bb.mTickers[symbol]['volume24h'] det_turnover24h.value = bb.mTickers[symbol]['turnover24h'] mPage['detailed']['container'].visible = True mPage['main']['container'].visible = False formSearch.visible = False page.update() # Филтрация списка def filter_proccess(e): serchVar = search.value.upper() for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].visible = False if serchVar in keyElem: sybolsList[keyElem]['container'].visible = True page.update() # Отмена фильтрации def clear_filter(e): search.value = '' for keyElem, dataElem in sybolsList.items(): sybolsList[keyElem]['container'].visible = True page.update() # Генерация главной страницы def main_page(): response = requests.get("https://api.bybit.com/v5/market/instruments-info?category=spot") data = response.json() lastPrice = 0.00000000 rv = ft.ResponsiveRow([]) for elem in data['result']['list']: var_text = ft.Text(elem['symbol']+' '+str(lastPrice)) var_elem = ft.Container( ft.CupertinoButton( content=var_text, opacity_on_click=0.3, on_click=lambda e, symbol=elem['symbol']: detailed_open(symbol), color="black" ), padding=5, col={"sm": 6, "md": 4, "xl": 2}, border = ft.border.all(1, ft.colors.PRIMARY) ) sybolsList[elem['symbol']] = {'container': var_elem, 'text': var_text, 'lastPrice': lastPrice} rv.controls.append(var_elem) mPage['main']['container'].controls.append(rv) page.update() # Деальная информация det_title = ft.Text("--/--", size = 50, weight = ft.FontWeight.BOLD) det_title_con = ft.Container(det_title,padding = 10, alignment=ft.alignment.center, border = ft.border.all(1, ft.colors.PRIMARY)) det_lastPrice = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_highPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_lowPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_prevPrice24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_volume24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) det_turnover24h = ft.Text("0.00000000", size = 20, weight = ft.FontWeight.BOLD) mPage = { 'main': {'container': ft.ListView(expand = 1, spacing = 10, padding = 10)}, 'detailed': {'container': ft.ResponsiveRow([ det_title_con, ft.Row([ft.Text("Последняя цена: ", size = 20), det_lastPrice]), ft.Row([ft.Text("Самая высокая цена за 24 часа: ", size = 20), det_highPrice24h]), ft.Row([ft.Text("Самая низкая цена за 24 часа: ", size = 20), det_lowPrice24h]), ft.Row([ft.Text("Процентное изменение рыночной цены: ", size = 20), det_prevPrice24h]), ft.Row([ft.Text("Объем за 24 часа: ", size = 20), det_volume24h]), ft.Row([ft.Text("Оборот за 24 часа: ", size = 20), det_turnover24h]) ])} } mPage['main']['container'].visible = True mPage['detailed']['container'].visible = False # Фильтр search = ft.TextField(label="Поиск", on_change=filter_proccess) searchContainer = ft.Container(search ,padding=10) btnFilter = ft.IconButton(ft.icons.FILTER_ALT_OFF, icon_size=30,tooltip = "Отмена фильтра", on_click = clear_filter) formSearch = ft.Row([searchContainer, btnFilter]) # Верхнее меню page.appbar = ft.AppBar( title=ft.Text("Bybit - торговые пары"), center_title=False, bgcolor=ft.colors.SURFACE_VARIANT, actions=[formSearch], ) # Нижнее меню page.navigation_bar = ft.CupertinoNavigationBar( bgcolor=ft.colors.SURFACE_VARIANT, #color="black", on_change=lambda e: bottom_menu(e), destinations=[ft.NavigationBarDestination(icon=ft.icons.HOME_ROUNDED, label="Main")] ) page.add(mPage['main']['container'], mPage['detailed']['container']) # Генерация главной страницы ws = threading.Thread(target = main_page, daemon=True) ws.start() # Запуск ws bb = bybit() # Запуск обновления торговых пар ws = threading.Thread(target = update_data_pair, daemon=True) ws.start() ft.app(target=main)
Исходный код

Заключение

В этом примере мы продемонстрировали, как можно реализовать несколько сцен в Python Flet. Также было показано, как можно обновлять элементы сцены в режиме реального времени.