From cb436048d2b3955b714dec9d2d7157eabba4ec32 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:10:24 -0300 Subject: [PATCH 01/29] OpenInterest imports for cryptofeed --- piker/brokers/deribit/api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index f846a5c0..10736083 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -52,12 +52,14 @@ from cryptofeed import FeedHandler from cryptofeed.defines import ( DERIBIT, L1_BOOK, TRADES, - OPTION, CALL, PUT + OPTION, CALL, PUT, + OPEN_INTEREST, ) from cryptofeed.symbols import Symbol from cryptofeed.types import ( L1Book, Trade, + OpenInterest, ) from piker.brokers import SymbolNotFound from .venues import ( -- 2.34.1 From b646133ead262e259aa9bd03df5b1efd70054ef3 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:11:04 -0300 Subject: [PATCH 02/29] minor get_config fix --- piker/brokers/deribit/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 10736083..1297193b 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -228,7 +228,7 @@ def get_config() -> dict[str, Any]: ) conf_option = section.get('option', {}) - section.clear # clear the dict to reuse it + section = {} # clear the dict to reuse it section['deribit'] = {} section['deribit']['key_id'] = conf_option.get('api_key') section['deribit']['key_secret'] = conf_option.get('api_secret') -- 2.34.1 From 17249205c957eed162f0f2bf0fad1bd7e1cf1b84 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:15:01 -0300 Subject: [PATCH 03/29] get_instrumets for cryptofeed.FeedHandler --- piker/brokers/deribit/api.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 1297193b..67301911 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -361,6 +361,35 @@ class Client: return flat + async def get_instruments( + self, + currency: str = 'btc', + kind: str = 'option', + expired: bool = False, + + ) -> list[Symbol]: + """ + Get instruments for cryptoFeed.FeedHandler. + """ + params: dict[str, str] = { + 'currency': currency.upper(), + 'kind': kind, + 'expired': expired, + } + + r: JSONRPCResult = await self._json_rpc_auth_wrapper( + 'public/get_instruments', + params, + ) + resp = r.result + response_list = [] + + for i in range(len(resp) // 10): + element = resp[i] + response_list.append(piker_sym_to_cb_sym(element['instrument_name'])) + + return response_list + async def submit_limit( self, symbol: str, -- 2.34.1 From 564cd63014883f09b96611ac3e552531fb39ef4a Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:15:38 -0300 Subject: [PATCH 04/29] aio_open_interest_feed_relay --- piker/brokers/deribit/api.py | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 67301911..15a9f88f 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -769,6 +769,68 @@ async def maybe_open_price_feed( yield feed +async def aio_open_interest_feed_relay( + fh: FeedHandler, + instruments: list, + from_trio: asyncio.Queue, + to_trio: trio.abc.SendChannel, +) -> None: + async def _trade( + trade: Trade, # cryptofeed, NOT ours from `.venues`! + receipt_timestamp: int, + ) -> None: + ''' + Proxy-thru `cryptofeed.FeedHandler` "trades" to `piker`-side. + + ''' + # Get timestamp and convert it to isoformat + date = (datetime.utcfromtimestamp(trade.timestamp)).isoformat() + print('Trade...') + print(date) + print(trade) + print('=======================') + to_trio.send_nowait(('trade', trade)) + + # trade and oi are user defined functions that + # will be called when trade and open interest updates are received + # data type is not dict, is an object: cryptofeed.types.OpenINterest + async def _oi( + oi: OpenInterest, + receipt_timestamp: int, + ) -> None: + ''' + Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. + + ''' + # Get timestamp and convert it to isoformat + date = (datetime.utcfromtimestamp(oi.timestamp)).isoformat() + print('>>>> Open Interest...') + print(date) + print(oi) + print('==========================') + to_trio.send_nowait(('oi', oi)) + + callbacks = {TRADES: _trade, OPEN_INTEREST: _oi} + fh.add_feed( + DERIBIT, + channels=[TRADES, OPEN_INTEREST], + symbols=instruments, + callbacks=callbacks + ) + + if not fh.running: + fh.run( + start_loop=False, + install_signal_handlers=False + ) + + # sync with trio + to_trio.send_nowait(None) + + # run until cancelled + await asyncio.sleep(float('inf')) + + # TODO, move all to `.broker` submod! # async def aio_order_feed_relay( -- 2.34.1 From 733b58250f78dd99af5485e93697092462047943 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:15:51 -0300 Subject: [PATCH 05/29] open_oi_feed --- piker/brokers/deribit/api.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 15a9f88f..332681f6 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -831,6 +831,31 @@ async def aio_open_interest_feed_relay( await asyncio.sleep(float('inf')) +@acm +async def open_oi_feed( +) -> to_asyncio.LinkedTaskChannel: + + instruments: list[Symbol] + async with get_client( + ) as client: + instruments = await client.get_instruments() + + fh: FeedHandler + first: None + chan: to_asyncio.LinkedTaskChannel + async with ( + maybe_open_feed_handler() as fh, + to_asyncio.open_channel_from( + partial( + aio_open_interest_feed_relay, + fh, + instruments + ) + ) as (first, chan) + ): + yield chan + + # TODO, move all to `.broker` submod! # async def aio_order_feed_relay( -- 2.34.1 From 16480bd2d4d7598c57ab6017b1551c8bb52ea7b8 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:15:59 -0300 Subject: [PATCH 06/29] maybe_open_oi_feed --- piker/brokers/deribit/api.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 332681f6..4eb15c73 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -856,6 +856,20 @@ async def open_oi_feed( yield chan +@acm +async def maybe_open_oi_feed( +) -> trio.abc.ReceiveStream: + + # TODO: add a predicate to maybe_open_context + feed: to_asyncio.LinkedTaskChannel + async with maybe_open_context( + acm_func=open_oi_feed, + ) as (cache_hit, feed): + if cache_hit: + yield broadcast_receiver(feed, 10) + else: + yield feed + # TODO, move all to `.broker` submod! # async def aio_order_feed_relay( -- 2.34.1 From f2f7855e5444be6b87e7c1fe8f7fec4e15466e67 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 26 Nov 2024 15:16:21 -0300 Subject: [PATCH 07/29] max_pain_daemon --- max_pain.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 max_pain.py diff --git a/max_pain.py b/max_pain.py new file mode 100644 index 00000000..22e30a6d --- /dev/null +++ b/max_pain.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +import trio +import tractor +from piker.brokers.deribit.api import ( + Client, + get_client, + maybe_open_oi_feed, +) + + +async def max_pain_daemon( +) -> None: + async with maybe_open_oi_feed() as oi_feed: + print('Im in...') + + +async def main(): + + async with tractor.open_nursery() as n: + + p: tractor.Portal = await n.start_actor( + 'max_pain_daemon', + enable_modules=[__name__], + infect_asyncio=True, + ) + await p.run(max_pain_daemon) + +if __name__ == '__main__': + trio.run(main) -- 2.34.1 From 7b02df9b49599b4ba3b9f773ca367034b014029d Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 29 Nov 2024 10:38:17 -0300 Subject: [PATCH 08/29] Update api.py This function receive a date in this format DDMMMYY and returns timestamps int --- piker/brokers/deribit/api.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 4eb15c73..420fd101 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -112,6 +112,10 @@ def deribit_timestamp(when: datetime) -> int: ) +def get_timestamp_int(expiry_date: str) -> int: + return int(time.mktime(time.strptime(expiry_date, '%d%b%y'))) + + def str_to_cb_sym(name: str) -> Symbol: base, strike_price, expiry_date, option_type = name.split('-') @@ -124,8 +128,9 @@ def str_to_cb_sym(name: str) -> Symbol: else: raise Exception("Couldn\'t parse option type") - new_expiry_date = get_values_from_cb_normalized_date(expiry_date) - + new_expiry_date: int = get_timestamp_int( + get_values_from_cb_normalized_date(expiry_date) + ) return Symbol( base=base, quote=quote, @@ -145,6 +150,7 @@ def piker_sym_to_cb_sym(name: str) -> Symbol: )= tuple( name.upper().split('-')) + new_expiry_date = get_timestamp_int(expiry_date) quote: str = base if option_type == 'P': @@ -160,7 +166,7 @@ def piker_sym_to_cb_sym(name: str) -> Symbol: type=OPTION, strike_price=strike_price, option_type=option_type, - expiry_date=expiry_date + expiry_date=new_expiry_date ) -- 2.34.1 From 4ccda643b83d39af6717209cf10b5813dda65f58 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 29 Nov 2024 10:39:48 -0300 Subject: [PATCH 09/29] Update api.py covers cases when option_type comes as PUT or P, same with calls CALL or C --- piker/brokers/deribit/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 420fd101..e3c52f28 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -153,9 +153,9 @@ def piker_sym_to_cb_sym(name: str) -> Symbol: new_expiry_date = get_timestamp_int(expiry_date) quote: str = base - if option_type == 'P': + if option_type == 'P' or option_type == 'PUT': option_type = PUT - elif option_type == 'C': + elif option_type == 'C' or option_type == 'CALL': option_type = CALL else: raise Exception("Couldn\'t parse option type") -- 2.34.1 From 24bf19c1fb0ea71c013f67c57a40ece585f1e426 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 29 Nov 2024 10:41:20 -0300 Subject: [PATCH 10/29] Update api.py get_currencies function --- piker/brokers/deribit/api.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index e3c52f28..86e6e0f4 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -319,6 +319,20 @@ class Client: return balances + async def get_currencies( + self, + + ) -> list[dict]: + ''' + Return the set of currencies for deribit. + ''' + assets = {} + resp = await self._json_rpc_auth_wrapper( + 'public/get_currencies', + params={} + ) + return resp.result + async def get_assets( self, venue: str | None = None, @@ -331,11 +345,7 @@ class Client: ''' assets = {} - resp = await self._json_rpc_auth_wrapper( - 'public/get_currencies', - params={} - ) - currencies: list[dict] = resp.result + currencies = await self.get_currencies() for currency in currencies: name: str = currency['currency'] tx_tick: Decimal = digits_to_dec(currency['fee_precision']) @@ -844,6 +854,8 @@ async def open_oi_feed( instruments: list[Symbol] async with get_client( ) as client: + # to get all currencies available in deribit + # currencies = await client.get_currencies() instruments = await client.get_instruments() fh: FeedHandler -- 2.34.1 From 9abbd8ca1ece1026dd95c6c9c0fc0b9a46e8b52b Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 29 Nov 2024 10:49:07 -0300 Subject: [PATCH 11/29] Update api.py open_interest for each strike price and each expiry date --- piker/brokers/deribit/api.py | 51 +++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 86e6e0f4..686a42a8 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -788,6 +788,7 @@ async def maybe_open_price_feed( async def aio_open_interest_feed_relay( fh: FeedHandler, instruments: list, + open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]], from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: @@ -799,12 +800,6 @@ async def aio_open_interest_feed_relay( Proxy-thru `cryptofeed.FeedHandler` "trades" to `piker`-side. ''' - # Get timestamp and convert it to isoformat - date = (datetime.utcfromtimestamp(trade.timestamp)).isoformat() - print('Trade...') - print(date) - print(trade) - print('=======================') to_trio.send_nowait(('trade', trade)) # trade and oi are user defined functions that @@ -818,18 +813,46 @@ async def aio_open_interest_feed_relay( Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. ''' - # Get timestamp and convert it to isoformat - date = (datetime.utcfromtimestamp(oi.timestamp)).isoformat() + nonlocal open_interests print('>>>> Open Interest...') - print(date) print(oi) - print('==========================') + symbol: Symbol = str_to_cb_sym(oi.symbol) + piker_sym: str = cb_sym_to_deribit_inst(symbol) + print(f'{piker_sym}') + ( + base, + expiry_date, + strike_price, + option_type + ) = tuple( + piker_sym.split('-') + ) + if not f'{expiry_date}' in open_interests: + open_interests[f'{expiry_date}'] = { + f'{strike_price}': { + 'C': [], + 'P': [], + } + } + if not f'{strike_price}' in open_interests[f'{expiry_date}']: + open_interests[f'{expiry_date}'][f'{strike_price}'] = { + 'C': [], + 'P': [], + } + + open_interests[f'{expiry_date}'][f'{strike_price}'][f'{option_type}'].append( + {f'{oi.timestamp}': oi.open_interest} + ) + print(f'open_interests:') + print(f'{open_interests}') + print(f'open_interests expiry dates: {len(open_interests)}') to_trio.send_nowait(('oi', oi)) + channels = [TRADES, OPEN_INTEREST] callbacks = {TRADES: _trade, OPEN_INTEREST: _oi} fh.add_feed( DERIBIT, - channels=[TRADES, OPEN_INTEREST], + channels=channels, symbols=instruments, callbacks=callbacks ) @@ -851,13 +874,14 @@ async def aio_open_interest_feed_relay( async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: - instruments: list[Symbol] + instruments: list[Symbol] = [] async with get_client( ) as client: # to get all currencies available in deribit # currencies = await client.get_currencies() instruments = await client.get_instruments() + open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]] = {} fh: FeedHandler first: None chan: to_asyncio.LinkedTaskChannel @@ -867,7 +891,8 @@ async def open_oi_feed( partial( aio_open_interest_feed_relay, fh, - instruments + instruments, + open_interests, ) ) as (first, chan) ): -- 2.34.1 From a9110b119623383ed4e3a88e6a45aa2a033479ca Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Mon, 2 Dec 2024 09:47:20 -0300 Subject: [PATCH 12/29] Update api.py Now we get the data for an e specific expiration date if and expiry_date is passed, or for all expiration if expiry_date is None --- piker/brokers/deribit/api.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 686a42a8..2cf5bf3f 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -123,7 +123,7 @@ def str_to_cb_sym(name: str) -> Symbol: if option_type == 'put': option_type = PUT - elif option_type == 'call': + elif option_type == 'call': option_type = CALL else: raise Exception("Couldn\'t parse option type") @@ -382,6 +382,7 @@ class Client: currency: str = 'btc', kind: str = 'option', expired: bool = False, + expiry_date: str = None, ) -> list[Symbol]: """ @@ -400,9 +401,11 @@ class Client: resp = r.result response_list = [] - for i in range(len(resp) // 10): + for i in range(len(resp)): element = resp[i] - response_list.append(piker_sym_to_cb_sym(element['instrument_name'])) + name = f'{element["instrument_name"].split("-")[1]}' + if not expiry_date or name == expiry_date.upper(): + response_list.append(piker_sym_to_cb_sym(element['instrument_name'])) return response_list @@ -879,7 +882,9 @@ async def open_oi_feed( ) as client: # to get all currencies available in deribit # currencies = await client.get_currencies() - instruments = await client.get_instruments() + instruments = await client.get_instruments( + expiry_date='6DEC24' + ) open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]] = {} fh: FeedHandler -- 2.34.1 From 6e08c60d53731f46a6781217ec31bb98609872c3 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 3 Dec 2024 14:29:35 -0300 Subject: [PATCH 13/29] deactivate cryptofeed debug log --- max_pain.py | 2 -- piker/brokers/deribit/api.py | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/max_pain.py b/max_pain.py index 22e30a6d..b5d4d815 100644 --- a/max_pain.py +++ b/max_pain.py @@ -2,8 +2,6 @@ import trio import tractor from piker.brokers.deribit.api import ( - Client, - get_client, maybe_open_oi_feed, ) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 2cf5bf3f..22d78c67 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -242,6 +242,7 @@ def get_config() -> dict[str, Any]: section['log'] = {} section['log']['filename'] = 'feedhandler.log' section['log']['level'] = 'DEBUG' + section['log']['disabled'] = True return section -- 2.34.1 From 5de14bc3f9a50b41bc3b07036eb292b79617b1dd Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Tue, 3 Dec 2024 14:35:57 -0300 Subject: [PATCH 14/29] added first calcs for max_pain --- piker/brokers/deribit/api.py | 80 ++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 22d78c67..99325f7d 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -793,6 +793,9 @@ async def aio_open_interest_feed_relay( fh: FeedHandler, instruments: list, open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]], + losses_cache: dict[str, Decimal], + max_losses: Decimal, + max_pain: Decimal, from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: @@ -817,12 +820,13 @@ async def aio_open_interest_feed_relay( Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. ''' + nonlocal losses_cache + nonlocal max_losses + nonlocal max_pain nonlocal open_interests - print('>>>> Open Interest...') - print(oi) symbol: Symbol = str_to_cb_sym(oi.symbol) piker_sym: str = cb_sym_to_deribit_inst(symbol) - print(f'{piker_sym}') + data: dict = oi.raw['params']['data'] ( base, expiry_date, @@ -836,24 +840,65 @@ async def aio_open_interest_feed_relay( f'{strike_price}': { 'C': [], 'P': [], + 'strike_losses': Decimal(0), } } if not f'{strike_price}' in open_interests[f'{expiry_date}']: open_interests[f'{expiry_date}'][f'{strike_price}'] = { 'C': [], 'P': [], + 'strike_losses': Decimal(0), } - open_interests[f'{expiry_date}'][f'{strike_price}'][f'{option_type}'].append( - {f'{oi.timestamp}': oi.open_interest} + index_price: Decimal = data['index_price'] + price_delta: Decimal = abs(index_price - Decimal(strike_price)) + open_interest: Decimal = oi.open_interest + + losses: Decimal = price_delta * open_interest + + if not f'{strike_price}' in losses_cache: + losses_cache[f'{strike_price}'] = { + 'C': Decimal(0), + 'P': Decimal(0), + } + + losses_cache[f'{strike_price}'][f'{option_type}'] = losses + + strike_losses: Decimal = ( + losses_cache[f'{strike_price}']['C'] + + + losses_cache[f'{strike_price}']['P'] ) - print(f'open_interests:') - print(f'{open_interests}') - print(f'open_interests expiry dates: {len(open_interests)}') - to_trio.send_nowait(('oi', oi)) + + print(f'>>>> Open Interest...') + print(f'max_losses: {max_losses}\n') + print(f'max_pain: {max_pain}') + print('-----------------------------------------------') + open_interests[f'{expiry_date}'][f'{strike_price}'][f'{option_type}'] = { + 'date': oi.timestamp, + 'open_interest': open_interest, + 'index_price': index_price, + 'strike_price': strike_price, + 'price_delta': price_delta, + 'losses': losses, # this updates the global value call_losses and put_losses + } + # calculate with latest values stored in call_losses and put_losses global cache. + open_interests[f'{expiry_date}'][f'{strike_price}']['strike_losses'] = strike_losses + + for strike in open_interests[f'{expiry_date}']: + if open_interests[f'{expiry_date}'][strike]['strike_losses'] > max_losses: + max_losses = open_interests[f'{expiry_date}'][strike]['strike_losses'] + max_pain = strike + print('-----------------------------------------------') + print(f'strike_price: {strike_price}') + print(f'strike_losses: {open_interests[f'{expiry_date}'][strike]['strike_losses']}') + print(f'{pformat(open_interests[f'{expiry_date}'][strike])}') + print('-----------------------------------------------') + channels = [TRADES, OPEN_INTEREST] - callbacks = {TRADES: _trade, OPEN_INTEREST: _oi} + callbacks={TRADES: _trade, OPEN_INTEREST: _oi} + fh.add_feed( DERIBIT, channels=channels, @@ -878,16 +923,22 @@ async def aio_open_interest_feed_relay( async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: + expiry_date: str = '6DEC24' # '6DEC24' '26SEP25' '27JUN25' '13DEC24' instruments: list[Symbol] = [] async with get_client( ) as client: # to get all currencies available in deribit # currencies = await client.get_currencies() instruments = await client.get_instruments( - expiry_date='6DEC24' + expiry_date=expiry_date, ) - - open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]] = {} + losses_cache: dict[str, Decimal] = { # {'': } + 'C': Decimal(0), + 'P': Decimal(0), + } + max_losses: Decimal = Decimal(0) + max_pain: Decimal = Decimal(0) + open_interests: dict[str, dict[str, dict[str, list[dict]]]] = {} fh: FeedHandler first: None chan: to_asyncio.LinkedTaskChannel @@ -899,6 +950,9 @@ async def open_oi_feed( fh, instruments, open_interests, + losses_cache, + max_losses, + max_pain, ) ) as (first, chan) ): -- 2.34.1 From ec2123175ad784526880838d10ccc030fff97a62 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Wed, 4 Dec 2024 19:18:29 -0300 Subject: [PATCH 15/29] some refactor --- piker/brokers/deribit/api.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 99325f7d..07aed466 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -851,10 +851,16 @@ async def aio_open_interest_feed_relay( } index_price: Decimal = data['index_price'] - price_delta: Decimal = abs(index_price - Decimal(strike_price)) open_interest: Decimal = oi.open_interest + price_delta: Decimal + if f'{option_type}' == 'C': + price_delta = index_price - Decimal(strike_price) - losses: Decimal = price_delta * open_interest + elif f'{option_type}' == 'P': + price_delta = Decimal(strike_price) - index_price + + notional_value = open_interest * index_price + losses: Decimal = max(0, price_delta * open_interest) if not f'{strike_price}' in losses_cache: losses_cache[f'{strike_price}'] = { @@ -870,29 +876,27 @@ async def aio_open_interest_feed_relay( losses_cache[f'{strike_price}']['P'] ) - print(f'>>>> Open Interest...') - print(f'max_losses: {max_losses}\n') - print(f'max_pain: {max_pain}') - print('-----------------------------------------------') open_interests[f'{expiry_date}'][f'{strike_price}'][f'{option_type}'] = { 'date': oi.timestamp, 'open_interest': open_interest, 'index_price': index_price, 'strike_price': strike_price, 'price_delta': price_delta, + 'notional_value': notional_value, 'losses': losses, # this updates the global value call_losses and put_losses } # calculate with latest values stored in call_losses and put_losses global cache. open_interests[f'{expiry_date}'][f'{strike_price}']['strike_losses'] = strike_losses for strike in open_interests[f'{expiry_date}']: - if open_interests[f'{expiry_date}'][strike]['strike_losses'] > max_losses: + if strike_losses > max_losses: max_losses = open_interests[f'{expiry_date}'][strike]['strike_losses'] max_pain = strike - print('-----------------------------------------------') - print(f'strike_price: {strike_price}') - print(f'strike_losses: {open_interests[f'{expiry_date}'][strike]['strike_losses']}') - print(f'{pformat(open_interests[f'{expiry_date}'][strike])}') + print(f'>>>> Open Interest...') + print(f'expiration: {expiry_date}') + print(f'>>>> max_pain: {max_pain}') + print(f'max_losses: {max_losses}') + print(f'{pformat(open_interests[f'{expiry_date}'][max_pain])}') print('-----------------------------------------------') @@ -923,7 +927,7 @@ async def aio_open_interest_feed_relay( async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: - expiry_date: str = '6DEC24' # '6DEC24' '26SEP25' '27JUN25' '13DEC24' + expiry_date: str = '20DEC24' instruments: list[Symbol] = [] async with get_client( ) as client: @@ -936,6 +940,7 @@ async def open_oi_feed( 'C': Decimal(0), 'P': Decimal(0), } +# max_losses: Decimal = Decimal('Infinity') max_losses: Decimal = Decimal(0) max_pain: Decimal = Decimal(0) open_interests: dict[str, dict[str, dict[str, list[dict]]]] = {} -- 2.34.1 From c4600a039261aab633dc01c94a8284716de1b777 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Thu, 5 Dec 2024 23:29:45 -0300 Subject: [PATCH 16/29] auxiliar methods --- piker/brokers/deribit/api.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 07aed466..336a3636 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -246,6 +246,20 @@ def get_config() -> dict[str, Any]: return section +def check_if_complete( + oi: dict[str, dict[str, Decimal | None]], + + ) -> bool: + for strike in oi: + if ( + oi[strike]['C'] == None + or + oi[strike]['P'] == None + ): + return False + + return True + class Client: ''' @@ -410,6 +424,27 @@ class Client: return response_list + def get_strikes_dict( + self, + instruments: list[Symbol], + + ) -> dict[str, dict[str, Decimal | None]]: + """ + Get a dict with strike prices as keys. + """ + + response: dict[str, dict[str, Decimal | None]] = {} + + for i in range(len(instruments)): + element = instruments[i] + strike = f'{str(element).split('-')[1]}' + response[f'{strike}'] = { + 'C': None, + 'P': None, + } + + return response + async def submit_limit( self, symbol: str, -- 2.34.1 From bf86772d4b3e1b9825d65ddd191cee493dd3f43e Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Thu, 5 Dec 2024 23:31:36 -0300 Subject: [PATCH 17/29] oi max_pain major refactor Now the max_pain is calculated taking into account all strike prices and all close prices to find the intrinsic value as deribit. --- piker/brokers/deribit/api.py | 125 ++++++++++++----------------------- 1 file changed, 44 insertions(+), 81 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 336a3636..57861368 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -827,13 +827,15 @@ async def maybe_open_price_feed( async def aio_open_interest_feed_relay( fh: FeedHandler, instruments: list, - open_interests: dict[str, dict[str, dict[str, list[dict[str, Decimal]]]]], - losses_cache: dict[str, Decimal], - max_losses: Decimal, - max_pain: Decimal, + intrinsic_values: dict[str, Decimal], + oi_by_strikes: dict[str, dict[str, Decimal]], from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: + + max_losses: Decimal = Decimal('Infinity') + max_pain: Decimal = Decimal(0) + async def _trade( trade: Trade, # cryptofeed, NOT ours from `.venues`! receipt_timestamp: int, @@ -855,13 +857,13 @@ async def aio_open_interest_feed_relay( Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. ''' - nonlocal losses_cache + nonlocal intrinsic_values + nonlocal oi_by_strikes nonlocal max_losses nonlocal max_pain - nonlocal open_interests + symbol: Symbol = str_to_cb_sym(oi.symbol) piker_sym: str = cb_sym_to_deribit_inst(symbol) - data: dict = oi.raw['params']['data'] ( base, expiry_date, @@ -870,69 +872,37 @@ async def aio_open_interest_feed_relay( ) = tuple( piker_sym.split('-') ) - if not f'{expiry_date}' in open_interests: - open_interests[f'{expiry_date}'] = { - f'{strike_price}': { - 'C': [], - 'P': [], - 'strike_losses': Decimal(0), - } - } - if not f'{strike_price}' in open_interests[f'{expiry_date}']: - open_interests[f'{expiry_date}'][f'{strike_price}'] = { - 'C': [], - 'P': [], - 'strike_losses': Decimal(0), - } - - index_price: Decimal = data['index_price'] open_interest: Decimal = oi.open_interest - price_delta: Decimal - if f'{option_type}' == 'C': - price_delta = index_price - Decimal(strike_price) + oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest - elif f'{option_type}' == 'P': - price_delta = Decimal(strike_price) - index_price + is_ready = check_if_complete(oi_by_strikes) + if is_ready: + for strike in oi_by_strikes: + s: Decimal = Decimal(f'{strike}') + close_losses = Decimal(0) + closes: list[str] = sorted(oi_by_strikes.keys()) + call_cash: Decimal = Decimal(0) + put_cash: Decimal = Decimal(0) + for close in closes: + c: Decimal = Decimal(f'{close}') + call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C']) + put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P']) + + intrinsic_values[f'{strike}'] = {} + intrinsic_values[f'{strike}']['C'] = call_cash + intrinsic_values[f'{strike}']['P'] = put_cash + intrinsic_values[f'{strike}']['total'] = (call_cash + put_cash) - notional_value = open_interest * index_price - losses: Decimal = max(0, price_delta * open_interest) - - if not f'{strike_price}' in losses_cache: - losses_cache[f'{strike_price}'] = { - 'C': Decimal(0), - 'P': Decimal(0), - } - - losses_cache[f'{strike_price}'][f'{option_type}'] = losses - - strike_losses: Decimal = ( - losses_cache[f'{strike_price}']['C'] - + - losses_cache[f'{strike_price}']['P'] - ) - - open_interests[f'{expiry_date}'][f'{strike_price}'][f'{option_type}'] = { - 'date': oi.timestamp, - 'open_interest': open_interest, - 'index_price': index_price, - 'strike_price': strike_price, - 'price_delta': price_delta, - 'notional_value': notional_value, - 'losses': losses, # this updates the global value call_losses and put_losses - } - # calculate with latest values stored in call_losses and put_losses global cache. - open_interests[f'{expiry_date}'][f'{strike_price}']['strike_losses'] = strike_losses - - for strike in open_interests[f'{expiry_date}']: - if strike_losses > max_losses: - max_losses = open_interests[f'{expiry_date}'][strike]['strike_losses'] - max_pain = strike - print(f'>>>> Open Interest...') - print(f'expiration: {expiry_date}') - print(f'>>>> max_pain: {max_pain}') - print(f'max_losses: {max_losses}') - print(f'{pformat(open_interests[f'{expiry_date}'][max_pain])}') - print('-----------------------------------------------') + for strike in intrinsic_values: + if intrinsic_values[f'{strike}']['total'] < max_losses: + max_losses = intrinsic_values[f'{strike}']['total'] + max_pain = strike + + print('-----------------------------------------------') + print(f'time: {oi.timestamp}') + print(f'max_pain: {max_pain}') + print(f'max_losses: {max_losses}') + print('-----------------------------------------------') channels = [TRADES, OPEN_INTEREST] @@ -964,21 +934,16 @@ async def open_oi_feed( expiry_date: str = '20DEC24' instruments: list[Symbol] = [] + intrinsic_values: dict[str, dict[str, Decimal]] = {} + oi_by_strikes: dict[str, dict[str, Decimal]] + async with get_client( ) as client: - # to get all currencies available in deribit - # currencies = await client.get_currencies() instruments = await client.get_instruments( expiry_date=expiry_date, ) - losses_cache: dict[str, Decimal] = { # {'': } - 'C': Decimal(0), - 'P': Decimal(0), - } -# max_losses: Decimal = Decimal('Infinity') - max_losses: Decimal = Decimal(0) - max_pain: Decimal = Decimal(0) - open_interests: dict[str, dict[str, dict[str, list[dict]]]] = {} + oi_by_strikes = client.get_strikes_dict(instruments) + fh: FeedHandler first: None chan: to_asyncio.LinkedTaskChannel @@ -989,10 +954,8 @@ async def open_oi_feed( aio_open_interest_feed_relay, fh, instruments, - open_interests, - losses_cache, - max_losses, - max_pain, + intrinsic_values, + oi_by_strikes, ) ) as (first, chan) ): -- 2.34.1 From 2b70518eb95a293418ca096b52f5dbe7e5ef17dc Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Thu, 5 Dec 2024 23:32:09 -0300 Subject: [PATCH 18/29] Update poetry.lock --- poetry.lock | 445 ++++++++++++++++++++++++++-------------------------- 1 file changed, 224 insertions(+), 221 deletions(-) diff --git a/poetry.lock b/poetry.lock index 64fc2ba4..b35a4da8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -173,7 +173,7 @@ name = "asyncvnc" version = "1.1.0" description = "Asynchronous VNC for Python" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.7" files = [] develop = false @@ -1769,62 +1769,82 @@ test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] [[package]] name = "pycares" -version = "4.4.0" +version = "4.5.0" description = "Python interface for c-ares" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pycares-4.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:24da119850841d16996713d9c3374ca28a21deee056d609fbbed29065d17e1f6"}, - {file = "pycares-4.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8f64cb58729689d4d0e78f0bfb4c25ce2f851d0274c0273ac751795c04b8798a"}, - {file = "pycares-4.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33e2a1120887e89075f7f814ec144f66a6ce06a54f5722ccefc62fbeda83cff"}, - {file = "pycares-4.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c680fef1b502ee680f8f0b95a41af4ec2c234e50e16c0af5bbda31999d3584bd"}, - {file = "pycares-4.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fff16b09042ba077f7b8aa5868d1d22456f0002574d0ba43462b10a009331677"}, - {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:229a1675eb33bc9afb1fc463e73ee334950ccc485bc83a43f6ae5839fb4d5fa3"}, - {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3aebc73e5ad70464f998f77f2da2063aa617cbd8d3e8174dd7c5b4518f967153"}, - {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6ef64649eba56448f65e26546d85c860709844d2fc22ef14d324fe0b27f761a9"}, - {file = "pycares-4.4.0-cp310-cp310-win32.whl", hash = "sha256:4afc2644423f4eef97857a9fd61be9758ce5e336b4b0bd3d591238bb4b8b03e0"}, - {file = "pycares-4.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5ed4e04af4012f875b78219d34434a6d08a67175150ac1b79eb70ab585d4ba8c"}, - {file = "pycares-4.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bce8db2fc6f3174bd39b81405210b9b88d7b607d33e56a970c34a0c190da0490"}, - {file = "pycares-4.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a0303428d013ccf5c51de59c83f9127aba6200adb7fd4be57eddb432a1edd2a"}, - {file = "pycares-4.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afb91792f1556f97be7f7acb57dc7756d89c5a87bd8b90363a77dbf9ea653817"}, - {file = "pycares-4.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b61579cecf1f4d616e5ea31a6e423a16680ab0d3a24a2ffe7bb1d4ee162477ff"}, - {file = "pycares-4.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7af06968cbf6851566e806bf3e72825b0e6671832a2cbe840be1d2d65350710"}, - {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ceb12974367b0a68a05d52f4162b29f575d241bd53de155efe632bf2c943c7f6"}, - {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2eeec144bcf6a7b6f2d74d6e70cbba7886a84dd373c886f06cb137a07de4954c"}, - {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3a6f7cfdfd11eb5493d6d632e582408c8f3b429f295f8799c584c108b28db6f"}, - {file = "pycares-4.4.0-cp311-cp311-win32.whl", hash = "sha256:34736a2ffaa9c08ca9c707011a2d7b69074bbf82d645d8138bba771479b2362f"}, - {file = "pycares-4.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:eb66c30eb11e877976b7ead13632082a8621df648c408b8e15cdb91a452dd502"}, - {file = "pycares-4.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fd644505a8cfd7f6584d33a9066d4e3d47700f050ef1490230c962de5dfb28c6"}, - {file = "pycares-4.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52084961262232ec04bd75f5043aed7e5d8d9695e542ff691dfef0110209f2d4"}, - {file = "pycares-4.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0c5368206057884cde18602580083aeaad9b860e2eac14fd253543158ce1e93"}, - {file = "pycares-4.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:112a4979c695b1c86f6782163d7dec58d57a3b9510536dcf4826550f9053dd9a"}, - {file = "pycares-4.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d186dafccdaa3409194c0f94db93c1a5d191145a275f19da6591f9499b8e7b8"}, - {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:64965dc19c578a683ea73487a215a8897276224e004d50eeb21f0bc7a0b63c88"}, - {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ed2a38e34bec6f2586435f6ff0bc5fe11d14bebd7ed492cf739a424e81681540"}, - {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:94d6962db81541eb0396d2f0dfcbb18cdb8c8b251d165efc2d974ae652c547d4"}, - {file = "pycares-4.4.0-cp312-cp312-win32.whl", hash = "sha256:1168a48a834813aa80f412be2df4abaf630528a58d15c704857448b20b1675c0"}, - {file = "pycares-4.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:db24c4e7fea4a052c6e869cbf387dd85d53b9736cfe1ef5d8d568d1ca925e977"}, - {file = "pycares-4.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:21a5a0468861ec7df7befa69050f952da13db5427ae41ffe4713bc96291d1d95"}, - {file = "pycares-4.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22c00bf659a9fa44d7b405cf1cd69b68b9d37537899898d8cbe5dffa4016b273"}, - {file = "pycares-4.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23aa3993a352491a47fcf17867f61472f32f874df4adcbb486294bd9fbe8abee"}, - {file = "pycares-4.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813d661cbe2e37d87da2d16b7110a6860e93ddb11735c6919c8a3545c7b9c8d8"}, - {file = "pycares-4.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77cf5a2fd5583c670de41a7f4a7b46e5cbabe7180d8029f728571f4d2e864084"}, - {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3eaa6681c0a3e3f3868c77aca14b7760fed35fdfda2fe587e15c701950e7bc69"}, - {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad58e284a658a8a6a84af2e0b62f2f961f303cedfe551854d7bd40c3cbb61912"}, - {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bfb89ca9e3d0a9b5332deeb666b2ede9d3469107742158f4aeda5ce032d003f4"}, - {file = "pycares-4.4.0-cp38-cp38-win32.whl", hash = "sha256:f36bdc1562142e3695555d2f4ac0cb69af165eddcefa98efc1c79495b533481f"}, - {file = "pycares-4.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:902461a92b6a80fd5041a2ec5235680c7cc35e43615639ec2a40e63fca2dfb51"}, - {file = "pycares-4.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7bddc6adba8f699728f7fc1c9ce8cef359817ad78e2ed52b9502cb5f8dc7f741"}, - {file = "pycares-4.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cb49d5805cd347c404f928c5ae7c35e86ba0c58ffa701dbe905365e77ce7d641"}, - {file = "pycares-4.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cf3349fa3a2e67ed387a7974c11d233734636fe19facfcda261b411af14d80"}, - {file = "pycares-4.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf2eaa83a5987e48fa63302f0fe7ce3275cfda87b34d40fef9ce703fb3ac002"}, - {file = "pycares-4.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82bba2ab77eb5addbf9758d514d9bdef3c1bfe7d1649a47bd9a0d55a23ef478b"}, - {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c6a8bde63106f162fca736e842a916853cad3c8d9d137e11c9ffa37efa818b02"}, - {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5f646eec041db6ffdbcaf3e0756fb92018f7af3266138c756bb09d2b5baadec"}, - {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9dc04c54c6ea615210c1b9e803d0e2d2255f87a3d5d119b6482c8f0dfa15b26b"}, - {file = "pycares-4.4.0-cp39-cp39-win32.whl", hash = "sha256:97892cced5794d721fb4ff8765764aa4ea48fe8b2c3820677505b96b83d4ef47"}, - {file = "pycares-4.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:917f08f0b5d9324e9a34211e68d27447c552b50ab967044776bbab7e42a553a2"}, - {file = "pycares-4.4.0.tar.gz", hash = "sha256:f47579d508f2f56eddd16ce72045782ad3b1b3b678098699e2b6a1b30733e1c2"}, + {file = "pycares-4.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13a82fad8239d6fbcf916099bee17d8b5666d0ddb77dace431e0f7961c9427ab"}, + {file = "pycares-4.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fefc7bebbe39b2e3b4b9615471233a8f7356b96129a7db9030313a3ae4ecc42d"}, + {file = "pycares-4.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e322e8ce810026f6e0c7c2a254b9ed02191ab8d42fa2ce6808ede1bdccab8e65"}, + {file = "pycares-4.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:723ba0803b016294430e40e544503fed9164949b694342c2552ab189e2b688ef"}, + {file = "pycares-4.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e48b20b59cdc929cc712a8b22e89c273256e482b49bb8999af98d2c6fc4563c2"}, + {file = "pycares-4.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de6e55bd9af595b112ac6080ac0a0d52b5853d0d8e6d01ac65ff09e51e62490a"}, + {file = "pycares-4.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6f4b9063e3dd70460400367917698f209c10aabb68bf70b09e364895444487d"}, + {file = "pycares-4.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:95522d4840d702fd766439a7c7cd747935aa54cf0b8675e9fadd8414dd9dd0df"}, + {file = "pycares-4.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4709ce4fd9dbee24b1397f71a2adb3267323bb5ad5e7fde3f87873d172dd156"}, + {file = "pycares-4.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8addbf3408af1010f50fd67ef634a6cb239ccb9c534c32a40713f3b8d306a98e"}, + {file = "pycares-4.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d0428ef42fcf575e197047e6a47892404faa34231902a453b3dfed66af4178b3"}, + {file = "pycares-4.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:aed5c2732f3a6bdbbfab202267d37044ca1162f690b9d34b7ece97ba43f27453"}, + {file = "pycares-4.5.0-cp310-cp310-win32.whl", hash = "sha256:b1859ea770a7abec40a6d02b5ab03c2396c4900c01f4e50ddb6c0dca4c2a6a7c"}, + {file = "pycares-4.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9f87d8da20a3a80ab05fe80c14a62bf078bd726ca6af609edbeb376fb97d50ab"}, + {file = "pycares-4.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ca7a1dba7b88290710db45012e0903c21c839fa0a2b9ddc100bba8e66bfb251"}, + {file = "pycares-4.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:160e92588cdf1a0fa3a7015f47990b508d50efd9109ea4d719dee31c058f0648"}, + {file = "pycares-4.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f38e45d23660ed1dafdb956fd263ae4735530ef1578aa2bf2caabb94cee4523"}, + {file = "pycares-4.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f742acc6d29a99ffc14e3f154b3848ea05c5533b71065e0f0a0fd99c527491b2"}, + {file = "pycares-4.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceaf71bcd7b6447705e689b8fee8836c20c6148511a90122981f524a84bfcca9"}, + {file = "pycares-4.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdc3c0be7b5b83e78e28818fecd0405bd401110dd6e2e66f7f10713c1188362c"}, + {file = "pycares-4.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd458ee69800195247aa19b5675c5914cbc091c5a220e4f0e96777a31bb555c1"}, + {file = "pycares-4.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6649d713df73266708642fc3d04f110c0a66bee510fbce4cc5fed79df42083"}, + {file = "pycares-4.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ac57d7bda925c10b997434e7ce30a2c3689c2e96bab9fd0a1165d5577378eecd"}, + {file = "pycares-4.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba17d8e5eeec4b2e0eb1a6a840bae9e62cd1c1c9cbc8dc9db9d1b9fdf33d0b54"}, + {file = "pycares-4.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9e9b7d1a8de703283e4735c0e532ba4bc600e88de872dcd1a9a4950cf74d9f4f"}, + {file = "pycares-4.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c6922ecbe458c13a4a2c1177bbce38abc44b5f086bc82115a92eab34418915f"}, + {file = "pycares-4.5.0-cp311-cp311-win32.whl", hash = "sha256:1004b8a17614e33410b4b1bb68360977667f1cc9ab2dbcfb27240d6703e4cb6a"}, + {file = "pycares-4.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:2c9c1055c622258a0f315560b2880a372363484b87cbef48af092624804caa72"}, + {file = "pycares-4.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:506efbe5017807747ccd1bdcb3c2f6e64635bc01fee01a50c0b97d649018c162"}, + {file = "pycares-4.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c469ec9fbe0526f45a98f67c1ea55be03abf30809c4f9c9be4bc93fb6806304d"}, + {file = "pycares-4.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597c0950ede240c3a779f023fcf2442207fc11e570d3ca4ccdbb0db5bbaf2588"}, + {file = "pycares-4.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aa0da03c4df6ed0f87dd52a293bd0508734515041cc5be0f85d9edc1814914f"}, + {file = "pycares-4.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1ebf52767c777d10a1b3d03844b9b05cc892714b3ee177d5d9fbff74fb9fa"}, + {file = "pycares-4.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb20d84269ddffb177b6048e3bc03d0b9ffe17592093d900d5544805958d86b3"}, + {file = "pycares-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3125df81b657971ee5c0333f8f560ba0151db1eb7cf04aea7d783bb433b306c1"}, + {file = "pycares-4.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:525c77ea44546c12f379641aee163585d403cf50e29b04a06059d6aac894e956"}, + {file = "pycares-4.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1fd87cb26b317a9988abfcfa4e4dbc55d5f20177e5979ad4d854468a9246c187"}, + {file = "pycares-4.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a90aecd41188884e57ae32507a2c6b010c60b791a253083761bbb37a488ecaed"}, + {file = "pycares-4.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0d3de65cab653979dcc491e03f596566c9d40346c9deb088e0f9fe70600d8737"}, + {file = "pycares-4.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27a77b43604b3ba24e4fc49fd3ea59f50f7d89c7255f1f1ea46928b26cccacfa"}, + {file = "pycares-4.5.0-cp312-cp312-win32.whl", hash = "sha256:6028cb8766f0fea1d2caa69fac23621fbe2cff9ce6968374e165737258703a33"}, + {file = "pycares-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:2ce10672c4cfd1c5fb6718e8b25f0336ca11c89aab88aa6df53dafc4e41df740"}, + {file = "pycares-4.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:011cd670da7caf55664c944abb71ec39af82b837f8d48da7cf0eec80f5682c4c"}, + {file = "pycares-4.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b5c67930497fb2b1dbcaa85f8c4188fc2cb62e41d787deeed2d33cfe9dd6bf52"}, + {file = "pycares-4.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d435a3b8468c656a7e7180dd7c4794510f6c612c33ad61a0fff6e440621f8b5"}, + {file = "pycares-4.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8371f5ee1efb33d6276e275d152c9c5605e5f2e58a9e168519ec1f9e13dd95ae"}, + {file = "pycares-4.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c76a9096fd5dc49c61c5235ea7032e8b43f4382800d64ca1e0e0cda700c082aa"}, + {file = "pycares-4.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b604af76b57469ff68b44e9e4c857eaee43bc5035f4f183f07f4f7149191fe1b"}, + {file = "pycares-4.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c589bd4f9160bfdb2f8080cf564bb120a4312cf091db07fe417f8e58a896a63c"}, + {file = "pycares-4.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:361262805bb09742c364ec0117842043c950339e38561009bcabbb6ac89458ef"}, + {file = "pycares-4.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d2afb3c0776467055bf33db843ef483d25639be0f32e3a13ef5d4dc64098bf5"}, + {file = "pycares-4.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bc7a1d8ed7c7a4de17706a3c89b305b02eb64c778897e6727c043e5b9dd0d853"}, + {file = "pycares-4.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5703ec878b5c1efacdbf24ceaedfa606112fc67af5564f4db99c2c210f3ffadc"}, + {file = "pycares-4.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d87758e09dbf52c27ed7cf7bc7eaf8b3226217d10c52b03d61a14d59f40fcae1"}, + {file = "pycares-4.5.0-cp313-cp313-win32.whl", hash = "sha256:3316d490b4ce1a69f034881ac1ea7608f5f24ea5293db24ab574ac70b7d7e407"}, + {file = "pycares-4.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:018e700fb0d1a2db5ec96e404ffa85ed97cc96e96d6af0bb9548111e37cf36a3"}, + {file = "pycares-4.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:78c9890d93108c70708babee8a783e6021233f1f0a763d3634add6fd429aae58"}, + {file = "pycares-4.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba69f8123995aa3df99f6ebc726fc6a4b08e467a957b215c0a82749b901d5eed"}, + {file = "pycares-4.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32d33c4ffae31d1b544adebe0b9aee2be1fb18aedd3f4f91e41c495ccbafd6d8"}, + {file = "pycares-4.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17a060cfc469828abf7f5945964d505bd8c0a756942fee159538f7885169752e"}, + {file = "pycares-4.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1d0d5e69fa29e41b590a9dd5842454e8f34e2b928c92540aaf87e0161de8120"}, + {file = "pycares-4.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f096699c46f5dde2c7a8d91501a36d2d58500f4d63682e2ec14a0fed7cca6402"}, + {file = "pycares-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:429fe2065581a64a5f024f507b5f679bf37ea0ed39c3ba6289dba907e1c8a8f4"}, + {file = "pycares-4.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9ea2f6d48e64b413b97b41b47392087b452af9bf9f9d4d6d05305a159f45909f"}, + {file = "pycares-4.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:96d3aecd747a3fcd1e12c1ea1481b0813b4e0e80d40f314db7a86dda5bb1bd94"}, + {file = "pycares-4.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:32919f6eda7f5ea4df3e64149fc5792b0d455277d23d6d0fc365142062f35d80"}, + {file = "pycares-4.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:37add862461f9a3fc7ee4dd8b68465812b39456e21cebd5a33c414131ac05060"}, + {file = "pycares-4.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ed1d050d2c6d74a77c1b6c51fd99426cc000b4202a50d28d6ca75f7433099a6b"}, + {file = "pycares-4.5.0-cp39-cp39-win32.whl", hash = "sha256:887ac451ffe6e39ee46d3d0989c7bb829933d77e1dad5776511d825fc7e6a25b"}, + {file = "pycares-4.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c8b87c05740595bc8051dc98e51f022f003750e7da90f62f7a9fd50e330b196"}, + {file = "pycares-4.5.0.tar.gz", hash = "sha256:025b6c2ffea4e9fb8f9a097381c2fecb24aff23fbd6906e70da22ec9ba60e19d"}, ] [package.dependencies] @@ -1858,16 +1878,6 @@ files = [ [package.extras] windows-terminal = ["colorama (>=0.4.6)"] -[[package]] -name = "pyperclip" -version = "1.9.0" -description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" -optional = false -python-versions = "*" -files = [ - {file = "pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310"}, -] - [[package]] name = "pyqt6" version = "6.7.1" @@ -2345,10 +2355,8 @@ develop = true [package.dependencies] colorlog = "^6.8.2" -httpx = "^0.27.2" msgspec = "^0.18.5" pdbp = "^1.5.0" -pyperclip = "^1.9.0" tricycle = "^0.4.1" trio = "^0.24" trio-typing = "^0.10.0" @@ -2649,81 +2657,76 @@ files = [ [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] @@ -2798,93 +2801,93 @@ test = ["pytest"] [[package]] name = "yarl" -version = "1.17.1" +version = "1.18.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" files = [ - {file = "yarl-1.17.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1794853124e2f663f0ea54efb0340b457f08d40a1cef78edfa086576179c91"}, - {file = "yarl-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fbea1751729afe607d84acfd01efd95e3b31db148a181a441984ce9b3d3469da"}, - {file = "yarl-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ee427208c675f1b6e344a1f89376a9613fc30b52646a04ac0c1f6587c7e46ec"}, - {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b74ff4767d3ef47ffe0cd1d89379dc4d828d4873e5528976ced3b44fe5b0a21"}, - {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62a91aefff3d11bf60e5956d340eb507a983a7ec802b19072bb989ce120cd948"}, - {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:846dd2e1243407133d3195d2d7e4ceefcaa5f5bf7278f0a9bda00967e6326b04"}, - {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3"}, - {file = "yarl-1.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc7c92c1baa629cb03ecb0c3d12564f172218fb1739f54bf5f3881844daadc6d"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae3476e934b9d714aa8000d2e4c01eb2590eee10b9d8cd03e7983ad65dfbfcba"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c7e177c619342e407415d4f35dec63d2d134d951e24b5166afcdfd1362828e17"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64cc6e97f14cf8a275d79c5002281f3040c12e2e4220623b5759ea7f9868d6a5"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:84c063af19ef5130084db70ada40ce63a84f6c1ef4d3dbc34e5e8c4febb20822"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:482c122b72e3c5ec98f11457aeb436ae4aecca75de19b3d1de7cf88bc40db82f"}, - {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:380e6c38ef692b8fd5a0f6d1fa8774d81ebc08cfbd624b1bca62a4d4af2f9931"}, - {file = "yarl-1.17.1-cp310-cp310-win32.whl", hash = "sha256:16bca6678a83657dd48df84b51bd56a6c6bd401853aef6d09dc2506a78484c7b"}, - {file = "yarl-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:561c87fea99545ef7d692403c110b2f99dced6dff93056d6e04384ad3bc46243"}, - {file = "yarl-1.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217"}, - {file = "yarl-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988"}, - {file = "yarl-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75"}, - {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca"}, - {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74"}, - {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f"}, - {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d"}, - {file = "yarl-1.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4"}, - {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4"}, - {file = "yarl-1.17.1-cp311-cp311-win32.whl", hash = "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7"}, - {file = "yarl-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3"}, - {file = "yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61"}, - {file = "yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d"}, - {file = "yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139"}, - {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5"}, - {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac"}, - {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463"}, - {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147"}, - {file = "yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c"}, - {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199"}, - {file = "yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96"}, - {file = "yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df"}, - {file = "yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488"}, - {file = "yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374"}, - {file = "yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac"}, - {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170"}, - {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8"}, - {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938"}, - {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e"}, - {file = "yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299"}, - {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258"}, - {file = "yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2"}, - {file = "yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda"}, - {file = "yarl-1.17.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8994b29c462de9a8fce2d591028b986dbbe1b32f3ad600b2d3e1c482c93abad6"}, - {file = "yarl-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9cbfbc5faca235fbdf531b93aa0f9f005ec7d267d9d738761a4d42b744ea159"}, - {file = "yarl-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b40d1bf6e6f74f7c0a567a9e5e778bbd4699d1d3d2c0fe46f4b717eef9e96b95"}, - {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5efe0661b9fcd6246f27957f6ae1c0eb29bc60552820f01e970b4996e016004"}, - {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5c4804e4039f487e942c13381e6c27b4b4e66066d94ef1fae3f6ba8b953f383"}, - {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5d6a6c9602fd4598fa07e0389e19fe199ae96449008d8304bf5d47cb745462e"}, - {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4c9156c4d1eb490fe374fb294deeb7bc7eaccda50e23775b2354b6a6739934"}, - {file = "yarl-1.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6324274b4e0e2fa1b3eccb25997b1c9ed134ff61d296448ab8269f5ac068c4c"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d8a8b74d843c2638f3864a17d97a4acda58e40d3e44b6303b8cc3d3c44ae2d29"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7fac95714b09da9278a0b52e492466f773cfe37651cf467a83a1b659be24bf71"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c180ac742a083e109c1a18151f4dd8675f32679985a1c750d2ff806796165b55"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578d00c9b7fccfa1745a44f4eddfdc99d723d157dad26764538fbdda37209857"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1a3b91c44efa29e6c8ef8a9a2b583347998e2ba52c5d8280dbd5919c02dfc3b5"}, - {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a7ac5b4984c468ce4f4a553df281450df0a34aefae02e58d77a0847be8d1e11f"}, - {file = "yarl-1.17.1-cp39-cp39-win32.whl", hash = "sha256:7294e38f9aa2e9f05f765b28ffdc5d81378508ce6dadbe93f6d464a8c9594473"}, - {file = "yarl-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:eb6dce402734575e1a8cc0bb1509afca508a400a57ce13d306ea2c663bad1138"}, - {file = "yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06"}, - {file = "yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:074fee89caab89a97e18ef5f29060ef61ba3cae6cd77673acc54bfdd3214b7b7"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b026cf2c32daf48d90c0c4e406815c3f8f4cfe0c6dfccb094a9add1ff6a0e41a"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae38bd86eae3ba3d2ce5636cc9e23c80c9db2e9cb557e40b98153ed102b5a736"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:685cc37f3f307c6a8e879986c6d85328f4c637f002e219f50e2ef66f7e062c1d"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8254dbfce84ee5d1e81051ee7a0f1536c108ba294c0fdb5933476398df0654f3"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20de4a8b04de70c49698dc2390b7fd2d18d424d3b876371f9b775e2b462d4b41"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0a2074a37285570d54b55820687de3d2f2b9ecf1b714e482e48c9e7c0402038"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f576ed278860df2721a5d57da3381040176ef1d07def9688a385c8330db61a1"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3a3709450a574d61be6ac53d582496014342ea34876af8dc17cc16da32826c9a"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bd80ed29761490c622edde5dd70537ca8c992c2952eb62ed46984f8eff66d6e8"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:32141e13a1d5a48525e519c9197d3f4d9744d818d5c7d6547524cc9eccc8971e"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8b8d3e4e014fb4274f1c5bf61511d2199e263909fb0b8bda2a7428b0894e8dc6"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:701bb4a8f4de191c8c0cc9a1e6d5142f4df880e9d1210e333b829ca9425570ed"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a45d94075ac0647621eaaf693c8751813a3eccac455d423f473ffed38c8ac5c9"}, + {file = "yarl-1.18.0-cp310-cp310-win32.whl", hash = "sha256:34176bfb082add67cb2a20abd85854165540891147f88b687a5ed0dc225750a0"}, + {file = "yarl-1.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:73553bbeea7d6ec88c08ad8027f4e992798f0abc459361bf06641c71972794dc"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b8e8c516dc4e1a51d86ac975b0350735007e554c962281c432eaa5822aa9765c"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e6b4466714a73f5251d84b471475850954f1fa6acce4d3f404da1d55d644c34"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c893f8c1a6d48b25961e00922724732d00b39de8bb0b451307482dc87bddcd74"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13aaf2bdbc8c86ddce48626b15f4987f22e80d898818d735b20bd58f17292ee8"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd21c0128e301851de51bc607b0a6da50e82dc34e9601f4b508d08cc89ee7929"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205de377bd23365cd85562c9c6c33844050a93661640fda38e0567d2826b50df"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed69af4fe2a0949b1ea1d012bf065c77b4c7822bad4737f17807af2adb15a73c"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e1c18890091aa3cc8a77967943476b729dc2016f4cfe11e45d89b12519d4a93"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91b8fb9427e33f83ca2ba9501221ffaac1ecf0407f758c4d2f283c523da185ee"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:536a7a8a53b75b2e98ff96edb2dfb91a26b81c4fed82782035767db5a465be46"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a64619a9c47c25582190af38e9eb382279ad42e1f06034f14d794670796016c0"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c73a6bbc97ba1b5a0c3c992ae93d721c395bdbb120492759b94cc1ac71bc6350"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a173401d7821a2a81c7b47d4e7d5c4021375a1441af0c58611c1957445055056"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7520e799b1f84e095cce919bd6c23c9d49472deeef25fe1ef960b04cca51c3fc"}, + {file = "yarl-1.18.0-cp311-cp311-win32.whl", hash = "sha256:c4cb992d8090d5ae5f7afa6754d7211c578be0c45f54d3d94f7781c495d56716"}, + {file = "yarl-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:52c136f348605974c9b1c878addd6b7a60e3bf2245833e370862009b86fa4689"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1ece25e2251c28bab737bdf0519c88189b3dd9492dc086a1d77336d940c28ced"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:454902dc1830d935c90b5b53c863ba2a98dcde0fbaa31ca2ed1ad33b2a7171c6"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01be8688fc211dc237e628fcc209dda412d35de7642453059a0553747018d075"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d26f1fa9fa2167bb238f6f4b20218eb4e88dd3ef21bb8f97439fa6b5313e30d"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b234a4a9248a9f000b7a5dfe84b8cb6210ee5120ae70eb72a4dcbdb4c528f72f"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe94d1de77c4cd8caff1bd5480e22342dbd54c93929f5943495d9c1e8abe9f42"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4c90c5363c6b0a54188122b61edb919c2cd1119684999d08cd5e538813a28e"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a98ecadc5a241c9ba06de08127ee4796e1009555efd791bac514207862b43d"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9106025c7f261f9f5144f9aa7681d43867eed06349a7cfb297a1bc804de2f0d1"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f275ede6199d0f1ed4ea5d55a7b7573ccd40d97aee7808559e1298fe6efc8dbd"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f7edeb1dcc7f50a2c8e08b9dc13a413903b7817e72273f00878cb70e766bdb3b"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c083f6dd6951b86e484ebfc9c3524b49bcaa9c420cb4b2a78ef9f7a512bfcc85"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:80741ec5b471fbdfb997821b2842c59660a1c930ceb42f8a84ba8ca0f25a66aa"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1a3297b9cad594e1ff0c040d2881d7d3a74124a3c73e00c3c71526a1234a9f7"}, + {file = "yarl-1.18.0-cp312-cp312-win32.whl", hash = "sha256:cd6ab7d6776c186f544f893b45ee0c883542b35e8a493db74665d2e594d3ca75"}, + {file = "yarl-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:039c299a0864d1f43c3e31570045635034ea7021db41bf4842693a72aca8df3a"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6fb64dd45453225f57d82c4764818d7a205ee31ce193e9f0086e493916bd4f72"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3adaaf9c6b1b4fc258584f4443f24d775a2086aee82d1387e48a8b4f3d6aecf6"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da206d1ec78438a563c5429ab808a2b23ad7bc025c8adbf08540dde202be37d5"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:576d258b21c1db4c6449b1c572c75d03f16a482eb380be8003682bdbe7db2f28"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e547c0a375c4bfcdd60eef82e7e0e8698bf84c239d715f5c1278a73050393"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3818eabaefb90adeb5e0f62f047310079d426387991106d4fbf3519eec7d90a"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f72421246c21af6a92fbc8c13b6d4c5427dfd949049b937c3b731f2f9076bd"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fa7d37f2ada0f42e0723632993ed422f2a679af0e200874d9d861720a54f53e"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:42ba84e2ac26a3f252715f8ec17e6fdc0cbf95b9617c5367579fafcd7fba50eb"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6a49ad0102c0f0ba839628d0bf45973c86ce7b590cdedf7540d5b1833ddc6f00"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96404e8d5e1bbe36bdaa84ef89dc36f0e75939e060ca5cd45451aba01db02902"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a0509475d714df8f6d498935b3f307cd122c4ca76f7d426c7e1bb791bcd87eda"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ff116f0285b5c8b3b9a2680aeca29a858b3b9e0402fc79fd850b32c2bcb9f8b"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2580c1d7e66e6d29d6e11855e3b1c6381971e0edd9a5066e6c14d79bc8967af"}, + {file = "yarl-1.18.0-cp313-cp313-win32.whl", hash = "sha256:14408cc4d34e202caba7b5ac9cc84700e3421a9e2d1b157d744d101b061a4a88"}, + {file = "yarl-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db1537e9cb846eb0ff206eac667f627794be8b71368c1ab3207ec7b6f8c5afc"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fa2c9cb607e0f660d48c54a63de7a9b36fef62f6b8bd50ff592ce1137e73ac7d"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c0f4808644baf0a434a3442df5e0bedf8d05208f0719cedcd499e168b23bfdc4"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7db9584235895a1dffca17e1c634b13870852094f6389b68dcc6338086aa7b08"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f8d27d6f93ceeeb80aa6980e883aa57895270f7f41842b92247e65d7aeddf"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:609ffd44fed2ed88d9b4ef62ee860cf86446cf066333ad4ce4123505b819e581"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f172b8b2c72a13a06ea49225a9c47079549036ad1b34afa12d5491b881f5b993"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89ae7de94631b60d468412c18290d358a9d805182373d804ec839978b120422"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:466d31fd043ef9af822ee3f1df8fdff4e8c199a7f4012c2642006af240eade17"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7609b8462351c4836b3edce4201acb6dd46187b207c589b30a87ffd1813b48dc"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d9d4f5e471e8dc49b593a80766c2328257e405f943c56a3dc985c125732bc4cf"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:67b336c15e564d76869c9a21316f90edf546809a5796a083b8f57c845056bc01"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b212452b80cae26cb767aa045b051740e464c5129b7bd739c58fbb7deb339e7b"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:38b39b7b3e692b6c92b986b00137a3891eddb66311b229d1940dcbd4f025083c"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a7ee6884a8848792d58b854946b685521f41d8871afa65e0d4a774954e9c9e89"}, + {file = "yarl-1.18.0-cp39-cp39-win32.whl", hash = "sha256:b4095c5019bb889aa866bf12ed4c85c0daea5aafcb7c20d1519f02a1e738f07f"}, + {file = "yarl-1.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:2d90f2e4d16a5b0915ee065218b435d2ef619dd228973b1b47d262a6f7cd8fa5"}, + {file = "yarl-1.18.0-py3-none-any.whl", hash = "sha256:dbf53db46f7cf176ee01d8d98c39381440776fcda13779d269a8ba664f69bec0"}, + {file = "yarl-1.18.0.tar.gz", hash = "sha256:20d95535e7d833889982bfe7cc321b7f63bf8879788fee982c76ae2b24cfb715"}, ] [package.dependencies] -- 2.34.1 From cbc5168b8d44c55061f02ac9b9ef835f3d30ce2c Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Thu, 5 Dec 2024 23:43:13 -0300 Subject: [PATCH 19/29] renaming variable fixed variable name for better understanding. --- piker/brokers/deribit/api.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 57861368..83e8b2a7 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -833,7 +833,7 @@ async def aio_open_interest_feed_relay( to_trio: trio.abc.SendChannel, ) -> None: - max_losses: Decimal = Decimal('Infinity') + total_intrinsic_value: Decimal = Decimal('Infinity') max_pain: Decimal = Decimal(0) async def _trade( @@ -859,7 +859,7 @@ async def aio_open_interest_feed_relay( ''' nonlocal intrinsic_values nonlocal oi_by_strikes - nonlocal max_losses + nonlocal total_intrinsic_value nonlocal max_pain symbol: Symbol = str_to_cb_sym(oi.symbol) @@ -894,14 +894,14 @@ async def aio_open_interest_feed_relay( intrinsic_values[f'{strike}']['total'] = (call_cash + put_cash) for strike in intrinsic_values: - if intrinsic_values[f'{strike}']['total'] < max_losses: - max_losses = intrinsic_values[f'{strike}']['total'] + if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value: + total_intrinsic_value = intrinsic_values[f'{strike}']['total'] max_pain = strike print('-----------------------------------------------') - print(f'time: {oi.timestamp}') - print(f'max_pain: {max_pain}') - print(f'max_losses: {max_losses}') + print(f'expiry date: {expiry_date}') + print(f'max_pain: {max_pain}') + print(f'total intrinsic value: {total_intrinsic_value}') print('-----------------------------------------------') @@ -931,8 +931,7 @@ async def aio_open_interest_feed_relay( @acm async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: - - expiry_date: str = '20DEC24' + expiry_date: str = '6DEC24' instruments: list[Symbol] = [] intrinsic_values: dict[str, dict[str, Decimal]] = {} oi_by_strikes: dict[str, dict[str, Decimal]] -- 2.34.1 From ec1da6134bb00176bdd1c86fd00139e0f9461112 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Thu, 5 Dec 2024 23:49:02 -0300 Subject: [PATCH 20/29] Update api.py Now intrinsic values list is initialize in the aio_open_interest_feed_relay instead in the scope above. --- piker/brokers/deribit/api.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 83e8b2a7..f01f6112 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -827,12 +827,12 @@ async def maybe_open_price_feed( async def aio_open_interest_feed_relay( fh: FeedHandler, instruments: list, - intrinsic_values: dict[str, Decimal], oi_by_strikes: dict[str, dict[str, Decimal]], from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: + intrinsic_values: dict[str, dict[str, Decimal]] = {} total_intrinsic_value: Decimal = Decimal('Infinity') max_pain: Decimal = Decimal(0) @@ -933,7 +933,6 @@ async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: expiry_date: str = '6DEC24' instruments: list[Symbol] = [] - intrinsic_values: dict[str, dict[str, Decimal]] = {} oi_by_strikes: dict[str, dict[str, Decimal]] async with get_client( @@ -953,7 +952,6 @@ async def open_oi_feed( aio_open_interest_feed_relay, fh, instruments, - intrinsic_values, oi_by_strikes, ) ) as (first, chan) -- 2.34.1 From ca5e1b6ed14460dbde74f5044187cccba7ae8d8f Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 6 Dec 2024 07:41:48 -0300 Subject: [PATCH 21/29] removed unused variable minor refactor expiry date changed to 20DEC24 --- piker/brokers/deribit/api.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index f01f6112..b0bedaa2 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -875,12 +875,10 @@ async def aio_open_interest_feed_relay( open_interest: Decimal = oi.open_interest oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest - is_ready = check_if_complete(oi_by_strikes) - if is_ready: + if check_if_complete(oi_by_strikes): + closes: list[str] = sorted(oi_by_strikes.keys()) for strike in oi_by_strikes: s: Decimal = Decimal(f'{strike}') - close_losses = Decimal(0) - closes: list[str] = sorted(oi_by_strikes.keys()) call_cash: Decimal = Decimal(0) put_cash: Decimal = Decimal(0) for close in closes: @@ -888,10 +886,11 @@ async def aio_open_interest_feed_relay( call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C']) put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P']) - intrinsic_values[f'{strike}'] = {} - intrinsic_values[f'{strike}']['C'] = call_cash - intrinsic_values[f'{strike}']['P'] = put_cash - intrinsic_values[f'{strike}']['total'] = (call_cash + put_cash) + intrinsic_values[strike] = { + 'C': call_cash, + 'P': put_cash, + 'total': call_cash + put_cash, + } for strike in intrinsic_values: if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value: @@ -931,7 +930,7 @@ async def aio_open_interest_feed_relay( @acm async def open_oi_feed( ) -> to_asyncio.LinkedTaskChannel: - expiry_date: str = '6DEC24' + expiry_date: str = '20DEC24' instruments: list[Symbol] = [] oi_by_strikes: dict[str, dict[str, Decimal]] -- 2.34.1 From 57059da68255eacca488987f4d8ee86a7ccfe519 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sat, 7 Dec 2024 10:13:12 -0300 Subject: [PATCH 22/29] moved function out of api --- max_pain.py | 14 ++++++++++++++ piker/brokers/deribit/api.py | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/max_pain.py b/max_pain.py index b5d4d815..9e10289d 100644 --- a/max_pain.py +++ b/max_pain.py @@ -10,6 +10,20 @@ async def max_pain_daemon( ) -> None: async with maybe_open_oi_feed() as oi_feed: print('Im in...') + def check_if_complete( + oi: dict[str, dict[str, Decimal | None]], + + ) -> bool: + for strike in oi: + if ( + oi[strike]['C'] == None + or + oi[strike]['P'] == None + ): + return False + + return True + async def main(): diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index b0bedaa2..19a3297a 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -246,20 +246,6 @@ def get_config() -> dict[str, Any]: return section -def check_if_complete( - oi: dict[str, dict[str, Decimal | None]], - - ) -> bool: - for strike in oi: - if ( - oi[strike]['C'] == None - or - oi[strike]['P'] == None - ): - return False - - return True - class Client: ''' -- 2.34.1 From 3e613ab2a04fa5eb7650638dbc90399e0f0b2cb4 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sat, 7 Dec 2024 10:16:37 -0300 Subject: [PATCH 23/29] fix the input values for acm related to oi --- max_pain.py | 2 -- piker/brokers/deribit/api.py | 9 ++++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/max_pain.py b/max_pain.py index 9e10289d..d6f4e147 100644 --- a/max_pain.py +++ b/max_pain.py @@ -8,8 +8,6 @@ from piker.brokers.deribit.api import ( async def max_pain_daemon( ) -> None: - async with maybe_open_oi_feed() as oi_feed: - print('Im in...') def check_if_complete( oi: dict[str, dict[str, Decimal | None]], diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 19a3297a..159aa486 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -812,8 +812,8 @@ async def maybe_open_price_feed( async def aio_open_interest_feed_relay( fh: FeedHandler, - instruments: list, oi_by_strikes: dict[str, dict[str, Decimal]], + instruments: list[Symbol], from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: @@ -915,6 +915,7 @@ async def aio_open_interest_feed_relay( @acm async def open_oi_feed( + instruments: list[Symbol], ) -> to_asyncio.LinkedTaskChannel: expiry_date: str = '20DEC24' instruments: list[Symbol] = [] @@ -946,12 +947,18 @@ async def open_oi_feed( @acm async def maybe_open_oi_feed( + instruments: list[Symbol], ) -> trio.abc.ReceiveStream: # TODO: add a predicate to maybe_open_context feed: to_asyncio.LinkedTaskChannel async with maybe_open_context( acm_func=open_oi_feed, + kwargs={ + 'instruments': instruments + }, + key=f'{instruments[0]}', + ) as (cache_hit, feed): if cache_hit: yield broadcast_receiver(feed, 10) -- 2.34.1 From 0563b916a37969a1f0e439ab5d9f2fcb2cefd4e7 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sat, 7 Dec 2024 10:17:27 -0300 Subject: [PATCH 24/29] major refactor all the logic now in the max_pain script --- max_pain.py | 84 ++++++++++++++++++++++++++++++++++++ piker/brokers/deribit/api.py | 59 +++---------------------- 2 files changed, 91 insertions(+), 52 deletions(-) diff --git a/max_pain.py b/max_pain.py index d6f4e147..a2d1d64b 100644 --- a/max_pain.py +++ b/max_pain.py @@ -1,13 +1,22 @@ #!/usr/bin/env python +from decimal import ( + Decimal, +) import trio import tractor +from pprint import pformat from piker.brokers.deribit.api import ( + get_client, maybe_open_oi_feed, ) async def max_pain_daemon( ) -> None: + expiry_date: str = '13DEC24' + instruments: list[Symbol] = [] + oi_by_strikes: dict[str, dict[str, Decimal]] + def check_if_complete( oi: dict[str, dict[str, Decimal | None]], @@ -22,6 +31,81 @@ async def max_pain_daemon( return True + def get_max_pain( + oi_by_strikes: dict[str, dict[str, Decimal]] + ) -> dict[str, str | Decimal]: + ''' + This method requires only the strike_prices and oi for call + and puts, the closes list are the same as the strike_prices + the idea is to sum all the calls and puts cash for each strike + and the ITM strikes from that strike, the lowest value is what we + are looking for the intrinsic value. + + ''' + + nonlocal timestamp + # We meed to find the lowest value, so we start at + # infinity to ensure that, and the max_pain must be + # an amount greater than zero. + total_intrinsic_value: Decimal = Decimal('Infinity') + max_pain: Decimal = Decimal(0) + + intrinsic_values: dict[str, dict[str, Decimal]] = {} + closes: list[str] = sorted(oi_by_strikes.keys()) + for strike in oi_by_strikes: + s: Decimal = Decimal(f'{strike}') + call_cash: Decimal = Decimal(0) + put_cash: Decimal = Decimal(0) + for close in closes: + c: Decimal = Decimal(f'{close}') + call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C']) + put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P']) + + intrinsic_values[strike] = { + 'C': call_cash, + 'P': put_cash, + 'total': call_cash + put_cash, + } + + for strike in intrinsic_values: + if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value: + total_intrinsic_value = intrinsic_values[f'{strike}']['total'] + max_pain = strike\ + + return { + 'timestamp': timestamp, + 'expiry_date': expiry_date, + 'total_intrinsic_value': total_intrinsic_value, + 'max_pain': max_pain, + } + + + async with get_client( + ) as client: + instruments = await client.get_instruments( + expiry_date=expiry_date, + ) + oi_by_strikes = client.get_strikes_dict(instruments) + + async with maybe_open_oi_feed( + instruments, + ) as oi_feed: + async for msg in oi_feed: + if 'oi' == msg[0]: + timestamp = msg[1]['timestamp'] + strike_price = msg[1]['strike_price'] + option_type = msg[1]['option_type'] + open_interest = msg[1]['open_interest'] + oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest + + if check_if_complete(oi_by_strikes): + max_pain = get_max_pain(oi_by_strikes) + print('-----------------------------------------------') + print(f'timestamp: {max_pain['timestamp']}') + print(f'expiry_date: {max_pain['expiry_date']}') + print(f'max_pain: {max_pain['max_pain']}') + print(f'total intrinsic value: {max_pain['total_intrinsic_value']}') + print('-----------------------------------------------') async def main(): diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 159aa486..e05f86a5 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -812,16 +812,10 @@ async def maybe_open_price_feed( async def aio_open_interest_feed_relay( fh: FeedHandler, - oi_by_strikes: dict[str, dict[str, Decimal]], instruments: list[Symbol], from_trio: asyncio.Queue, to_trio: trio.abc.SendChannel, ) -> None: - - intrinsic_values: dict[str, dict[str, Decimal]] = {} - total_intrinsic_value: Decimal = Decimal('Infinity') - max_pain: Decimal = Decimal(0) - async def _trade( trade: Trade, # cryptofeed, NOT ours from `.venues`! receipt_timestamp: int, @@ -843,11 +837,6 @@ async def aio_open_interest_feed_relay( Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. ''' - nonlocal intrinsic_values - nonlocal oi_by_strikes - nonlocal total_intrinsic_value - nonlocal max_pain - symbol: Symbol = str_to_cb_sym(oi.symbol) piker_sym: str = cb_sym_to_deribit_inst(symbol) ( @@ -858,36 +847,13 @@ async def aio_open_interest_feed_relay( ) = tuple( piker_sym.split('-') ) - open_interest: Decimal = oi.open_interest - oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest - - if check_if_complete(oi_by_strikes): - closes: list[str] = sorted(oi_by_strikes.keys()) - for strike in oi_by_strikes: - s: Decimal = Decimal(f'{strike}') - call_cash: Decimal = Decimal(0) - put_cash: Decimal = Decimal(0) - for close in closes: - c: Decimal = Decimal(f'{close}') - call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C']) - put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P']) - - intrinsic_values[strike] = { - 'C': call_cash, - 'P': put_cash, - 'total': call_cash + put_cash, - } - - for strike in intrinsic_values: - if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value: - total_intrinsic_value = intrinsic_values[f'{strike}']['total'] - max_pain = strike - - print('-----------------------------------------------') - print(f'expiry date: {expiry_date}') - print(f'max_pain: {max_pain}') - print(f'total intrinsic value: {total_intrinsic_value}') - print('-----------------------------------------------') + msg = { + 'timestamp': oi.timestamp, + 'strike_price': strike_price, + 'option_type': option_type, + 'open_interest': Decimal(oi.open_interest), + } + to_trio.send_nowait(('oi', msg)) channels = [TRADES, OPEN_INTEREST] @@ -917,16 +883,6 @@ async def aio_open_interest_feed_relay( async def open_oi_feed( instruments: list[Symbol], ) -> to_asyncio.LinkedTaskChannel: - expiry_date: str = '20DEC24' - instruments: list[Symbol] = [] - oi_by_strikes: dict[str, dict[str, Decimal]] - - async with get_client( - ) as client: - instruments = await client.get_instruments( - expiry_date=expiry_date, - ) - oi_by_strikes = client.get_strikes_dict(instruments) fh: FeedHandler first: None @@ -938,7 +894,6 @@ async def open_oi_feed( aio_open_interest_feed_relay, fh, instruments, - oi_by_strikes, ) ) as (first, chan) ): -- 2.34.1 From f31d868a55affe2ad56fed846176a69093a8dbf3 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sat, 7 Dec 2024 10:37:34 -0300 Subject: [PATCH 25/29] get_config refactor --- piker/brokers/deribit/api.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index e05f86a5..82cb8d8f 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -234,17 +234,18 @@ def get_config() -> dict[str, Any]: ) conf_option = section.get('option', {}) - section = {} # clear the dict to reuse it - section['deribit'] = {} - section['deribit']['key_id'] = conf_option.get('api_key') - section['deribit']['key_secret'] = conf_option.get('api_secret') - section['log'] = {} - section['log']['filename'] = 'feedhandler.log' - section['log']['level'] = 'DEBUG' - section['log']['disabled'] = True - - return section + return { + 'deribit': { + 'key_id': conf_option.get('api_key'), + 'key_secret': conf_option.get('api_secret'), + }, + 'log': { + 'filename': 'feedhandler.log', + 'level': 'DEBUG', + 'disabled': True, + } + } class Client: @@ -912,7 +913,7 @@ async def maybe_open_oi_feed( kwargs={ 'instruments': instruments }, - key=f'{instruments[0]}', + key=f'{instruments[0].base}', ) as (cache_hit, feed): if cache_hit: -- 2.34.1 From 3295303e37eb561ac3af3dc641b55cfd7f6248b7 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sat, 7 Dec 2024 11:15:43 -0300 Subject: [PATCH 26/29] More configs refactor Now in the broker config file are the log configs for cryptofeed. --- piker/brokers/deribit/api.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 82cb8d8f..7efa6b65 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -234,16 +234,16 @@ def get_config() -> dict[str, Any]: ) conf_option = section.get('option', {}) - + conf_log = conf_option.get('log', {}) return { 'deribit': { - 'key_id': conf_option.get('api_key'), - 'key_secret': conf_option.get('api_secret'), + 'key_id': conf_option['key_id'], + 'key_secret': conf_option['key_secret'], }, 'log': { - 'filename': 'feedhandler.log', - 'level': 'DEBUG', - 'disabled': True, + 'filename': conf_log['filename'], + 'level': conf_log['level'], + 'disabled': conf_log['disabled'], } } -- 2.34.1 From f26a42e76f588d0ba0f2de8f72fbcd98d0c503ed Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sun, 8 Dec 2024 10:51:17 -0300 Subject: [PATCH 27/29] datetime for humans --- max_pain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/max_pain.py b/max_pain.py index a2d1d64b..e8b0f933 100644 --- a/max_pain.py +++ b/max_pain.py @@ -4,6 +4,7 @@ from decimal import ( ) import trio import tractor +from datetime import datetime from pprint import pformat from piker.brokers.deribit.api import ( get_client, @@ -101,7 +102,7 @@ async def max_pain_daemon( if check_if_complete(oi_by_strikes): max_pain = get_max_pain(oi_by_strikes) print('-----------------------------------------------') - print(f'timestamp: {max_pain['timestamp']}') + print(f'timestamp: {datetime.fromtimestamp(max_pain['timestamp'])}') print(f'expiry_date: {max_pain['expiry_date']}') print(f'max_pain: {max_pain['max_pain']}') print(f'total intrinsic value: {max_pain['total_intrinsic_value']}') -- 2.34.1 From 1ac643018aad41115a05f24fdbe7e5eb7fb38039 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sun, 8 Dec 2024 13:34:58 -0300 Subject: [PATCH 28/29] added aux method for update and check if completed --- max_pain.py | 56 ++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/max_pain.py b/max_pain.py index e8b0f933..aef67944 100644 --- a/max_pain.py +++ b/max_pain.py @@ -11,6 +11,15 @@ from piker.brokers.deribit.api import ( maybe_open_oi_feed, ) +def check_if_complete( + oi: dict[str, dict[str, Decimal | None]] + ) -> bool: + return all( + oi[strike]['C'] is not None + and + oi[strike]['P'] is not None for strike in oi + ) + async def max_pain_daemon( ) -> None: @@ -18,19 +27,17 @@ async def max_pain_daemon( instruments: list[Symbol] = [] oi_by_strikes: dict[str, dict[str, Decimal]] - def check_if_complete( - oi: dict[str, dict[str, Decimal | None]], - - ) -> bool: - for strike in oi: - if ( - oi[strike]['C'] == None - or - oi[strike]['P'] == None - ): - return False - - return True + def update_oi_by_strikes(msg: tuple): + nonlocal oi_by_strikes + if 'oi' == msg[0]: + strike_price = msg[1]['strike_price'] + option_type = msg[1]['option_type'] + open_interest = msg[1]['open_interest'] + oi_by_strikes.setdefault( + strike_price, {} + ).update( + {option_type: open_interest} + ) def get_max_pain( oi_by_strikes: dict[str, dict[str, Decimal]] @@ -92,21 +99,18 @@ async def max_pain_daemon( instruments, ) as oi_feed: async for msg in oi_feed: - if 'oi' == msg[0]: - timestamp = msg[1]['timestamp'] - strike_price = msg[1]['strike_price'] - option_type = msg[1]['option_type'] - open_interest = msg[1]['open_interest'] - oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest + update_oi_by_strikes(msg) if check_if_complete(oi_by_strikes): - max_pain = get_max_pain(oi_by_strikes) - print('-----------------------------------------------') - print(f'timestamp: {datetime.fromtimestamp(max_pain['timestamp'])}') - print(f'expiry_date: {max_pain['expiry_date']}') - print(f'max_pain: {max_pain['max_pain']}') - print(f'total intrinsic value: {max_pain['total_intrinsic_value']}') - print('-----------------------------------------------') + if 'oi' == msg[0]: + timestamp = msg[1]['timestamp'] + max_pain = get_max_pain(oi_by_strikes) + print('-----------------------------------------------') + print(f'timestamp: {datetime.fromtimestamp(max_pain['timestamp'])}') + print(f'expiry_date: {max_pain['expiry_date']}') + print(f'max_pain: {max_pain['max_pain']}') + print(f'total intrinsic value: {max_pain['total_intrinsic_value']}') + print('-----------------------------------------------') async def main(): -- 2.34.1 From 3526d5d5642a808d99093fd38bef548f4e95bbf8 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Sun, 8 Dec 2024 13:38:23 -0300 Subject: [PATCH 29/29] minor refactor cleaning the code --- max_pain.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/max_pain.py b/max_pain.py index aef67944..468b1d3d 100644 --- a/max_pain.py +++ b/max_pain.py @@ -57,28 +57,25 @@ async def max_pain_daemon( # an amount greater than zero. total_intrinsic_value: Decimal = Decimal('Infinity') max_pain: Decimal = Decimal(0) - + call_cash: Decimal = Decimal(0) + put_cash: Decimal = Decimal(0) intrinsic_values: dict[str, dict[str, Decimal]] = {} - closes: list[str] = sorted(oi_by_strikes.keys()) - for strike in oi_by_strikes: - s: Decimal = Decimal(f'{strike}') - call_cash: Decimal = Decimal(0) - put_cash: Decimal = Decimal(0) - for close in closes: - c: Decimal = Decimal(f'{close}') - call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C']) - put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P']) - + closes: list = sorted(Decimal(close) for close in oi_by_strikes) + + for strike, oi in oi_by_strikes.items(): + s = Decimal(strike) + call_cash = sum(max(0, (s - c) * oi_by_strikes[str(c)]['C']) for c in closes) + put_cash = sum(max(0, (c - s) * oi_by_strikes[str(c)]['P']) for c in closes) + intrinsic_values[strike] = { 'C': call_cash, 'P': put_cash, 'total': call_cash + put_cash, } - for strike in intrinsic_values: - if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value: - total_intrinsic_value = intrinsic_values[f'{strike}']['total'] - max_pain = strike\ + if intrinsic_values[strike]['total'] < total_intrinsic_value: + total_intrinsic_value = intrinsic_values[strike]['total'] + max_pain = s return { 'timestamp': timestamp, @@ -87,7 +84,6 @@ async def max_pain_daemon( 'max_pain': max_pain, } - async with get_client( ) as client: instruments = await client.get_instruments( -- 2.34.1