diff --git a/examples/rest/demo_correlation_matrix.py b/examples/rest/demo_correlation_matrix.py index f056ab6d..df939590 100644 --- a/examples/rest/demo_correlation_matrix.py +++ b/examples/rest/demo_correlation_matrix.py @@ -40,6 +40,7 @@ essential to do your own research or consult a financial advisor for personalized advice when investing. """ + import pandas as pd # type: ignore import numpy as np # type: ignore import seaborn as sns # type: ignore diff --git a/examples/tools/flatfiles-stock-trades/exchange-heatmap.py b/examples/tools/flatfiles-stock-trades/exchange-heatmap.py new file mode 100644 index 00000000..dd618552 --- /dev/null +++ b/examples/tools/flatfiles-stock-trades/exchange-heatmap.py @@ -0,0 +1,68 @@ +# We can use a Python script that aggregates trades by exchange into 30-minute +# chunks, setting the stage for a visual analysis. This approach will highlight +# trade flows, including opening hours and peak activity times, across the +# exchanges. Please see https://polygon.io/blog/insights-from-trade-level-data +# +import pandas as pd +import seaborn as sns +import matplotlib.pyplot as plt +import numpy as np +import pytz + +# Replace '2024-04-05.csv' with the path to your actual file +file_path = "2024-04-05.csv" + +# Load the CSV file into a pandas DataFrame +df = pd.read_csv(file_path) + +# Convert 'participant_timestamp' to datetime (assuming nanoseconds Unix timestamp) +df["participant_timestamp"] = pd.to_datetime( + df["participant_timestamp"], unit="ns", utc=True +) + +# Convert to Eastern Time (ET), accounting for both EST and EDT +df["participant_timestamp"] = df["participant_timestamp"].dt.tz_convert( + "America/New_York" +) + +# Create a new column for 30-minute time intervals, now in ET +df["time_interval"] = df["participant_timestamp"].dt.floor("30T").dt.time + +# Ensure full 24-hour coverage by generating all possible 30-minute intervals +all_intervals = pd.date_range(start="00:00", end="23:59", freq="30T").time +all_exchanges = df["exchange"].unique() +full_index = pd.MultiIndex.from_product( + [all_exchanges, all_intervals], names=["exchange", "time_interval"] +) + +# Group by 'exchange' and 'time_interval', count trades, and reset index +grouped = ( + df.groupby(["exchange", "time_interval"]) + .size() + .reindex(full_index, fill_value=0) + .reset_index(name="trade_count") +) + +# Pivot the DataFrame for the heatmap, ensuring all intervals and exchanges are represented +pivot_table = grouped.pivot("exchange", "time_interval", "trade_count").fillna(0) + +# Apply a log scale transformation to the trade counts + 1 to handle zero trades correctly +log_scale_data = np.log1p(pivot_table.values) + +# Plotting the heatmap using the log scale data +plt.figure(figsize=(20, 10)) +sns.heatmap( + log_scale_data, + annot=False, + cmap="Reds", + linewidths=0.5, + cbar=False, + xticklabels=[t.strftime("%H:%M") for t in all_intervals], + yticklabels=pivot_table.index, +) +plt.title("Trade Count Heatmap by Exchange and Time Interval (Log Scale, ET)") +plt.ylabel("Exchange") +plt.xlabel("Time Interval (ET)") +plt.xticks(rotation=45) +plt.tight_layout() # Adjust layout to not cut off labels +plt.show() diff --git a/examples/tools/flatfiles-stock-trades/exchanges-seen.py b/examples/tools/flatfiles-stock-trades/exchanges-seen.py new file mode 100644 index 00000000..7c4d2aba --- /dev/null +++ b/examples/tools/flatfiles-stock-trades/exchanges-seen.py @@ -0,0 +1,23 @@ +# Here's a Python script for analyzing the dataset, that identifies the +# distribution of trades across different exchanges and calculates their +# respective percentages of the total trades. Please see +# https://polygon.io/blog/insights-from-trade-level-data +# +import pandas as pd + +# Replace '2024-04-05.csv' with the path to your actual file +file_path = "2024-04-05.csv" + +# Load the CSV file into a pandas DataFrame +df = pd.read_csv(file_path) + +# Count the number of trades for each exchange +exchange_counts = df["exchange"].value_counts() + +# Calculate the total number of trades +total_trades = exchange_counts.sum() + +# Print out all exchanges and their percentage of total trades +for exchange, count in exchange_counts.items(): + percentage = (count / total_trades) * 100 + print(f"Exchange {exchange}: {count} trades, {percentage:.2f}% of total trades") diff --git a/examples/tools/flatfiles-stock-trades/heatmap.png b/examples/tools/flatfiles-stock-trades/heatmap.png new file mode 100644 index 00000000..9cf4c0ac Binary files /dev/null and b/examples/tools/flatfiles-stock-trades/heatmap.png differ diff --git a/examples/tools/flatfiles-stock-trades/histogram.png b/examples/tools/flatfiles-stock-trades/histogram.png new file mode 100644 index 00000000..1ccb62dd Binary files /dev/null and b/examples/tools/flatfiles-stock-trades/histogram.png differ diff --git a/examples/tools/flatfiles-stock-trades/readme.md b/examples/tools/flatfiles-stock-trades/readme.md new file mode 100644 index 00000000..c794b3ba --- /dev/null +++ b/examples/tools/flatfiles-stock-trades/readme.md @@ -0,0 +1,86 @@ +# Polygon.io Flat Files Stock Trades Analysis Scripts + +This repository contains Python scripts for analyzing stock market trading data using Flat Files from Polygon.io. These scripts demonstrate various ways to dissect and visualize trade data for comprehensive market analysis. + +Please see the tutorial: [Deep Dive into Trade-Level Data with Flat Files](https://polygon.io/blog/insights-from-trade-level-data) + +## Scripts Overview + +### **exchange-heatmap.py** +This script aggregates trades by exchange into 30-minute chunks and creates a heatmap visualization. It highlights the flow of trades and peak activity times across different exchanges, providing insights into how different exchanges operate throughout the day. + +![Treemap Visualization](./heatmap.png) + +### **exchanges-seen.py** +Analyzes the distribution of trades across different exchanges and calculates their respective percentages of total trades. This script helps identify which exchanges handle the most trading volume, offering a perspective on market structure. + +``` +Exchange 4: 25,570,324 trades, 36.32% of total trades +Exchange 12: 15,147,689 trades, 21.52% of total trades +Exchange 11: 6,877,306 trades, 9.77% of total trades +Exchange 19: 5,098,852 trades, 7.24% of total trades +Exchange 10: 4,006,611 trades, 5.69% of total trades +Exchange 8: 3,686,168 trades, 5.24% of total trades +Exchange 15: 2,446,340 trades, 3.47% of total trades +Exchange 21: 2,173,744 trades, 3.09% of total trades +Exchange 7: 1,509,083 trades, 2.14% of total trades +Exchange 20: 1,296,811 trades, 1.84% of total trades +Exchange 18: 674,553 trades, 0.96% of total trades +Exchange 13: 527,767 trades, 0.75% of total trades +Exchange 2: 417,295 trades, 0.59% of total trades +Exchange 3: 393,919 trades, 0.56% of total trades +Exchange 17: 230,210 trades, 0.33% of total trades +Exchange 1: 183,010 trades, 0.26% of total trades +Exchange 9: 159,020 trades, 0.23% of total trades +Exchange 14: 1,211 trades, 0.00% of total trades +``` + +### **top-10-tickers.py** +Identifies the top 10 most traded stocks and calculates their respective percentages of the total trades. This script provides a clear view of the market's most active stocks, highlighting where the most trading activity is concentrated. + +``` +TSLA: 1,549,605 trades, 2.20% of total trades +NVDA: 788,331 trades, 1.12% of total trades +SPY: 669,762 trades, 0.95% of total trades +AMD: 587,140 trades, 0.83% of total trades +MDIA: 561,698 trades, 0.80% of total trades +AAPL: 540,870 trades, 0.77% of total trades +SOXL: 533,511 trades, 0.76% of total trades +QQQ: 508,822 trades, 0.72% of total trades +CADL: 466,604 trades, 0.66% of total trades +AMZN: 465,526 trades, 0.66% of total trades +``` + +### **trades-histogram.py** +Creates a histogram that aggregates trades into 30-minute intervals throughout the day. This visualization helps understand the distribution of trading volume across different times, including pre-market, regular trading hours, and after-hours. + +![Treemap Visualization](./histogram.png) + +## Download the Data + +First, let's download an actual file and explore the data and see what we can learn. We start by downloading the trades for 2024-04-05 via the [File Browser](https://polygon.io/flat-files/stocks-trades/2024/04). The `us_stocks_sip/trades_v1/2024/04/2024-04-05.csv.gz` file is about 1.35GB and is in a compressed gzip format. + +``` +gunzip 2024-04-05.csv.gz +``` + +## Getting Started + +To run these scripts, you will need Python 3 and several dependencies installed, including pandas, matplotlib, seaborn, and pytz. Ensure that you have the trading data file available and modify the `file_path` variable in each script to point to your data file location. + +``` +pip install pandas matplotlib seaborn pytz +``` + +## Usage + +Each script is designed to be run independently: + +```bash +python exchange-heatmap.py +python exchanges-seen.py +python top-10-tickers.py +python trades-histogram.py +``` + +Adjust the script parameters as necessary to fit your specific analysis needs or to accommodate different datasets. \ No newline at end of file diff --git a/examples/tools/flatfiles-stock-trades/top-10-tickers.py b/examples/tools/flatfiles-stock-trades/top-10-tickers.py new file mode 100644 index 00000000..5b0be7d2 --- /dev/null +++ b/examples/tools/flatfiles-stock-trades/top-10-tickers.py @@ -0,0 +1,25 @@ +# Here's a Python script for analyzing the dataset, that identifies the top 10 +# most traded stocks and calculates their respective percentages of the total +# trades. Please see https://polygon.io/blog/insights-from-trade-level-data +# +import pandas as pd + +# Replace '2024-04-05.csv' with the path to your actual file +file_path = "2024-04-05.csv" + +# Load the CSV file into a pandas DataFrame +df = pd.read_csv(file_path) + +# Count the number of trades for each ticker +trade_counts = df["ticker"].value_counts() + +# Calculate the total number of trades +total_trades = trade_counts.sum() + +# Get the top 10 traded stocks +top_10_traded = trade_counts.head(10) + +# Print out the top 10 traded stocks and their percentage of total trades +for ticker, count in top_10_traded.items(): + percentage = (count / total_trades) * 100 + print(f"{ticker}: {count} trades, {percentage:.2f}% of total trades") diff --git a/examples/tools/flatfiles-stock-trades/trades-histogram.py b/examples/tools/flatfiles-stock-trades/trades-histogram.py new file mode 100644 index 00000000..b41ad1af --- /dev/null +++ b/examples/tools/flatfiles-stock-trades/trades-histogram.py @@ -0,0 +1,63 @@ +# To visualize these dynamics, we can use a Python script to create a histogram +# aggregating trades into 30-minute intervals, providing a clear view of when +# trading activity concentrates during the day. This analysis aims to highlight +# the distribution of trading volume across the day, from pre-market to after- +# hours. Please see https://polygon.io/blog/insights-from-trade-level-data +# +import pandas as pd +import matplotlib.pyplot as plt + +# Replace '2024-04-05.csv' with the path to your actual file +file_path = "2024-04-05.csv" + +# Load the CSV file into a pandas DataFrame +df = pd.read_csv(file_path) + +# Convert 'participant_timestamp' to datetime (assuming nanoseconds Unix timestamp) +df["participant_timestamp"] = pd.to_datetime( + df["participant_timestamp"], unit="ns", utc=True +) + +# Convert to Eastern Time (ET), accounting for both EST and EDT +df["participant_timestamp"] = df["participant_timestamp"].dt.tz_convert( + "America/New_York" +) + +# Create a new column for 30-minute time intervals, now in ET +df["time_interval"] = df["participant_timestamp"].dt.floor("30T") + +# Aggregate trades into 30-minute intervals for the entire dataset +trade_counts_per_interval = df.groupby("time_interval").size() + +# Prepare the plot +plt.figure(figsize=(15, 7)) + +# Plotting the histogram/bar chart +bars = plt.bar( + trade_counts_per_interval.index, trade_counts_per_interval.values, width=0.02 +) + +# Adding trade count annotations on each bar +for bar in bars: + height = bar.get_height() + plt.annotate( + f"{int(height)}", + xy=(bar.get_x() + bar.get_width() / 2, height), + xytext=(0, 3), # 3 points vertical offset + textcoords="offset points", + ha="center", + va="bottom", + ) + +plt.title("Trade Counts Aggregated by 30-Minute Intervals (ET)") +plt.xlabel("Time Interval (ET)") +plt.ylabel("Number of Trades") +plt.xticks(rotation=45, ha="right") + +# Ensure that every 30-minute interval is represented on the x-axis +plt.gca().set_xticklabels( + [t.strftime("%Y-%m-%d %H:%M") for t in trade_counts_per_interval.index], rotation=90 +) + +plt.tight_layout() +plt.show() diff --git a/polygon/rest/models/conditions.py b/polygon/rest/models/conditions.py index 3fc0d776..98baa261 100644 --- a/polygon/rest/models/conditions.py +++ b/polygon/rest/models/conditions.py @@ -47,12 +47,16 @@ class UpdateRules: @staticmethod def from_dict(d): return UpdateRules( - consolidated=None - if "consolidated" not in d - else Consolidated.from_dict(d["consolidated"]), - market_center=None - if "market_center" not in d - else MarketCenter.from_dict(d["market_center"]), + consolidated=( + None + if "consolidated" not in d + else Consolidated.from_dict(d["consolidated"]) + ), + market_center=( + None + if "market_center" not in d + else MarketCenter.from_dict(d["market_center"]) + ), ) @@ -82,11 +86,15 @@ def from_dict(d): id=d.get("id", None), legacy=d.get("legacy", None), name=d.get("name", None), - sip_mapping=None - if "sip_mapping" not in d - else SipMapping.from_dict(d["sip_mapping"]), + sip_mapping=( + None + if "sip_mapping" not in d + else SipMapping.from_dict(d["sip_mapping"]) + ), type=d.get("type", None), - update_rules=None - if "update_rules" not in d - else UpdateRules.from_dict(d["update_rules"]), + update_rules=( + None + if "update_rules" not in d + else UpdateRules.from_dict(d["update_rules"]) + ), ) diff --git a/polygon/rest/models/contracts.py b/polygon/rest/models/contracts.py index dc69f614..469779b6 100644 --- a/polygon/rest/models/contracts.py +++ b/polygon/rest/models/contracts.py @@ -32,9 +32,11 @@ class OptionsContract: @staticmethod def from_dict(d): return OptionsContract( - additional_underlyings=None - if "additional_underlyings" not in d - else [Underlying.from_dict(u) for u in d["additional_underlyings"]], + additional_underlyings=( + None + if "additional_underlyings" not in d + else [Underlying.from_dict(u) for u in d["additional_underlyings"]] + ), cfi=d.get("cfi", None), contract_type=d.get("contract_type", None), correction=d.get("correction", None), diff --git a/polygon/rest/models/financials.py b/polygon/rest/models/financials.py index 85a63e37..1a480c48 100644 --- a/polygon/rest/models/financials.py +++ b/polygon/rest/models/financials.py @@ -74,16 +74,22 @@ class CashFlowStatement: @staticmethod def from_dict(d): return CashFlowStatement( - exchange_gains_losses=None - if "exchange_gains_losses" not in d - else ExchangeGainsLosses.from_dict(d["exchange_gains_losses"]), - net_cash_flow=None - if "net_cash_flow" not in d - else NetCashFlow.from_dict(d["net_cash_flow"]), - net_cash_flow_from_financing_activities=None - if "net_cash_flow_from_financing_activities" not in d - else NetCashFlowFromFinancingActivities.from_dict( - d["net_cash_flow_from_financing_activities"] + exchange_gains_losses=( + None + if "exchange_gains_losses" not in d + else ExchangeGainsLosses.from_dict(d["exchange_gains_losses"]) + ), + net_cash_flow=( + None + if "net_cash_flow" not in d + else NetCashFlow.from_dict(d["net_cash_flow"]) + ), + net_cash_flow_from_financing_activities=( + None + if "net_cash_flow_from_financing_activities" not in d + else NetCashFlowFromFinancingActivities.from_dict( + d["net_cash_flow_from_financing_activities"] + ) ), ) @@ -145,18 +151,24 @@ class ComprehensiveIncome: @staticmethod def from_dict(d): return ComprehensiveIncome( - comprehensive_income_loss=None - if "comprehensive_income_loss" not in d - else ComprehensiveIncomeLoss.from_dict(d["comprehensive_income_loss"]), - comprehensive_income_loss_attributable_to_parent=None - if "comprehensive_income_loss_attributable_to_parent" not in d - else ComprehensiveIncomeLossAttributableToParent.from_dict( - d["comprehensive_income_loss_attributable_to_parent"] + comprehensive_income_loss=( + None + if "comprehensive_income_loss" not in d + else ComprehensiveIncomeLoss.from_dict(d["comprehensive_income_loss"]) + ), + comprehensive_income_loss_attributable_to_parent=( + None + if "comprehensive_income_loss_attributable_to_parent" not in d + else ComprehensiveIncomeLossAttributableToParent.from_dict( + d["comprehensive_income_loss_attributable_to_parent"] + ) ), - other_comprehensive_income_loss=None - if "other_comprehensive_income_loss" not in d - else OtherComprehensiveIncomeLoss.from_dict( - d["other_comprehensive_income_loss"] + other_comprehensive_income_loss=( + None + if "other_comprehensive_income_loss" not in d + else OtherComprehensiveIncomeLoss.from_dict( + d["other_comprehensive_income_loss"] + ) ), ) @@ -248,18 +260,26 @@ class IncomeStatement: @staticmethod def from_dict(d): return IncomeStatement( - basic_earnings_per_share=None - if "basic_earnings_per_share" not in d - else BasicEarningsPerShare.from_dict(d["basic_earnings_per_share"]), - cost_of_revenue=None - if "cost_of_revenue" not in d - else CostOfRevenue.from_dict(d["cost_of_revenue"]), - gross_profit=None - if "gross_profit" not in d - else GrossProfit.from_dict(d["gross_profit"]), - operating_expenses=None - if "operating_expenses" not in d - else OperatingExpenses.from_dict(d["operating_expenses"]), + basic_earnings_per_share=( + None + if "basic_earnings_per_share" not in d + else BasicEarningsPerShare.from_dict(d["basic_earnings_per_share"]) + ), + cost_of_revenue=( + None + if "cost_of_revenue" not in d + else CostOfRevenue.from_dict(d["cost_of_revenue"]) + ), + gross_profit=( + None + if "gross_profit" not in d + else GrossProfit.from_dict(d["gross_profit"]) + ), + operating_expenses=( + None + if "operating_expenses" not in d + else OperatingExpenses.from_dict(d["operating_expenses"]) + ), revenues=None if "revenues" not in d else Revenues.from_dict(d["revenues"]), ) @@ -275,18 +295,28 @@ class Financials: @staticmethod def from_dict(d): return Financials( - balance_sheet=None - if "balance_sheet" not in d - else {k: DataPoint.from_dict(v) for (k, v) in d["balance_sheet"].items()}, - cash_flow_statement=None - if "cash_flow_statement" not in d - else CashFlowStatement.from_dict(d["cash_flow_statement"]), - comprehensive_income=None - if "comprehensive_income" not in d - else ComprehensiveIncome.from_dict(d["comprehensive_income"]), - income_statement=None - if "income_statement" not in d - else IncomeStatement.from_dict(d["income_statement"]), + balance_sheet=( + None + if "balance_sheet" not in d + else { + k: DataPoint.from_dict(v) for (k, v) in d["balance_sheet"].items() + } + ), + cash_flow_statement=( + None + if "cash_flow_statement" not in d + else CashFlowStatement.from_dict(d["cash_flow_statement"]) + ), + comprehensive_income=( + None + if "comprehensive_income" not in d + else ComprehensiveIncome.from_dict(d["comprehensive_income"]) + ), + income_statement=( + None + if "income_statement" not in d + else IncomeStatement.from_dict(d["income_statement"]) + ), ) @@ -311,9 +341,9 @@ def from_dict(d): company_name=d.get("company_name", None), end_date=d.get("end_date", None), filing_date=d.get("filing_date", None), - financials=None - if "financials" not in d - else Financials.from_dict(d["financials"]), + financials=( + None if "financials" not in d else Financials.from_dict(d["financials"]) + ), fiscal_period=d.get("fiscal_period", None), fiscal_year=d.get("fiscal_year", None), source_filing_file_url=d.get("source_filing_file_url", None), diff --git a/polygon/rest/models/markets.py b/polygon/rest/models/markets.py index 509caa86..321d23ab 100644 --- a/polygon/rest/models/markets.py +++ b/polygon/rest/models/markets.py @@ -73,16 +73,22 @@ class MarketStatus: def from_dict(d): return MarketStatus( after_hours=d.get("afterHours", None), - currencies=None - if "currencies" not in d - else MarketCurrencies.from_dict(d["currencies"]), + currencies=( + None + if "currencies" not in d + else MarketCurrencies.from_dict(d["currencies"]) + ), early_hours=d.get("earlyHours", None), - exchanges=None - if "exchanges" not in d - else MarketExchanges.from_dict(d["exchanges"]), - indicesGroups=None - if "indicesGroups" not in d - else MarketIndices.from_dict(d["indicesGroups"]), + exchanges=( + None + if "exchanges" not in d + else MarketExchanges.from_dict(d["exchanges"]) + ), + indicesGroups=( + None + if "indicesGroups" not in d + else MarketIndices.from_dict(d["indicesGroups"]) + ), market=d.get("market", None), server_time=d.get("serverTime", None), ) diff --git a/polygon/rest/models/snapshot.py b/polygon/rest/models/snapshot.py index d97f17c3..ceb5f7f8 100644 --- a/polygon/rest/models/snapshot.py +++ b/polygon/rest/models/snapshot.py @@ -70,9 +70,9 @@ def from_dict(d): type=d.get("type", None), ticker=d.get("ticker", None), market_status=d.get("market_status", None), - session=None - if "session" not in d - else IndicesSession.from_dict(d["session"]), + session=( + None if "session" not in d else IndicesSession.from_dict(d["session"]) + ), error=d.get("error", None), message=d.get("message", None), ) @@ -96,12 +96,12 @@ class TickerSnapshot: def from_dict(d): return TickerSnapshot( day=None if "day" not in d else Agg.from_dict(d["day"]), - last_quote=None - if "lastQuote" not in d - else LastQuote.from_dict(d["lastQuote"]), - last_trade=None - if "lastTrade" not in d - else LastTrade.from_dict(d["lastTrade"]), + last_quote=( + None if "lastQuote" not in d else LastQuote.from_dict(d["lastQuote"]) + ), + last_trade=( + None if "lastTrade" not in d else LastTrade.from_dict(d["lastTrade"]) + ), min=None if "min" not in d else MinuteSnapshot.from_dict(d["min"]), prev_day=None if "prevDay" not in d else Agg.from_dict(d["prevDay"]), ticker=d.get("ticker", None), @@ -223,24 +223,32 @@ class OptionContractSnapshot: def from_dict(d): return OptionContractSnapshot( break_even_price=d.get("break_even_price", None), - day=None - if "day" not in d - else DayOptionContractSnapshot.from_dict(d["day"]), - details=None - if "details" not in d - else OptionDetails.from_dict(d["details"]), + day=( + None + if "day" not in d + else DayOptionContractSnapshot.from_dict(d["day"]) + ), + details=( + None if "details" not in d else OptionDetails.from_dict(d["details"]) + ), greeks=None if "greeks" not in d else Greeks.from_dict(d["greeks"]), implied_volatility=d.get("implied_volatility", None), - last_quote=None - if "last_quote" not in d - else LastQuoteOptionContractSnapshot.from_dict(d["last_quote"]), - last_trade=None - if "last_trade" not in d - else LastTradeOptionContractSnapshot.from_dict(d["last_trade"]), + last_quote=( + None + if "last_quote" not in d + else LastQuoteOptionContractSnapshot.from_dict(d["last_quote"]) + ), + last_trade=( + None + if "last_trade" not in d + else LastTradeOptionContractSnapshot.from_dict(d["last_trade"]) + ), open_interest=d.get("open_interest", None), - underlying_asset=None - if "underlying_asset" not in d - else UnderlyingAsset.from_dict(d["underlying_asset"]), + underlying_asset=( + None + if "underlying_asset" not in d + else UnderlyingAsset.from_dict(d["underlying_asset"]) + ), fair_market_value=d.get("fmv", None), ) @@ -274,12 +282,16 @@ class SnapshotTickerFullBook: def from_dict(d): return SnapshotTickerFullBook( ticker=d.get("ticker", None), - bids=None - if "bids" not in d - else [OrderBookQuote.from_dict(o) for o in d["bids"]], - asks=None - if "asks" not in d - else [OrderBookQuote.from_dict(o) for o in d["asks"]], + bids=( + None + if "bids" not in d + else [OrderBookQuote.from_dict(o) for o in d["bids"]] + ), + asks=( + None + if "asks" not in d + else [OrderBookQuote.from_dict(o) for o in d["asks"]] + ), bid_count=d.get("bidCount", None), ask_count=d.get("askCount", None), spread=d.get("spread", None), @@ -404,22 +416,32 @@ def from_dict(d): return UniversalSnapshot( ticker=d.get("ticker", None), type=d.get("type", None), - session=None - if "session" not in d - else UniversalSnapshotSession.from_dict(d["session"]), - last_quote=None - if "last_quote" not in d - else UniversalSnapshotLastQuote.from_dict(d["last_quote"]), - last_trade=None - if "last_trade" not in d - else UniversalSnapshotLastTrade.from_dict(d["last_trade"]), + session=( + None + if "session" not in d + else UniversalSnapshotSession.from_dict(d["session"]) + ), + last_quote=( + None + if "last_quote" not in d + else UniversalSnapshotLastQuote.from_dict(d["last_quote"]) + ), + last_trade=( + None + if "last_trade" not in d + else UniversalSnapshotLastTrade.from_dict(d["last_trade"]) + ), greeks=None if "greeks" not in d else Greeks.from_dict(d["greeks"]), - underlying_asset=None - if "underlying_asset" not in d - else UniversalSnapshotUnderlyingAsset.from_dict(d["underlying_asset"]), - details=None - if "details" not in d - else UniversalSnapshotDetails.from_dict(d["details"]), + underlying_asset=( + None + if "underlying_asset" not in d + else UniversalSnapshotUnderlyingAsset.from_dict(d["underlying_asset"]) + ), + details=( + None + if "details" not in d + else UniversalSnapshotDetails.from_dict(d["details"]) + ), break_even_price=d.get("break_even_price", None), implied_volatility=d.get("implied_volatility", None), open_interest=d.get("open_interest", None), diff --git a/polygon/rest/models/tickers.py b/polygon/rest/models/tickers.py index 1c2ea947..f7ff2bed 100644 --- a/polygon/rest/models/tickers.py +++ b/polygon/rest/models/tickers.py @@ -108,9 +108,9 @@ class TickerDetails: def from_dict(d): return TickerDetails( active=d.get("active", None), - address=None - if "address" not in d - else CompanyAddress.from_dict(d["address"]), + address=( + None if "address" not in d else CompanyAddress.from_dict(d["address"]) + ), branding=None if "branding" not in d else Branding.from_dict(d["branding"]), cik=d.get("cik", None), composite_figi=d.get("composite_figi", None), @@ -169,9 +169,9 @@ def from_dict(d): image_url=d.get("image_url", None), keywords=d.get("keywords", None), published_utc=d.get("published_utc", None), - publisher=None - if "publisher" not in d - else Publisher.from_dict(d["publisher"]), + publisher=( + None if "publisher" not in d else Publisher.from_dict(d["publisher"]) + ), tickers=d.get("tickers", None), title=d.get("title", None), ) diff --git a/polygon/websocket/__init__.py b/polygon/websocket/__init__.py index b9f45a2e..77865d3f 100644 --- a/polygon/websocket/__init__.py +++ b/polygon/websocket/__init__.py @@ -127,9 +127,9 @@ async def connect( self.schedule_resub = False try: - cmsg: Union[ - List[WebSocketMessage], Union[str, bytes] - ] = await asyncio.wait_for(s.recv(), timeout=1) + cmsg: Union[List[WebSocketMessage], Union[str, bytes]] = ( + await asyncio.wait_for(s.recv(), timeout=1) + ) except asyncio.TimeoutError: continue