sovai 0.2.30__tar.gz → 0.2.32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sovai-0.2.30 → sovai-0.2.32}/PKG-INFO +2 -1
- {sovai-0.2.30 → sovai-0.2.32}/pyproject.toml +1 -1
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/pandas_extensions.py +80 -1
- {sovai-0.2.30 → sovai-0.2.32}/sovai/get_plots.py +1 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +70 -0
- {sovai-0.2.30 → sovai-0.2.32}/LICENSE +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/README.md +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/api_config.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/basic_auth.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/computations/functions.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/signal_evaluation.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/get_compute.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/get_data.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/get_reports.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/get_tools.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/accounting/accounting_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/news/news_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/token_auth.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/converter.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/file_management.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/plot.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/port_manager.py +0 -0
- {sovai-0.2.30 → sovai-0.2.32}/sovai/utils/stream.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sovai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.32
|
|
4
4
|
Summary: python for asset management
|
|
5
5
|
License: Proprietary License
|
|
6
6
|
Author: Derek Snow
|
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
15
|
Provides-Extra: full
|
|
15
16
|
Requires-Dist: boto3 (>=1.20)
|
|
16
17
|
Requires-Dist: dash (>=2.0) ; extra == "full"
|
|
@@ -101,7 +101,10 @@ import pandas as pd
|
|
|
101
101
|
from typing import Union, List
|
|
102
102
|
from sovai.extensions.ask_df_llm import Ask
|
|
103
103
|
from sovai.extensions.filter_df import Filter
|
|
104
|
-
|
|
104
|
+
import pandas as pd
|
|
105
|
+
from functools import lru_cache
|
|
106
|
+
import re
|
|
107
|
+
from typing import Union, Tuple
|
|
105
108
|
|
|
106
109
|
class CustomDataFrame(pd.DataFrame):
|
|
107
110
|
@property
|
|
@@ -125,6 +128,82 @@ class CustomDataFrame(pd.DataFrame):
|
|
|
125
128
|
filtered_df = Filter.filter(conditions, df_multi=self, verbose=verbose)
|
|
126
129
|
return CustomDataFrame(filtered_df)
|
|
127
130
|
|
|
131
|
+
@staticmethod
|
|
132
|
+
@lru_cache(maxsize=1)
|
|
133
|
+
def _load_combined_df():
|
|
134
|
+
df = pd.read_parquet("https://storage.googleapis.com/sovai-public/concats/filters/latest.parquet")
|
|
135
|
+
# print("Columns in combined DataFrame:", df.columns) # Debug print
|
|
136
|
+
# print("Index name:", df.index.name) # Debug print for index name
|
|
137
|
+
return df
|
|
138
|
+
|
|
139
|
+
def merge_data(self, column: str) -> 'CustomDataFrame':
|
|
140
|
+
"""
|
|
141
|
+
Merge the current DataFrame with the combined DataFrame based on ticker and a specified column.
|
|
142
|
+
|
|
143
|
+
:param column: The column from the combined DataFrame to merge.
|
|
144
|
+
:return: A new CustomDataFrame with the merged data.
|
|
145
|
+
"""
|
|
146
|
+
# Load the combined DataFrame
|
|
147
|
+
df_combined = self._load_combined_df()
|
|
148
|
+
|
|
149
|
+
# Ensure the specified column exists in the combined DataFrame
|
|
150
|
+
if column not in df_combined.columns:
|
|
151
|
+
raise ValueError(f"Column '{column}' not found in the combined DataFrame.")
|
|
152
|
+
|
|
153
|
+
# Identify the ticker information in the current DataFrame
|
|
154
|
+
ticker_info = self._identify_ticker_info()
|
|
155
|
+
|
|
156
|
+
# Prepare the current DataFrame for merging
|
|
157
|
+
df_to_merge = self.copy()
|
|
158
|
+
if ticker_info[0] != 'column':
|
|
159
|
+
df_to_merge = df_to_merge.reset_index()
|
|
160
|
+
|
|
161
|
+
# Standardize ticker format in the current DataFrame
|
|
162
|
+
|
|
163
|
+
# Prepare the combined DataFrame for merging
|
|
164
|
+
df_combined_merged = df_combined.reset_index()
|
|
165
|
+
|
|
166
|
+
# Perform the merge
|
|
167
|
+
merged_df = pd.merge(df_to_merge, df_combined_merged[['ticker', column]],
|
|
168
|
+
left_on=ticker_info[1], right_on='ticker',
|
|
169
|
+
how='left')
|
|
170
|
+
|
|
171
|
+
# Drop the redundant 'ticker' column from the merge if it's not the original ticker column
|
|
172
|
+
if 'ticker' in merged_df.columns and 'ticker' != ticker_info[1]:
|
|
173
|
+
merged_df = merged_df.drop('ticker', axis=1)
|
|
174
|
+
|
|
175
|
+
# Restore the original index structure
|
|
176
|
+
if ticker_info[0] == 'index':
|
|
177
|
+
merged_df = merged_df.set_index(ticker_info[1])
|
|
178
|
+
elif ticker_info[0] == 'multi_index':
|
|
179
|
+
index_cols = [col for col in df_to_merge.columns if col not in self.columns]
|
|
180
|
+
merged_df = merged_df.set_index(index_cols)
|
|
181
|
+
|
|
182
|
+
return CustomDataFrame(merged_df)
|
|
183
|
+
|
|
184
|
+
def _identify_ticker_info(self) -> Tuple[str, str]:
|
|
185
|
+
"""
|
|
186
|
+
Identify the location and name of ticker information in the DataFrame.
|
|
187
|
+
|
|
188
|
+
:return: A tuple of (location, column_name).
|
|
189
|
+
Location can be 'index', 'multi_index', or 'column'.
|
|
190
|
+
"""
|
|
191
|
+
# Check if ticker is in the index
|
|
192
|
+
if self.index.name and 'ticker' in self.index.name.lower():
|
|
193
|
+
return ('index', self.index.name)
|
|
194
|
+
elif isinstance(self.index, pd.MultiIndex):
|
|
195
|
+
for name in self.index.names:
|
|
196
|
+
if name and 'ticker' in name.lower():
|
|
197
|
+
return ('multi_index', name)
|
|
198
|
+
|
|
199
|
+
# If ticker is not in the index, check the columns
|
|
200
|
+
for col in self.columns:
|
|
201
|
+
if 'ticker' in col.lower():
|
|
202
|
+
return ('column', col)
|
|
203
|
+
|
|
204
|
+
raise ValueError("Couldn't identify ticker information in the DataFrame.")
|
|
205
|
+
|
|
206
|
+
|
|
128
207
|
def get_latest(self, column=None):
|
|
129
208
|
# Your get_latest implementation
|
|
130
209
|
if isinstance(self.index, pd.MultiIndex) and "date" in self.index.names:
|
|
@@ -95,6 +95,7 @@ PLOT_FUNCTION_MAPPER = {
|
|
|
95
95
|
("allocation", "line", "local", True): create_line_plot_allocation,
|
|
96
96
|
("allocation", "stacked", "local", True): create_stacked_bar_plot_allocation,
|
|
97
97
|
("earnings", "line", "local", True): create_earnings_surprise_plot,
|
|
98
|
+
("earnings", "tree", "local", True): earnings_tree,
|
|
98
99
|
("bankruptcy", "compare", "local", True): plot_bankruptcy_monthly_line,
|
|
99
100
|
("bankruptcy", "pca_clusters", "local", True): plot_pca_clusters,
|
|
100
101
|
("bankruptcy", "predictions", "local", True): plot_ticker_widget,
|
|
@@ -114,3 +114,73 @@ def create_earnings_surprise_plot():
|
|
|
114
114
|
return app.run_server(
|
|
115
115
|
debug=False, port=get_unique_port(app_name)
|
|
116
116
|
) # Apply exponential moving average to smooth the data
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
import plotly.express as px
|
|
120
|
+
import pandas as pd
|
|
121
|
+
import numpy as np
|
|
122
|
+
|
|
123
|
+
def earnings_tree():
|
|
124
|
+
df_earn = data("earnings/surprise")
|
|
125
|
+
df_earn = df_earn.merge_data("market_cap")
|
|
126
|
+
# Ensure 'ticker' is a column, not an index
|
|
127
|
+
if 'ticker' not in df_earn.columns:
|
|
128
|
+
df_earn = df_earn.reset_index()
|
|
129
|
+
|
|
130
|
+
# Calculate market cap deciles and handle NaN values
|
|
131
|
+
df_earn['market_cap_decile'] = pd.qcut(df_earn['market_cap'].rank(method='first'), q=10, labels=range(1, 11))
|
|
132
|
+
df_earn['market_cap_decile'] = df_earn['market_cap_decile'].astype(str).replace('nan', 'Unknown')
|
|
133
|
+
|
|
134
|
+
# Update decile labels
|
|
135
|
+
df_earn['market_cap_decile'] = df_earn['market_cap_decile'].apply(lambda x: f"{x} Cap Decile" if x != 'Unknown' else x)
|
|
136
|
+
|
|
137
|
+
# Create the main treemap
|
|
138
|
+
fig = px.treemap(
|
|
139
|
+
df_earn,
|
|
140
|
+
path=[px.Constant("All"), 'market_cap_decile', "ticker"],
|
|
141
|
+
values="market_cap",
|
|
142
|
+
color="surprise_probability",
|
|
143
|
+
color_continuous_scale="RdYlBu",
|
|
144
|
+
color_continuous_midpoint=0,
|
|
145
|
+
hover_data=["surprise_probability", "market_cap", "date"],
|
|
146
|
+
title="Earnings Surprise Probability and Market Cap Treemap",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Update layout for better appearance
|
|
150
|
+
fig.update_layout(
|
|
151
|
+
font=dict(family="Arial", size=14),
|
|
152
|
+
title=dict(font=dict(size=20, color="lightgrey")),
|
|
153
|
+
coloraxis_colorbar=dict(
|
|
154
|
+
title="Surprise Probability",
|
|
155
|
+
tickformat=".2%",
|
|
156
|
+
len=0.75,
|
|
157
|
+
thickness=20,
|
|
158
|
+
title_font=dict(size=16),
|
|
159
|
+
tickfont=dict(size=14),
|
|
160
|
+
),
|
|
161
|
+
height=900,
|
|
162
|
+
# width=1200,
|
|
163
|
+
# plot_bgcolor='rgba(240,240,240,0.8)',
|
|
164
|
+
# paper_bgcolor='rgba(240,240,240,0.8)',
|
|
165
|
+
margin=dict(t=50, l=25, r=25, b=25),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Update traces for better text visibility and style
|
|
169
|
+
fig.update_traces(
|
|
170
|
+
textposition="middle center",
|
|
171
|
+
textfont=dict(family="Arial", size=12, color="black"),
|
|
172
|
+
hovertemplate=(
|
|
173
|
+
"<b>%{label}</b><br>"
|
|
174
|
+
"Date: %{customdata[2]}<br>"
|
|
175
|
+
"Surprise Probability: %{customdata[0]:.2%}<br>"
|
|
176
|
+
"Market Cap: $%{customdata[1]:,.0f}M"
|
|
177
|
+
"<extra></extra>"
|
|
178
|
+
),
|
|
179
|
+
marker=dict(
|
|
180
|
+
cornerradius=5,
|
|
181
|
+
line=dict(width=1, color="white"),
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Show the plot
|
|
186
|
+
fig.show()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|