From 5b5913a8ff5966e9db285bacd2962dc6e71793cf Mon Sep 17 00:00:00 2001 From: Graeme Holliday Date: Mon, 2 Dec 2024 19:00:07 -0500 Subject: [PATCH] update to v9.2 --- .github/workflows/python-app.yml | 4 +- Makefile | 2 +- pyproject.toml | 7 +- ttcli/app.py | 13 +- ttcli/data/ttcli.cfg | 25 +- ttcli/option.py | 1066 ++++++++++++++++++------------ ttcli/portfolio.py | 567 +++++++++------- ttcli/utils.py | 152 +++-- uv.lock | 739 ++++++++++----------- 9 files changed, 1447 insertions(+), 1128 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index ba8b9b4..5a3947c 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -23,6 +23,6 @@ jobs: - name: Lint with ruff run: | uv run ruff check ttcli/ - - name: Type check with mypy + - name: Type check with pyright run: | - uv run mypy -p ttcli + uv run pyright ttcli/ diff --git a/Makefile b/Makefile index a0580fa..fe89a6c 100644 --- a/Makefile +++ b/Makefile @@ -6,4 +6,4 @@ install: lint: uv run ruff check ttcli/ - uv run mypy -p ttcli + uv run pyright ttcli/ diff --git a/pyproject.toml b/pyproject.toml index 44e858c..1c8f484 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ authors = [ dependencies = [ "asyncclick>=8.1.7.2", "rich>=13.8.1", - "tastytrade>=8.3", + "tastytrade>=9.2", ] [project.urls] @@ -25,9 +25,12 @@ Homepage = "https://github.com/tastyware/tastytrade-cli" [tool.uv] dev-dependencies = [ "ipykernel>=6.29.5", - "mypy>=1.11.2", + "pyright>=1.1.389", "ruff>=0.6.7", ] [project.scripts] tt = "ttcli.app:main" + +[tool.hatch.build.targets.wheel] +packages = ["ttcli"] diff --git a/ttcli/app.py b/ttcli/app.py index 98f9de5..abd93cf 100644 --- a/ttcli/app.py +++ b/ttcli/app.py @@ -1,11 +1,8 @@ -import asyncio -import sys - import asyncclick as click from ttcli.option import option from ttcli.portfolio import portfolio -from ttcli.utils import CONTEXT_SETTINGS, VERSION, logger +from ttcli.utils import CONTEXT_SETTINGS, VERSION @click.group(context_settings=CONTEXT_SETTINGS) @@ -15,11 +12,7 @@ async def app(): def main(): - if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith('win'): - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - logger.debug('Using Windows-specific event loop policy') - app.add_command(option) - app.add_command(portfolio, name='pf') + app.add_command(portfolio, name="pf") - app(_anyio_backend='asyncio') + app(_anyio_backend="asyncio") diff --git a/ttcli/data/ttcli.cfg b/ttcli/data/ttcli.cfg index e028c66..f2d1f68 100644 --- a/ttcli/data/ttcli.cfg +++ b/ttcli/data/ttcli.cfg @@ -6,19 +6,20 @@ [portfolio] bp-target-percent-variation = 10 bp-max-percent-per-position = 5.0 -portfolio-delta-target = 0 -portfolio-delta-variation = 5 -positions-show-mark-price = false -positions-show-trade-price = false -positions-show-delta = false -positions-show-theta = false -positions-show-gamma = false +delta-target = 0 +delta-variation = 5 +[portfolio.positions] +show-mark-price = false +show-trade-price = false +show-delta = false +show-theta = false +show-gamma = false [order] bp-warn-above-percent = 5 # TODO: make this a float -[option] -chain-show-delta = true -chain-show-volume = false -chain-show-open-interest = false -chain-show-theta = false +[option.chain] +show-delta = true +show-volume = true +show-open-interest = true +show-theta = true diff --git a/ttcli/option.py b/ttcli/option.py index 5d0efb5..18df9e9 100644 --- a/ttcli/option.py +++ b/ttcli/option.py @@ -1,3 +1,4 @@ +import asyncio from decimal import Decimal from typing import Optional @@ -5,19 +6,28 @@ from rich.console import Console from rich.table import Table from tastytrade import DXLinkStreamer -from tastytrade.dxfeed import EventType, Greeks, Quote -from tastytrade.instruments import (Future, FutureOption, - NestedFutureOptionChain, - NestedFutureOptionChainExpiration, - NestedOptionChain, - NestedOptionChainExpiration, Option) -from tastytrade.order import (NewOrder, OrderAction, OrderTimeInForce, - OrderType, PriceEffect) -from tastytrade.utils import get_tasty_monthly +from tastytrade.dxfeed import Greeks, Summary, Quote, Trade +from tastytrade.instruments import ( + Future, + FutureOption, + NestedFutureOptionChain, + NestedFutureOptionChainExpiration, + NestedOptionChain, + NestedOptionChainExpiration, + Option, +) +from tastytrade.order import NewOrder, OrderAction, OrderTimeInForce, OrderType +from tastytrade.utils import TastytradeError, get_tasty_monthly from datetime import datetime -from ttcli.utils import (ZERO, RenewableSession, get_confirmation, is_monthly, - print_error, print_warning, test_order_handle_errors) +from ttcli.utils import ( + RenewableSession, + get_confirmation, + is_monthly, + listen_events, + print_error, + print_warning, +) def round_to_width(x, base=Decimal(1)): @@ -25,53 +35,51 @@ def round_to_width(x, base=Decimal(1)): def choose_expiration( - chain: NestedOptionChain, - include_weeklies: bool = False + chain: NestedOptionChain, include_weeklies: bool = False ) -> NestedOptionChainExpiration: exps = [e for e in chain.expirations] if not include_weeklies: exps = [e for e in exps if is_monthly(e.expiration_date)] exps.sort(key=lambda e: e.expiration_date) default = get_tasty_monthly() - default_option = None + default_option: NestedOptionChainExpiration for i, exp in enumerate(exps): if exp.expiration_date == default: default_option = exp - print(f'{i + 1}) {exp.expiration_date} (default)') + print(f"{i + 1}) {exp.expiration_date} (default)") else: - print(f'{i + 1}) {exp.expiration_date}') + print(f"{i + 1}) {exp.expiration_date}") choice = 0 while choice not in range(1, len(exps) + 1): try: - raw = input('Please choose an expiration: ') + raw = input("Please choose an expiration: ") choice = int(raw) except ValueError: - return default_option + return default_option # type: ignore return exps[choice - 1] def choose_futures_expiration( - chain: NestedFutureOptionChain, - include_weeklies: bool = False + chain: NestedFutureOptionChain, include_weeklies: bool = False ) -> NestedFutureOptionChainExpiration: - chain = chain.option_chains[0] + subchain = chain.option_chains[0] if include_weeklies: - exps = [e for e in chain.expirations] + exps = [e for e in subchain.expirations] else: - exps = [e for e in chain.expirations if e.expiration_type != 'Weekly'] + exps = [e for e in subchain.expirations if e.expiration_type != "Weekly"] exps.sort(key=lambda e: e.expiration_date) # find closest to 45 DTE default = min(exps, key=lambda e: abs(e.days_to_expiration - 45)) for i, exp in enumerate(exps): if exp == default: - print(f'{i + 1}) {exp.expiration_date} [{exp.underlying_symbol}] (default)') + print(f"{i + 1}) {exp.expiration_date} [{exp.underlying_symbol}] (default)") else: - print(f'{i + 1}) {exp.expiration_date} [{exp.underlying_symbol}]') + print(f"{i + 1}) {exp.expiration_date} [{exp.underlying_symbol}]") choice = 0 while choice not in range(1, len(exps) + 1): try: - raw = input('Please choose an expiration: ') + raw = input("Please choose an expiration: ") choice = int(raw) except ValueError: return default @@ -79,386 +87,536 @@ def choose_futures_expiration( return exps[choice - 1] -async def listen_quotes( - n_quotes: int, - streamer: DXLinkStreamer, - skip: str | None = None -) -> dict[str, Quote]: - quote_dict = {} - async for quote in streamer.listen(EventType.QUOTE): - if quote.eventSymbol != skip: - quote_dict[quote.eventSymbol] = quote - if len(quote_dict) == n_quotes: - return quote_dict - - -async def listen_greeks( - n_greeks: int, - streamer: DXLinkStreamer -) -> dict[str, Greeks]: - greeks_dict = {} - async for greeks in streamer.listen(EventType.GREEKS): - greeks_dict[greeks.eventSymbol] = greeks - if len(greeks_dict) == n_greeks: - return greeks_dict - - -async def listen_summaries( - n_summaries: int, - streamer: DXLinkStreamer -) -> dict[str, Quote]: - summary_dict = {} - async for summary in streamer.listen(EventType.SUMMARY): - summary_dict[summary.eventSymbol] = summary - if len(summary_dict) == n_summaries: - return summary_dict - - -async def listen_trades( - n_trades: int, - streamer: DXLinkStreamer -) -> dict[str, Quote]: - trade_dict = {} - async for trade in streamer.listen(EventType.TRADE): - trade_dict[trade.eventSymbol] = trade - if len(trade_dict) == n_trades: - return trade_dict - - -@click.group(chain=True, help='Buy, sell, and analyze options.') +@click.group(chain=True, help="Buy, sell, and analyze options.") async def option(): pass -@option.command(help='Buy or sell calls with the given parameters.') -@click.option('-s', '--strike', type=Decimal, help='The chosen strike for the option.') -@click.option('-d', '--delta', type=int, help='The chosen delta for the option.') -@click.option('-w', '--width', type=int, help='Turns the order into a spread with the given width.') -@click.option('--gtc', is_flag=True, help='Place a GTC order instead of a day order.') -@click.option('--weeklies', is_flag=True, help='Show all expirations, not just monthlies.') -@click.option('--dte', type=int, help='Days to expiration for the option.') -@click.argument('symbol', type=str) -@click.argument('quantity', type=int) -async def call(symbol: str, quantity: int, strike: Optional[Decimal] = None, width: Optional[int] = None, - gtc: bool = False, weeklies: bool = False, delta: Optional[int] = None, dte: Optional[int] = None): +@option.command(help="Buy or sell calls with the given parameters.") +@click.option("-s", "--strike", type=Decimal, help="The chosen strike for the option.") +@click.option("-d", "--delta", type=int, help="The chosen delta for the option.") +@click.option( + "-w", + "--width", + type=int, + help="Turns the order into a spread with the given width.", +) +@click.option("--gtc", is_flag=True, help="Place a GTC order instead of a day order.") +@click.option( + "--weeklies", is_flag=True, help="Show all expirations, not just monthlies." +) +@click.option("--dte", type=int, help="Days to expiration for the option.") +@click.argument("symbol", type=str) +@click.argument("quantity", type=int) +async def call( + symbol: str, + quantity: int, + strike: Optional[Decimal] = None, + width: Optional[int] = None, + gtc: bool = False, + weeklies: bool = False, + delta: Optional[int] = None, + dte: Optional[int] = None, +): if strike is not None and delta is not None: - print_error('Must specify either delta or strike, but not both.') + print_error("Must specify either delta or strike, but not both.") return elif not strike and not delta: - print_error('Please specify either delta or strike for the option.') + print_error("Please specify either delta or strike for the option.") return elif delta is not None and abs(delta) > 99: - print_error('Delta value is too high, -99 <= delta <= 99') + print_error("Delta value is too high, -99 <= delta <= 99") return sesh = RenewableSession() - if symbol[0] == '/': # futures options + if symbol[0] == "/": # futures options chain = NestedFutureOptionChain.get_chain(sesh, symbol) if dte is not None: - subchain = min(chain.option_chains[0].expirations, - key=lambda exp: abs(exp.days_to_expiration - dte)) + subchain = min( + chain.option_chains[0].expirations, + key=lambda exp: abs(exp.days_to_expiration - dte), + ) else: subchain = choose_futures_expiration(chain, weeklies) tick_size = subchain.tick_sizes[0].value else: chain = NestedOptionChain.get_chain(sesh, symbol) if dte is not None: - subchain = min(chain.expirations, - key=lambda exp: abs((exp.expiration_date - datetime.now().date()).days - dte)) + subchain = min( + chain.expirations, + key=lambda exp: abs( + (exp.expiration_date - datetime.now().date()).days - dte + ), + ) else: subchain = choose_expiration(chain, weeklies) tick_size = chain.tick_sizes[0].value - precision = tick_size.as_tuple().exponent - precision = abs(precision) if precision < 0 else ZERO - precision_str = f'.{precision}f' + precision: int = tick_size.as_tuple().exponent # type: ignore + precision = abs(precision) if precision < 0 else 0 + precision_str = f".{precision}f" async with DXLinkStreamer(sesh) as streamer: if not strike: dxfeeds = [s.call_streamer_symbol for s in subchain.strikes] - await streamer.subscribe(EventType.GREEKS, dxfeeds) - greeks_dict = await listen_greeks(len(dxfeeds), streamer) + await streamer.subscribe(Greeks, dxfeeds) + greeks_dict = await listen_events(dxfeeds, Greeks, streamer) greeks = list(greeks_dict.values()) lowest = 100 selected = None for g in greeks: - diff = abs(g.delta * Decimal(100) - delta) + diff = abs(g.delta * 100 - Decimal(delta)) # type: ignore if diff < lowest: selected = g lowest = diff # set strike with the closest delta - strike = next(s.strike_price for s in subchain.strikes - if s.call_streamer_symbol == selected.eventSymbol) + strike = next( + s.strike_price + for s in subchain.strikes + if s.call_streamer_symbol == selected.eventSymbol + ) + strike_symbol = next( + s.call_streamer_symbol for s in subchain.strikes if s.strike_price == strike + ) if width: - spread_strike = next(s for s in subchain.strikes if s.strike_price == strike + width) - await streamer.subscribe(EventType.QUOTE, [selected.eventSymbol, spread_strike.call_streamer_symbol]) - quote_dict = await listen_quotes(2, streamer) - bid = quote_dict[selected.eventSymbol].bidPrice - quote_dict[spread_strike.call_streamer_symbol].askPrice - ask = quote_dict[selected.eventSymbol].askPrice - quote_dict[spread_strike.call_streamer_symbol].bidPrice - mid = (bid + ask) / Decimal(2) + spread_strike = next( + s for s in subchain.strikes if s.strike_price == strike + width + ) + dxfeeds = [strike_symbol, spread_strike.call_streamer_symbol] + quote_dict = await listen_events(dxfeeds, Quote, streamer) + bid = ( + quote_dict[strike_symbol].bidPrice # type: ignore + - quote_dict[spread_strike.call_streamer_symbol].askPrice # type: ignore + ) + ask = ( + quote_dict[strike_symbol].askPrice # type: ignore + - quote_dict[spread_strike.call_streamer_symbol].bidPrice # type: ignore + ) else: - await streamer.subscribe(EventType.QUOTE, [selected.eventSymbol]) - quote = await streamer.get_event(EventType.QUOTE) + await streamer.subscribe(Quote, [strike_symbol]) + quote = await streamer.get_event(Quote) bid = quote.bidPrice ask = quote.askPrice - mid = (bid + ask) / Decimal(2) + mid = (bid + ask) / Decimal(2) # type: ignore mid = round_to_width(mid, tick_size) console = Console() if width: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} call spread {subchain.expiration_date}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} call spread {subchain.expiration_date}", + ) else: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} {strike}C {subchain.expiration_date}') - table.add_column('Bid', style='green', justify='center') - table.add_column('Mid', justify='center') - table.add_column('Ask', style='red', justify='center') - table.add_row(f'{bid:{precision_str}}', f'{mid:{precision_str}}', f'{ask:{precision_str}}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} {strike}C {subchain.expiration_date}", + ) + table.add_column("Bid", style="green", justify="center") + table.add_column("Mid", justify="center") + table.add_column("Ask", style="red", justify="center") + table.add_row( + f"{bid:{precision_str}}", f"{mid:{precision_str}}", f"{ask:{precision_str}}" + ) console.print(table) - price = input('Please enter a limit price per quantity (default mid): ') + price = input("Please enter a limit price per quantity (default mid): ") price = mid if not price else Decimal(price) - short_symbol = next(s.call for s in subchain.strikes if s.strike_price == strike) + short_symbol = next( + s.call for s in subchain.strikes if s.strike_price == strike + ) if width: - if symbol[0] == '/': # futures options - res = FutureOption.get_future_options(sesh, [short_symbol, spread_strike.call]) + if symbol[0] == "/": # futures options + res = FutureOption.get_future_options( + sesh, + [short_symbol, spread_strike.call], # type: ignore + ) else: - res = Option.get_options(sesh, [short_symbol, spread_strike.call]) + res = Option.get_options(sesh, [short_symbol, spread_strike.call]) # type: ignore res.sort(key=lambda x: x.strike_price) legs = [ - res[0].build_leg(abs(quantity), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN), - res[1].build_leg(abs(quantity), OrderAction.BUY_TO_OPEN if quantity < 0 else OrderAction.SELL_TO_OPEN) + res[0].build_leg( + Decimal(abs(quantity)), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), + res[1].build_leg( + Decimal(abs(quantity)), + OrderAction.BUY_TO_OPEN + if quantity < 0 + else OrderAction.SELL_TO_OPEN, + ), ] else: - if symbol[0] == '/': + if symbol[0] == "/": call = FutureOption.get_future_option(sesh, short_symbol) else: call = Option.get_option(sesh, short_symbol) - legs = [call.build_leg(abs(quantity), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN)] + legs = [ + call.build_leg( + Decimal(abs(quantity)), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ) + ] + m = 1 if quantity < 0 else -1 order = NewOrder( time_in_force=OrderTimeInForce.GTC if gtc else OrderTimeInForce.DAY, order_type=OrderType.LIMIT, legs=legs, - price=price, - price_effect=PriceEffect.CREDIT if quantity < 0 else PriceEffect.DEBIT + price=price * m, ) acc = sesh.get_account() - - data = test_order_handle_errors(acc, sesh, order) - if data is None: - return + data = acc.place_order(sesh, order, dry_run=True) nl = acc.get_balances(sesh).net_liquidating_value bp = data.buying_power_effect.change_in_buying_power percent = bp / nl * Decimal(100) - fees = data.fee_calculation.total_fees - - table = Table(show_header=True, header_style='bold', title_style='bold', title='Order Review') - table.add_column('Quantity', justify='center') - table.add_column('Symbol', justify='center') - table.add_column('Strike', justify='center') - table.add_column('Type', justify='center') - table.add_column('Expiration', justify='center') - table.add_column('Price', justify='center') - table.add_column('BP', justify='center') - table.add_column('BP %', justify='center') - table.add_column('Fees', justify='center') - table.add_row(f'{quantity:+}', symbol, f'${strike:{precision_str}}', 'CALL', f'{subchain.expiration_date}', f'${price:{precision_str}}', - f'${bp:.2f}', f'{percent:.2f}%', f'${fees:.2f}') + fees = data.fee_calculation.total_fees # type: ignore + + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title="Order Review", + ) + table.add_column("Quantity", justify="center") + table.add_column("Symbol", justify="center") + table.add_column("Strike", justify="center") + table.add_column("Type", justify="center") + table.add_column("Expiration", justify="center") + table.add_column("Price", justify="center") + table.add_column("BP", justify="center") + table.add_column("BP %", justify="center") + table.add_column("Fees", justify="center") + table.add_row( + f"{quantity:+}", + symbol, + f"${strike:{precision_str}}", + "CALL", + f"{subchain.expiration_date}", + f"${price:{precision_str}}", + f"${bp:.2f}", + f"{percent:.2f}%", + f"${fees:.2f}", + ) if width: - table.add_row(f'{-quantity:+}', symbol, f'${spread_strike.strike_price:{precision_str}}', - 'CALL', f'{subchain.expiration_date}', '-', '-', '-', '-') + table.add_row( + f"{-quantity:+}", + symbol, + f"${spread_strike.strike_price:{precision_str}}", # type: ignore + "CALL", + f"{subchain.expiration_date}", + "-", + "-", + "-", + "-", + ) console.print(table) if data.warnings: for warning in data.warnings: print_warning(warning.message) - warn_percent = sesh.config.getint('order', 'bp-warn-above-percent', fallback=None) + warn_percent = sesh.config.getint( + "order", "bp-warn-above-percent", fallback=None + ) if warn_percent and percent > warn_percent: - print_warning(f'Buying power usage is above target of {warn_percent}%!') - if get_confirmation('Send order? Y/n '): + print_warning(f"Buying power usage is above target of {warn_percent}%!") + if get_confirmation("Send order? Y/n "): acc.place_order(sesh, order, dry_run=False) -@option.command(help='Buy or sell puts with the given parameters.') -@click.option('-s', '--strike', type=Decimal, help='The chosen strike for the option.') -@click.option('-d', '--delta', type=int, help='The chosen delta for the option.') -@click.option('-w', '--width', type=int, help='Turns the order into a spread with the given width.') -@click.option('--gtc', is_flag=True, help='Place a GTC order instead of a day order.') -@click.option('--weeklies', is_flag=True, help='Show all expirations, not just monthlies.') -@click.option('--dte', type=int, help='Days to expiration for the option.') -@click.argument('symbol', type=str) -@click.argument('quantity', type=int) -async def put(symbol: str, quantity: int, strike: Optional[int] = None, width: Optional[int] = None, - gtc: bool = False, weeklies: bool = False, delta: Optional[int] = None, dte: Optional[int] = None): +@option.command(help="Buy or sell puts with the given parameters.") +@click.option("-s", "--strike", type=Decimal, help="The chosen strike for the option.") +@click.option("-d", "--delta", type=int, help="The chosen delta for the option.") +@click.option( + "-w", + "--width", + type=int, + help="Turns the order into a spread with the given width.", +) +@click.option("--gtc", is_flag=True, help="Place a GTC order instead of a day order.") +@click.option( + "--weeklies", is_flag=True, help="Show all expirations, not just monthlies." +) +@click.option("--dte", type=int, help="Days to expiration for the option.") +@click.argument("symbol", type=str) +@click.argument("quantity", type=int) +async def put( + symbol: str, + quantity: int, + strike: Optional[Decimal] = None, + width: Optional[int] = None, + gtc: bool = False, + weeklies: bool = False, + delta: Optional[int] = None, + dte: Optional[int] = None, +): if strike is not None and delta is not None: - print_error('Must specify either delta or strike, but not both.') + print_error("Must specify either delta or strike, but not both.") return elif not strike and not delta: - print_error('Please specify either delta or strike for the option.') + print_error("Please specify either delta or strike for the option.") return elif delta is not None and abs(delta) > 99: - print_error('Delta value is too high, -99 <= delta <= 99') + print_error("Delta value is too high, -99 <= delta <= 99") return sesh = RenewableSession() - if symbol[0] == '/': # futures options + if symbol[0] == "/": # futures options chain = NestedFutureOptionChain.get_chain(sesh, symbol) if dte is not None: - subchain = min(chain.option_chains[0].expirations, - key=lambda exp: abs(exp.days_to_expiration - dte)) + subchain = min( + chain.option_chains[0].expirations, + key=lambda exp: abs(exp.days_to_expiration - dte), + ) else: subchain = choose_futures_expiration(chain, weeklies) tick_size = subchain.tick_sizes[0].value else: chain = NestedOptionChain.get_chain(sesh, symbol) if dte is not None: - subchain = min(chain.expirations, - key=lambda exp: abs((exp.expiration_date - datetime.now().date()).days - dte)) + subchain = min( + chain.expirations, + key=lambda exp: abs( + (exp.expiration_date - datetime.now().date()).days - dte + ), + ) else: subchain = choose_expiration(chain, weeklies) tick_size = chain.tick_sizes[0].value - precision = tick_size.as_tuple().exponent - precision = abs(precision) if precision < 0 else ZERO - precision_str = f'.{precision}f' + precision: int = tick_size.as_tuple().exponent # type: ignore + precision = abs(precision) if precision < 0 else 0 + precision_str = f".{precision}f" async with DXLinkStreamer(sesh) as streamer: if not strike: dxfeeds = [s.put_streamer_symbol for s in subchain.strikes] - await streamer.subscribe(EventType.GREEKS, dxfeeds) - greeks_dict = await listen_greeks(len(dxfeeds), streamer) + await streamer.subscribe(Greeks, dxfeeds) + greeks_dict = await listen_events(dxfeeds, Greeks, streamer) greeks = list(greeks_dict.values()) lowest = 100 selected = None for g in greeks: - diff = abs(g.delta * Decimal(100) + delta) + diff = abs(g.delta * 100 + Decimal(delta)) # type: ignore if diff < lowest: selected = g lowest = diff # set strike with the closest delta - strike = next(s.strike_price for s in subchain.strikes - if s.put_streamer_symbol == selected.eventSymbol) + strike = next( + s.strike_price + for s in subchain.strikes + if s.put_streamer_symbol == selected.eventSymbol + ) + strike_symbol = next( + s.put_streamer_symbol for s in subchain.strikes if s.strike_price == strike + ) if width: - spread_strike = next(s for s in subchain.strikes if s.strike_price == strike - width) - await streamer.subscribe(EventType.QUOTE, [selected.eventSymbol, spread_strike.put_streamer_symbol]) - quote_dict = await listen_quotes(2, streamer) - bid = quote_dict[selected.eventSymbol].bidPrice - quote_dict[spread_strike.put_streamer_symbol].askPrice - ask = quote_dict[selected.eventSymbol].askPrice - quote_dict[spread_strike.put_streamer_symbol].bidPrice - mid = (bid + ask) / Decimal(2) + spread_strike = next( + s for s in subchain.strikes if s.strike_price == strike - width + ) + dxfeeds = [strike_symbol, spread_strike.put_streamer_symbol] + quote_dict = await listen_events(dxfeeds, Quote, streamer) + bid = ( + quote_dict[strike_symbol].bidPrice # type: ignore + - quote_dict[spread_strike.put_streamer_symbol].askPrice # type: ignore + ) + ask = ( + quote_dict[strike_symbol].askPrice # type: ignore + - quote_dict[spread_strike.put_streamer_symbol].bidPrice # type: ignore + ) else: - await streamer.subscribe(EventType.QUOTE, [selected.eventSymbol]) - quote = await streamer.get_event(EventType.QUOTE) + await streamer.subscribe(Quote, [strike_symbol]) + quote = await streamer.get_event(Quote) bid = quote.bidPrice ask = quote.askPrice - mid = (bid + ask) / Decimal(2) + mid = (bid + ask) / Decimal(2) # type: ignore mid = round_to_width(mid, tick_size) console = Console() if width: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} put spread {subchain.expiration_date}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} put spread {subchain.expiration_date}", + ) else: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} {strike}P {subchain.expiration_date}') - table.add_column('Bid', style='green', justify='center') - table.add_column('Mid', justify='center') - table.add_column('Ask', style='red', justify='center') - table.add_row(f'{bid:{precision_str}}', f'{mid:{precision_str}}', f'{ask:{precision_str}}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} {strike}P {subchain.expiration_date}", + ) + table.add_column("Bid", style="green", justify="center") + table.add_column("Mid", justify="center") + table.add_column("Ask", style="red", justify="center") + table.add_row( + f"{bid:{precision_str}}", f"{mid:{precision_str}}", f"{ask:{precision_str}}" + ) console.print(table) - price = input('Please enter a limit price per quantity (default mid): ') + price = input("Please enter a limit price per quantity (default mid): ") price = mid if not price else Decimal(price) short_symbol = next(s.put for s in subchain.strikes if s.strike_price == strike) if width: - if symbol[0] == '/': # futures options - res = FutureOption.get_future_options(sesh, [short_symbol, spread_strike.put]) + if symbol[0] == "/": # futures options + res = FutureOption.get_future_options( + sesh, + [short_symbol, spread_strike.put], # type: ignore + ) else: - res = Option.get_options(sesh, [short_symbol, spread_strike.put]) + res = Option.get_options(sesh, [short_symbol, spread_strike.put]) # type: ignore res.sort(key=lambda x: x.strike_price, reverse=True) legs = [ - res[0].build_leg(abs(quantity), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN), - res[1].build_leg(abs(quantity), OrderAction.BUY_TO_OPEN if quantity < 0 else OrderAction.SELL_TO_OPEN) + res[0].build_leg( + Decimal(abs(quantity)), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), + res[1].build_leg( + Decimal(abs(quantity)), + OrderAction.BUY_TO_OPEN + if quantity < 0 + else OrderAction.SELL_TO_OPEN, + ), ] else: - if symbol[0] == '/': # futures options + if symbol[0] == "/": # futures options put = FutureOption.get_future_option(sesh, short_symbol) else: put = Option.get_option(sesh, short_symbol) - legs = [put.build_leg(abs(quantity), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN)] + legs = [ + put.build_leg( + Decimal(abs(quantity)), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ) + ] + m = 1 if quantity < 0 else -1 order = NewOrder( time_in_force=OrderTimeInForce.GTC if gtc else OrderTimeInForce.DAY, order_type=OrderType.LIMIT, legs=legs, - price=price, - price_effect=PriceEffect.CREDIT if quantity < 0 else PriceEffect.DEBIT + price=price * m, ) acc = sesh.get_account() - data = test_order_handle_errors(acc, sesh, order) - if data is None: + try: + data = acc.place_order(sesh, order, dry_run=True) + except TastytradeError as e: + print_error(str(e)) return nl = acc.get_balances(sesh).net_liquidating_value bp = data.buying_power_effect.change_in_buying_power percent = bp / nl * Decimal(100) - fees = data.fee_calculation.total_fees - - table = Table(show_header=True, header_style='bold', title_style='bold', title='Order Review') - table.add_column('Quantity', justify='center') - table.add_column('Symbol', justify='center') - table.add_column('Strike', justify='center') - table.add_column('Type', justify='center') - table.add_column('Expiration', justify='center') - table.add_column('Price', justify='center') - table.add_column('BP', justify='center') - table.add_column('BP %', justify='center') - table.add_column('Fees', justify='center') - table.add_row(f'{quantity:+}', symbol, f'${strike:{precision_str}}', 'PUT', f'{subchain.expiration_date}', f'${price:{precision_str}}', - f'${bp:.2f}', f'{percent:.2f}%', f'${fees:.2f}') + fees = data.fee_calculation.total_fees # type: ignore + + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title="Order Review", + ) + table.add_column("Quantity", justify="center") + table.add_column("Symbol", justify="center") + table.add_column("Strike", justify="center") + table.add_column("Type", justify="center") + table.add_column("Expiration", justify="center") + table.add_column("Price", justify="center") + table.add_column("BP", justify="center") + table.add_column("BP %", justify="center") + table.add_column("Fees", justify="center") + table.add_row( + f"{quantity:+}", + symbol, + f"${strike:{precision_str}}", + "PUT", + f"{subchain.expiration_date}", + f"${price:{precision_str}}", + f"${bp:.2f}", + f"{percent:.2f}%", + f"${fees:.2f}", + ) if width: - table.add_row(f'{-quantity:+}', symbol, f'${spread_strike.strike_price:{precision_str}}', - 'PUT', f'{subchain.expiration_date}', '-', '-', '-', '-') + table.add_row( + f"{-quantity:+}", + symbol, + f"${spread_strike.strike_price:{precision_str}}", # type: ignore + "PUT", + f"{subchain.expiration_date}", + "-", + "-", + "-", + "-", + ) console.print(table) if data.warnings: for warning in data.warnings: print_warning(warning.message) - warn_percent = sesh.config.getint('order', 'bp-warn-above-percent', fallback=None) + warn_percent = sesh.config.getint( + "order", "bp-warn-above-percent", fallback=None + ) if warn_percent and percent > warn_percent: - print_warning(f'Buying power usage is above target of {warn_percent}%!') - if get_confirmation('Send order? Y/n '): + print_warning(f"Buying power usage is above target of {warn_percent}%!") + if get_confirmation("Send order? Y/n "): acc.place_order(sesh, order, dry_run=False) -@option.command(help='Buy or sell strangles with the given parameters.') -@click.option('-c', '--call', type=Decimal, help='The chosen strike for the call option.') -@click.option('-p', '--put', type=Decimal, help='The chosen strike for the put option.') -@click.option('-d', '--delta', type=int, help='The chosen delta for both options.') -@click.option('-w', '--width', type=int, help='Turns the order into an iron condor with the given width.') -@click.option('--gtc', is_flag=True, help='Place a GTC order instead of a day order.') -@click.option('--weeklies', is_flag=True, help='Show all expirations, not just monthlies.') -@click.argument('symbol', type=str) -@click.argument('quantity', type=int) -async def strangle(symbol: str, quantity: int, call: Optional[Decimal] = None, width: Optional[int] = None, - gtc: bool = False, weeklies: bool = False, delta: Optional[int] = None, put: Optional[Decimal] = None): +@option.command(help="Buy or sell strangles with the given parameters.") +@click.option( + "-c", "--call", type=Decimal, help="The chosen strike for the call option." +) +@click.option("-p", "--put", type=Decimal, help="The chosen strike for the put option.") +@click.option("-d", "--delta", type=int, help="The chosen delta for both options.") +@click.option( + "-w", + "--width", + type=int, + help="Turns the order into an iron condor with the given width.", +) +@click.option("--gtc", is_flag=True, help="Place a GTC order instead of a day order.") +@click.option( + "--weeklies", is_flag=True, help="Show all expirations, not just monthlies." +) +@click.argument("symbol", type=str) +@click.argument("quantity", type=int) +async def strangle( + symbol: str, + quantity: int, + call: Optional[Decimal] = None, + width: Optional[int] = None, + gtc: bool = False, + weeklies: bool = False, + delta: Optional[int] = None, + put: Optional[Decimal] = None, +): if (call is not None or put is not None) and delta is not None: - print_error('Must specify either delta or strike, but not both.') + print_error("Must specify either delta or strike, but not both.") return elif delta is not None and (call is not None or put is not None): - print_error('Please specify either delta, or strikes for both options.') + print_error("Please specify either delta, or strikes for both options.") return elif delta is not None and abs(delta) > 99: - print_error('Delta value is too high, -99 <= delta <= 99') + print_error("Delta value is too high, -99 <= delta <= 99") return sesh = RenewableSession() - if symbol[0] == '/': # futures options + if symbol[0] == "/": # futures options chain = NestedFutureOptionChain.get_chain(sesh, symbol) subchain = choose_futures_expiration(chain, weeklies) tick_size = subchain.tick_sizes[0].value @@ -466,93 +624,112 @@ async def strangle(symbol: str, quantity: int, call: Optional[Decimal] = None, w chain = NestedOptionChain.get_chain(sesh, symbol) subchain = choose_expiration(chain, weeklies) tick_size = chain.tick_sizes[0].value - precision = tick_size.as_tuple().exponent - precision = abs(precision) if precision < 0 else ZERO - precision_str = f'.{precision}f' + precision: int = tick_size.as_tuple().exponent # type: ignore + precision = abs(precision) if precision < 0 else 0 + precision_str = f".{precision}f" async with DXLinkStreamer(sesh) as streamer: if delta is not None: put_dxf = [s.put_streamer_symbol for s in subchain.strikes] call_dxf = [s.call_streamer_symbol for s in subchain.strikes] dxfeeds = put_dxf + call_dxf - await streamer.subscribe(EventType.GREEKS, dxfeeds) - greeks_dict = await listen_greeks(len(dxfeeds), streamer) + greeks_dict = await listen_events(dxfeeds, Greeks, streamer) put_greeks = [v for v in greeks_dict.values() if v.eventSymbol in put_dxf] call_greeks = [v for v in greeks_dict.values() if v.eventSymbol in call_dxf] lowest = 100 selected_put = None for g in put_greeks: - diff = abs(g.delta * Decimal(100) + delta) + diff = abs(g.delta * 100 + delta) if diff < lowest: selected_put = g.eventSymbol lowest = diff lowest = 100 selected_call = None for g in call_greeks: - diff = abs(g.delta * Decimal(100) - delta) + diff = abs(g.delta * 100 - delta) if diff < lowest: selected_call = g.eventSymbol lowest = diff # set strike with the closest delta - put_strike = next(s for s in subchain.strikes - if s.put_streamer_symbol == selected_put) - call_strike = next(s for s in subchain.strikes - if s.call_streamer_symbol == selected_call) + put_strike = next( + s for s in subchain.strikes if s.put_streamer_symbol == selected_put + ) + call_strike = next( + s for s in subchain.strikes if s.call_streamer_symbol == selected_call + ) else: put_strike = next(s for s in subchain.strikes if s.strike_price == put) call_strike = next(s for s in subchain.strikes if s.strike_price == call) if width: - put_spread_strike = next(s for s in subchain.strikes if s.strike_price == put_strike.strike_price - width) - call_spread_strike = next(s for s in subchain.strikes if s.strike_price == call_strike.strike_price + width) - await streamer.subscribe( - EventType.QUOTE, - [ - call_strike.call_streamer_symbol, - put_strike.put_streamer_symbol, - put_spread_strike.put_streamer_symbol, - call_spread_strike.call_streamer_symbol - ] + put_spread_strike = next( + s + for s in subchain.strikes + if s.strike_price == put_strike.strike_price - width + ) + call_spread_strike = next( + s + for s in subchain.strikes + if s.strike_price == call_strike.strike_price + width + ) + dxfeeds = [ + call_strike.call_streamer_symbol, + put_strike.put_streamer_symbol, + put_spread_strike.put_streamer_symbol, + call_spread_strike.call_streamer_symbol, + ] + quote_dict = await listen_events(dxfeeds, Quote, streamer) + bid = ( + quote_dict[call_strike.call_streamer_symbol].bidPrice # type: ignore + + quote_dict[put_strike.put_streamer_symbol].bidPrice # type: ignore + - quote_dict[put_spread_strike.put_streamer_symbol].askPrice # type: ignore + - quote_dict[call_spread_strike.call_streamer_symbol].askPrice # type: ignore + ) + ask = ( + quote_dict[call_strike.call_streamer_symbol].askPrice # type: ignore + + quote_dict[put_strike.put_streamer_symbol].askPrice # type: ignore + - quote_dict[put_spread_strike.put_streamer_symbol].bidPrice # type: ignore + - quote_dict[call_spread_strike.call_streamer_symbol].bidPrice # type: ignore ) - quote_dict = await listen_quotes(4, streamer) - bid = (quote_dict[call_strike.call_streamer_symbol].bidPrice + - quote_dict[put_strike.put_streamer_symbol].bidPrice - - quote_dict[put_spread_strike.put_streamer_symbol].askPrice - - quote_dict[call_spread_strike.call_streamer_symbol].askPrice) - ask = (quote_dict[call_strike.call_streamer_symbol].askPrice + - quote_dict[put_strike.put_streamer_symbol].askPrice - - quote_dict[put_spread_strike.put_streamer_symbol].bidPrice - - quote_dict[call_spread_strike.call_streamer_symbol].bidPrice) - mid = (bid + ask) / Decimal(2) else: - await streamer.subscribe(EventType.QUOTE, [put_strike.put_streamer_symbol, call_strike.call_streamer_symbol]) - quote_dict = await listen_quotes(2, streamer) - bid = sum([q.bidPrice for q in quote_dict.values()]) - ask = sum([q.askPrice for q in quote_dict.values()]) - mid = (bid + ask) / Decimal(2) + dxfeeds = [put_strike.put_streamer_symbol, call_strike.call_streamer_symbol] + quote_dict = await listen_events(dxfeeds, Quote, streamer) + bid = sum([q.bidPrice for q in quote_dict.values()]) # type: ignore + ask = sum([q.askPrice for q in quote_dict.values()]) # type: ignore + mid = (bid + ask) / Decimal(2) mid = round_to_width(mid, tick_size) console = Console() if width: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} iron condor {subchain.expiration_date}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} iron condor {subchain.expiration_date}", + ) else: - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Quote for {symbol} {put_strike.strike_price}/{call_strike.strike_price} strangle {subchain.expiration_date}') - table.add_column('Bid', style='green', justify='center') - table.add_column('Mid', justify='center') - table.add_column('Ask', style='red', justify='center') - table.add_row(f'{bid:{precision_str}}', f'{mid:{precision_str}}', f'{ask:{precision_str}}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Quote for {symbol} {put_strike.strike_price}/{call_strike.strike_price} strangle {subchain.expiration_date}", + ) + table.add_column("Bid", style="green", justify="center") + table.add_column("Mid", justify="center") + table.add_column("Ask", style="red", justify="center") + table.add_row( + f"{bid:{precision_str}}", f"{mid:{precision_str}}", f"{ask:{precision_str}}" + ) console.print(table) - price = input('Please enter a limit price per quantity (default mid): ') + price = input("Please enter a limit price per quantity (default mid): ") price = mid if not price else Decimal(price) tt_symbols = [put_strike.put, call_strike.call] if width: - tt_symbols += [put_spread_strike.put, call_spread_strike.call] - if symbol[0] == '/': # futures options + tt_symbols += [put_spread_strike.put, call_spread_strike.call] # type: ignore + if symbol[0] == "/": # futures options options = FutureOption.get_future_options(sesh, tt_symbols) else: options = Option.get_options(sesh, tt_symbols) @@ -560,184 +737,253 @@ async def strangle(symbol: str, quantity: int, call: Optional[Decimal] = None, w q = Decimal(quantity) if width: legs = [ - options[0].build_leg(abs(q), OrderAction.BUY_TO_OPEN if quantity < 0 else OrderAction.SELL_TO_OPEN), - options[1].build_leg(abs(q), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN), - options[2].build_leg(abs(q), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN), - options[3].build_leg(abs(q), OrderAction.BUY_TO_OPEN if quantity < 0 else OrderAction.SELL_TO_OPEN) + options[0].build_leg( + abs(q), + OrderAction.BUY_TO_OPEN + if quantity < 0 + else OrderAction.SELL_TO_OPEN, + ), + options[1].build_leg( + abs(q), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), + options[2].build_leg( + abs(q), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), + options[3].build_leg( + abs(q), + OrderAction.BUY_TO_OPEN + if quantity < 0 + else OrderAction.SELL_TO_OPEN, + ), ] else: legs = [ - options[0].build_leg(abs(q), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN), - options[1].build_leg(abs(q), OrderAction.SELL_TO_OPEN if quantity < 0 else OrderAction.BUY_TO_OPEN) + options[0].build_leg( + abs(q), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), + options[1].build_leg( + abs(q), + OrderAction.SELL_TO_OPEN + if quantity < 0 + else OrderAction.BUY_TO_OPEN, + ), ] + m = 1 if quantity < 0 else -1 order = NewOrder( time_in_force=OrderTimeInForce.GTC if gtc else OrderTimeInForce.DAY, order_type=OrderType.LIMIT, legs=legs, - price=price, - price_effect=PriceEffect.CREDIT if quantity < 0 else PriceEffect.DEBIT + price=price * m, ) acc = sesh.get_account() - data = test_order_handle_errors(acc, sesh, order) - if data is None: + try: + data = acc.place_order(sesh, order, dry_run=True) + except TastytradeError as e: + print_error(str(e)) return nl = acc.get_balances(sesh).net_liquidating_value bp = data.buying_power_effect.change_in_buying_power percent = bp / nl * Decimal(100) - fees = data.fee_calculation.total_fees - - table = Table(header_style='bold', title_style='bold', title='Order Review') - table.add_column('Quantity', justify='center') - table.add_column('Symbol', justify='center') - table.add_column('Strike', justify='center') - table.add_column('Type', justify='center') - table.add_column('Expiration', justify='center') - table.add_column('Price', justify='center') - table.add_column('BP', justify='center') - table.add_column('BP %', justify='center') - table.add_column('Fees', justify='center') + fees = data.fee_calculation.total_fees # type: ignore + + table = Table(header_style="bold", title_style="bold", title="Order Review") + table.add_column("Quantity", justify="center") + table.add_column("Symbol", justify="center") + table.add_column("Strike", justify="center") + table.add_column("Type", justify="center") + table.add_column("Expiration", justify="center") + table.add_column("Price", justify="center") + table.add_column("BP", justify="center") + table.add_column("BP %", justify="center") + table.add_column("Fees", justify="center") table.add_row( - f'{quantity:+}', + f"{quantity:+}", symbol, - f'${put_strike.strike_price:{precision_str}}', - 'PUT', - f'{subchain.expiration_date}', - f'${price:.2f}', - f'${bp:.2f}', - f'{percent:.2f}%', - f'${fees:.2f}' + f"${put_strike.strike_price:{precision_str}}", + "PUT", + f"{subchain.expiration_date}", + f"${price:.2f}", + f"${bp:.2f}", + f"{percent:.2f}%", + f"${fees:.2f}", ) table.add_row( - f'{quantity:+}', + f"{quantity:+}", symbol, - f'${call_strike.strike_price:{precision_str}}', - 'CALL', - f'{subchain.expiration_date}', - '-', - '-', - '-', - '-' + f"${call_strike.strike_price:{precision_str}}", + "CALL", + f"{subchain.expiration_date}", + "-", + "-", + "-", + "-", ) if width: table.add_row( - f'{-quantity:+}', + f"{-quantity:+}", symbol, - f'${put_spread_strike.strike_price:{precision_str}}', - 'PUT', - f'{subchain.expiration_date}', - '-', - '-', - '-', - '-' + f"${put_spread_strike.strike_price:{precision_str}}", # type: ignore + "PUT", + f"{subchain.expiration_date}", + "-", + "-", + "-", + "-", ) table.add_row( - f'{-quantity:+}', + f"{-quantity:+}", symbol, - f'${call_spread_strike.strike_price:{precision_str}}', - 'CALL', - f'{subchain.expiration_date}', - '-', - '-', - '-', - '-' + f"${call_spread_strike.strike_price:{precision_str}}", # type: ignore + "CALL", + f"{subchain.expiration_date}", + "-", + "-", + "-", + "-", ) console.print(table) if data.warnings: for warning in data.warnings: print_warning(warning.message) - warn_percent = sesh.config.getint('order', 'bp-warn-above-percent', fallback=None) + warn_percent = sesh.config.getint( + "order", "bp-warn-above-percent", fallback=None + ) if warn_percent and percent > warn_percent: - print_warning(f'Buying power usage is above target of {warn_percent}%!') - if get_confirmation('Send order? Y/n '): + print_warning(f"Buying power usage is above target of {warn_percent}%!") + if get_confirmation("Send order? Y/n "): acc.place_order(sesh, order, dry_run=False) -@option.command(help='Fetch and display an options chain.') -@click.option('-w', '--weeklies', is_flag=True, - help='Show all expirations, not just monthlies.') -@click.option('-s', '--strikes', type=int, default=8, - help='The number of strikes to fetch above and below the spot price.') -@click.argument('symbol', type=str) +@option.command(help="Fetch and display an options chain.") +@click.option( + "-w", "--weeklies", is_flag=True, help="Show all expirations, not just monthlies." +) +@click.option( + "-s", + "--strikes", + type=int, + default=8, + help="The number of strikes to fetch above and below the spot price.", +) +@click.argument("symbol", type=str) async def chain(symbol: str, strikes: int = 8, weeklies: bool = False): sesh = RenewableSession() async with DXLinkStreamer(sesh) as streamer: - if symbol[0] == '/': # futures options + if symbol[0] == "/": # futures options chain = NestedFutureOptionChain.get_chain(sesh, symbol) subchain = choose_futures_expiration(chain, weeklies) - precision = subchain.tick_sizes[0].value.as_tuple().exponent + precision: int = subchain.tick_sizes[0].value.as_tuple().exponent # type: ignore else: chain = NestedOptionChain.get_chain(sesh, symbol) - precision = chain.tick_sizes[0].value.as_tuple().exponent + precision: int = chain.tick_sizes[0].value.as_tuple().exponent # type: ignore subchain = choose_expiration(chain, weeklies) - precision = abs(precision) if precision < 0 else ZERO - precision = f'.{precision}f' + precision = abs(precision) if precision < 0 else 0 + precision_str = f".{precision}f" console = Console() - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Options chain for {symbol} expiring {subchain.expiration_date}') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Options chain for {symbol} expiring {subchain.expiration_date}", + ) - show_delta = sesh.config.getboolean('option', 'chain-show-delta', fallback=True) - show_theta = sesh.config.getboolean('option', 'chain-show-theta', fallback=False) - show_oi = sesh.config.getboolean('option', 'chain-show-open-interest', fallback=False) - show_volume = sesh.config.getboolean('option', 'chain-show-volume', fallback=False) + show_delta = sesh.config.getboolean("option.chain", "show-delta", fallback=True) + show_theta = sesh.config.getboolean( + "option.chain", "show-theta", fallback=False + ) + show_oi = sesh.config.getboolean( + "option.chain", "show-open-interest", fallback=False + ) + show_volume = sesh.config.getboolean( + "option.chain", "show-volume", fallback=False + ) if show_volume: - table.add_column(u'Volume', justify='right') + table.add_column("Volume", justify="right") if show_oi: - table.add_column(u'Open Int', justify='right') + table.add_column("Open Int", justify="right") if show_theta: - table.add_column(u'Call \u03B8', justify='center') + table.add_column("Call \u03b8", justify="center") if show_delta: - table.add_column(u'Call \u0394', justify='center') - table.add_column('Bid', style='green', justify='right') - table.add_column('Ask', style='red', justify='right') - table.add_column('Strike', justify='center') - table.add_column('Bid', style='green', justify='right') - table.add_column('Ask', style='red', justify='right') + table.add_column("Call \u0394", justify="center") + table.add_column("Bid", style="green", justify="right") + table.add_column("Ask", style="red", justify="right") + table.add_column("Strike", justify="center") + table.add_column("Bid", style="green", justify="right") + table.add_column("Ask", style="red", justify="right") if show_delta: - table.add_column(u'Put \u0394', justify='center') + table.add_column("Put \u0394", justify="center") if show_theta: - table.add_column(u'Put \u03B8', justify='center') + table.add_column("Put \u03b8", justify="center") if show_oi: - table.add_column(u'Open Int', justify='right') + table.add_column("Open Int", justify="right") if show_volume: - table.add_column(u'Volume', justify='right') + table.add_column("Volume", justify="right") - if symbol[0] == '/': # futures options - future = Future.get_future(sesh, subchain.underlying_symbol) - await streamer.subscribe(EventType.QUOTE, [future.streamer_symbol]) + if symbol[0] == "/": # futures options + future = Future.get_future(sesh, subchain.underlying_symbol) # type: ignore + await streamer.subscribe(Quote, [future.streamer_symbol]) else: - await streamer.subscribe(EventType.QUOTE, [symbol]) - quote = await streamer.get_event(EventType.QUOTE) - strike_price = (quote.bidPrice + quote.askPrice) / 2 + await streamer.subscribe(Quote, [symbol]) + quote = await streamer.get_event(Quote) + strike_price = (quote.bidPrice + quote.askPrice) / 2 # type: ignore subchain.strikes.sort(key=lambda s: s.strike_price) if strikes * 2 < len(subchain.strikes): mid_index = 0 while subchain.strikes[mid_index].strike_price < strike_price: mid_index += 1 - all_strikes = subchain.strikes[mid_index - strikes:mid_index + strikes] + all_strikes = subchain.strikes[mid_index - strikes : mid_index + strikes] else: all_strikes = subchain.strikes - dxfeeds = ([s.call_streamer_symbol for s in all_strikes] + - [s.put_streamer_symbol for s in all_strikes]) - await streamer.subscribe(EventType.QUOTE, dxfeeds) - await streamer.subscribe(EventType.GREEKS, dxfeeds) - if show_oi: - await streamer.subscribe(EventType.SUMMARY, dxfeeds) - if show_volume: - await streamer.subscribe(EventType.TRADE, dxfeeds) + dxfeeds = [s.call_streamer_symbol for s in all_strikes] + [ + s.put_streamer_symbol for s in all_strikes + ] - greeks_dict = await listen_greeks(len(dxfeeds), streamer) # take into account the symbol we subscribed to - quote_dict = await listen_quotes(len(dxfeeds), streamer, skip=symbol if symbol[0] != '/' else future.streamer_symbol) + streamer_symbol = symbol if symbol[0] != "/" else future.streamer_symbol # type: ignore + + async def listen_quotes(quote: Quote, symbol: str) -> dict[str, Quote]: + quote_dict = {symbol: quote} + await streamer.subscribe(Quote, dxfeeds) + async for quote in streamer.listen(Quote): + if quote.bidPrice is not None and quote.askPrice is not None: + quote_dict[quote.eventSymbol] = quote + if len(quote_dict) == len(dxfeeds) + 1: + return quote_dict + return quote_dict # unreachable + + greeks_task = asyncio.create_task(listen_events(dxfeeds, Greeks, streamer)) + quote_task = asyncio.create_task(listen_quotes(quote, streamer_symbol)) + tasks = [greeks_task, quote_task] if show_oi: - summary_dict = await listen_summaries(len(dxfeeds), streamer) + summary_task = asyncio.create_task( + listen_events(dxfeeds, Summary, streamer) + ) + tasks.append(summary_task) + if show_volume: + trade_task = asyncio.create_task(listen_events(dxfeeds, Trade, streamer)) + tasks.append(trade_task) + await asyncio.gather(*tasks) # wait for all tasks + greeks_dict = greeks_task.result() + quote_dict = quote_task.result() + if show_oi: + summary_dict = summary_task.result() # type: ignore if show_volume: - trade_dict = await listen_trades(len(dxfeeds), streamer) + trade_dict = trade_task.result() # type: ignore for i, strike in enumerate(all_strikes): put_bid = quote_dict[strike.put_streamer_symbol].bidPrice @@ -745,28 +991,32 @@ async def chain(symbol: str, strikes: int = 8, weeklies: bool = False): call_bid = quote_dict[strike.call_streamer_symbol].bidPrice call_ask = quote_dict[strike.call_streamer_symbol].askPrice row = [ - f'{call_bid:{precision}}', - f'{call_ask:{precision}}', - f'{strike.strike_price:{precision}}', - f'{put_bid:{precision}}', - f'{put_ask:{precision}}' + f"{call_bid:{precision_str}}", + f"{call_ask:{precision_str}}", + f"{strike.strike_price:{precision_str}}", + f"{put_bid:{precision_str}}", + f"{put_ask:{precision_str}}", ] prepend = [] if show_delta: put_delta = int(greeks_dict[strike.put_streamer_symbol].delta * 100) call_delta = int(greeks_dict[strike.call_streamer_symbol].delta * 100) - prepend.append(f'{call_delta:g}') - row.append(f'{put_delta:g}') - + prepend.append(f"{call_delta:g}") + row.append(f"{put_delta:g}") + if show_theta: - prepend.append(f'{abs(greeks_dict[strike.put_streamer_symbol].theta):.2f}') - row.append(f'{abs(greeks_dict[strike.call_streamer_symbol].theta):.2f}') + prepend.append( + f"{abs(greeks_dict[strike.put_streamer_symbol].theta):.2f}" + ) + row.append(f"{abs(greeks_dict[strike.call_streamer_symbol].theta):.2f}") if show_oi: - prepend.append(f'{summary_dict[strike.put_streamer_symbol].openInterest}') - row.append(f'{summary_dict[strike.call_streamer_symbol].openInterest}') + prepend.append( + f"{summary_dict[strike.put_streamer_symbol].openInterest}" # type: ignore + ) + row.append(f"{summary_dict[strike.call_streamer_symbol].openInterest}") # type: ignore if show_volume: - prepend.append(f'{trade_dict[strike.put_streamer_symbol].dayVolume}') - row.append(f'{trade_dict[strike.call_streamer_symbol].dayVolume}') + prepend.append(f"{trade_dict[strike.put_streamer_symbol].dayVolume}") # type: ignore + row.append(f"{trade_dict[strike.call_streamer_symbol].dayVolume}") # type: ignore prepend.reverse() table.add_row(*(prepend + row), end_section=(i == strikes - 1)) diff --git a/ttcli/portfolio.py b/ttcli/portfolio.py index 59f2c0d..45d39e2 100644 --- a/ttcli/portfolio.py +++ b/ttcli/portfolio.py @@ -6,57 +6,69 @@ import asyncclick as click from rich.console import Console from rich.table import Table -from tastytrade import (DXLinkStreamer, Equity, NewOrder, OrderAction, - OrderTimeInForce, PriceEffect) +from tastytrade import DXLinkStreamer from tastytrade.account import MarginReportEntry -from tastytrade.dxfeed import EventType, Greeks, Summary, Trade -from tastytrade.instruments import Cryptocurrency, Future, FutureOption, Option +from tastytrade.dxfeed import Greeks, Summary, Trade +from tastytrade.instruments import Cryptocurrency, Equity, Future, FutureOption, Option from tastytrade.metrics import MarketMetricInfo, get_market_metrics -from tastytrade.order import (InstrumentType, OrderType, - TradeableTastytradeJsonDataclass) -from tastytrade.utils import today_in_new_york +from tastytrade.order import ( + InstrumentType, + NewOrder, + OrderAction, + OrderTimeInForce, + OrderType, + TradeableTastytradeJsonDataclass, +) +from tastytrade.utils import TastytradeError, today_in_new_york -from ttcli.utils import (ZERO, RenewableSession, get_confirmation, print_warning, - test_order_handle_errors) +from ttcli.utils import ( + ZERO, + RenewableSession, + get_confirmation, + print_error, + print_warning, +) -@click.group(help='View positions and stats for your portfolio.') +@click.group(help="View positions and stats for your portfolio.") async def portfolio(): pass def conditional_color(value: Decimal, dollars: bool = True) -> str: - d = '$' if dollars else '' - return (f'[red]-{d}{abs(value):.2f}[/red]' - if value < 0 - else f'[green]{d}{value:.2f}[/green]') + d = "$" if dollars else "" + return ( + f"[red]-{d}{abs(value):.2f}[/red]" + if value < 0 + else f"[green]{d}{value:.2f}[/green]" + ) def get_indicators(today: date, metrics: MarketMetricInfo) -> str: indicators = [] if metrics.dividend_next_date and metrics.dividend_next_date > today: days_til = (metrics.dividend_next_date - today).days - indicators.append(f'[deep_sky_blue2]D {days_til}[/deep_sky_blue2]') + indicators.append(f"[deep_sky_blue2]D {days_til}[/deep_sky_blue2]") if ( - metrics.earnings and - metrics.earnings.expected_report_date and - metrics.earnings.expected_report_date > today + metrics.earnings + and metrics.earnings.expected_report_date + and metrics.earnings.expected_report_date > today ): days_til = (metrics.earnings.expected_report_date - today).days - indicators.append(f'[medium_orchid]E {days_til}[/medium_orchid]') - return ' '.join(indicators) if indicators else '' + indicators.append(f"[medium_orchid]E {days_til}[/medium_orchid]") + return " ".join(indicators) if indicators else "" -@portfolio.command(help='View your current positions.') -@click.option('--all', is_flag=True, help='Show positions for all accounts.') +@portfolio.command(help="View your current positions.") +@click.option("--all", is_flag=True, help="Show positions for all accounts.") async def positions(all: bool = False): sesh = RenewableSession() console = Console() - table = Table(header_style='bold', title_style='bold', title='Positions') - table.add_column('#', justify='left') + table = Table(header_style="bold", title_style="bold", title="Positions") + table.add_column("#", justify="left") today = today_in_new_york() if all: - table.add_column('Account', justify='left') + table.add_column("Account", justify="left") positions = [] account_dict = {} for account in sesh.accounts: @@ -68,69 +80,69 @@ async def positions(all: bool = False): positions.sort(key=lambda pos: pos.symbol) pos_dict = {pos.symbol: pos for pos in positions} options_symbols = [ - p.symbol - for p in positions - if p.instrument_type == InstrumentType.EQUITY_OPTION + p.symbol for p in positions if p.instrument_type == InstrumentType.EQUITY_OPTION ] - options = (Option.get_options(sesh, options_symbols) - if options_symbols else []) + options = Option.get_options(sesh, options_symbols) if options_symbols else [] options_dict = {o.symbol: o for o in options} future_options_symbols = [ - p.symbol - for p in positions - if p.instrument_type == InstrumentType.FUTURE_OPTION + p.symbol for p in positions if p.instrument_type == InstrumentType.FUTURE_OPTION ] future_options = ( FutureOption.get_future_options(sesh, future_options_symbols) - if future_options_symbols else [] + if future_options_symbols + else [] ) future_options_dict = {fo.symbol: fo for fo in future_options} futures_symbols = [ - p.symbol - for p in positions - if p.instrument_type == InstrumentType.FUTURE + p.symbol for p in positions if p.instrument_type == InstrumentType.FUTURE ] + [fo.underlying_symbol for fo in future_options] - futures = (Future.get_futures(sesh, futures_symbols) - if futures_symbols else []) + futures = Future.get_futures(sesh, futures_symbols) if futures_symbols else [] futures_dict = {f.symbol: f for f in futures} crypto_symbols = [ p.symbol for p in positions if p.instrument_type == InstrumentType.CRYPTOCURRENCY ] - cryptos = (Cryptocurrency.get_cryptocurrencies(sesh, crypto_symbols) - if crypto_symbols else []) + cryptos = ( + Cryptocurrency.get_cryptocurrencies(sesh, crypto_symbols) + if crypto_symbols + else [] + ) crypto_dict = {c.symbol: c for c in cryptos} - greeks_symbols = ([o.streamer_symbol for o in options] + - [fo.streamer_symbol for fo in future_options]) - equity_symbols = [p.symbol for p in positions - if p.instrument_type == InstrumentType.EQUITY] + greeks_symbols = [o.streamer_symbol for o in options] + [ + fo.streamer_symbol for fo in future_options + ] + equity_symbols = [ + p.symbol for p in positions if p.instrument_type == InstrumentType.EQUITY + ] equities = Equity.get_equities(sesh, equity_symbols) equity_dict = {e.symbol: e for e in equities} - all_symbols = list(set( - [o.underlying_symbol for o in options] + - [c.streamer_symbol for c in cryptos] + - equity_symbols + - [f.streamer_symbol for f in futures] - )) + greeks_symbols + all_symbols = ( + list( + set( + [o.underlying_symbol for o in options] + + [c.streamer_symbol for c in cryptos] + + equity_symbols + + [f.streamer_symbol for f in futures] + ) + ) + + greeks_symbols + ) # get greeks for options greeks_dict: dict[str, Greeks] = {} summary_dict: dict[str, Decimal] = {} async with DXLinkStreamer(sesh) as streamer: if greeks_symbols != []: - await streamer.subscribe(EventType.GREEKS, greeks_symbols) # type: ignore - await streamer.subscribe(EventType.SUMMARY, all_symbols) # type: ignore - await streamer.subscribe(EventType.TRADE, ['SPY']) + await streamer.subscribe(Greeks, greeks_symbols) # type: ignore + await streamer.subscribe(Summary, all_symbols) # type: ignore + await streamer.subscribe(Trade, ["SPY"]) if greeks_symbols != []: - async for greeks in streamer.listen(EventType.GREEKS): - greeks = cast(Greeks, greeks) + async for greeks in streamer.listen(Greeks): greeks_dict[greeks.eventSymbol] = greeks if len(greeks_dict) == len(greeks_symbols): break - spy = await streamer.get_event(EventType.TRADE) - spy = cast(Trade, spy) - async for summary in streamer.listen(EventType.SUMMARY): - summary = cast(Summary, summary) + spy = await streamer.get_event(Trade) + async for summary in streamer.listen(Summary): summary_dict[summary.eventSymbol] = summary.prevDayClosePrice or ZERO if len(summary_dict) == len(all_symbols): break @@ -141,37 +153,47 @@ async def positions(all: bool = False): metrics = get_market_metrics(sesh, list(tt_symbols)) metrics_dict = {metric.symbol: metric for metric in metrics} - table_show_mark = sesh.config.getboolean('portfolio', 'positions-show-mark-price', fallback=False) - table_show_trade = sesh.config.getboolean('portfolio', 'positions-show-trade-price', fallback=False) - table_show_delta = sesh.config.getboolean('portfolio', 'positions-show-delta', fallback=False) - table_show_theta = sesh.config.getboolean('portfolio', 'positions-show-theta', fallback=False) - table_show_gamma = sesh.config.getboolean('portfolio', 'positions-show-gamma', fallback=False) - table.add_column('Symbol', justify='left') - table.add_column('Qty', justify='right') - table.add_column('Day P/L', justify='right') - table.add_column('Total P/L', justify='right') + table_show_mark = sesh.config.getboolean( + "portfolio.positions", "show-mark-price", fallback=False + ) + table_show_trade = sesh.config.getboolean( + "portfolio.positions", "show-trade-price", fallback=False + ) + table_show_delta = sesh.config.getboolean( + "portfolio.positions", "show-delta", fallback=False + ) + table_show_theta = sesh.config.getboolean( + "portfolio.positions", "show-theta", fallback=False + ) + table_show_gamma = sesh.config.getboolean( + "portfolio.positions", "show-gamma", fallback=False + ) + table.add_column("Symbol", justify="left") + table.add_column("Qty", justify="right") + table.add_column("Day P/L", justify="right") + table.add_column("Total P/L", justify="right") if table_show_mark: - table.add_column('Mark Price', justify='right') + table.add_column("Mark Price", justify="right") if table_show_trade: - table.add_column('Trade Price', justify='right') - table.add_column('IV Rank', justify='right') + table.add_column("Trade Price", justify="right") + table.add_column("IV Rank", justify="right") if table_show_delta: - table.add_column('Delta', justify='right') + table.add_column("Delta", justify="right") if table_show_theta: - table.add_column('Theta', justify='right') + table.add_column("Theta", justify="right") if table_show_gamma: - table.add_column('Gamma', justify='right') - table.add_column(u'\u03B2 Delta', justify='right') - table.add_column('Net Liq', justify='right') - table.add_column('Indicators', justify='center') + table.add_column("Gamma", justify="right") + table.add_column("\u03b2 Delta", justify="right") + table.add_column("Net Liq", justify="right") + table.add_column("Indicators", justify="center") sums = defaultdict(lambda: ZERO) closing: dict[int, TradeableTastytradeJsonDataclass] = {} for i, pos in enumerate(positions): - row = [f'{i+1}'] + row = [f"{i+1}"] mark = pos.mark or 0 mark_price = pos.mark_price or 0 - m = (1 if pos.quantity_direction == 'Long' else -1) - #mark_price = mark / pos.quantity + m = 1 if pos.quantity_direction == "Long" else -1 + # mark_price = mark / pos.quantity if all: row.append(account_dict[pos.account_number]) # type: ignore net_liq = Decimal(mark * m) @@ -186,7 +208,7 @@ async def positions(all: bool = False): gamma = greeks_dict[o.streamer_symbol].gamma * 100 * m # type: ignore metrics = metrics_dict[o.underlying_symbol] beta = metrics.beta or 0 - bwd = beta * mark * delta / spy_price + bwd = beta * mark * delta / spy_price ivr = (metrics.tos_implied_volatility_index_rank or 0) * 100 indicators = get_indicators(today, metrics) pnl = m * (mark_price - pos.average_open_price * pos.multiplier) @@ -203,8 +225,16 @@ async def positions(all: bool = False): f = futures_dict[o.underlying_symbol] metrics = metrics_dict[o.root_symbol] indicators = get_indicators(today, metrics) - bwd = (summary_dict[f.streamer_symbol] * # type: ignore - metrics.beta * delta / spy_price) if metrics.beta else 0 + bwd = ( + ( + summary_dict[f.streamer_symbol] # type: ignore + * metrics.beta + * delta + / spy_price + ) + if metrics.beta + else 0 + ) ivr = (metrics.tos_implied_volatility_index_rank or 0) * 100 trade_price = pos.average_open_price / f.display_factor pnl = (mark_price - trade_price) * m @@ -250,91 +280,90 @@ async def positions(all: bool = False): ivr = None pnl = mark - pos.average_open_price * pos.quantity * m trade_price = pos.average_open_price - indicators = '' + indicators = "" pos.quantity = round(pos.quantity, 2) c = crypto_dict[pos.symbol] closing[i + 1] = c day_change = mark_price - summary_dict[c.streamer_symbol] # type: ignore pnl_day = day_change * pos.quantity * pos.multiplier else: - print(f'Skipping {pos.symbol}, unknown instrument type ' - f'{pos.instrument_type}!') + print( + f"Skipping {pos.symbol}, unknown instrument type " + f"{pos.instrument_type}!" + ) continue if pos.created_at.date() == today: pnl_day = pnl - sums['pnl'] += pnl - sums['pnl_day'] += pnl_day - sums['bwd'] += bwd - sums['net_liq'] += net_liq - row.extend([ - pos.symbol, - f'{pos.quantity * m:g}', - conditional_color(pnl_day), - conditional_color(pnl) - ]) + sums["pnl"] += pnl + sums["pnl_day"] += pnl_day + sums["bwd"] += bwd + sums["net_liq"] += net_liq + row.extend( + [ + pos.symbol, + f"{pos.quantity * m:g}", + conditional_color(pnl_day), + conditional_color(pnl), + ] + ) if table_show_mark: - row.append(f'${mark_price:.2f}') + row.append(f"${mark_price:.2f}") if table_show_trade: - row.append(f'${trade_price:.2f}') - row.append(f'{ivr:.1f}' if ivr else '--') + row.append(f"${trade_price:.2f}") + row.append(f"{ivr:.1f}" if ivr else "--") if table_show_delta: - row.append(f'{delta:.2f}') + row.append(f"{delta:.2f}") if table_show_theta: - row.append(f'{theta:.2f}') + row.append(f"{theta:.2f}") if table_show_gamma: - row.append(f'{gamma:.2f}') - row.extend([ - f'{bwd:.2f}', - conditional_color(net_liq), - indicators - ]) + row.append(f"{gamma:.2f}") + row.extend([f"{bwd:.2f}", conditional_color(net_liq), indicators]) table.add_row(*row, end_section=(i == len(positions) - 1)) # summary - final_row = [''] + final_row = [""] if all: - final_row.append('') - final_row.extend([ - '', - '', - conditional_color(sums['pnl_day']), - conditional_color(sums['pnl']) - ]) + final_row.append("") + final_row.extend( + ["", "", conditional_color(sums["pnl_day"]), conditional_color(sums["pnl"])] + ) if table_show_mark: - final_row.append('') + final_row.append("") if table_show_trade: - final_row.append('') - final_row.append('') + final_row.append("") + final_row.append("") if table_show_delta: - final_row.append('') + final_row.append("") if table_show_theta: - final_row.append('') + final_row.append("") if table_show_gamma: - final_row.append('') - final_row.extend([ - f"{sums['bwd']:.2f}", - conditional_color(sums['net_liq']), - '' - ]) + final_row.append("") + final_row.extend([f"{sums['bwd']:.2f}", conditional_color(sums["net_liq"]), ""]) table.add_row(*final_row) console.print(table) if not all: - delta_target = sesh.config.getint('portfolio', 'portfolio-delta-target', fallback=0) # delta neutral - delta_variation = sesh.config.getint('portfolio', 'portfolio-delta-variation', fallback=5) - delta_diff = delta_target - sums['bwd'] + delta_target = sesh.config.getint( + "portfolio", "delta-target", fallback=0 + ) # delta neutral + delta_variation = sesh.config.getint("portfolio", "delta-variation", fallback=5) + delta_diff = delta_target - sums["bwd"] if abs(delta_diff) > delta_variation: - print_warning(f'Portfolio beta-weighting misses target of {delta_target} substantially!') - close = get_confirmation('Close out a position? y/N ', default=False) + print_warning( + f"Portfolio beta-weighting misses target of {delta_target} substantially!" + ) + close = get_confirmation("Close out a position? y/N ", default=False) if not close: return # get the position(s) to close - to_close = input('Enter the number(s) of the leg(s) to include in closing order, separated by commas: ') + to_close = input( + "Enter the number(s) of the leg(s) to include in closing order, separated by commas: " + ) if not to_close: return - to_close = [int(i) for i in to_close.split(',')] + to_close = [int(i) for i in to_close.split(",")] close_objs = [closing[i] for i in to_close] account_number = pos_dict[close_objs[0].symbol].account_number if any(pos_dict[o.symbol].account_number != account_number for o in close_objs): - print('All legs must be in the same account!') + print("All legs must be in the same account!") return account = next(a for a in sesh.accounts if a.account_number == account_number) legs = [] @@ -342,71 +371,96 @@ async def positions(all: bool = False): tif = OrderTimeInForce.DAY for o in close_objs: pos = pos_dict[o.symbol] - total_price += pos.mark_price * (1 if pos.quantity_direction == 'Long' else -1) # type: ignore + total_price += pos.mark_price * (1 if pos.quantity_direction == "Long" else -1) # type: ignore if isinstance(o, Future): - action = (OrderAction.SELL - if pos.quantity_direction == 'Long' - else OrderAction.BUY) + action = ( + OrderAction.SELL + if pos.quantity_direction == "Long" + else OrderAction.BUY + ) else: - action = (OrderAction.SELL_TO_CLOSE - if pos.quantity_direction == 'Long' - else OrderAction.BUY_TO_CLOSE) + action = ( + OrderAction.SELL_TO_CLOSE + if pos.quantity_direction == "Long" + else OrderAction.BUY_TO_CLOSE + ) if isinstance(o, Cryptocurrency): tif = OrderTimeInForce.GTC legs.append(o.build_leg(pos.quantity, action)) - console.print(f'Mark price for trade: {conditional_color(total_price)}') - price = input('Please enter a limit price per quantity (default mark): ') + console.print(f"Mark price for trade: {conditional_color(total_price)}") + price = input("Please enter a limit price per quantity (default mark): ") if price: total_price = Decimal(price) else: total_price = round(total_price, 2) - + order = NewOrder( time_in_force=tif, order_type=OrderType.LIMIT, legs=legs, - price=abs(total_price), - price_effect=PriceEffect.CREDIT if total_price > 0 else PriceEffect.DEBIT + price=total_price, ) - data = test_order_handle_errors(account, sesh, order) - if not data: + try: + data = account.place_order(sesh, order, dry_run=True) + except TastytradeError as e: + print_error(str(e)) return bp = data.buying_power_effect.change_in_buying_power - bp *= -1 if data.buying_power_effect.change_in_buying_power_effect == PriceEffect.DEBIT else 1 fees = data.fee_calculation.total_fees if data.fee_calculation else 0 - table = Table(show_header=True, header_style='bold', title_style='bold', title='Order Review') - table.add_column('Symbol', justify='center') - table.add_column('Price', justify='center') - table.add_column('BP Effect', justify='center') - table.add_column('Fees', justify='center') - table.add_row(order.legs[0].symbol, conditional_color(total_price), - conditional_color(bp), f'[red]${fees:.2f}[/red]') + table = Table( + show_header=True, header_style="bold", title_style="bold", title="Order Review" + ) + table.add_column("Symbol", justify="center") + table.add_column("Price", justify="center") + table.add_column("BP Effect", justify="center") + table.add_column("Fees", justify="center") + table.add_row( + order.legs[0].symbol, + conditional_color(total_price), + conditional_color(bp), + f"[red]${fees:.2f}[/red]", + ) for i in range(1, len(order.legs)): - table.add_row(order.legs[i].symbol, '-', '-', '-') + table.add_row(order.legs[i].symbol, "-", "-", "-") console.print(table) if data.warnings: for warning in data.warnings: print_warning(warning.message) - if get_confirmation('Send order? Y/n '): + if get_confirmation("Send order? Y/n "): account.place_order(sesh, order, dry_run=False) -@portfolio.command(help='View your previous positions.') -@click.option('--start-date', type=click.DateTime(['%Y-%m-%d']), help='The start date for the search date range.') -@click.option('--end-date', type=click.DateTime(['%Y-%m-%d']), help='The end date for the search date range.') -@click.option('-s', '--symbol', type=str, help='Filter by underlying symbol.') -@click.option('-t', '--type', type=click.Choice(InstrumentType), help='Filter by instrument type.') # type: ignore -@click.option('--asc', is_flag=True, help='Sort by ascending time instead of descending.') +@portfolio.command(help="View your previous positions.") +@click.option( + "--start-date", + type=click.DateTime(["%Y-%m-%d"]), + help="The start date for the search date range.", +) +@click.option( + "--end-date", + type=click.DateTime(["%Y-%m-%d"]), + help="The end date for the search date range.", +) +@click.option("-s", "--symbol", type=str, help="Filter by underlying symbol.") +@click.option( + "-t", + "--type", + type=click.Choice(list(InstrumentType)), + help="Filter by instrument type.", +) # type: ignore +@click.option( + "--asc", is_flag=True, help="Sort by ascending time instead of descending." +) async def history( start_date: datetime | None = None, end_date: datetime | None = None, symbol: str | None = None, type: InstrumentType | None = None, - asc: bool = False + asc: bool = False, ): sesh = RenewableSession() acc = sesh.get_account() @@ -414,120 +468,147 @@ async def history( sesh, start_date=start_date.date() if start_date else None, end_date=end_date.date() if end_date else None, - underlying_symbol=symbol if symbol and symbol[0] != '/' else None, - futures_symbol=symbol if symbol and symbol[0] == '/' else None, - instrument_type=type + underlying_symbol=symbol if symbol and symbol[0] != "/" else None, + futures_symbol=symbol if symbol and symbol[0] == "/" else None, + instrument_type=type, ) if asc: history.reverse() console = Console() - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Transaction list for account {acc.nickname} ({acc.account_number})') - table.add_column('Date/Time') - table.add_column('Root Symbol') - table.add_column('Txn Type') - table.add_column('Description') - table.add_column('Gross P/L', justify='right') - table.add_column('Fees', style='red', justify='right') - table.add_column('Net P/L', justify='right') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Transaction list for account {acc.nickname} ({acc.account_number})", + ) + table.add_column("Date/Time") + table.add_column("Root Symbol") + table.add_column("Txn Type") + table.add_column("Description") + table.add_column("Gross P/L", justify="right") + table.add_column("Fees", style="red", justify="right") + table.add_column("Net P/L", justify="right") last_id = history[-1].id totals = defaultdict(lambda: ZERO) for txn in history: fees = ( - (txn.commission or ZERO) + - (txn.clearing_fees or ZERO) + - (txn.regulatory_fees or ZERO) + - (txn.proprietary_index_option_fees or ZERO) + (txn.commission or ZERO) + + (txn.clearing_fees or ZERO) + + (txn.regulatory_fees or ZERO) + + (txn.proprietary_index_option_fees or ZERO) + ) + totals["fees"] += fees + totals["gross"] += txn.value + totals["net"] += txn.net_value + table.add_row( + *[ + txn.executed_at.strftime("%Y-%m-%d %H:%M"), + txn.underlying_symbol or "--", + txn.transaction_type, + txn.description, + conditional_color(txn.value), + f"-${fees:.2f}", + conditional_color(txn.net_value), + ], + end_section=(txn.id == last_id), ) - totals['fees'] -= fees - gross = txn.value * (-1 if txn.value_effect == PriceEffect.DEBIT else 1) - totals['gross'] += gross - net = txn.net_value * (-1 if txn.net_value_effect == PriceEffect.DEBIT else 1) - totals['net'] += net - table.add_row(*[ - txn.executed_at.strftime('%Y-%m-%d %H:%M'), - txn.underlying_symbol or '--', - txn.transaction_type, - txn.description, - conditional_color(gross), - f'-${fees:.2f}', - conditional_color(net) - ], end_section=(txn.id == last_id)) # add last row - table.add_row(*[ - '', - '', - '', - '', - conditional_color(totals['gross']), - conditional_color(totals['fees']), - conditional_color(totals['net']) - ]) + table.add_row( + *[ + "", + "", + "", + "", + conditional_color(totals["gross"]), + conditional_color(totals["fees"]), + conditional_color(totals["net"]), + ] + ) console.print(table) -@portfolio.command(help='View margin usage by position for an account.') +@portfolio.command(help="View margin usage by position for an account.") async def margin(): sesh = RenewableSession() acc = sesh.get_account() margin = acc.get_margin_requirements(sesh) console = Console() - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Margin report for account {acc.nickname} ({acc.account_number})') - table.add_column('Symbol') - table.add_column('Used BP', justify='right') - table.add_column('BP %', justify='right') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Margin report for account {acc.nickname} ({acc.account_number})", + ) + table.add_column("Symbol") + table.add_column("Used BP", justify="right") + table.add_column("BP %", justify="right") last_entry = len(margin.groups) - 1 warnings = [] - max_percent = sesh.config.getfloat('portfolio', 'bp-max-percent-per-position', fallback=5.0) + max_percent = sesh.config.getfloat( + "portfolio", "bp-max-percent-per-position", fallback=5.0 + ) for i, entry in enumerate(margin.groups): + if not entry: + continue entry = cast(MarginReportEntry, entry) bp = entry.buying_power bp_percent = float(bp / margin.margin_equity * 100) if bp_percent > max_percent: - warnings.append(f'Per-position BP usage is too high for {entry.description}, max is {max_percent}%!') - table.add_row(*[ - entry.description, - conditional_color(bp), - f'{bp_percent:.1f}%' - ], end_section=(i == last_entry)) - table.add_row(*[ - '', - conditional_color(margin.margin_requirement), - f'{margin.margin_requirement / margin.margin_equity * 100:.1f}%' - ]) + warnings.append( + f"Per-position BP usage is too high for {entry.description}, max is {max_percent}%!" + ) + table.add_row( + *[entry.description, conditional_color(bp), f"{bp_percent:.1f}%"], + end_section=(i == last_entry), + ) + table.add_row( + *[ + "", + conditional_color(margin.margin_requirement), + f"{margin.margin_requirement / margin.margin_equity * 100:.1f}%", + ] + ) console.print(table) for warning in warnings: print_warning(warning) -@portfolio.command(help='View current balances for an account.') +@portfolio.command(help="View current balances for an account.") async def balance(): sesh = RenewableSession() acc = sesh.get_account() balances = acc.get_balances(sesh) console = Console() - table = Table(show_header=True, header_style='bold', title_style='bold', - title=f'Current balance for account {acc.nickname} ({acc.account_number})') - table.add_column('Cash', justify='right') - table.add_column('Net Liq', justify='right') - table.add_column('Free BP', justify='right') - table.add_column('Used BP', justify='right') - table.add_column('BP %', justify='right') + table = Table( + show_header=True, + header_style="bold", + title_style="bold", + title=f"Current balance for account {acc.nickname} ({acc.account_number})", + ) + table.add_column("Cash", justify="right") + table.add_column("Net Liq", justify="right") + table.add_column("Free BP", justify="right") + table.add_column("Used BP", justify="right") + table.add_column("BP %", justify="right") bp_percent = balances.maintenance_requirement / balances.margin_equity * 100 - table.add_row(*[ - conditional_color(balances.cash_balance), - conditional_color(balances.net_liquidating_value), - conditional_color(balances.derivative_buying_power), - conditional_color(balances.maintenance_requirement), - f'{bp_percent:.1f}%' - ]) + table.add_row( + *[ + conditional_color(balances.cash_balance), + conditional_color(balances.net_liquidating_value), + conditional_color(balances.derivative_buying_power), + conditional_color(balances.maintenance_requirement), + f"{bp_percent:.1f}%", + ] + ) async with DXLinkStreamer(sesh) as streamer: - await streamer.subscribe(EventType.TRADE, ['VIX']) - trade = await streamer.get_event(EventType.TRADE) + await streamer.subscribe(Trade, ["VIX"]) + trade = await streamer.get_event(Trade) console.print(table) - bp_variation = sesh.config.getint('portfolio', 'bp-target-percent-variation', fallback=10) + bp_variation = sesh.config.getint( + "portfolio", "bp-target-percent-variation", fallback=10 + ) vix_diff = trade.price - bp_percent # type: ignore if abs(vix_diff) > bp_variation: - print_warning(f'BP usage is dangerously high given VIX level of {round(trade.price)}!') # type: ignore - + print_warning( + f"BP usage is dangerously high given VIX level of {round(trade.price)}!" # type: ignore + ) # type: ignore diff --git a/ttcli/utils.py b/ttcli/utils.py index db22fce..bc44f18 100644 --- a/ttcli/utils.py +++ b/ttcli/utils.py @@ -7,66 +7,58 @@ from datetime import date from decimal import Decimal from importlib.resources import as_file, files -from typing import Optional +from typing import Any, Type +from httpx import AsyncClient, Client from rich import print as rich_print -from tastytrade import Account, Session -from tastytrade.order import NewOrder, PlacedOrderResponse +from tastytrade import Account, DXLinkStreamer, Session +from tastytrade.dxfeed import Quote +from tastytrade.streamer import EventType, U logger = logging.getLogger(__name__) -VERSION = '0.2' +VERSION = "0.3" ZERO = Decimal(0) -CONTEXT_SETTINGS = {'help_option_names': ['-h', '--help']} +CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]} -CUSTOM_CONFIG_PATH = '.config/ttcli/ttcli.cfg' -TOKEN_PATH = '.config/ttcli/.session' +CUSTOM_CONFIG_PATH = ".config/ttcli/ttcli.cfg" +TOKEN_PATH = ".config/ttcli/.session" def print_error(msg: str): - rich_print(f'[bold red]Error: {msg}[/bold red]') + rich_print(f"[bold red]Error: {msg}[/bold red]") def print_warning(msg: str): - rich_print(f'[light_coral]Warning: {msg}[/light_coral]') - - -def test_order_handle_errors( - account: Account, - session: 'RenewableSession', - order: NewOrder -) -> Optional[PlacedOrderResponse]: - url = f'{session.base_url}/accounts/{account.account_number}/orders/dry-run' - json = order.model_dump_json(exclude_none=True, by_alias=True) - response = session.client.post(url, data=json) - # modified to use our error handling - if response.status_code // 100 != 2: - content = response.json()['error'] - print_error(f"{content['message']}") - errors = content.get('errors') - if errors is not None: - for error in errors: - if "code" in error: - print_error(f"{error['message']}") - else: - print_error(f"{error['reason']}") - return None - else: - data = response.json()['data'] - return PlacedOrderResponse(**data) + rich_print(f"[light_coral]Warning: {msg}[/light_coral]") + + +async def listen_events( + dxfeeds: list[str], event_class: Type[U], streamer: DXLinkStreamer +) -> dict[str, U]: + event_dict = {} + await streamer.subscribe(event_class, dxfeeds) + async for event in streamer.listen(event_class): + if event_class == Quote and (event.bidPrice is None or event.askPrice is None): # type: ignore + continue + event_dict[event.eventSymbol] = event + if len(event_dict) == len(dxfeeds): + return event_dict + return event_dict # unreachable class RenewableSession(Session): def __init__(self): - custom_path = os.path.join(os.path.expanduser('~'), CUSTOM_CONFIG_PATH) - data_file = files('ttcli.data').joinpath('ttcli.cfg') - token_path = os.path.join(os.path.expanduser('~'), TOKEN_PATH) + custom_path = os.path.join(os.path.expanduser("~"), CUSTOM_CONFIG_PATH) + data_file = files("ttcli.data").joinpath("ttcli.cfg") + token_path = os.path.join(os.path.expanduser("~"), TOKEN_PATH) logged_in = False # try to load token if os.path.exists(token_path): - with open(token_path, 'rb') as f: - self.__dict__ = pickle.load(f) + with open(token_path, "rb") as f: + data = pickle.load(f) + self.deserialize(data) # make sure token hasn't expired logged_in = self.validate() @@ -86,48 +78,87 @@ def __init__(self): username, password = self._get_credentials() Session.__init__(self, username, password) - accounts = Account.get_accounts(self) - self.accounts = [acc for acc in accounts if not acc.is_closed] # write session token to cache os.makedirs(os.path.dirname(token_path), exist_ok=True) - with open(token_path, 'wb') as f: - pickle.dump(self.__dict__, f) - logger.debug('Logged in with new session, cached for next login.') + with open(token_path, "wb") as f: + pickle.dump(self.serialize(), f) + logger.debug("Logged in with new session, cached for next login.") else: - logger.debug('Logged in with cached session.') + logger.debug("Logged in with cached session.") + accounts = Account.get_accounts(self) + self.accounts = [acc for acc in accounts if not acc.is_closed] + + def deserialize(self, data: dict[str, Any]): + self.session_token = data["session_token"] + self.remember_token = data["remember_token"] + self.streamer_token = data["streamer_token"] + self.dxlink_url = data["dxlink_url"] + self.is_test = data["is_test"] + self.sync_client = Client( + base_url=data["base_url"], + headers={ + "Accept": "application/json", + "Content-Type": "application/json", + "Authorization": data["session_token"], + }, + ) + self.async_client = AsyncClient( + base_url=data["base_url"], + headers={ + "Accept": "application/json", + "Content-Type": "application/json", + "Authorization": data["session_token"], + }, + ) + + def serialize(self) -> dict[str, Any]: + return { + "session_token": self.session_token, + "remember_token": self.remember_token, + "base_url": str(self.sync_client.base_url), + "streamer_token": self.streamer_token, + "dxlink_url": self.dxlink_url, + "is_test": self.is_test, + } def _get_credentials(self): - username = os.getenv('TT_USERNAME') - password = os.getenv('TT_PASSWORD') - if self.config.has_section('general'): - username = username or self.config['general'].get('username') - password = password or self.config['general'].get('password') + username = os.getenv("TT_USERNAME") + password = os.getenv("TT_PASSWORD") + if self.config.has_section("general"): + username = username or self.config["general"].get("username") + password = password or self.config["general"].get("password") if not username: - username = getpass.getpass('Username: ') + username = getpass.getpass("Username: ") if not password: - password = getpass.getpass('Password: ') + password = getpass.getpass("Password: ") return username, password def get_account(self) -> Account: - account = self.config['general'].get('default-account', None) + account = self.config["general"].get("default-account", None) if account: try: return next(a for a in self.accounts if a.account_number == account) except StopIteration: - print_warning('Default account is set, but the account doesn\'t appear to exist!') + print_warning( + "Default account is set, but the account doesn't appear to exist!" + ) for i in range(len(self.accounts)): if i == 0: - print(f'{i + 1}) {self.accounts[i].account_number} ' - f'{self.accounts[i].nickname} (default)') + print( + f"{i + 1}) {self.accounts[i].account_number} " + f"{self.accounts[i].nickname} (default)" + ) else: - print(f'{i + 1}) {self.accounts[i].account_number} {self.accounts[i].nickname}') + print( + f"{i + 1}) {self.accounts[i].account_number} {self.accounts[i].nickname}" + ) choice = 0 while choice not in range(1, len(self.accounts) + 1): try: - raw = input('Please choose an account: ') + raw = input("Please choose an account: ") choice = int(raw) except ValueError: return self.accounts[0] @@ -143,8 +174,7 @@ def get_confirmation(prompt: str, default: bool = True) -> bool: answer = input(prompt).lower() if not answer: return default - if answer[0] == 'y': + if answer[0] == "y": return True - if answer[0] == 'n': + if answer[0] == "n": return False - diff --git a/uv.lock b/uv.lock index 39da9cb..a21c9af 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,8 @@ version = 1 requires-python = ">=3.10" resolution-markers = [ + "python_full_version < '3.11'", + "python_full_version == '3.11.*'", "python_full_version == '3.12.*'", "python_full_version >= '3.13'", ] @@ -16,15 +18,17 @@ wheels = [ [[package]] name = "anyio" -version = "4.6.0" +version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "idna", marker = "python_full_version >= '3.12'" }, - { name = "sniffio", marker = "python_full_version >= '3.12'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } +sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, + { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, ] [[package]] @@ -41,7 +45,7 @@ name = "asttokens" version = "2.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six", marker = "python_full_version >= '3.12'" }, + { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/45/1d/f03bcb60c4a3212e15f99a56085d93093a497718adf828d050b9d675da81/asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0", size = 62284 } wheels = [ @@ -53,8 +57,8 @@ name = "asyncclick" version = "8.1.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.12'" }, - { name = "colorama", marker = "python_full_version >= '3.12' and platform_system == 'Windows'" }, + { name = "anyio" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/bf/59d836c3433d7aa07f76c2b95c4eb763195ea8a5d7f9ad3311ed30c2af61/asyncclick-8.1.7.2.tar.gz", hash = "sha256:219ea0f29ccdc1bb4ff43bcab7ce0769ac6d48a04f997b43ec6bee99a222daa0", size = 349073 } wheels = [ @@ -75,7 +79,7 @@ name = "cffi" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser", marker = "python_full_version >= '3.12'" }, + { name = "pycparser" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } wheels = [ @@ -127,60 +131,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, ] -[[package]] -name = "charset-normalizer" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/61/095a0aa1a84d1481998b534177c8566fdc50bb1233ea9a0478cd3cc075bd/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", size = 194219 }, - { url = "https://files.pythonhosted.org/packages/cc/94/f7cf5e5134175de79ad2059edf2adce18e0685ebdb9227ff0139975d0e93/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", size = 122521 }, - { url = "https://files.pythonhosted.org/packages/46/6a/d5c26c41c49b546860cc1acabdddf48b0b3fb2685f4f5617ac59261b44ae/charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", size = 120383 }, - { url = "https://files.pythonhosted.org/packages/b8/60/e2f67915a51be59d4539ed189eb0a2b0d292bf79270410746becb32bc2c3/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", size = 138223 }, - { url = "https://files.pythonhosted.org/packages/05/8c/eb854996d5fef5e4f33ad56927ad053d04dc820e4a3d39023f35cad72617/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", size = 148101 }, - { url = "https://files.pythonhosted.org/packages/f6/93/bb6cbeec3bf9da9b2eba458c15966658d1daa8b982c642f81c93ad9b40e1/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", size = 140699 }, - { url = "https://files.pythonhosted.org/packages/da/f1/3702ba2a7470666a62fd81c58a4c40be00670e5006a67f4d626e57f013ae/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", size = 142065 }, - { url = "https://files.pythonhosted.org/packages/3f/ba/3f5e7be00b215fa10e13d64b1f6237eb6ebea66676a41b2bcdd09fe74323/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", size = 144505 }, - { url = "https://files.pythonhosted.org/packages/33/c3/3b96a435c5109dd5b6adc8a59ba1d678b302a97938f032e3770cc84cd354/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", size = 139425 }, - { url = "https://files.pythonhosted.org/packages/43/05/3bf613e719efe68fb3a77f9c536a389f35b95d75424b96b426a47a45ef1d/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", size = 145287 }, - { url = "https://files.pythonhosted.org/packages/58/78/a0bc646900994df12e07b4ae5c713f2b3e5998f58b9d3720cce2aa45652f/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", size = 149929 }, - { url = "https://files.pythonhosted.org/packages/eb/5c/97d97248af4920bc68687d9c3b3c0f47c910e21a8ff80af4565a576bd2f0/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", size = 141605 }, - { url = "https://files.pythonhosted.org/packages/a8/31/47d018ef89f95b8aded95c589a77c072c55e94b50a41aa99c0a2008a45a4/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", size = 142646 }, - { url = "https://files.pythonhosted.org/packages/ae/d5/4fecf1d58bedb1340a50f165ba1c7ddc0400252d6832ff619c4568b36cc0/charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", size = 92846 }, - { url = "https://files.pythonhosted.org/packages/a2/a0/4af29e22cb5942488cf45630cbdd7cefd908768e69bdd90280842e4e8529/charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", size = 100343 }, - { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, - { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, - { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, - { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, - { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, - { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, - { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, - { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, - { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, - { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, - { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, - { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, - { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, - { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, - { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, - { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, - { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, - { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, - { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, - { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, - { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, - { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, - { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, - { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, - { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, - { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, - { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, - { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -195,7 +145,7 @@ name = "comm" version = "0.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "traitlets", marker = "python_full_version >= '3.12'" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210 } wheels = [ @@ -204,23 +154,27 @@ wheels = [ [[package]] name = "debugpy" -version = "1.8.6" +version = "1.8.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/b3/05c94639560cf0eaef33662ee5102d3e2a8b9e8c527c53190bf7187bacdb/debugpy-1.8.6.zip", hash = "sha256:c931a9371a86784cee25dec8d65bc2dc7a21f3f1552e3833d9ef8f919d22280a", size = 4956612 } +sdist = { url = "https://files.pythonhosted.org/packages/e4/5e/7667b95c9d7ddb25c047143a3a47685f9be2a5d3d177a85a730b22dc6e5c/debugpy-1.8.8.zip", hash = "sha256:e6355385db85cbd666be703a96ab7351bc9e6c61d694893206f8001e22aee091", size = 4928684 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/ce/5e093945df2da28dbd1bc14c631d71431d1aa08adc629e221c9658841f82/debugpy-1.8.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:30f467c5345d9dfdcc0afdb10e018e47f092e383447500f125b4e013236bf14b", size = 2089048 }, - { url = "https://files.pythonhosted.org/packages/d4/7a/a5fe4eaf648016a27a875403735a089ba7cc9a4cc906d37c8fdb2997b50d/debugpy-1.8.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d73d8c52614432f4215d0fe79a7e595d0dd162b5c15233762565be2f014803b", size = 3547450 }, - { url = "https://files.pythonhosted.org/packages/bf/fe/53d6d46e4a1cb5fb1a979695a9a26c8a04aed6d6ce4ba808a6d42341beba/debugpy-1.8.6-cp310-cp310-win32.whl", hash = "sha256:e3e182cd98eac20ee23a00653503315085b29ab44ed66269482349d307b08df9", size = 5151732 }, - { url = "https://files.pythonhosted.org/packages/ce/68/127cfc6012fbeef126eab1e168ad788ee9832b8b0d572743e5c6fa03ea83/debugpy-1.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:e3a82da039cfe717b6fb1886cbbe5c4a3f15d7df4765af857f4307585121c2dd", size = 5183983 }, - { url = "https://files.pythonhosted.org/packages/9f/cc/3158aa2c96c677e324981230dfd33087ef4bfb5afb1d9cd40b7a1b35edb2/debugpy-1.8.6-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:67479a94cf5fd2c2d88f9615e087fcb4fec169ec780464a3f2ba4a9a2bb79955", size = 2203403 }, - { url = "https://files.pythonhosted.org/packages/d5/9f/5691af62c556392ee45ed9b5c3fde4aaa7cb3b519cc8bea92fc27eab31fc/debugpy-1.8.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb8653f6cbf1dd0a305ac1aa66ec246002145074ea57933978346ea5afdf70b", size = 3120088 }, - { url = "https://files.pythonhosted.org/packages/5e/3e/e32b36f9a391af4f8ff6b9c068ee822b5e4aa2d9cf4dc0937696e9249fa6/debugpy-1.8.6-cp311-cp311-win32.whl", hash = "sha256:cdaf0b9691879da2d13fa39b61c01887c34558d1ff6e5c30e2eb698f5384cd43", size = 5077329 }, - { url = "https://files.pythonhosted.org/packages/9d/de/ddad801b7fdbe2f97c744b44bb61169c4e0ab48a90f881c8f43b463f206b/debugpy-1.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:43996632bee7435583952155c06881074b9a742a86cee74e701d87ca532fe833", size = 5101373 }, - { url = "https://files.pythonhosted.org/packages/b8/9e/882dae43f281fc4742fd9e5d2e0f5dae77f38d4f345e78bf1ed5e1f6202e/debugpy-1.8.6-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:db891b141fc6ee4b5fc6d1cc8035ec329cabc64bdd2ae672b4550c87d4ecb128", size = 2526807 }, - { url = "https://files.pythonhosted.org/packages/77/cf/6c0497f4b092cb4a408dda5ab84750032e5535f994d21eb812086d62094d/debugpy-1.8.6-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:567419081ff67da766c898ccf21e79f1adad0e321381b0dfc7a9c8f7a9347972", size = 4162582 }, - { url = "https://files.pythonhosted.org/packages/8e/66/e9c0aef0a5118aeaa6dfccb6d4f388602271cfb37c689da5e7b6168075d2/debugpy-1.8.6-cp312-cp312-win32.whl", hash = "sha256:c9834dfd701a1f6bf0f7f0b8b1573970ae99ebbeee68314116e0ccc5c78eea3c", size = 5193541 }, - { url = "https://files.pythonhosted.org/packages/c2/97/2196c4132c29f7cd8e574bb05a4b03ed35f94e3fcd1f56e72ea9f10732f4/debugpy-1.8.6-cp312-cp312-win_amd64.whl", hash = "sha256:e4ce0570aa4aca87137890d23b86faeadf184924ad892d20c54237bcaab75d8f", size = 5233374 }, - { url = "https://files.pythonhosted.org/packages/05/ce/785925e87ce735cc3da7fb2bd66d8ca83173d8a0b60ce35a59a60b8d636f/debugpy-1.8.6-py2.py3-none-any.whl", hash = "sha256:b48892df4d810eff21d3ef37274f4c60d32cdcafc462ad5647239036b0f0649f", size = 5209208 }, + { url = "https://files.pythonhosted.org/packages/77/79/677d71c342d5f24baf81d262c9e0c19cac3b17b4e4587c0574eaa3964ab1/debugpy-1.8.8-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:e59b1607c51b71545cb3496876544f7186a7a27c00b436a62f285603cc68d1c6", size = 2088337 }, + { url = "https://files.pythonhosted.org/packages/11/b3/4119fa89b66bcc64a3b186ea52ee7c22bccc5d1765ee890887678b0e3e76/debugpy-1.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6531d952b565b7cb2fbd1ef5df3d333cf160b44f37547a4e7cf73666aca5d8d", size = 3567953 }, + { url = "https://files.pythonhosted.org/packages/e8/4a/01f70b44af27c13d720446ce9bf14467c90411e90e6c6ffbb7c45845d23d/debugpy-1.8.8-cp310-cp310-win32.whl", hash = "sha256:b01f4a5e5c5fb1d34f4ccba99a20ed01eabc45a4684f4948b5db17a319dfb23f", size = 5128658 }, + { url = "https://files.pythonhosted.org/packages/2b/a5/c4210f3842db0911a49b3030bfc217e0772bfd33d7aa50996bc762e8a334/debugpy-1.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:535f4fb1c024ddca5913bb0eb17880c8f24ba28aa2c225059db145ee557035e9", size = 5157545 }, + { url = "https://files.pythonhosted.org/packages/38/55/6b5596ea6d5490e17abc2896f1fbe83d31205a22629805daccd30686721c/debugpy-1.8.8-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:c399023146e40ae373753a58d1be0a98bf6397fadc737b97ad612886b53df318", size = 2187057 }, + { url = "https://files.pythonhosted.org/packages/3f/f7/c2ee07f6335c3620c1435aef2c4d3d4853f6b7fb0789aa2c52a84498ef90/debugpy-1.8.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09cc7b162586ea2171eea055985da2702b0723f6f907a423c9b2da5996ad67ba", size = 3139844 }, + { url = "https://files.pythonhosted.org/packages/0d/68/01d335338b68bdebab11de573f4631c7bf0404666ccbf474621123497702/debugpy-1.8.8-cp311-cp311-win32.whl", hash = "sha256:eea8821d998ebeb02f0625dd0d76839ddde8cbf8152ebbe289dd7acf2cdc6b98", size = 5049405 }, + { url = "https://files.pythonhosted.org/packages/22/1d/3f69460b4b8f01dace3882513de71a446eb37ee57fe2112be948fadebde8/debugpy-1.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:d4483836da2a533f4b1454dffc9f668096ac0433de855f0c22cdce8c9f7e10c4", size = 5075025 }, + { url = "https://files.pythonhosted.org/packages/c2/04/8e79824c4d9100049bda056aeaf8f2765d1325a4521a87f8bb373c977236/debugpy-1.8.8-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:0cc94186340be87b9ac5a707184ec8f36547fb66636d1029ff4f1cc020e53996", size = 2514549 }, + { url = "https://files.pythonhosted.org/packages/a5/6b/c336d1eba1aedc9f654aefcdfe47ec41657d149f28ca1477c5f9009681c6/debugpy-1.8.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64674e95916e53c2e9540a056e5f489e0ad4872645399d778f7c598eacb7b7f9", size = 4229617 }, + { url = "https://files.pythonhosted.org/packages/63/9c/d9276c41e9e14164b31bcba789c87a355c091d0fc2d4e4e36a4881c9aa54/debugpy-1.8.8-cp312-cp312-win32.whl", hash = "sha256:5c6e885dbf12015aed73770f29dec7023cb310d0dc2ba8bfbeb5c8e43f80edc9", size = 5167033 }, + { url = "https://files.pythonhosted.org/packages/6d/1c/fd4bc22196b2d0defaa9f644ea4d676d0cb53b6434091b5fa2d4e49c85f2/debugpy-1.8.8-cp312-cp312-win_amd64.whl", hash = "sha256:19ffbd84e757a6ca0113574d1bf5a2298b3947320a3e9d7d8dc3377f02d9f864", size = 5209968 }, + { url = "https://files.pythonhosted.org/packages/90/45/6745f342bbf41bde7eb5dbf5567b794a4a5498a7a729146cb3101b875b30/debugpy-1.8.8-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:705cd123a773d184860ed8dae99becd879dfec361098edbefb5fc0d3683eb804", size = 2499523 }, + { url = "https://files.pythonhosted.org/packages/5c/39/0374610062a384648db9b7b315d0c906facf23613bfd19527135a7c0a420/debugpy-1.8.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890fd16803f50aa9cb1a9b9b25b5ec321656dd6b78157c74283de241993d086f", size = 4218219 }, + { url = "https://files.pythonhosted.org/packages/cc/19/5b8a68eb9bbafd6bfd27ba0ed93d411f3fd50935ecdd2df242de2110a7c9/debugpy-1.8.8-cp313-cp313-win32.whl", hash = "sha256:90244598214bbe704aa47556ec591d2f9869ff9e042e301a2859c57106649add", size = 5171845 }, + { url = "https://files.pythonhosted.org/packages/cd/04/7381dab68e40ca877d5beffc25ad1a0d3d2557cf7465405435fac9e27ef5/debugpy-1.8.8-cp313-cp313-win_amd64.whl", hash = "sha256:4b93e4832fd4a759a0c465c967214ed0c8a6e8914bced63a28ddb0dd8c5f078b", size = 5206890 }, + { url = "https://files.pythonhosted.org/packages/03/99/ec2190d03df5dbd610418919bd1c3d8e6f61d0a97894e11ade6d3260cfb8/debugpy-1.8.8-py2.py3-none-any.whl", hash = "sha256:ec684553aba5b4066d4de510859922419febc710df7bba04fe9e7ef3de15d34f", size = 5157124 }, ] [[package]] @@ -232,21 +186,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, ] +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + [[package]] name = "exchange-calendars" -version = "4.5.6" +version = "4.5.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "korean-lunar-calendar", marker = "python_full_version >= '3.12'" }, - { name = "numpy", marker = "python_full_version >= '3.12'" }, - { name = "pandas", marker = "python_full_version >= '3.12'" }, - { name = "pyluach", marker = "python_full_version >= '3.12'" }, - { name = "toolz", marker = "python_full_version >= '3.12'" }, - { name = "tzdata", marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b6/71/bd708daa5c1765de54e53adb8f032727bb589196db3d100369305a1d4a7d/exchange_calendars-4.5.6.tar.gz", hash = "sha256:5db77178cf849f81dd6dcc99995e2163b928c0f45dcd0a2c395958beb1dbb145", size = 3638691 } + { name = "korean-lunar-calendar" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pyluach" }, + { name = "toolz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/f2/f84975a1b65b3778acc0ec201778d129738f7c90b24d575eb7c15af2469d/exchange_calendars-4.5.7.tar.gz", hash = "sha256:03e451302250be94b902e108349e01ba3c608b08e4e1e7a661332d06af2086f5", size = 3797261 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/8f/f3303c61b8e925ded53f37b3bb3365e349449ef40b687e39cd7b59f87d14/exchange_calendars-4.5.6-py3-none-any.whl", hash = "sha256:5abf5ebcb8ceef0ced36fe4e20071d42517091bf081e6c44354cb343009d672b", size = 196161 }, + { url = "https://files.pythonhosted.org/packages/77/d5/14eddb60b9d534bb53cf630cae6aba319fae754e73a720c2cf924de7ceac/exchange_calendars-4.5.7-py3-none-any.whl", hash = "sha256:a9606f6942c877eb97d60db988fe7a3cd67f97f0ac68a219cc42fbe55c36da36", size = 196739 }, ] [[package]] @@ -259,12 +222,41 @@ wheels = [ ] [[package]] -name = "fake-useragent" -version = "1.5.1" +name = "h11" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/a1/1f662631ab153975fa8dbf09296324ecbaf53370dce922054e8de6b57370/fake-useragent-1.5.1.tar.gz", hash = "sha256:6387269f5a2196b5ba7ed8935852f75486845a1c95c50e72460e6a8e762f5c49", size = 22631 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/99/60d8cf1b26938c2e0a57e232f7f15641dfcd6f8deda454d73e4145910ff6/fake_useragent-1.5.1-py3-none-any.whl", hash = "sha256:57415096557c8a4e23b62a375c21c55af5fd4ba30549227f562d2c4f5b60e3b3", size = 17190 }, + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + +[[package]] +name = "httpcore" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 }, +] + +[[package]] +name = "httpx" +version = "0.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 }, ] [[package]] @@ -281,19 +273,19 @@ name = "ipykernel" version = "6.29.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "python_full_version >= '3.12' and platform_system == 'Darwin'" }, - { name = "comm", marker = "python_full_version >= '3.12'" }, - { name = "debugpy", marker = "python_full_version >= '3.12'" }, - { name = "ipython", marker = "python_full_version >= '3.12'" }, - { name = "jupyter-client", marker = "python_full_version >= '3.12'" }, - { name = "jupyter-core", marker = "python_full_version >= '3.12'" }, - { name = "matplotlib-inline", marker = "python_full_version >= '3.12'" }, - { name = "nest-asyncio", marker = "python_full_version >= '3.12'" }, - { name = "packaging", marker = "python_full_version >= '3.12'" }, - { name = "psutil", marker = "python_full_version >= '3.12'" }, - { name = "pyzmq", marker = "python_full_version >= '3.12'" }, - { name = "tornado", marker = "python_full_version >= '3.12'" }, - { name = "traitlets", marker = "python_full_version >= '3.12'" }, + { name = "appnope", marker = "platform_system == 'Darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367 } wheels = [ @@ -302,34 +294,36 @@ wheels = [ [[package]] name = "ipython" -version = "8.27.0" +version = "8.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" }, - { name = "decorator", marker = "python_full_version >= '3.12'" }, - { name = "jedi", marker = "python_full_version >= '3.12'" }, - { name = "matplotlib-inline", marker = "python_full_version >= '3.12'" }, - { name = "pexpect", marker = "python_full_version >= '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", marker = "python_full_version >= '3.12'" }, - { name = "pygments", marker = "python_full_version >= '3.12'" }, - { name = "stack-data", marker = "python_full_version >= '3.12'" }, - { name = "traitlets", marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/57/24/d4fabaca03c8804bf0b8d994c8ae3a20e57e9330d277fb43d83e558dec5e/ipython-8.27.0.tar.gz", hash = "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e", size = 5494984 } + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/e0/a3f36dde97e12121106807d80485423ae4c5b27ce60d40d4ab0bab18a9db/ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb", size = 5497513 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a2/6c725958e6f135d8e5de081e69841bb2c1d84b3fc259d02eb092b8fc203a/ipython-8.27.0-py3-none-any.whl", hash = "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c", size = 818986 }, + { url = "https://files.pythonhosted.org/packages/c5/a5/c15ed187f1b3fac445bb42a2dedd8dec1eee1718b35129242049a13a962f/ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8", size = 819911 }, ] [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "parso", marker = "python_full_version >= '3.12'" }, + { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/99/99b493cec4bf43176b678de30f81ed003fd6a647a301b9c927280c600f0a/jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", size = 1227821 } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0", size = 1569361 }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, ] [[package]] @@ -337,11 +331,11 @@ name = "jupyter-client" version = "8.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-core", marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.12'" }, - { name = "pyzmq", marker = "python_full_version >= '3.12'" }, - { name = "tornado", marker = "python_full_version >= '3.12'" }, - { name = "traitlets", marker = "python_full_version >= '3.12'" }, + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } wheels = [ @@ -353,9 +347,9 @@ name = "jupyter-core" version = "5.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "platformdirs", marker = "python_full_version >= '3.12'" }, - { name = "pywin32", marker = "python_full_version >= '3.12' and platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, - { name = "traitlets", marker = "python_full_version >= '3.12'" }, + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } wheels = [ @@ -376,7 +370,7 @@ name = "markdown-it-py" version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mdurl", marker = "python_full_version >= '3.12'" }, + { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } wheels = [ @@ -388,7 +382,7 @@ name = "matplotlib-inline" version = "0.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "traitlets", marker = "python_full_version >= '3.12'" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } wheels = [ @@ -405,118 +399,92 @@ wheels = [ ] [[package]] -name = "mypy" -version = "1.11.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions", marker = "python_full_version >= '3.12'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5c/86/5d7cbc4974fd564550b80fbb8103c05501ea11aa7835edf3351d90095896/mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79", size = 3078806 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/cd/815368cd83c3a31873e5e55b317551500b12f2d1d7549720632f32630333/mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a", size = 10939401 }, - { url = "https://files.pythonhosted.org/packages/f1/27/e18c93a195d2fad75eb96e1f1cbc431842c332e8eba2e2b77eaf7313c6b7/mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef", size = 10111697 }, - { url = "https://files.pythonhosted.org/packages/dc/08/cdc1fc6d0d5a67d354741344cc4aa7d53f7128902ebcbe699ddd4f15a61c/mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383", size = 12500508 }, - { url = "https://files.pythonhosted.org/packages/64/12/aad3af008c92c2d5d0720ea3b6674ba94a98cdb86888d389acdb5f218c30/mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8", size = 13020712 }, - { url = "https://files.pythonhosted.org/packages/03/e6/a7d97cc124a565be5e9b7d5c2a6ebf082379ffba99646e4863ed5bbcb3c3/mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7", size = 9567319 }, - { url = "https://files.pythonhosted.org/packages/e2/aa/cc56fb53ebe14c64f1fe91d32d838d6f4db948b9494e200d2f61b820b85d/mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385", size = 10859630 }, - { url = "https://files.pythonhosted.org/packages/04/c8/b19a760fab491c22c51975cf74e3d253b8c8ce2be7afaa2490fbf95a8c59/mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca", size = 10037973 }, - { url = "https://files.pythonhosted.org/packages/88/57/7e7e39f2619c8f74a22efb9a4c4eff32b09d3798335625a124436d121d89/mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104", size = 12416659 }, - { url = "https://files.pythonhosted.org/packages/fc/a6/37f7544666b63a27e46c48f49caeee388bf3ce95f9c570eb5cfba5234405/mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4", size = 12897010 }, - { url = "https://files.pythonhosted.org/packages/84/8b/459a513badc4d34acb31c736a0101c22d2bd0697b969796ad93294165cfb/mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6", size = 9562873 }, - { url = "https://files.pythonhosted.org/packages/35/3a/ed7b12ecc3f6db2f664ccf85cb2e004d3e90bec928e9d7be6aa2f16b7cdf/mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318", size = 10990335 }, - { url = "https://files.pythonhosted.org/packages/04/e4/1a9051e2ef10296d206519f1df13d2cc896aea39e8683302f89bf5792a59/mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36", size = 10007119 }, - { url = "https://files.pythonhosted.org/packages/f3/3c/350a9da895f8a7e87ade0028b962be0252d152e0c2fbaafa6f0658b4d0d4/mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987", size = 12506856 }, - { url = "https://files.pythonhosted.org/packages/b6/49/ee5adf6a49ff13f4202d949544d3d08abb0ea1f3e7f2a6d5b4c10ba0360a/mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca", size = 12952066 }, - { url = "https://files.pythonhosted.org/packages/27/c0/b19d709a42b24004d720db37446a42abadf844d5c46a2c442e2a074d70d9/mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70", size = 9664000 }, - { url = "https://files.pythonhosted.org/packages/42/3a/bdf730640ac523229dd6578e8a581795720a9321399de494374afc437ec5/mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12", size = 2619625 }, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" +name = "nest-asyncio" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] [[package]] -name = "nest-asyncio" -version = "1.6.0" +name = "nodeenv" +version = "1.9.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, ] [[package]] name = "numpy" -version = "2.1.1" +version = "2.1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/5f/9003bb3e632f2b58f5e3a3378902dcc73c5518070736c6740fe52454e8e1/numpy-2.1.1.tar.gz", hash = "sha256:d0cf7d55b1051387807405b3898efafa862997b4cba8aa5dbe657be794afeafd", size = 18874860 } +sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/37/e3de47233b3ba458b1021a6f95029198b2f68a83eb886a862640b6ec3e9a/numpy-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8a0e34993b510fc19b9a2ce7f31cb8e94ecf6e924a40c0c9dd4f62d0aac47d9", size = 21150738 }, - { url = "https://files.pythonhosted.org/packages/69/30/f41c9b6dab4e1ec56b40d1daa81ce9f9f8d26da6d02af18768a883676bd5/numpy-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7dd86dfaf7c900c0bbdcb8b16e2f6ddf1eb1fe39c6c8cca6e94844ed3152a8fd", size = 13758247 }, - { url = "https://files.pythonhosted.org/packages/e1/30/d2f71d3419ada3b3735e2ce9cea7dfe22c268ac9fbb24e0b5ac5fc222633/numpy-2.1.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:5889dd24f03ca5a5b1e8a90a33b5a0846d8977565e4ae003a63d22ecddf6782f", size = 5353756 }, - { url = "https://files.pythonhosted.org/packages/84/64/879bd6877488441cfaa578c96bdc4b43710d7e3ae4f8260fbd04821da395/numpy-2.1.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:59ca673ad11d4b84ceb385290ed0ebe60266e356641428c845b39cd9df6713ab", size = 6886809 }, - { url = "https://files.pythonhosted.org/packages/cd/c4/869f8db87f5c9df86b93ca42036f58911ff162dd091a41e617977ab50d1f/numpy-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ce49a34c44b6de5241f0b38b07e44c1b2dcacd9e36c30f9c2fcb1bb5135db7", size = 13977367 }, - { url = "https://files.pythonhosted.org/packages/7d/4b/a509d346fffede6120cc17610cc500819417ee9c3da7f08d9aaf15cab2a3/numpy-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913cc1d311060b1d409e609947fa1b9753701dac96e6581b58afc36b7ee35af6", size = 16326516 }, - { url = "https://files.pythonhosted.org/packages/4a/0c/fdba41b2ddeb7a052f84d85fb17d5e168af0e8034b3a2d6e369b7cc2966f/numpy-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:caf5d284ddea7462c32b8d4a6b8af030b6c9fd5332afb70e7414d7fdded4bfd0", size = 16702642 }, - { url = "https://files.pythonhosted.org/packages/bf/8d/a8da065a46515efdbcf81a92535b816ea17194ce5b767df1f13815c32179/numpy-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57eb525e7c2a8fdee02d731f647146ff54ea8c973364f3b850069ffb42799647", size = 14475522 }, - { url = "https://files.pythonhosted.org/packages/b9/d2/5b7cf5851af48c35a73b85750b41f9b622760ee11659665a688e6b3f7cb7/numpy-2.1.1-cp310-cp310-win32.whl", hash = "sha256:9a8e06c7a980869ea67bbf551283bbed2856915f0a792dc32dd0f9dd2fb56728", size = 6535211 }, - { url = "https://files.pythonhosted.org/packages/e5/6a/b1f7d73fec1942ded4b474a78c3fdd11c4fad5232143f41dd7e6ae166080/numpy-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d10c39947a2d351d6d466b4ae83dad4c37cd6c3cdd6d5d0fa797da56f710a6ae", size = 12865289 }, - { url = "https://files.pythonhosted.org/packages/f7/86/2c01070424a42b286ea0271203682c3d3e81e10ce695545b35768307b383/numpy-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d07841fd284718feffe7dd17a63a2e6c78679b2d386d3e82f44f0108c905550", size = 21154850 }, - { url = "https://files.pythonhosted.org/packages/ef/4e/d3426d9e620a18bbb979f28e4dc7f9a2c35eb7cf726ffcb33545ebdd3e6a/numpy-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5613cfeb1adfe791e8e681128f5f49f22f3fcaa942255a6124d58ca59d9528f", size = 13789477 }, - { url = "https://files.pythonhosted.org/packages/c6/6e/fb6b1b2da9f4c757f55b202f10b6af0fe4fee87ace6e830228a12ab8ae5d/numpy-2.1.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0b8cc2715a84b7c3b161f9ebbd942740aaed913584cae9cdc7f8ad5ad41943d0", size = 5351769 }, - { url = "https://files.pythonhosted.org/packages/58/9a/07c8a9dc7254f3265ae014e33768d1cfd8eb73ee6cf215f4ec3b497e4255/numpy-2.1.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b49742cdb85f1f81e4dc1b39dcf328244f4d8d1ded95dea725b316bd2cf18c95", size = 6890872 }, - { url = "https://files.pythonhosted.org/packages/08/4e/3b50fa3b1e045793056ed5a1fc6f89dd897ff9cb00900ca6377fe552d442/numpy-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d5f8a8e3bc87334f025194c6193e408903d21ebaeb10952264943a985066ca", size = 13984256 }, - { url = "https://files.pythonhosted.org/packages/d9/37/108d692f7e2544b9ae972c7bfa06c26717871c273ccec86470bc3132b04d/numpy-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d51fc141ddbe3f919e91a096ec739f49d686df8af254b2053ba21a910ae518bf", size = 16337778 }, - { url = "https://files.pythonhosted.org/packages/95/2d/df81a1be3be6d3a92fd12dfd6c26a0dc026b276136ec1056562342a484a2/numpy-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98ce7fb5b8063cfdd86596b9c762bf2b5e35a2cdd7e967494ab78a1fa7f8b86e", size = 16710448 }, - { url = "https://files.pythonhosted.org/packages/8f/34/4b2e604c5c44bd64b6c85e89d88871b41e60233b3ddf97419b37ae5b0c72/numpy-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24c2ad697bd8593887b019817ddd9974a7f429c14a5469d7fad413f28340a6d2", size = 14489002 }, - { url = "https://files.pythonhosted.org/packages/9f/0d/67c04b6bfefd0abbe7f60f7e4f11e3aca15d688faec1d1df089966105a9a/numpy-2.1.1-cp311-cp311-win32.whl", hash = "sha256:397bc5ce62d3fb73f304bec332171535c187e0643e176a6e9421a6e3eacef06d", size = 6533215 }, - { url = "https://files.pythonhosted.org/packages/94/7a/4c00332a3ca79702bbc86228afd0e84e6f91b47222ec8cdf00677dd16481/numpy-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:ae8ce252404cdd4de56dcfce8b11eac3c594a9c16c231d081fb705cf23bd4d9e", size = 12870550 }, - { url = "https://files.pythonhosted.org/packages/36/11/c573ef66c004f991989c2c6218229d9003164525549409aec5ec9afc0285/numpy-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c803b7934a7f59563db459292e6aa078bb38b7ab1446ca38dd138646a38203e", size = 20884403 }, - { url = "https://files.pythonhosted.org/packages/6b/6c/a9fbef5fd2f9685212af2a9e47485cde9357c3e303e079ccf85127516f2d/numpy-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6435c48250c12f001920f0751fe50c0348f5f240852cfddc5e2f97e007544cbe", size = 13493375 }, - { url = "https://files.pythonhosted.org/packages/34/f2/1316a6b08ad4c161d793abe81ff7181e9ae2e357a5b06352a383b9f8e800/numpy-2.1.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3269c9eb8745e8d975980b3a7411a98976824e1fdef11f0aacf76147f662b15f", size = 5088823 }, - { url = "https://files.pythonhosted.org/packages/be/15/fabf78a6d4a10c250e87daf1cd901af05e71501380532ac508879cc46a7e/numpy-2.1.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fac6e277a41163d27dfab5f4ec1f7a83fac94e170665a4a50191b545721c6521", size = 6619825 }, - { url = "https://files.pythonhosted.org/packages/9f/8a/76ddef3e621541ddd6984bc24d256a4e3422d036790cbbe449e6cad439ee/numpy-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd8f556cdc8cfe35e70efb92463082b7f43dd7e547eb071ffc36abc0ca4699b", size = 13696705 }, - { url = "https://files.pythonhosted.org/packages/cb/22/2b840d297183916a95847c11f82ae11e248fa98113490b2357f774651e1d/numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b9cd92c8f8e7b313b80e93cedc12c0112088541dcedd9197b5dee3738c1201", size = 16041649 }, - { url = "https://files.pythonhosted.org/packages/c7/e8/6f4825d8f576cfd5e4d6515b9eec22bd618868bdafc8a8c08b446dcb65f0/numpy-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9c680df4de71cd58582b51e88a61feed4abcc7530bcd3d48483f20fc76f2a", size = 16409358 }, - { url = "https://files.pythonhosted.org/packages/bf/f8/5edf1105b0dc24fd66fc3e9e7f3bca3d920cde571caaa4375ec1566073c3/numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313", size = 14172488 }, - { url = "https://files.pythonhosted.org/packages/f4/c2/dddca3e69a024d2f249a5b68698328163cbdafb7e65fbf6d36373bbabf12/numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed", size = 6237195 }, - { url = "https://files.pythonhosted.org/packages/b7/98/5640a09daa3abf0caeaefa6e7bf0d10c0aa28a77c84e507d6a716e0e23df/numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270", size = 12568082 }, - { url = "https://files.pythonhosted.org/packages/6b/9e/8bc6f133bc6d359ccc9ec051853aded45504d217685191f31f46d36b7065/numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5", size = 20834810 }, - { url = "https://files.pythonhosted.org/packages/32/1b/429519a2fa28681814c511574017d35f3aab7136d554cc65f4c1526dfbf5/numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5", size = 13507739 }, - { url = "https://files.pythonhosted.org/packages/25/18/c732d7dd9896d11e4afcd487ac65e62f9fa0495563b7614eb850765361fa/numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136", size = 5074465 }, - { url = "https://files.pythonhosted.org/packages/3e/37/838b7ae9262c370ab25312bab365492016f11810ffc03ebebbd54670b669/numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0", size = 6606418 }, - { url = "https://files.pythonhosted.org/packages/8b/b9/7ff3bfb71e316a5b43a124c4b7a5881ab12f3c32636014bef1f757f19dbd/numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb", size = 13692464 }, - { url = "https://files.pythonhosted.org/packages/42/78/75bcf16e6737cd196ff7ecf0e1fd3f953293a34dff4fd93fb488e8308536/numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df", size = 16037763 }, - { url = "https://files.pythonhosted.org/packages/23/99/36bf5ffe034d06df307bc783e25cf164775863166dcd878879559fe0379f/numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78", size = 16410374 }, - { url = "https://files.pythonhosted.org/packages/7f/16/04c5dab564887d4cd31a9ed30e51467fa70d52a4425f5a9bd1eed5b3d34c/numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556", size = 14169873 }, - { url = "https://files.pythonhosted.org/packages/09/e0/d1b5adbf1731886c4186c59a9fa208585df9452a43a2b60e79af7c649717/numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b", size = 6234118 }, - { url = "https://files.pythonhosted.org/packages/d0/9c/2391ee6e9ebe77232ddcab29d92662b545e99d78c3eb3b4e26d59b9ca1ca/numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0", size = 12561742 }, - { url = "https://files.pythonhosted.org/packages/38/0e/c4f754f9e73f9bb520e8bf418c646f2c4f70c5d5f2bc561e90f884593193/numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553", size = 20858403 }, - { url = "https://files.pythonhosted.org/packages/32/fc/d69092b9171efa0cb8079577e71ce0cac0e08f917d33f6e99c916ed51d44/numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480", size = 13519851 }, - { url = "https://files.pythonhosted.org/packages/14/2a/d7cf2cd9f15b23f623075546ea64a2c367cab703338ca22aaaecf7e704df/numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f", size = 5115444 }, - { url = "https://files.pythonhosted.org/packages/8e/00/e87b2cb4afcecca3b678deefb8fa53005d7054f3b5c39596e5554e5d98f8/numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468", size = 6628903 }, - { url = "https://files.pythonhosted.org/packages/ab/9d/337ae8721b3beec48c3413d71f2d44b2defbf3c6f7a85184fc18b7b61f4a/numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef", size = 13665945 }, - { url = "https://files.pythonhosted.org/packages/c0/90/ee8668e84c5d5cc080ef3beb622c016adf19ca3aa51afe9dbdcc6a9baf59/numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f", size = 16023473 }, - { url = "https://files.pythonhosted.org/packages/38/a0/57c24b2131879183051dc698fbb53fd43b77c3fa85b6e6311014f2bc2973/numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c", size = 16400624 }, - { url = "https://files.pythonhosted.org/packages/bb/4c/14a41eb5c9548c6cee6af0936eabfd985c69230ffa2f2598321431a9aa0a/numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec", size = 14155072 }, - { url = "https://files.pythonhosted.org/packages/94/9a/d6a5d138b53ccdc002fdf07f0d1a960326c510e66cbfff7180c88d37c482/numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5", size = 20982055 }, - { url = "https://files.pythonhosted.org/packages/40/b5/78d8b5481aeef6d2aad3724c6aa5398045d2657038dfe54c055cae1fcf75/numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504", size = 6750222 }, - { url = "https://files.pythonhosted.org/packages/eb/9a/59a548ad57df8c432bfac4556504a9fae5c082ffea53d108fcf7ce2956e4/numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd", size = 16141236 }, - { url = "https://files.pythonhosted.org/packages/02/31/3cbba87e998748b2e33ca5bc6fcc5662c867037f980918e302aebdf139a2/numpy-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:99f4a9ee60eed1385a86e82288971a51e71df052ed0b2900ed30bc840c0f2e39", size = 12789681 }, + { url = "https://files.pythonhosted.org/packages/f1/80/d572a4737626372915bca41c3afbfec9d173561a39a0a61bacbbfd1dafd4/numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff", size = 21152472 }, + { url = "https://files.pythonhosted.org/packages/6f/bb/7bfba10c791ae3bb6716da77ad85a82d5fac07fc96fb0023ef0571df9d20/numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5", size = 13747967 }, + { url = "https://files.pythonhosted.org/packages/da/d6/2df7bde35f0478455f0be5934877b3e5a505f587b00230f54a519a6b55a5/numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1", size = 5354921 }, + { url = "https://files.pythonhosted.org/packages/d1/bb/75b945874f931494891eac6ca06a1764d0e8208791f3addadb2963b83527/numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd", size = 6888603 }, + { url = "https://files.pythonhosted.org/packages/68/a7/fde73636f6498dbfa6d82fc336164635fe592f1ad0d13285fcb6267fdc1c/numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3", size = 13889862 }, + { url = "https://files.pythonhosted.org/packages/05/db/5d9c91b2e1e2e72be1369278f696356d44975befcae830daf2e667dcb54f/numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098", size = 16328151 }, + { url = "https://files.pythonhosted.org/packages/3e/6a/7eb732109b53ae64a29e25d7e68eb9d6611037f6354875497008a49e74d3/numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c", size = 16704107 }, + { url = "https://files.pythonhosted.org/packages/88/cc/278113b66a1141053cbda6f80e4200c6da06b3079c2d27bda1fde41f2c1f/numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4", size = 14385789 }, + { url = "https://files.pythonhosted.org/packages/f5/69/eb20f5e1bfa07449bc67574d2f0f7c1e6b335fb41672e43861a7727d85f2/numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23", size = 6536706 }, + { url = "https://files.pythonhosted.org/packages/8e/8b/1c131ab5a94c1086c289c6e1da1d843de9dbd95fe5f5ee6e61904c9518e2/numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0", size = 12864165 }, + { url = "https://files.pythonhosted.org/packages/ad/81/c8167192eba5247593cd9d305ac236847c2912ff39e11402e72ae28a4985/numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d", size = 21156252 }, + { url = "https://files.pythonhosted.org/packages/da/74/5a60003fc3d8a718d830b08b654d0eea2d2db0806bab8f3c2aca7e18e010/numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41", size = 13784119 }, + { url = "https://files.pythonhosted.org/packages/47/7c/864cb966b96fce5e63fcf25e1e4d957fe5725a635e5f11fe03f39dd9d6b5/numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9", size = 5352978 }, + { url = "https://files.pythonhosted.org/packages/09/ac/61d07930a4993dd9691a6432de16d93bbe6aa4b1c12a5e573d468eefc1ca/numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09", size = 6892570 }, + { url = "https://files.pythonhosted.org/packages/27/2f/21b94664f23af2bb52030653697c685022119e0dc93d6097c3cb45bce5f9/numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a", size = 13896715 }, + { url = "https://files.pythonhosted.org/packages/7a/f0/80811e836484262b236c684a75dfc4ba0424bc670e765afaa911468d9f39/numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b", size = 16339644 }, + { url = "https://files.pythonhosted.org/packages/fa/81/ce213159a1ed8eb7d88a2a6ef4fbdb9e4ffd0c76b866c350eb4e3c37e640/numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee", size = 16712217 }, + { url = "https://files.pythonhosted.org/packages/7d/84/4de0b87d5a72f45556b2a8ee9fc8801e8518ec867fc68260c1f5dcb3903f/numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0", size = 14399053 }, + { url = "https://files.pythonhosted.org/packages/7e/1c/e5fabb9ad849f9d798b44458fd12a318d27592d4bc1448e269dec070ff04/numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9", size = 6534741 }, + { url = "https://files.pythonhosted.org/packages/1e/48/a9a4b538e28f854bfb62e1dea3c8fea12e90216a276c7777ae5345ff29a7/numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2", size = 12869487 }, + { url = "https://files.pythonhosted.org/packages/8a/f0/385eb9970309643cbca4fc6eebc8bb16e560de129c91258dfaa18498da8b/numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e", size = 20849658 }, + { url = "https://files.pythonhosted.org/packages/54/4a/765b4607f0fecbb239638d610d04ec0a0ded9b4951c56dc68cef79026abf/numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958", size = 13492258 }, + { url = "https://files.pythonhosted.org/packages/bd/a7/2332679479c70b68dccbf4a8eb9c9b5ee383164b161bee9284ac141fbd33/numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8", size = 5090249 }, + { url = "https://files.pythonhosted.org/packages/c1/67/4aa00316b3b981a822c7a239d3a8135be2a6945d1fd11d0efb25d361711a/numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564", size = 6621704 }, + { url = "https://files.pythonhosted.org/packages/5e/da/1a429ae58b3b6c364eeec93bf044c532f2ff7b48a52e41050896cf15d5b1/numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512", size = 13606089 }, + { url = "https://files.pythonhosted.org/packages/9e/3e/3757f304c704f2f0294a6b8340fcf2be244038be07da4cccf390fa678a9f/numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b", size = 16043185 }, + { url = "https://files.pythonhosted.org/packages/43/97/75329c28fea3113d00c8d2daf9bc5828d58d78ed661d8e05e234f86f0f6d/numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc", size = 16410751 }, + { url = "https://files.pythonhosted.org/packages/ad/7a/442965e98b34e0ae9da319f075b387bcb9a1e0658276cc63adb8c9686f7b/numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0", size = 14082705 }, + { url = "https://files.pythonhosted.org/packages/ac/b6/26108cf2cfa5c7e03fb969b595c93131eab4a399762b51ce9ebec2332e80/numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9", size = 6239077 }, + { url = "https://files.pythonhosted.org/packages/a6/84/fa11dad3404b7634aaab50733581ce11e5350383311ea7a7010f464c0170/numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a", size = 12566858 }, + { url = "https://files.pythonhosted.org/packages/4d/0b/620591441457e25f3404c8057eb924d04f161244cb8a3680d529419aa86e/numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f", size = 20836263 }, + { url = "https://files.pythonhosted.org/packages/45/e1/210b2d8b31ce9119145433e6ea78046e30771de3fe353f313b2778142f34/numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598", size = 13507771 }, + { url = "https://files.pythonhosted.org/packages/55/44/aa9ee3caee02fa5a45f2c3b95cafe59c44e4b278fbbf895a93e88b308555/numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57", size = 5075805 }, + { url = "https://files.pythonhosted.org/packages/78/d6/61de6e7e31915ba4d87bbe1ae859e83e6582ea14c6add07c8f7eefd8488f/numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe", size = 6608380 }, + { url = "https://files.pythonhosted.org/packages/3e/46/48bdf9b7241e317e6cf94276fe11ba673c06d1fdf115d8b4ebf616affd1a/numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43", size = 13602451 }, + { url = "https://files.pythonhosted.org/packages/70/50/73f9a5aa0810cdccda9c1d20be3cbe4a4d6ea6bfd6931464a44c95eef731/numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56", size = 16039822 }, + { url = "https://files.pythonhosted.org/packages/ad/cd/098bc1d5a5bc5307cfc65ee9369d0ca658ed88fbd7307b0d49fab6ca5fa5/numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a", size = 16411822 }, + { url = "https://files.pythonhosted.org/packages/83/a2/7d4467a2a6d984549053b37945620209e702cf96a8bc658bc04bba13c9e2/numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef", size = 14079598 }, + { url = "https://files.pythonhosted.org/packages/e9/6a/d64514dcecb2ee70bfdfad10c42b76cab657e7ee31944ff7a600f141d9e9/numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f", size = 6236021 }, + { url = "https://files.pythonhosted.org/packages/bb/f9/12297ed8d8301a401e7d8eb6b418d32547f1d700ed3c038d325a605421a4/numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed", size = 12560405 }, + { url = "https://files.pythonhosted.org/packages/a7/45/7f9244cd792e163b334e3a7f02dff1239d2890b6f37ebf9e82cbe17debc0/numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f", size = 20859062 }, + { url = "https://files.pythonhosted.org/packages/b1/b4/a084218e7e92b506d634105b13e27a3a6645312b93e1c699cc9025adb0e1/numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4", size = 13515839 }, + { url = "https://files.pythonhosted.org/packages/27/45/58ed3f88028dcf80e6ea580311dc3edefdd94248f5770deb980500ef85dd/numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e", size = 5116031 }, + { url = "https://files.pythonhosted.org/packages/37/a8/eb689432eb977d83229094b58b0f53249d2209742f7de529c49d61a124a0/numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0", size = 6629977 }, + { url = "https://files.pythonhosted.org/packages/42/a3/5355ad51ac73c23334c7caaed01adadfda49544f646fcbfbb4331deb267b/numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408", size = 13575951 }, + { url = "https://files.pythonhosted.org/packages/c4/70/ea9646d203104e647988cb7d7279f135257a6b7e3354ea6c56f8bafdb095/numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6", size = 16022655 }, + { url = "https://files.pythonhosted.org/packages/14/ce/7fc0612903e91ff9d0b3f2eda4e18ef9904814afcae5b0f08edb7f637883/numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f", size = 16399902 }, + { url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180 }, + { url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907 }, + { url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098 }, + { url = "https://files.pythonhosted.org/packages/00/e7/8d8bb791b62586cc432ecbb70632b4f23b7b7c88df41878de7528264f6d7/numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f", size = 20983893 }, + { url = "https://files.pythonhosted.org/packages/5e/f3/cb8118a044b5007586245a650360c9f5915b2f4232dd7658bb7a63dd1d02/numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4", size = 6752501 }, + { url = "https://files.pythonhosted.org/packages/53/f5/365b46439b518d2ec6ebb880cc0edf90f225145dfd4db7958334f7164530/numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d", size = 16142601 }, + { url = "https://files.pythonhosted.org/packages/03/c2/d1fee6ba999aa7cd41ca6856937f2baaf604c3eec1565eae63451ec31e5e/numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb", size = 12771397 }, ] [[package]] name = "packaging" -version = "24.1" +version = "24.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] [[package]] @@ -524,10 +492,10 @@ name = "pandas" version = "2.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.12'" }, - { name = "pytz", marker = "python_full_version >= '3.12'" }, - { name = "tzdata", marker = "python_full_version >= '3.12'" }, + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 } wheels = [ @@ -572,10 +540,10 @@ name = "pandas-market-calendars" version = "4.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exchange-calendars", marker = "python_full_version >= '3.12'" }, - { name = "pandas", marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.12'" }, - { name = "pytz", marker = "python_full_version >= '3.12'" }, + { name = "exchange-calendars" }, + { name = "pandas" }, + { name = "python-dateutil" }, + { name = "pytz" }, ] sdist = { url = "https://files.pythonhosted.org/packages/37/2c/c28db2fbd50027f0f62adde71a7d01de02dba877c7a57607e397f43e857c/pandas_market_calendars-4.4.1.tar.gz", hash = "sha256:43e933eb8c323345d6d6457bd1fed7ae5fa9df2dda774a9ba3c1a496bad88994", size = 135556 } wheels = [ @@ -596,7 +564,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "python_full_version >= '3.12'" }, + { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ @@ -614,31 +582,31 @@ wheels = [ [[package]] name = "prompt-toolkit" -version = "3.0.47" +version = "3.0.48" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "wcwidth", marker = "python_full_version >= '3.12'" }, + { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/47/6d/0279b119dafc74c1220420028d490c4399b790fc1256998666e3a341879f/prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360", size = 425859 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/4f/feb5e137aff82f7c7f3248267b97451da3644f6cdc218edfe549fb354127/prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", size = 424684 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/23/22750c4b768f09386d1c3cc4337953e8936f48a888fa6dddfb669b2c9088/prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", size = 386411 }, + { url = "https://files.pythonhosted.org/packages/a9/6a/fd08d94654f7e67c52ca30523a178b3f8ccc4237fce4be90d39c938a831a/prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e", size = 386595 }, ] [[package]] name = "psutil" -version = "6.0.0" +version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 }, - { url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 }, - { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, - { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, - { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, - { url = "https://files.pythonhosted.org/packages/cd/5f/60038e277ff0a9cc8f0c9ea3d0c5eb6ee1d2470ea3f9389d776432888e47/psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", size = 292046 }, - { url = "https://files.pythonhosted.org/packages/8b/20/2ff69ad9c35c3df1858ac4e094f20bd2374d33c8643cf41da8fd7cdcb78b/psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", size = 253560 }, - { url = "https://files.pythonhosted.org/packages/73/44/561092313ae925f3acfaace6f9ddc4f6a9c748704317bad9c8c8f8a36a79/psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", size = 257399 }, - { url = "https://files.pythonhosted.org/packages/7c/06/63872a64c312a24fb9b4af123ee7007a306617da63ff13bcc1432386ead7/psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0", size = 251988 }, + { url = "https://files.pythonhosted.org/packages/da/2b/f4dea5d993d9cd22ad958eea828a41d5d225556123d372f02547c29c4f97/psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e", size = 246648 }, + { url = "https://files.pythonhosted.org/packages/9f/14/4aa97a7f2e0ac33a050d990ab31686d651ae4ef8c86661fef067f00437b9/psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85", size = 249905 }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, ] [[package]] @@ -673,9 +641,9 @@ name = "pydantic" version = "2.9.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "annotated-types", marker = "python_full_version >= '3.12'" }, - { name = "pydantic-core", marker = "python_full_version >= '3.12'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.12'" }, + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } wheels = [ @@ -687,7 +655,7 @@ name = "pydantic-core" version = "2.23.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version >= '3.12'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } wheels = [ @@ -767,12 +735,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/83/2e585d06d49e0320050b3d7d8ae0dfbd1459e976ff9f4b4d8bcca983d474/pyluach-2.2.0-py3-none-any.whl", hash = "sha256:d1eb49d6292087e9290f4661ae01b60c8c933704ec8c9cef82673b349ff96adf", size = 25037 }, ] +[[package]] +name = "pyright" +version = "1.1.389" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/4e/9a5ab8745e7606b88c2c7ca223449ac9d82a71fd5e31df47b453f2cb39a1/pyright-1.1.389.tar.gz", hash = "sha256:716bf8cc174ab8b4dcf6828c3298cac05c5ed775dda9910106a5dcfe4c7fe220", size = 21940 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl", hash = "sha256:41e9620bba9254406dc1f621a88ceab5a88af4c826feb4f614d95691ed243a60", size = 18581 }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six", marker = "python_full_version >= '3.12'" }, + { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ @@ -790,17 +771,21 @@ wheels = [ [[package]] name = "pywin32" -version = "306" +version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/dc/28c668097edfaf4eac4617ef7adf081b9cf50d254672fcf399a70f5efc41/pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", size = 8506422 }, - { url = "https://files.pythonhosted.org/packages/d3/d6/891894edec688e72c2e308b3243fad98b4066e1839fd2fe78f04129a9d31/pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", size = 9226392 }, - { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, - { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, - { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, - { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, - { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, - { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, + { url = "https://files.pythonhosted.org/packages/72/a6/3e9f2c474895c1bb61b11fa9640be00067b5c5b363c501ee9c3fa53aec01/pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e", size = 5927028 }, + { url = "https://files.pythonhosted.org/packages/d9/b4/84e2463422f869b4b718f79eb7530a4c1693e96b8a4e5e968de38be4d2ba/pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e", size = 6558484 }, + { url = "https://files.pythonhosted.org/packages/9f/8f/fb84ab789713f7c6feacaa08dad3ec8105b88ade8d1c4f0f0dfcaaa017d6/pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c", size = 7971454 }, + { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, + { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, + { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, ] [[package]] @@ -808,7 +793,7 @@ name = "pyzmq" version = "26.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi", marker = "python_full_version >= '3.12' and implementation_name == 'pypy'" }, + { name = "cffi", marker = "implementation_name == 'pypy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } wheels = [ @@ -876,57 +861,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/d2/3b2ab40f455a256cb6672186bea95cd97b459ce4594050132d71e76f0d6f/pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", size = 550762 }, ] -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi", marker = "python_full_version >= '3.12'" }, - { name = "charset-normalizer", marker = "python_full_version >= '3.12'" }, - { name = "idna", marker = "python_full_version >= '3.12'" }, - { name = "urllib3", marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - [[package]] name = "rich" -version = "13.8.1" +version = "13.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", marker = "python_full_version >= '3.12'" }, - { name = "pygments", marker = "python_full_version >= '3.12'" }, + { name = "markdown-it-py" }, + { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/76/40f084cb7db51c9d1fa29a7120717892aeda9a7711f6225692c957a93535/rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a", size = 222080 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/11/dadb85e2bd6b1f1ae56669c3e1f0410797f9605d752d68fb47b77f525b31/rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06", size = 241608 }, + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] [[package]] name = "ruff" -version = "0.6.7" +version = "0.7.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/7c/3045a526c57cef4b5ec4d5d154692e31429749a49810a53e785de334c4f6/ruff-0.6.7.tar.gz", hash = "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5", size = 3073785 } +sdist = { url = "https://files.pythonhosted.org/packages/4b/06/09d1276df977eece383d0ed66052fc24ec4550a61f8fbc0a11200e690496/ruff-0.7.3.tar.gz", hash = "sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313", size = 3243664 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/c4/1c5c636f83f905c537785016e9cdd7a36df53c025a2d07940580ecb37bcf/ruff-0.6.7-py3-none-linux_armv6l.whl", hash = "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2", size = 10336748 }, - { url = "https://files.pythonhosted.org/packages/84/d9/aa15a56be7ad796f4d7625362aff588f9fc013bbb7323a63571628a2cf2d/ruff-0.6.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a", size = 9958833 }, - { url = "https://files.pythonhosted.org/packages/27/25/5dd1c32bfc3ad3136c8ebe84312d1bdd2e6c908ac7f60692ec009b7050a8/ruff-0.6.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab", size = 9633369 }, - { url = "https://files.pythonhosted.org/packages/0e/3e/01b25484f3cb08fe6fddedf1f55f3f3c0af861a5b5f5082fbe60ab4b2596/ruff-0.6.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9", size = 10637415 }, - { url = "https://files.pythonhosted.org/packages/8a/c9/5bb9b849e4777e0f961de43edf95d2af0ab34999a5feee957be096887876/ruff-0.6.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef", size = 10097389 }, - { url = "https://files.pythonhosted.org/packages/52/cf/e08f1c290c7d848ddfb2ae811f24f445c18e1d3e50e01c38ffa7f5a50494/ruff-0.6.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99", size = 10951440 }, - { url = "https://files.pythonhosted.org/packages/a2/2d/ca8aa0da5841913c302d8034c6de0ce56c401c685184d8dd23cfdd0003f9/ruff-0.6.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d", size = 11708900 }, - { url = "https://files.pythonhosted.org/packages/89/fc/9a83c57baee977c82392e19a328b52cebdaf61601af3d99498e278ef5104/ruff-0.6.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b", size = 11258892 }, - { url = "https://files.pythonhosted.org/packages/d3/a3/254cc7afef702c68ae9079290c2a1477ae0e81478589baf745026d8a4eb5/ruff-0.6.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18", size = 12367932 }, - { url = "https://files.pythonhosted.org/packages/9f/55/53f10c1bd8c3b2ae79aed18e62b22c6346f9296aa0ec80489b8442bd06a9/ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b", size = 10838629 }, - { url = "https://files.pythonhosted.org/packages/84/72/fb335c2b25432c63d15383ecbd7bfc1915e68cdf8d086a08042052144255/ruff-0.6.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5", size = 10648824 }, - { url = "https://files.pythonhosted.org/packages/92/a8/d57e135a8ad99b6a0c6e2a5c590bcacdd57f44340174f4409c3893368610/ruff-0.6.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624", size = 10174368 }, - { url = "https://files.pythonhosted.org/packages/a7/6f/1a30a6e81dcf2fa9ff3f7011eb87fe76c12a3c6bba74db6a1977d763de1f/ruff-0.6.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14", size = 10514383 }, - { url = "https://files.pythonhosted.org/packages/0b/25/df6f2575bc9fe43a6dedfd8dee12896f09a94303e2c828d5f85856bb69a0/ruff-0.6.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb", size = 10902340 }, - { url = "https://files.pythonhosted.org/packages/68/62/f2c1031e2fb7b94f9bf0603744e73db4ef90081b0eb1b9639a6feefd52ea/ruff-0.6.7-py3-none-win32.whl", hash = "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35", size = 8448033 }, - { url = "https://files.pythonhosted.org/packages/97/80/193d1604a3f7d75eb1b2a7ce6bf0fdbdbc136889a65caacea6ffb29501b1/ruff-0.6.7-py3-none-win_amd64.whl", hash = "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977", size = 9273543 }, - { url = "https://files.pythonhosted.org/packages/8e/a8/4abb5a9f58f51e4b1ea386be5ab2e547035bc1ee57200d1eca2f8909a33e/ruff-0.6.7-py3-none-win_arm64.whl", hash = "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8", size = 8618044 }, + { url = "https://files.pythonhosted.org/packages/c0/56/933d433c2489e4642487b835f53dd9ff015fb3d8fa459b09bb2ce42d7c4b/ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344", size = 10372090 }, + { url = "https://files.pythonhosted.org/packages/20/ea/1f0a22a6bcdd3fc26c73f63a025d05bd565901b729d56bcb093c722a6c4c/ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0", size = 10190037 }, + { url = "https://files.pythonhosted.org/packages/16/74/aca75666e0d481fe394e76a8647c44ea919087748024924baa1a17371e3e/ruff-0.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9", size = 9811998 }, + { url = "https://files.pythonhosted.org/packages/20/a1/cf446a0d7f78ea1f0bd2b9171c11dfe746585c0c4a734b25966121eb4f5d/ruff-0.7.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5", size = 10620626 }, + { url = "https://files.pythonhosted.org/packages/cd/c1/82b27d09286ae855f5d03b1ad37cf243f21eb0081732d4d7b0d658d439cb/ruff-0.7.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299", size = 10177598 }, + { url = "https://files.pythonhosted.org/packages/b9/42/c0acac22753bf74013d035a5ef6c5c4c40ad4d6686bfb3fda7c6f37d9b37/ruff-0.7.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e", size = 11171963 }, + { url = "https://files.pythonhosted.org/packages/43/18/bb0befb7fb9121dd9009e6a72eb98e24f1bacb07c6f3ecb55f032ba98aed/ruff-0.7.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29", size = 11856157 }, + { url = "https://files.pythonhosted.org/packages/5e/91/04e98d7d6e32eca9d1372be595f9abc7b7f048795e32eb2edbd8794d50bd/ruff-0.7.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5", size = 11440331 }, + { url = "https://files.pythonhosted.org/packages/f5/dc/3fe99f2ce10b76d389041a1b9f99e7066332e479435d4bebcceea16caff5/ruff-0.7.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67", size = 12725354 }, + { url = "https://files.pythonhosted.org/packages/43/7b/1daa712de1c5bc6cbbf9fa60e9c41cc48cda962dc6d2c4f2a224d2c3007e/ruff-0.7.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2", size = 11010091 }, + { url = "https://files.pythonhosted.org/packages/b6/db/1227a903587432eb569e57a95b15a4f191a71fe315cde4c0312df7bc85da/ruff-0.7.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d", size = 10610687 }, + { url = "https://files.pythonhosted.org/packages/db/e2/dc41ee90c3085aadad4da614d310d834f641aaafddf3dfbba08210c616ce/ruff-0.7.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2", size = 10254843 }, + { url = "https://files.pythonhosted.org/packages/6f/09/5f6cac1c91542bc5bd33d40b4c13b637bf64d7bb29e091dadb01b62527fe/ruff-0.7.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2", size = 10730962 }, + { url = "https://files.pythonhosted.org/packages/d3/42/89a4b9a24ef7d00269e24086c417a006f9a3ffeac2c80f2629eb5ce140ee/ruff-0.7.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16", size = 11101907 }, + { url = "https://files.pythonhosted.org/packages/b0/5c/efdb4777686683a8edce94ffd812783bddcd3d2454d38c5ac193fef7c500/ruff-0.7.3-py3-none-win32.whl", hash = "sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc", size = 8611095 }, + { url = "https://files.pythonhosted.org/packages/bb/b8/28fbc6a4efa50178f973972d1c84b2d0a33cdc731588522ab751ac3da2f5/ruff-0.7.3-py3-none-win_amd64.whl", hash = "sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088", size = 9418283 }, + { url = "https://files.pythonhosted.org/packages/3f/77/b587cba6febd5e2003374f37eb89633f79f161e71084f94057c8653b7fb3/ruff-0.7.3-py3-none-win_arm64.whl", hash = "sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c", size = 8725228 }, ] [[package]] @@ -952,9 +923,9 @@ name = "stack-data" version = "0.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "asttokens", marker = "python_full_version >= '3.12'" }, - { name = "executing", marker = "python_full_version >= '3.12'" }, - { name = "pure-eval", marker = "python_full_version >= '3.12'" }, + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ @@ -963,58 +934,57 @@ wheels = [ [[package]] name = "tastytrade" -version = "8.3" +version = "9.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "fake-useragent", marker = "python_full_version >= '3.12'" }, - { name = "pandas-market-calendars", marker = "python_full_version >= '3.12'" }, - { name = "pydantic", marker = "python_full_version >= '3.12'" }, - { name = "requests", marker = "python_full_version >= '3.12'" }, - { name = "websockets", marker = "python_full_version >= '3.12'" }, + { name = "httpx" }, + { name = "pandas-market-calendars" }, + { name = "pydantic" }, + { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/2b/b514ebd9e8b30d28f08e44d11eccac4434fb868b2e615be6a821112496d5/tastytrade-8.3.tar.gz", hash = "sha256:35d75a21b81dea47301fa586dab50cd8cbd8089f27c350ee66678823a6472a43", size = 40916 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/e2/dfe31d53b3bd1a43553ef406f3a427eb179846812ca1e939535853a98f4b/tastytrade-9.2.tar.gz", hash = "sha256:0a67aea7da0d39f98babf377b274756251e54f2dd7ec35889f26d7c13280689f", size = 117936 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/5e/abe55648b20dfdbfdbfccf4438b6fa6925904ff1afe79da27ce38d992d02/tastytrade-8.3-py3-none-any.whl", hash = "sha256:e93b90ad9323421b0799b95a5d5b680dc6b9a0ba9a9d5f4fe455758b60a1e8f5", size = 42239 }, + { url = "https://files.pythonhosted.org/packages/3f/15/e7544a1d7d7433f5c33af9d261ef7ea10c472cb5e2afb4ac189b5ddcc7a5/tastytrade-9.2-py3-none-any.whl", hash = "sha256:fedd92a34d0697dbc4bc37c6942954d766b79eca6ab1f3e67a1a262bb770cdcc", size = 47790 }, ] [[package]] name = "tastytrade-cli" version = "0.2" -source = { virtual = "." } +source = { editable = "." } dependencies = [ - { name = "asyncclick", marker = "python_full_version >= '3.12'" }, - { name = "rich", marker = "python_full_version >= '3.12'" }, - { name = "tastytrade", marker = "python_full_version >= '3.12'" }, + { name = "asyncclick" }, + { name = "rich" }, + { name = "tastytrade" }, ] [package.dev-dependencies] dev = [ - { name = "ipykernel", marker = "python_full_version >= '3.12'" }, - { name = "mypy", marker = "python_full_version >= '3.12'" }, - { name = "ruff", marker = "python_full_version >= '3.12'" }, + { name = "ipykernel" }, + { name = "pyright" }, + { name = "ruff" }, ] [package.metadata] requires-dist = [ { name = "asyncclick", specifier = ">=8.1.7.2" }, { name = "rich", specifier = ">=13.8.1" }, - { name = "tastytrade", specifier = ">=8.3" }, + { name = "tastytrade", specifier = ">=9.2" }, ] [package.metadata.requires-dev] dev = [ { name = "ipykernel", specifier = ">=6.29.5" }, - { name = "mypy", specifier = ">=1.11.2" }, + { name = "pyright", specifier = ">=1.1.389" }, { name = "ruff", specifier = ">=0.6.7" }, ] [[package]] name = "toolz" -version = "0.12.1" +version = "1.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/bf/5e12db234df984f6df3c7f12f1428aa680ba4e101f63f4b8b3f9e8d2e617/toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d", size = 66550 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/8a/d82202c9f89eab30f9fc05380daae87d617e2ad11571ab23d7c13a29bb54/toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85", size = 56121 }, + { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383 }, ] [[package]] @@ -1062,15 +1032,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 }, ] -[[package]] -name = "urllib3" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, -] - [[package]] name = "wcwidth" version = "0.2.13" @@ -1082,59 +1043,59 @@ wheels = [ [[package]] name = "websockets" -version = "13.1" +version = "14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } +sdist = { url = "https://files.pythonhosted.org/packages/f4/1b/380b883ce05bb5f45a905b61790319a28958a9ab1e4b6b95ff5464b60ca1/websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", size = 162840 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/94/d15dbfc6a5eb636dbc754303fba18208f2e88cf97e733e1d64fb9cb5c89e/websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee", size = 157815 }, - { url = "https://files.pythonhosted.org/packages/30/02/c04af33f4663945a26f5e8cf561eb140c35452b50af47a83c3fbcfe62ae1/websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7", size = 155466 }, - { url = "https://files.pythonhosted.org/packages/35/e8/719f08d12303ea643655e52d9e9851b2dadbb1991d4926d9ce8862efa2f5/websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6", size = 155716 }, - { url = "https://files.pythonhosted.org/packages/91/e1/14963ae0252a8925f7434065d25dcd4701d5e281a0b4b460a3b5963d2594/websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b", size = 164806 }, - { url = "https://files.pythonhosted.org/packages/ec/fa/ab28441bae5e682a0f7ddf3d03440c0c352f930da419301f4a717f675ef3/websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa", size = 163810 }, - { url = "https://files.pythonhosted.org/packages/44/77/dea187bd9d16d4b91566a2832be31f99a40d0f5bfa55eeb638eb2c3bc33d/websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700", size = 164125 }, - { url = "https://files.pythonhosted.org/packages/cf/d9/3af14544e83f1437eb684b399e6ba0fa769438e869bf5d83d74bc197fae8/websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c", size = 164532 }, - { url = "https://files.pythonhosted.org/packages/1c/8a/6d332eabe7d59dfefe4b8ba6f46c8c5fabb15b71c8a8bc3d2b65de19a7b6/websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0", size = 163948 }, - { url = "https://files.pythonhosted.org/packages/1a/91/a0aeadbaf3017467a1ee03f8fb67accdae233fe2d5ad4b038c0a84e357b0/websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f", size = 163898 }, - { url = "https://files.pythonhosted.org/packages/71/31/a90fb47c63e0ae605be914b0b969d7c6e6ffe2038cd744798e4b3fbce53b/websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe", size = 158706 }, - { url = "https://files.pythonhosted.org/packages/93/ca/9540a9ba80da04dc7f36d790c30cae4252589dbd52ccdc92e75b0be22437/websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a", size = 159141 }, - { url = "https://files.pythonhosted.org/packages/b2/f0/cf0b8a30d86b49e267ac84addbebbc7a48a6e7bb7c19db80f62411452311/websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", size = 157813 }, - { url = "https://files.pythonhosted.org/packages/bf/e7/22285852502e33071a8cf0ac814f8988480ec6db4754e067b8b9d0e92498/websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", size = 155469 }, - { url = "https://files.pythonhosted.org/packages/68/d4/c8c7c1e5b40ee03c5cc235955b0fb1ec90e7e37685a5f69229ad4708dcde/websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", size = 155717 }, - { url = "https://files.pythonhosted.org/packages/c9/e4/c50999b9b848b1332b07c7fd8886179ac395cb766fda62725d1539e7bc6c/websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", size = 165379 }, - { url = "https://files.pythonhosted.org/packages/bc/49/4a4ad8c072f18fd79ab127650e47b160571aacfc30b110ee305ba25fffc9/websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", size = 164376 }, - { url = "https://files.pythonhosted.org/packages/af/9b/8c06d425a1d5a74fd764dd793edd02be18cf6fc3b1ccd1f29244ba132dc0/websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", size = 164753 }, - { url = "https://files.pythonhosted.org/packages/d5/5b/0acb5815095ff800b579ffc38b13ab1b915b317915023748812d24e0c1ac/websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", size = 165051 }, - { url = "https://files.pythonhosted.org/packages/30/93/c3891c20114eacb1af09dedfcc620c65c397f4fd80a7009cd12d9457f7f5/websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", size = 164489 }, - { url = "https://files.pythonhosted.org/packages/28/09/af9e19885539759efa2e2cd29b8b3f9eecef7ecefea40d46612f12138b36/websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", size = 164438 }, - { url = "https://files.pythonhosted.org/packages/b6/08/6f38b8e625b3d93de731f1d248cc1493327f16cb45b9645b3e791782cff0/websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", size = 158710 }, - { url = "https://files.pythonhosted.org/packages/fb/39/ec8832ecb9bb04a8d318149005ed8cee0ba4e0205835da99e0aa497a091f/websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", size = 159137 }, - { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, - { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, - { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, - { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, - { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, - { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, - { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, - { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, - { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, - { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, - { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, - { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, - { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, - { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, - { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, - { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, - { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, - { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, - { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, - { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, - { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, - { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, - { url = "https://files.pythonhosted.org/packages/2d/75/6da22cb3ad5b8c606963f9a5f9f88656256fecc29d420b4b2bf9e0c7d56f/websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", size = 155499 }, - { url = "https://files.pythonhosted.org/packages/c0/ba/22833d58629088fcb2ccccedfae725ac0bbcd713319629e97125b52ac681/websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", size = 155737 }, - { url = "https://files.pythonhosted.org/packages/95/54/61684fe22bdb831e9e1843d972adadf359cf04ab8613285282baea6a24bb/websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", size = 157095 }, - { url = "https://files.pythonhosted.org/packages/fc/f5/6652fb82440813822022a9301a30afde85e5ff3fb2aebb77f34aabe2b4e8/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6", size = 156701 }, - { url = "https://files.pythonhosted.org/packages/67/33/ae82a7b860fa8a08aba68818bdf7ff61f04598aa5ab96df4cd5a3e418ca4/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a", size = 156654 }, - { url = "https://files.pythonhosted.org/packages/63/0b/a1b528d36934f833e20f6da1032b995bf093d55cb416b9f2266f229fb237/websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23", size = 159192 }, - { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, + { url = "https://files.pythonhosted.org/packages/af/91/b1b375dbd856fd5fff3f117de0e520542343ecaf4e8fc60f1ac1e9f5822c/websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29", size = 161950 }, + { url = "https://files.pythonhosted.org/packages/61/8f/4d52f272d3ebcd35e1325c646e98936099a348374d4a6b83b524bded8116/websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179", size = 159601 }, + { url = "https://files.pythonhosted.org/packages/c4/b1/29e87b53eb1937992cdee094a0988aadc94f25cf0b37e90c75eed7123d75/websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250", size = 159854 }, + { url = "https://files.pythonhosted.org/packages/3f/e6/752a2f5e8321ae2a613062676c08ff2fccfb37dc837a2ee919178a372e8a/websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0", size = 168835 }, + { url = "https://files.pythonhosted.org/packages/60/27/ca62de7877596926321b99071639275e94bb2401397130b7cf33dbf2106a/websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0", size = 167844 }, + { url = "https://files.pythonhosted.org/packages/7e/db/f556a1d06635c680ef376be626c632e3f2bbdb1a0189d1d1bffb061c3b70/websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199", size = 168157 }, + { url = "https://files.pythonhosted.org/packages/b3/bc/99e5f511838c365ac6ecae19674eb5e94201aa4235bd1af3e6fa92c12905/websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58", size = 168561 }, + { url = "https://files.pythonhosted.org/packages/c6/e7/251491585bad61c79e525ac60927d96e4e17b18447cc9c3cfab47b2eb1b8/websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078", size = 167979 }, + { url = "https://files.pythonhosted.org/packages/ac/98/7ac2e4eeada19bdbc7a3a66a58e3ebdf33648b9e1c5b3f08c3224df168cf/websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434", size = 167925 }, + { url = "https://files.pythonhosted.org/packages/ab/3d/09e65c47ee2396b7482968068f6e9b516221e1032b12dcf843b9412a5dfb/websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10", size = 162831 }, + { url = "https://files.pythonhosted.org/packages/8a/67/59828a3d09740e6a485acccfbb66600632f2178b6ed1b61388ee96f17d5a/websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e", size = 163266 }, + { url = "https://files.pythonhosted.org/packages/97/ed/c0d03cb607b7fe1f7ff45e2cd4bb5cd0f9e3299ced79c2c303a6fff44524/websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512", size = 161949 }, + { url = "https://files.pythonhosted.org/packages/06/91/bf0a44e238660d37a2dda1b4896235d20c29a2d0450f3a46cd688f43b239/websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac", size = 159606 }, + { url = "https://files.pythonhosted.org/packages/ff/b8/7185212adad274c2b42b6a24e1ee6b916b7809ed611cbebc33b227e5c215/websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280", size = 159854 }, + { url = "https://files.pythonhosted.org/packages/5a/8a/0849968d83474be89c183d8ae8dcb7f7ada1a3c24f4d2a0d7333c231a2c3/websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1", size = 169402 }, + { url = "https://files.pythonhosted.org/packages/bd/4f/ef886e37245ff6b4a736a09b8468dae05d5d5c99de1357f840d54c6f297d/websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3", size = 168406 }, + { url = "https://files.pythonhosted.org/packages/11/43/e2dbd4401a63e409cebddedc1b63b9834de42f51b3c84db885469e9bdcef/websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", size = 168776 }, + { url = "https://files.pythonhosted.org/packages/6d/d6/7063e3f5c1b612e9f70faae20ebaeb2e684ffa36cb959eb0862ee2809b32/websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0", size = 169083 }, + { url = "https://files.pythonhosted.org/packages/49/69/e6f3d953f2fa0f8a723cf18cd011d52733bd7f6e045122b24e0e7f49f9b0/websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89", size = 168529 }, + { url = "https://files.pythonhosted.org/packages/70/ff/f31fa14561fc1d7b8663b0ed719996cf1f581abee32c8fb2f295a472f268/websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23", size = 168475 }, + { url = "https://files.pythonhosted.org/packages/f1/15/b72be0e4bf32ff373aa5baef46a4c7521b8ea93ad8b49ca8c6e8e764c083/websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e", size = 162833 }, + { url = "https://files.pythonhosted.org/packages/bc/ef/2d81679acbe7057ffe2308d422f744497b52009ea8bab34b6d74a2657d1d/websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09", size = 163263 }, + { url = "https://files.pythonhosted.org/packages/55/64/55698544ce29e877c9188f1aee9093712411a8fc9732cca14985e49a8e9c/websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", size = 161957 }, + { url = "https://files.pythonhosted.org/packages/a2/b1/b088f67c2b365f2c86c7b48edb8848ac27e508caf910a9d9d831b2f343cb/websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", size = 159620 }, + { url = "https://files.pythonhosted.org/packages/c1/89/2a09db1bbb40ba967a1b8225b07b7df89fea44f06de9365f17f684d0f7e6/websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", size = 159852 }, + { url = "https://files.pythonhosted.org/packages/ca/c1/f983138cd56e7d3079f1966e81f77ce6643f230cd309f73aa156bb181749/websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", size = 169675 }, + { url = "https://files.pythonhosted.org/packages/c1/c8/84191455d8660e2a0bdb33878d4ee5dfa4a2cedbcdc88bbd097303b65bfa/websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", size = 168619 }, + { url = "https://files.pythonhosted.org/packages/8d/a7/62e551fdcd7d44ea74a006dc193aba370505278ad76efd938664531ce9d6/websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", size = 169042 }, + { url = "https://files.pythonhosted.org/packages/ad/ed/1532786f55922c1e9c4d329608e36a15fdab186def3ca9eb10d7465bc1cc/websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", size = 169345 }, + { url = "https://files.pythonhosted.org/packages/ea/fb/160f66960d495df3de63d9bcff78e1b42545b2a123cc611950ffe6468016/websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", size = 168725 }, + { url = "https://files.pythonhosted.org/packages/cf/53/1bf0c06618b5ac35f1d7906444b9958f8485682ab0ea40dee7b17a32da1e/websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", size = 168712 }, + { url = "https://files.pythonhosted.org/packages/e5/22/5ec2f39fff75f44aa626f86fa7f20594524a447d9c3be94d8482cd5572ef/websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", size = 162838 }, + { url = "https://files.pythonhosted.org/packages/74/27/28f07df09f2983178db7bf6c9cccc847205d2b92ced986cd79565d68af4f/websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", size = 163277 }, + { url = "https://files.pythonhosted.org/packages/34/77/812b3ba5110ed8726eddf9257ab55ce9e85d97d4aa016805fdbecc5e5d48/websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9", size = 161966 }, + { url = "https://files.pythonhosted.org/packages/8d/24/4fcb7aa6986ae7d9f6d083d9d53d580af1483c5ec24bdec0978307a0f6ac/websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b", size = 159625 }, + { url = "https://files.pythonhosted.org/packages/f8/47/2a0a3a2fc4965ff5b9ce9324d63220156bd8bedf7f90824ab92a822e65fd/websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3", size = 159857 }, + { url = "https://files.pythonhosted.org/packages/dd/c8/d7b425011a15e35e17757e4df75b25e1d0df64c0c315a44550454eaf88fc/websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59", size = 169635 }, + { url = "https://files.pythonhosted.org/packages/93/39/6e3b5cffa11036c40bd2f13aba2e8e691ab2e01595532c46437b56575678/websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2", size = 168578 }, + { url = "https://files.pythonhosted.org/packages/cf/03/8faa5c9576299b2adf34dcccf278fc6bbbcda8a3efcc4d817369026be421/websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da", size = 169018 }, + { url = "https://files.pythonhosted.org/packages/8c/05/ea1fec05cc3a60defcdf0bb9f760c3c6bd2dd2710eff7ac7f891864a22ba/websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9", size = 169383 }, + { url = "https://files.pythonhosted.org/packages/21/1d/eac1d9ed787f80754e51228e78855f879ede1172c8b6185aca8cef494911/websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7", size = 168773 }, + { url = "https://files.pythonhosted.org/packages/0e/1b/e808685530185915299740d82b3a4af3f2b44e56ccf4389397c7a5d95d39/websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a", size = 168757 }, + { url = "https://files.pythonhosted.org/packages/b6/19/6ab716d02a3b068fbbeb6face8a7423156e12c446975312f1c7c0f4badab/websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6", size = 162834 }, + { url = "https://files.pythonhosted.org/packages/6c/fd/ab6b7676ba712f2fc89d1347a4b5bdc6aa130de10404071f2b2606450209/websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0", size = 163277 }, + { url = "https://files.pythonhosted.org/packages/fb/cd/382a05a1ba2a93bd9fb807716a660751295df72e77204fb130a102fcdd36/websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8", size = 159633 }, + { url = "https://files.pythonhosted.org/packages/b7/a0/fa7c62e2952ef028b422fbf420f9353d9dd4dfaa425de3deae36e98c0784/websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e", size = 159867 }, + { url = "https://files.pythonhosted.org/packages/c1/94/954b4924f868db31d5f0935893c7a8446515ee4b36bb8ad75a929469e453/websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098", size = 161121 }, + { url = "https://files.pythonhosted.org/packages/7a/2e/f12bbb41a8f2abb76428ba4fdcd9e67b5b364a3e7fa97c88f4d6950aa2d4/websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb", size = 160731 }, + { url = "https://files.pythonhosted.org/packages/13/97/b76979401f2373af1fe3e08f960b265cecab112e7dac803446fb98351a52/websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7", size = 160681 }, + { url = "https://files.pythonhosted.org/packages/39/9c/16916d9a436c109a1d7ba78817e8fee357b78968be3f6e6f517f43afa43d/websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d", size = 163316 }, + { url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277 }, ]