sovai 0.2.54__tar.gz → 0.2.56__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.54 → sovai-0.2.56}/PKG-INFO +2 -3
- {sovai-0.2.54 → sovai-0.2.56}/pyproject.toml +5 -2
- {sovai-0.2.54 → sovai-0.2.56}/sovai/__init__.py +4 -7
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/news/news_plots.py +27 -23
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high.py +87 -39
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/file_management.py +7 -0
- {sovai-0.2.54 → sovai-0.2.56}/LICENSE +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/README.md +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/data/codes.parq +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/data/tickers.parq +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/.DS_Store +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/api_config.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/basic_auth.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/computations/functions.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/pandas_extensions.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/signal_evaluation.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_compute.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_data copy.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_data.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_reports.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/get_tools.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/accounting/accounting_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/token_auth.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high copy 2.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high copy.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/converter.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/plot.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/port_manager.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/stream.py +0 -0
- {sovai-0.2.54 → sovai-0.2.56}/sovai/utils/verbose_utils.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.56
|
|
4
4
|
Summary: python for asset management
|
|
5
5
|
License: Proprietary License
|
|
6
6
|
Author: Derek Snow
|
|
@@ -8,8 +8,6 @@ Author-email: d.snow@outlook.com
|
|
|
8
8
|
Requires-Python: >=3.10
|
|
9
9
|
Classifier: License :: Other/Proprietary License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
13
|
Provides-Extra: full
|
|
@@ -51,6 +49,7 @@ Requires-Dist: scikit-learn ; extra == "full"
|
|
|
51
49
|
Requires-Dist: scipy ; extra == "full"
|
|
52
50
|
Requires-Dist: seaborn (>=0.13.2)
|
|
53
51
|
Requires-Dist: shap ; extra == "full"
|
|
52
|
+
Requires-Dist: skfolio (>=0.9.0,<0.10.0)
|
|
54
53
|
Requires-Dist: skfolio ; extra == "full"
|
|
55
54
|
Requires-Dist: statsforecast ; extra == "full"
|
|
56
55
|
Requires-Dist: tensorly ; extra == "full"
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sovai"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.56"
|
|
8
8
|
description = "python for asset management"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Derek Snow", email = "d.snow@outlook.com"}
|
|
@@ -37,6 +37,7 @@ dependencies = [
|
|
|
37
37
|
"fastapi-cache>=0.1.0",
|
|
38
38
|
"fastapi-cache2[redis]>=0.2.1",
|
|
39
39
|
"tqdm (>=4.67.1,<5.0.0)",
|
|
40
|
+
"skfolio (>=0.9.0,<0.10.0)"
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[tool.poetry]
|
|
@@ -66,7 +67,7 @@ exclude = [
|
|
|
66
67
|
|
|
67
68
|
# Keep Poetry's dependencies section for detailed version specs
|
|
68
69
|
[tool.poetry.dependencies]
|
|
69
|
-
python = "^3.
|
|
70
|
+
python = "^3.12"
|
|
70
71
|
pandas = ">=1.0"
|
|
71
72
|
numpy = ">=1.20"
|
|
72
73
|
pyarrow = ">=5.0"
|
|
@@ -145,3 +146,5 @@ traitlets = "^5.14.3"
|
|
|
145
146
|
jupyterlab = "^4.2.5"
|
|
146
147
|
pytest = "^7.0"
|
|
147
148
|
black = "^22.0"
|
|
149
|
+
jupyter = "^1.1.1"
|
|
150
|
+
ipykernel = "^6.29.5"
|
|
@@ -5,7 +5,7 @@ from .api_config import read_key, save_key, ApiConfig
|
|
|
5
5
|
from .get_data import data
|
|
6
6
|
from .basic_auth import basic_auth
|
|
7
7
|
from .token_auth import token_auth
|
|
8
|
-
from .utils.file_management import save_or_update_tickers, save_or_update_codes
|
|
8
|
+
from .utils.file_management import save_or_update_tickers, save_or_update_codes, update_data_files
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
import warnings
|
|
@@ -18,10 +18,6 @@ try:
|
|
|
18
18
|
except:
|
|
19
19
|
__version__ = "0.2.49" # Fallback to current version in pyproject.toml
|
|
20
20
|
|
|
21
|
-
# Call the function to ensure tickers data is up-to-date
|
|
22
|
-
save_or_update_tickers()
|
|
23
|
-
|
|
24
|
-
save_or_update_codes()
|
|
25
21
|
|
|
26
22
|
try:
|
|
27
23
|
from .get_plots import plot
|
|
@@ -32,11 +28,12 @@ try:
|
|
|
32
28
|
from .get_tools import sec_search, sec_filing, code, sec_graph
|
|
33
29
|
HAS_FULL_INSTALL = True
|
|
34
30
|
except ImportError as e:
|
|
35
|
-
print(
|
|
31
|
+
print("this is the lean installation, for full use sovai[full]")
|
|
32
|
+
# print(f"ImportError: {e}")
|
|
36
33
|
HAS_FULL_INSTALL = False
|
|
37
34
|
|
|
38
35
|
|
|
39
|
-
__all__ = ['read_key', 'save_key', 'ApiConfig', 'data', 'basic_auth', 'token_auth']
|
|
36
|
+
__all__ = ['read_key', 'save_key', 'ApiConfig', 'data', 'basic_auth', 'token_auth', 'update_data_files']
|
|
40
37
|
|
|
41
38
|
if HAS_FULL_INSTALL:
|
|
42
39
|
__all__ += ['plot', 'report', 'compute', 'nowcast', 'extension', 'sec_search', 'sec_filing', 'code', 'sec_graph']
|
|
@@ -4,7 +4,34 @@ import ipywidgets as widgets
|
|
|
4
4
|
from ipywidgets import interact
|
|
5
5
|
from sovai import data
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import numpy as np
|
|
10
|
+
import plotly.graph_objects as go
|
|
11
|
+
from plotly.subplots import make_subplots
|
|
12
|
+
import dash
|
|
13
|
+
from dash import dcc, html
|
|
14
|
+
from dash.dependencies import Input, Output, State
|
|
7
15
|
import random
|
|
16
|
+
from scipy.optimize import minimize
|
|
17
|
+
from scipy import stats
|
|
18
|
+
from sovai.utils.port_manager import get_unique_port
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
import pandas as pd
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
import random
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
import dash
|
|
28
|
+
from dash import dcc, html, Input, Output, State
|
|
29
|
+
import dash_bootstrap_components as dbc
|
|
30
|
+
import plotly.graph_objs as go
|
|
31
|
+
import pandas as pd
|
|
32
|
+
import numpy as np
|
|
33
|
+
|
|
34
|
+
|
|
8
35
|
|
|
9
36
|
# Global dictionary to keep track of apps and their ports
|
|
10
37
|
app_ports = {}
|
|
@@ -118,23 +145,6 @@ def plot_above_sentiment_returns(df_news=None, tickers=None):
|
|
|
118
145
|
fig.show()
|
|
119
146
|
|
|
120
147
|
|
|
121
|
-
|
|
122
|
-
import pandas as pd
|
|
123
|
-
import numpy as np
|
|
124
|
-
import plotly.graph_objects as go
|
|
125
|
-
from plotly.subplots import make_subplots
|
|
126
|
-
import dash
|
|
127
|
-
from dash import dcc, html
|
|
128
|
-
from dash.dependencies import Input, Output, State
|
|
129
|
-
import random
|
|
130
|
-
from scipy.optimize import minimize
|
|
131
|
-
from scipy import stats
|
|
132
|
-
from sovai.utils.port_manager import get_unique_port
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
import pandas as pd
|
|
137
|
-
import numpy as np
|
|
138
148
|
# from statsmodels.tsa.stattools import adfuller, coint
|
|
139
149
|
# from statsmodels.tsa.vector_ar.vecm import VECM
|
|
140
150
|
|
|
@@ -550,12 +560,6 @@ def plot_news_daily(ticker='NVDA'):
|
|
|
550
560
|
# plot_news_daily(ticker='AAPL')
|
|
551
561
|
|
|
552
562
|
|
|
553
|
-
import dash
|
|
554
|
-
from dash import dcc, html, Input, Output, State
|
|
555
|
-
import dash_bootstrap_components as dbc
|
|
556
|
-
import plotly.graph_objs as go
|
|
557
|
-
import pandas as pd
|
|
558
|
-
import numpy as np
|
|
559
563
|
|
|
560
564
|
def dash_news_ts_analysis(df_sentiment, df_polarity, df_topic):
|
|
561
565
|
# Dynamically get all topics from df_sentiment
|
|
@@ -115,7 +115,7 @@ class PartitionFinder:
|
|
|
115
115
|
|
|
116
116
|
@staticmethod
|
|
117
117
|
def find_ticker_partitions(
|
|
118
|
-
ticker_base_path: str,
|
|
118
|
+
ticker_base_path: str,
|
|
119
119
|
tickers: List[str],
|
|
120
120
|
has_year: bool = True,
|
|
121
121
|
start_year: Optional[int] = None,
|
|
@@ -123,93 +123,141 @@ class PartitionFinder:
|
|
|
123
123
|
) -> List[Tuple[str, str]]:
|
|
124
124
|
"""
|
|
125
125
|
Find all valid ticker partitions with optional year filtering.
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
Args:
|
|
128
128
|
ticker_base_path: Base path to ticker partitions
|
|
129
129
|
tickers: List of tickers to search for
|
|
130
130
|
has_year: Whether ticker partitions include year subdirectories
|
|
131
131
|
start_year: Optional starting year to filter by
|
|
132
132
|
end_year: Optional ending year to filter by
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
Returns:
|
|
135
135
|
List of tuples (path, ticker) for loading
|
|
136
136
|
"""
|
|
137
137
|
fs = get_s3_filesystem()
|
|
138
138
|
partitions = []
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
# Process each ticker
|
|
141
141
|
for ticker in tickers:
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
# Construct the base path for this ticker's partitions
|
|
143
|
+
ticker_path = f"{ticker_base_path}/ticker_partitioned={ticker}" # e.g., .../base/ticker_partitioned=AAPL
|
|
144
|
+
|
|
144
145
|
try:
|
|
145
|
-
# Case 1:
|
|
146
|
+
# Case 1: If the endpoint is configured with has_year=False
|
|
146
147
|
if not has_year:
|
|
148
|
+
# Add the base ticker path directly
|
|
147
149
|
partitions.append((ticker_path, ticker))
|
|
150
|
+
# Move to the next ticker
|
|
148
151
|
continue
|
|
149
|
-
|
|
150
|
-
# Case 2:
|
|
152
|
+
|
|
153
|
+
# Case 2: Endpoint has year partitioning (has_year=True)
|
|
154
|
+
# Call _extract_years. If start_year/end_year are None,
|
|
155
|
+
# _extract_years is responsible for returning ALL found years.
|
|
156
|
+
# If start_year/end_year have values, it returns filtered years.
|
|
157
|
+
verbose_mode.log(f"Extracting years for {ticker} at {ticker_path} (Range: {start_year}-{end_year})")
|
|
151
158
|
years = PartitionFinder._extract_years(
|
|
152
159
|
fs, ticker_path, start_year, end_year
|
|
153
160
|
)
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
verbose_mode.log(f"Found years for {ticker}: {years}")
|
|
162
|
+
|
|
163
|
+
# Generate specific year paths for EACH year returned by _extract_years
|
|
164
|
+
# If start_year/end_year were None, 'years' should contain ALL available years.
|
|
165
|
+
# If start_year/end_year were set, 'years' contains only the filtered years.
|
|
156
166
|
for year in years:
|
|
157
|
-
year_path = f"{ticker_path}/year={year}"
|
|
167
|
+
year_path = f"{ticker_path}/year={year}" # e.g., .../base/ticker_partitioned=AAPL/year=2023
|
|
158
168
|
partitions.append((year_path, ticker))
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
verbose_mode.log(f"Added partition task for: {year_path}")
|
|
170
|
+
|
|
171
|
+
# Fallback: This only runs if _extract_years found NO years AND a specific range WAS given.
|
|
172
|
+
# It does NOT run if start_year/end_year were None.
|
|
161
173
|
if not years and start_year and end_year:
|
|
174
|
+
verbose_mode.log(f"No years found via listing for {ticker} in range {start_year}-{end_year}. Constructing paths based on range.")
|
|
162
175
|
for year in range(start_year, end_year + 1):
|
|
163
176
|
year_path = f"{ticker_path}/year={year}"
|
|
177
|
+
# Note: These paths might not actually exist.
|
|
164
178
|
partitions.append((year_path, ticker))
|
|
165
|
-
|
|
179
|
+
verbose_mode.log(f"Added potential partition task (fallback): {year_path}")
|
|
180
|
+
|
|
166
181
|
except Exception as e:
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
# Log errors encountered for a specific ticker
|
|
183
|
+
logger.error(f"Error processing ticker {ticker} at path {ticker_path}: {e}", exc_info=True) # Use logger.error
|
|
184
|
+
|
|
169
185
|
if not partitions:
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
# Log if no partitions were found across ALL requested tickers matching the criteria
|
|
187
|
+
logger.warning(f"No ticker partitions ultimately found matching criteria. Base Path: {ticker_base_path}, Tickers: {tickers}, Has Year: {has_year}, Year Range: {start_year}-{end_year}") # Use logger.warning
|
|
188
|
+
|
|
172
189
|
return partitions
|
|
173
190
|
|
|
174
191
|
@staticmethod
|
|
175
192
|
def _extract_years(
|
|
176
|
-
fs: S3FileSystem,
|
|
177
|
-
ticker_path: str,
|
|
178
|
-
start_year: Optional[int],
|
|
193
|
+
fs: S3FileSystem,
|
|
194
|
+
ticker_path: str,
|
|
195
|
+
start_year: Optional[int],
|
|
179
196
|
end_year: Optional[int]
|
|
180
197
|
) -> List[int]:
|
|
181
198
|
"""
|
|
182
|
-
Extract valid years from ticker subdirectories.
|
|
183
|
-
|
|
199
|
+
Extract valid years from ticker subdirectories. [CORRECTED VERSION]
|
|
200
|
+
|
|
184
201
|
Args:
|
|
185
202
|
fs: S3 filesystem
|
|
186
|
-
ticker_path: Path to search for year directories
|
|
203
|
+
ticker_path: Path to search for year directories (e.g., .../ticker_partitioned=PFE)
|
|
187
204
|
start_year: Optional starting year filter
|
|
188
205
|
end_year: Optional ending year filter
|
|
189
|
-
|
|
206
|
+
|
|
190
207
|
Returns:
|
|
191
|
-
List of valid years within the specified range
|
|
208
|
+
List of valid years within the specified range, sorted.
|
|
192
209
|
"""
|
|
193
210
|
years = []
|
|
194
|
-
|
|
211
|
+
logger.debug(f"[_extract_years] Input: path='{ticker_path}', start={start_year}, end={end_year}")
|
|
195
212
|
try:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
logger.debug(f"[_extract_years] Listing contents of: {ticker_path} using get_file_info")
|
|
214
|
+
# Correct way to list directory contents using pyarrow fs API
|
|
215
|
+
selector = pa.fs.FileSelector(ticker_path, recursive=False)
|
|
216
|
+
subdirs_info = fs.get_file_info(selector) # Get list of FileInfo objects
|
|
217
|
+
logger.info(f"[_extract_years] Found {len(subdirs_info)} items in '{ticker_path}'")
|
|
218
|
+
|
|
219
|
+
for item_info in subdirs_info:
|
|
220
|
+
# Process only items that are directories
|
|
221
|
+
if item_info.type != pa.fs.FileType.Directory:
|
|
222
|
+
logger.debug(f"[_extract_years] Skipping non-directory item: {item_info.path}")
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
subdir_path = item_info.path
|
|
226
|
+
basename = os.path.basename(subdir_path.rstrip('/')) # Get last component
|
|
227
|
+
logger.debug(f"[_extract_years] Processing directory item: '{basename}'")
|
|
228
|
+
|
|
199
229
|
if basename.startswith('year='):
|
|
200
|
-
|
|
230
|
+
logger.debug(f"[_extract_years] Found potential year directory: {basename}")
|
|
231
|
+
year_str = basename.split('=', 1)[1] # Extract year string
|
|
201
232
|
try:
|
|
202
233
|
year = int(year_str)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
234
|
+
logger.debug(f"[_extract_years] Parsed year: {year}. Checking range: start={start_year}, end={end_year}")
|
|
235
|
+
|
|
236
|
+
# Apply year filtering logic
|
|
237
|
+
start_ok = (start_year is None or year >= start_year)
|
|
238
|
+
end_ok = (end_year is None or year <= end_year)
|
|
239
|
+
logger.debug(f"[_extract_years] Filter check for year {year}: start_ok={start_ok}, end_ok={end_ok}")
|
|
240
|
+
|
|
241
|
+
if start_ok and end_ok:
|
|
242
|
+
logger.info(f"[_extract_years] Year {year} is WITHIN range/criteria. Appending.")
|
|
206
243
|
years.append(year)
|
|
244
|
+
else:
|
|
245
|
+
logger.debug(f"[_extract_years] Year {year} is OUTSIDE range. Skipping.")
|
|
246
|
+
|
|
207
247
|
except ValueError:
|
|
208
|
-
|
|
248
|
+
logger.warning(f"[_extract_years] Invalid year format: '{year_str}' in path {subdir_path}")
|
|
249
|
+
else:
|
|
250
|
+
logger.debug(f"[_extract_years] Directory '{basename}' does not start with 'year='. Skipping.")
|
|
251
|
+
|
|
252
|
+
except FileNotFoundError:
|
|
253
|
+
# If the base ticker_path itself doesn't exist
|
|
254
|
+
logger.warning(f"[_extract_years] Directory not found for listing: {ticker_path}")
|
|
209
255
|
except Exception as e:
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
256
|
+
# Catch any other errors during listing/processing
|
|
257
|
+
logger.error(f"[_extract_years] Error listing or processing directory {ticker_path}: {e}", exc_info=True)
|
|
258
|
+
|
|
259
|
+
logger.info(f"[_extract_years] Returning extracted years: {sorted(years)} for path '{ticker_path}'")
|
|
260
|
+
return sorted(years)
|
|
213
261
|
|
|
214
262
|
@staticmethod
|
|
215
263
|
def find_date_partitions(
|
|
@@ -70,3 +70,10 @@ def save_or_update_codes():
|
|
|
70
70
|
codes_meta = pd.read_parquet(download_url)
|
|
71
71
|
codes_meta.to_parquet(output_path)
|
|
72
72
|
|
|
73
|
+
|
|
74
|
+
def update_data_files():
|
|
75
|
+
"""
|
|
76
|
+
Manually updates the tickers and codes data files if they are outdated.
|
|
77
|
+
"""
|
|
78
|
+
save_or_update_tickers()
|
|
79
|
+
save_or_update_codes()
|
|
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
|
|
File without changes
|