sovai 0.2.40__tar.gz → 0.2.42__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.40 → sovai-0.2.42}/PKG-INFO +4 -1
- {sovai-0.2.40 → sovai-0.2.42}/pyproject.toml +4 -3
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_data.py +220 -165
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side_s3_part_high.py +63 -4
- {sovai-0.2.40 → sovai-0.2.42}/LICENSE +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/README.md +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/data/codes.parq +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/data/tickers.parq +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/.DS_Store +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/api_config.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/basic_auth.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/computations/functions.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pandas_extensions.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/signal_evaluation.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_compute.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_data copy.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_reports.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/get_tools.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/accounting/accounting_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/news/news_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/token_auth.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/converter.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/file_management.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/plot.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/port_manager.py +0 -0
- {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/stream.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sovai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.42
|
|
4
4
|
Summary: python for asset management
|
|
5
5
|
License: Proprietary License
|
|
6
6
|
Author: Derek Snow
|
|
@@ -17,6 +17,9 @@ Requires-Dist: boto3 (>=1.20)
|
|
|
17
17
|
Requires-Dist: dash (>=2.0) ; extra == "full"
|
|
18
18
|
Requires-Dist: dash-bootstrap-components (>=1.6.0) ; extra == "full"
|
|
19
19
|
Requires-Dist: edgar-tool (>=1.3.3,<2.0.0)
|
|
20
|
+
Requires-Dist: fastapi-cache (>=0.1.0,<0.2.0)
|
|
21
|
+
Requires-Dist: fastapi-cache2[redis] (>=0.2.1,<0.3.0)
|
|
22
|
+
Requires-Dist: gcsfs (>=2024.10.0,<2025.0.0)
|
|
20
23
|
Requires-Dist: great-tables (>=0.9) ; extra == "full"
|
|
21
24
|
Requires-Dist: ipywidgets (>=8.1.3) ; extra == "full"
|
|
22
25
|
Requires-Dist: joblib (>=1.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "sovai"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.42"
|
|
4
4
|
description = "python for asset management"
|
|
5
5
|
authors = ["Derek Snow <d.snow@outlook.com>"]
|
|
6
6
|
license = "Proprietary License"
|
|
@@ -66,6 +66,9 @@ pyvis = "^0.3.2"
|
|
|
66
66
|
networkx = "^3.3"
|
|
67
67
|
seaborn = "^0.13.2"
|
|
68
68
|
s3fs = "^2024.10.0"
|
|
69
|
+
gcsfs = "^2024.10.0"
|
|
70
|
+
fastapi-cache = "^0.1.0"
|
|
71
|
+
fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"}
|
|
69
72
|
|
|
70
73
|
|
|
71
74
|
[tool.poetry.extras]
|
|
@@ -103,5 +106,3 @@ black = "^22.0"
|
|
|
103
106
|
|
|
104
107
|
|
|
105
108
|
[build-system]
|
|
106
|
-
requires = ["poetry-core"]
|
|
107
|
-
build-backend = "poetry.core.masonry.api"
|
|
@@ -23,7 +23,7 @@ import plotly.graph_objects as go
|
|
|
23
23
|
# Local imports
|
|
24
24
|
from sovai.api_config import ApiConfig
|
|
25
25
|
from sovai.errors.sovai_errors import InvalidInputData
|
|
26
|
-
from sovai.utils.converter import convert_data2df
|
|
26
|
+
from sovai.utils.converter import convert_data2df, process_dataframe
|
|
27
27
|
from sovai.utils.stream import stream_data, stream_data_pyarrow
|
|
28
28
|
from sovai.utils.datetime_formats import datetime_format
|
|
29
29
|
from sovai.utils.client_side import client_side_frame
|
|
@@ -307,7 +307,7 @@ ENDPOINT_TO_TICKER = {
|
|
|
307
307
|
"/news/activeness": "",
|
|
308
308
|
"/news/pronouns": "",
|
|
309
309
|
"/news/word_count": "",
|
|
310
|
-
"/news/sentiment_score": None
|
|
310
|
+
"/news/sentiment_score": "", # was None before?
|
|
311
311
|
"/insider/trading": "",
|
|
312
312
|
"/wikipedia/views": "",
|
|
313
313
|
"/accounting/weekly": "",
|
|
@@ -343,7 +343,9 @@ ENDPOINT_TO_TICKER = {
|
|
|
343
343
|
|
|
344
344
|
"/patents/applications": "",
|
|
345
345
|
"/patents/grants": "",
|
|
346
|
-
|
|
346
|
+
|
|
347
|
+
"/clinical/trials": "",
|
|
348
|
+
|
|
347
349
|
"/spending/awards": "",
|
|
348
350
|
"/spending/compensation": "",
|
|
349
351
|
"/spending/competition": "",
|
|
@@ -358,11 +360,11 @@ ENDPOINT_TO_TICKER = {
|
|
|
358
360
|
|
|
359
361
|
# Define endpoint sets for different processing methods
|
|
360
362
|
CLIENT_SIDE_ENDPOINTS_GCS = {
|
|
361
|
-
|
|
363
|
+
# "ratios/relative",
|
|
362
364
|
"market/prices",
|
|
363
365
|
"market/closeadj",
|
|
364
366
|
"short/volume",
|
|
365
|
-
|
|
367
|
+
# "complaints/public",
|
|
366
368
|
"complaints/private",
|
|
367
369
|
"lobbying/public",
|
|
368
370
|
}
|
|
@@ -379,7 +381,10 @@ CLIENT_SIDE_ENDPOINTS_S3 = {
|
|
|
379
381
|
CLIENT_SIDE_ENDPOINTS_S3_PART_HIGH = {
|
|
380
382
|
"patents/applications",
|
|
381
383
|
"patents/grants",
|
|
382
|
-
|
|
384
|
+
|
|
385
|
+
"clinical/trials",
|
|
386
|
+
|
|
387
|
+
|
|
383
388
|
"spending/awards",
|
|
384
389
|
"spending/compensation",
|
|
385
390
|
"spending/competition",
|
|
@@ -387,8 +392,29 @@ CLIENT_SIDE_ENDPOINTS_S3_PART_HIGH = {
|
|
|
387
392
|
"spending/entities",
|
|
388
393
|
"spending/location",
|
|
389
394
|
"spending/product",
|
|
395
|
+
|
|
390
396
|
"spending/transactions",
|
|
391
|
-
"lobbying/data"
|
|
397
|
+
"lobbying/data",
|
|
398
|
+
|
|
399
|
+
"accounting/weekly",
|
|
400
|
+
"ratios/normal",
|
|
401
|
+
"ratios/relative",
|
|
402
|
+
|
|
403
|
+
"complaints/public",
|
|
404
|
+
|
|
405
|
+
"factors/accounting",
|
|
406
|
+
"factors/alternative",
|
|
407
|
+
"factors/comprehensive",
|
|
408
|
+
"factors/coefficients",
|
|
409
|
+
"factors/standard_errors",
|
|
410
|
+
"factors/t_statistics",
|
|
411
|
+
"factors/model_metrics",
|
|
412
|
+
|
|
413
|
+
"breakout",
|
|
414
|
+
|
|
415
|
+
"corprisk/risks",
|
|
416
|
+
|
|
417
|
+
"visas/h1b"
|
|
392
418
|
}
|
|
393
419
|
|
|
394
420
|
|
|
@@ -999,7 +1025,6 @@ def get_api_handler() -> ApiRequestHandler:
|
|
|
999
1025
|
logger=logger
|
|
1000
1026
|
)
|
|
1001
1027
|
|
|
1002
|
-
|
|
1003
1028
|
def data(
|
|
1004
1029
|
endpoint: str,
|
|
1005
1030
|
tickers: Optional[Union[str, List[str]]] = None,
|
|
@@ -1018,6 +1043,7 @@ def data(
|
|
|
1018
1043
|
frequency: Optional[str] = None,
|
|
1019
1044
|
verbose: bool = False,
|
|
1020
1045
|
full_history: bool = False,
|
|
1046
|
+
source: Optional[str] = None,
|
|
1021
1047
|
) -> Union[DataFrameType, go.Figure, None]:
|
|
1022
1048
|
"""
|
|
1023
1049
|
Main function to retrieve data from the API.
|
|
@@ -1057,6 +1083,8 @@ def data(
|
|
|
1057
1083
|
# Set verbose mode based on parameter
|
|
1058
1084
|
verbose_mode.toggle_verbose(verbose)
|
|
1059
1085
|
verbose_mode.log(f"Starting data request for endpoint: {endpoint}")
|
|
1086
|
+
|
|
1087
|
+
result_data = None # Initialize the return value
|
|
1060
1088
|
|
|
1061
1089
|
# Initialize and process parameters
|
|
1062
1090
|
params = params or {}
|
|
@@ -1081,6 +1109,7 @@ def data(
|
|
|
1081
1109
|
parquet=params.get("parquet", parquet),
|
|
1082
1110
|
frequency=params.get("frequency", frequency),
|
|
1083
1111
|
full_history=params.get("full_history", full_history),
|
|
1112
|
+
source=params.get("source", source), # Add source parameter here
|
|
1084
1113
|
)
|
|
1085
1114
|
)
|
|
1086
1115
|
except Exception as e:
|
|
@@ -1109,169 +1138,195 @@ def data(
|
|
|
1109
1138
|
|
|
1110
1139
|
if not purge_cache and cache_key in _query_cache:
|
|
1111
1140
|
verbose_mode.log("Using cached data")
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
result = handler_func(
|
|
1128
|
-
normalized_endpoint, tickers, columns, start_date, end_date
|
|
1129
|
-
)
|
|
1130
|
-
_query_cache[cache_key] = result
|
|
1131
|
-
return result
|
|
1132
|
-
except Exception as e:
|
|
1133
|
-
logger.error(f"Client-side handler error for {normalized_endpoint}: {e}")
|
|
1134
|
-
# Fall through to API request if client-side handler fails
|
|
1135
|
-
|
|
1136
|
-
try:
|
|
1137
|
-
# Perform ticker mapping if needed
|
|
1138
|
-
if tickers is not None and not is_all(tickers):
|
|
1139
|
-
verbose_mode.log("Mapping ticker symbols")
|
|
1140
|
-
params = ticker_mapper(params, verbose)
|
|
1141
|
-
|
|
1142
|
-
# Create API request handler
|
|
1143
|
-
api_handler = get_api_handler()
|
|
1144
|
-
|
|
1145
|
-
# Make API request with retry logic
|
|
1146
|
-
verbose_mode.log("Sending API request")
|
|
1147
|
-
res = api_handler.get(
|
|
1148
|
-
endpoint=endpoint,
|
|
1149
|
-
params=params,
|
|
1150
|
-
body=body,
|
|
1151
|
-
stream=True
|
|
1152
|
-
)
|
|
1153
|
-
|
|
1154
|
-
verbose_mode.log(f"Response received - Status: {res.status_code}, Content-Type: {res.headers.get('content-type')}")
|
|
1155
|
-
|
|
1156
|
-
# Get appropriate ticker for endpoint
|
|
1157
|
-
tickers = get_ticker_from_endpoint(endpoint, tickers, ENDPOINT_TO_TICKER)
|
|
1158
|
-
verbose_mode.log(f"Using tickers: {tickers}")
|
|
1159
|
-
|
|
1160
|
-
# Get response metadata
|
|
1161
|
-
data_format = res.headers.get("X-Data-Format")
|
|
1162
|
-
content_type = res.headers["content-type"]
|
|
1163
|
-
plot_header = res.headers.get("X-Plotly-Data")
|
|
1164
|
-
result_data = None
|
|
1165
|
-
|
|
1166
|
-
# Handle binary data (parquet)
|
|
1167
|
-
if (content_type == "application/octet-stream") and not plot_header:
|
|
1168
|
-
if data_format == "pyarrow":
|
|
1169
|
-
verbose_mode.log("Processing pyarrow data stream")
|
|
1170
|
-
result_data = stream_data_pyarrow(res)
|
|
1171
|
-
else:
|
|
1172
|
-
verbose_mode.log("Processing binary data stream")
|
|
1173
|
-
result_data = stream_data(res)
|
|
1174
|
-
|
|
1175
|
-
# Wrap in CustomDataFrame if available
|
|
1176
|
-
if HAS_FULL_INSTALL:
|
|
1177
|
-
result_data = CustomDataFrame(result_data)
|
|
1178
|
-
else:
|
|
1179
|
-
result_data = pd.DataFrame(result_data)
|
|
1180
|
-
|
|
1181
|
-
_query_cache[cache_key] = result_data
|
|
1182
|
-
return result_data
|
|
1183
|
-
|
|
1184
|
-
# Handle 'all tickers' case
|
|
1185
|
-
if is_all(tickers):
|
|
1186
|
-
verbose_mode.log("Processing 'all tickers' response")
|
|
1187
|
-
urls = [u.strip() for u in res.text.strip('"').split(',') if u.strip()]
|
|
1188
|
-
result_data = None
|
|
1189
|
-
|
|
1190
|
-
# Try each URL until successful
|
|
1191
|
-
for i, url in enumerate(urls):
|
|
1192
|
-
verbose_mode.log(f"Attempting URL {i+1}/{len(urls)}: {url}")
|
|
1141
|
+
result_data = _query_cache[cache_key]
|
|
1142
|
+
else:
|
|
1143
|
+
# Process normalized endpoint for handler matching
|
|
1144
|
+
normalized_endpoint = normalize_endpoint(endpoint)
|
|
1145
|
+
|
|
1146
|
+
# Try client-side handlers for specific endpoints
|
|
1147
|
+
handler_result = None
|
|
1148
|
+
for endpoint_set, handler_func, message in ENDPOINT_HANDLERS:
|
|
1149
|
+
if (
|
|
1150
|
+
normalized_endpoint in endpoint_set and
|
|
1151
|
+
(tickers is not None or start_date is not None or end_date is not None) and
|
|
1152
|
+
frequency is None
|
|
1153
|
+
):
|
|
1154
|
+
verbose_mode.log(message)
|
|
1155
|
+
verbose_mode.log(f"Calling client-side handler with tickers={tickers}, start_date={start_date}, end_date={end_date}")
|
|
1193
1156
|
try:
|
|
1194
|
-
|
|
1195
|
-
|
|
1157
|
+
handler_result = handler_func(
|
|
1158
|
+
normalized_endpoint, tickers, columns, start_date, end_date
|
|
1159
|
+
)
|
|
1160
|
+
_query_cache[cache_key] = handler_result
|
|
1161
|
+
result_data = handler_result
|
|
1196
1162
|
break
|
|
1197
1163
|
except Exception as e:
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
if result_data is None:
|
|
1201
|
-
error_msg = "Failed to download data from all provided URLs"
|
|
1202
|
-
logger.error(error_msg)
|
|
1203
|
-
raise Exception(error_msg)
|
|
1204
|
-
|
|
1205
|
-
# Apply filters
|
|
1206
|
-
verbose_mode.log("Applying filters to data")
|
|
1207
|
-
result_data = filter_data(
|
|
1208
|
-
result_data,
|
|
1209
|
-
columns=columns,
|
|
1210
|
-
start_date=start_date,
|
|
1211
|
-
end_date=end_date,
|
|
1212
|
-
use_polars=use_polars
|
|
1213
|
-
)
|
|
1164
|
+
logger.error(f"Client-side handler error for {normalized_endpoint}: {e}")
|
|
1165
|
+
# Fall through to API request if client-side handler fails
|
|
1214
1166
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1167
|
+
# Only proceed with API request if no handler result
|
|
1168
|
+
if result_data is None:
|
|
1169
|
+
try:
|
|
1170
|
+
# Perform ticker mapping if needed
|
|
1171
|
+
if tickers is not None and not is_all(tickers):
|
|
1172
|
+
verbose_mode.log("Mapping ticker symbols")
|
|
1173
|
+
params = ticker_mapper(params, verbose)
|
|
1218
1174
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
# Handle JSON data
|
|
1222
|
-
elif not plot_header:
|
|
1223
|
-
verbose_mode.log("Processing JSON response")
|
|
1224
|
-
json_data = res.json()
|
|
1225
|
-
if HAS_FULL_INSTALL:
|
|
1226
|
-
result_data = CustomDataFrame(convert_data2df(json_data))
|
|
1227
|
-
else:
|
|
1228
|
-
result_data = pd.DataFrame(convert_data2df(json_data))
|
|
1229
|
-
|
|
1230
|
-
_query_cache[cache_key] = result_data
|
|
1231
|
-
|
|
1232
|
-
# Handle plot data
|
|
1233
|
-
if plot_header:
|
|
1234
|
-
verbose_mode.log("Processing plot data")
|
|
1235
|
-
if HAS_FULL_INSTALL:
|
|
1236
|
-
import pickle
|
|
1237
|
-
try:
|
|
1238
|
-
# Unpickle the data
|
|
1239
|
-
pickle_bytes = res.content
|
|
1240
|
-
fig = pickle.loads(pickle_bytes)
|
|
1241
|
-
fig = go.Figure(json.loads(fig))
|
|
1242
|
-
fig = set_dark_mode(fig)
|
|
1243
|
-
return fig
|
|
1244
|
-
except Exception as e:
|
|
1245
|
-
logger.error(f"Failed to process plot data: {e}")
|
|
1246
|
-
return None
|
|
1247
|
-
else:
|
|
1248
|
-
logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
|
|
1249
|
-
return None
|
|
1250
|
-
|
|
1251
|
-
# Generate plot if requested
|
|
1252
|
-
if plot:
|
|
1253
|
-
verbose_mode.log("Generating plot from data")
|
|
1254
|
-
if HAS_FULL_INSTALL and result_data is not None:
|
|
1255
|
-
return _draw_graphs(result_data)
|
|
1256
|
-
else:
|
|
1257
|
-
logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
|
|
1258
|
-
return None
|
|
1175
|
+
# Create API request handler
|
|
1176
|
+
api_handler = get_api_handler()
|
|
1259
1177
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1178
|
+
# Make API request with retry logic
|
|
1179
|
+
verbose_mode.log("Sending API request")
|
|
1180
|
+
res = api_handler.get(
|
|
1181
|
+
endpoint=endpoint,
|
|
1182
|
+
params=params,
|
|
1183
|
+
body=body,
|
|
1184
|
+
stream=True
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
verbose_mode.log(f"Response received - Status: {res.status_code}, Content-Type: {res.headers.get('content-type')}")
|
|
1188
|
+
|
|
1189
|
+
# Get appropriate ticker for endpoint
|
|
1190
|
+
tickers = get_ticker_from_endpoint(endpoint, tickers, ENDPOINT_TO_TICKER)
|
|
1191
|
+
verbose_mode.log(f"Using tickers: {tickers}")
|
|
1192
|
+
|
|
1193
|
+
# Get response metadata
|
|
1194
|
+
data_format = res.headers.get("X-Data-Format")
|
|
1195
|
+
content_type = res.headers["content-type"]
|
|
1196
|
+
plot_header = res.headers.get("X-Plotly-Data")
|
|
1197
|
+
|
|
1198
|
+
# Handle binary data (parquet)
|
|
1199
|
+
if (content_type == "application/octet-stream") and not plot_header:
|
|
1200
|
+
if data_format == "pyarrow":
|
|
1201
|
+
verbose_mode.log("Processing pyarrow data stream")
|
|
1202
|
+
data_result = stream_data_pyarrow(res)
|
|
1203
|
+
else:
|
|
1204
|
+
verbose_mode.log("Processing binary data stream")
|
|
1205
|
+
data_result = stream_data(res)
|
|
1206
|
+
|
|
1207
|
+
# Wrap in CustomDataFrame if available
|
|
1208
|
+
if HAS_FULL_INSTALL:
|
|
1209
|
+
data_result = CustomDataFrame(data_result)
|
|
1210
|
+
else:
|
|
1211
|
+
data_result = pd.DataFrame(data_result)
|
|
1212
|
+
|
|
1213
|
+
_query_cache[cache_key] = data_result
|
|
1214
|
+
result_data = data_result
|
|
1215
|
+
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
# Handle 'all tickers' case
|
|
1219
|
+
elif is_all(tickers):
|
|
1220
|
+
verbose_mode.log("Processing 'all tickers' response")
|
|
1221
|
+
urls = [u.strip() for u in res.text.strip('"').split(',') if u.strip()]
|
|
1222
|
+
data_result = None
|
|
1223
|
+
|
|
1224
|
+
# Try each URL until successful
|
|
1225
|
+
for i, url in enumerate(urls):
|
|
1226
|
+
verbose_mode.log(f"Attempting URL {i+1}/{len(urls)}: {url}")
|
|
1227
|
+
try:
|
|
1228
|
+
data_result = read_parquet(url, use_polars=use_polars)
|
|
1229
|
+
verbose_mode.log(f"Successfully downloaded data from URL {i+1}")
|
|
1230
|
+
break
|
|
1231
|
+
except Exception as e:
|
|
1232
|
+
verbose_mode.log(f"Failed to download from URL {i+1}: {str(e)}")
|
|
1233
|
+
|
|
1234
|
+
if data_result is None:
|
|
1235
|
+
error_msg = "Failed to download data from all provided URLs"
|
|
1236
|
+
logger.error(error_msg)
|
|
1237
|
+
raise Exception(error_msg)
|
|
1238
|
+
|
|
1239
|
+
# Apply filters
|
|
1240
|
+
verbose_mode.log("Applying filters to data")
|
|
1241
|
+
data_result = filter_data(
|
|
1242
|
+
data_result,
|
|
1243
|
+
columns=columns,
|
|
1244
|
+
start_date=start_date,
|
|
1245
|
+
end_date=end_date,
|
|
1246
|
+
use_polars=use_polars
|
|
1247
|
+
)
|
|
1248
|
+
|
|
1249
|
+
# Wrap in CustomDataFrame if available
|
|
1250
|
+
if HAS_FULL_INSTALL and not use_polars:
|
|
1251
|
+
data_result = CustomDataFrame(data_result)
|
|
1252
|
+
|
|
1253
|
+
_query_cache[cache_key] = data_result
|
|
1254
|
+
result_data = data_result
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
# result_data = process_dataframe(result_data)
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
# Before returning, apply source filtering if applicable
|
|
1261
|
+
if (result_data is not None and
|
|
1262
|
+
source is not None and
|
|
1263
|
+
hasattr(result_data, 'filter') and
|
|
1264
|
+
'source' not in result_data.columns):
|
|
1265
|
+
|
|
1266
|
+
if source == "delisted":
|
|
1267
|
+
verbose_mode.log("Filtering for delisted securities")
|
|
1268
|
+
result_data = result_data.filter(["isdelisted=Y"])
|
|
1269
|
+
elif source == "listed":
|
|
1270
|
+
verbose_mode.log("Filtering for listed securities")
|
|
1271
|
+
result_data = result_data.filter(["isdelisted=N"])
|
|
1272
|
+
|
|
1273
|
+
# Handle JSON data
|
|
1274
|
+
elif not plot_header:
|
|
1275
|
+
verbose_mode.log("Processing JSON response")
|
|
1276
|
+
json_data = res.json()
|
|
1277
|
+
if HAS_FULL_INSTALL:
|
|
1278
|
+
data_result = CustomDataFrame(convert_data2df(json_data))
|
|
1279
|
+
else:
|
|
1280
|
+
data_result = pd.DataFrame(convert_data2df(json_data))
|
|
1281
|
+
|
|
1282
|
+
_query_cache[cache_key] = data_result
|
|
1283
|
+
result_data = data_result
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
# Handle plot data
|
|
1287
|
+
if plot_header:
|
|
1288
|
+
verbose_mode.log("Processing plot data")
|
|
1289
|
+
if HAS_FULL_INSTALL:
|
|
1290
|
+
import pickle
|
|
1291
|
+
try:
|
|
1292
|
+
# Unpickle the data
|
|
1293
|
+
pickle_bytes = res.content
|
|
1294
|
+
fig = pickle.loads(pickle_bytes)
|
|
1295
|
+
fig = go.Figure(json.loads(fig))
|
|
1296
|
+
fig = set_dark_mode(fig)
|
|
1297
|
+
result_data = fig
|
|
1298
|
+
except Exception as e:
|
|
1299
|
+
logger.error(f"Failed to process plot data: {e}")
|
|
1300
|
+
result_data = None
|
|
1301
|
+
else:
|
|
1302
|
+
logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
|
|
1303
|
+
result_data = None
|
|
1304
|
+
|
|
1305
|
+
# Generate plot if requested
|
|
1306
|
+
if plot and result_data is not None and not plot_header:
|
|
1307
|
+
verbose_mode.log("Generating plot from data")
|
|
1308
|
+
if HAS_FULL_INSTALL:
|
|
1309
|
+
result_data = _draw_graphs(result_data)
|
|
1310
|
+
else:
|
|
1311
|
+
logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
|
|
1312
|
+
result_data = None
|
|
1313
|
+
|
|
1314
|
+
except InvalidInputData as err:
|
|
1315
|
+
logger.error(f"Invalid input data: {err}")
|
|
1316
|
+
raise
|
|
1317
|
+
|
|
1318
|
+
except (ConnectionError, TimeoutError) as err:
|
|
1319
|
+
logger.error(f"Network error: {err}")
|
|
1320
|
+
raise ConnectionError(f"Could not connect to API: {err}")
|
|
1321
|
+
|
|
1322
|
+
except Exception as err:
|
|
1323
|
+
logger.error(f"API request error: {err}")
|
|
1324
|
+
raise
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
result_data = process_dataframe(result_data)
|
|
1328
|
+
|
|
1329
|
+
return result_data
|
|
1275
1330
|
|
|
1276
1331
|
|
|
1277
1332
|
async def fetch_multiple_tickers(
|
|
@@ -585,7 +585,7 @@ ENDPOINT_CONFIG = {
|
|
|
585
585
|
"date_path": "sovai/sovai-patents-bulk/grants/date",
|
|
586
586
|
"has_year": True
|
|
587
587
|
},
|
|
588
|
-
"
|
|
588
|
+
"clinical/trials": {
|
|
589
589
|
"ticker_path": "sovai/sovai-clinical-trials-export/partitioned/ticker/ticker",
|
|
590
590
|
"date_path": "sovai/sovai-clinical-trials-export/partitioned/date/date",
|
|
591
591
|
"has_year": False
|
|
@@ -610,10 +610,9 @@ ENDPOINT_CONFIG = {
|
|
|
610
610
|
"date_path": "sovai/sovai-government/partitioned/contract/date",
|
|
611
611
|
"has_year": False
|
|
612
612
|
},
|
|
613
|
-
|
|
614
613
|
"spending/product": {
|
|
615
614
|
"ticker_path": "sovai/sovai-government/partitioned/product/ticker",
|
|
616
|
-
|
|
615
|
+
"date_path": "sovai/sovai-government/partitioned/product/date",
|
|
617
616
|
"has_year": False
|
|
618
617
|
},
|
|
619
618
|
"spending/transactions": {
|
|
@@ -631,9 +630,69 @@ ENDPOINT_CONFIG = {
|
|
|
631
630
|
},
|
|
632
631
|
"lobbying/data": {
|
|
633
632
|
"ticker_path": "sovai/sovai-lobbying/partitioned/ticker",
|
|
634
|
-
|
|
633
|
+
"date_path": "sovai/sovai-lobbying/partitioned/date",
|
|
634
|
+
"has_year": False
|
|
635
|
+
},
|
|
636
|
+
"accounting/weekly": {
|
|
637
|
+
"ticker_path": "sovai/sovai-accounting/partitioned/ticker",
|
|
638
|
+
"date_path": "sovai/sovai-accounting/partitioned/date",
|
|
639
|
+
"has_year": False
|
|
640
|
+
},
|
|
641
|
+
"ratios/normal": {
|
|
642
|
+
"ticker_path": "sovai/sovai-ratios/partitioned/ticker",
|
|
643
|
+
"date_path": "sovai/sovai-ratios/partitioned/date",
|
|
644
|
+
"has_year": False
|
|
645
|
+
},
|
|
646
|
+
"complaints/public": {
|
|
647
|
+
"ticker_path": "sovai/sovai-complaints/partitioned/ticker",
|
|
648
|
+
"date_path": "sovai/sovai-complaints/partitioned/date",
|
|
649
|
+
"has_year": False
|
|
650
|
+
},
|
|
651
|
+
"factors/accounting": {
|
|
652
|
+
"ticker_path": "sovai/sovai-factors/accounting/partitioned/ticker",
|
|
653
|
+
"date_path": "sovai/sovai-factors/accounting/partitioned/date",
|
|
654
|
+
"has_year": False
|
|
655
|
+
},
|
|
656
|
+
"factors/alternative": {
|
|
657
|
+
"ticker_path": "sovai/sovai-factors/alternative/partitioned/ticker",
|
|
658
|
+
"date_path": "sovai/sovai-factors/alternative/partitioned/date",
|
|
659
|
+
"has_year": False
|
|
660
|
+
},
|
|
661
|
+
"factors/comprehensive": {
|
|
662
|
+
"ticker_path": "sovai/sovai-factors/comprehensive/partitioned/ticker",
|
|
663
|
+
"date_path": "sovai/sovai-factors/comprehensive/partitioned/date",
|
|
664
|
+
"has_year": False
|
|
665
|
+
},
|
|
666
|
+
"factors/coefficients": {
|
|
667
|
+
"ticker_path": "sovai/sovai-factors/coefficients/partitioned/ticker",
|
|
668
|
+
"date_path": "sovai/sovai-factors/coefficients/partitioned/date",
|
|
669
|
+
"has_year": False
|
|
670
|
+
},
|
|
671
|
+
"factors/standard_errors": {
|
|
672
|
+
"ticker_path": "sovai/sovai-factors/standard_errors/partitioned/ticker",
|
|
673
|
+
"date_path": "sovai/sovai-factorss/standard_errors/partitioned/date",
|
|
674
|
+
"has_year": False
|
|
675
|
+
},
|
|
676
|
+
"factors/t_statistics": {
|
|
677
|
+
"ticker_path": "sovai/sovai-factors/t_statistics/partitioned/ticker",
|
|
678
|
+
"date_path": "sovai/sovai-factors/t_statistics/partitioned/date",
|
|
679
|
+
"has_year": False
|
|
680
|
+
},
|
|
681
|
+
"factors/model_metrics": {
|
|
682
|
+
"ticker_path": "sovai/sovai-factors/model_metrics/partitioned/ticker",
|
|
683
|
+
"date_path": "sovai/sovai-factors/model_metrics/partitioned/date",
|
|
635
684
|
"has_year": False
|
|
636
685
|
},
|
|
686
|
+
"breakout": {
|
|
687
|
+
"ticker_path": "sovai/sovai-breakout-price/partitioned/ticker",
|
|
688
|
+
"date_path": "sovai/sovai-breakout-price/partitioned/date",
|
|
689
|
+
"has_year": False
|
|
690
|
+
},
|
|
691
|
+
"visas/h1b": {
|
|
692
|
+
"ticker_path": "sovai/sovai-employment/partitioned/ticker",
|
|
693
|
+
"date_path": "sovai/sovai-employment/partitioned/date",
|
|
694
|
+
"has_year": False
|
|
695
|
+
}
|
|
637
696
|
}
|
|
638
697
|
|
|
639
698
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|