sovai 0.2.71__tar.gz → 0.2.73__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.71 → sovai-0.2.73}/PKG-INFO +1 -1
- {sovai-0.2.71 → sovai-0.2.73}/pyproject.toml +1 -1
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/signal_evaluation.py +66 -2
- {sovai-0.2.71 → sovai-0.2.73}/LICENSE +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/README.md +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/data/codes.parq +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/data/tickers.parq +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/.DS_Store +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/api_config.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/assets/tickers.parq +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/basic_auth.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/computations/functions.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/change_point_generator copy.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/pandas_extensions.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_compute.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_data copy 2.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_data copy.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_data.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_reports.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/get_tools.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/accounting/accounting_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/news/news_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/token_auth.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/client_side_s3_part_high.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/converter.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/file_management copy.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/file_management.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/plot.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/port_manager copy.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/port_manager.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/stream.py +0 -0
- {sovai-0.2.71 → sovai-0.2.73}/sovai/utils/verbose_utils.py +0 -0
|
@@ -423,6 +423,32 @@ from plotly.subplots import make_subplots
|
|
|
423
423
|
import numpy as np
|
|
424
424
|
|
|
425
425
|
|
|
426
|
+
def _get_first_valid_index(data):
|
|
427
|
+
"""
|
|
428
|
+
Find the first index where any series has valid (non-NaN) data.
|
|
429
|
+
|
|
430
|
+
Parameters:
|
|
431
|
+
-----------
|
|
432
|
+
data : pd.Series or pd.DataFrame
|
|
433
|
+
Time series data to check
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
--------
|
|
437
|
+
First valid index position, or None if all data is NaN
|
|
438
|
+
"""
|
|
439
|
+
if isinstance(data, pd.DataFrame):
|
|
440
|
+
# For DataFrames, find first row where at least one column is not NaN
|
|
441
|
+
valid_mask = data.notna().any(axis=1)
|
|
442
|
+
if valid_mask.any():
|
|
443
|
+
return data.index[valid_mask.argmax()]
|
|
444
|
+
elif isinstance(data, pd.Series):
|
|
445
|
+
# For Series, find first non-NaN value
|
|
446
|
+
valid_mask = data.notna()
|
|
447
|
+
if valid_mask.any():
|
|
448
|
+
return data.index[valid_mask.argmax()]
|
|
449
|
+
return None
|
|
450
|
+
|
|
451
|
+
|
|
426
452
|
def calculate_rolling_sharpe_ratio(returns, window=52, risk_free_rate=0):
|
|
427
453
|
excess_returns = returns - risk_free_rate
|
|
428
454
|
rolling_mean = excess_returns.rolling(window=window).mean()
|
|
@@ -438,6 +464,14 @@ def plot_cumulative_performance_with_sharpe_and_random(
|
|
|
438
464
|
# Calculate rolling Sharpe ratio
|
|
439
465
|
rolling_sharpe = calculate_rolling_sharpe_ratio(portfolio_returns)
|
|
440
466
|
average_sharpe = rolling_sharpe.mean()
|
|
467
|
+
|
|
468
|
+
# Find the first valid index across all series
|
|
469
|
+
first_valid_idx = _get_first_valid_index(cumulative_returns)
|
|
470
|
+
if first_valid_idx is not None:
|
|
471
|
+
cumulative_returns = cumulative_returns.loc[first_valid_idx:]
|
|
472
|
+
rolling_sharpe = rolling_sharpe.loc[rolling_sharpe.index >= first_valid_idx]
|
|
473
|
+
lower_5_strategy = lower_5_strategy.loc[lower_5_strategy.index >= first_valid_idx]
|
|
474
|
+
upper_95_strategy = upper_95_strategy.loc[upper_95_strategy.index >= first_valid_idx]
|
|
441
475
|
|
|
442
476
|
# Create the plot
|
|
443
477
|
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
|
@@ -589,6 +623,11 @@ def get_event_returns(returns, start_date, end_date):
|
|
|
589
623
|
|
|
590
624
|
|
|
591
625
|
def stress_plotting(portfolio_returns):
|
|
626
|
+
# Find the first valid index
|
|
627
|
+
first_valid_idx = _get_first_valid_index(portfolio_returns)
|
|
628
|
+
if first_valid_idx is not None:
|
|
629
|
+
portfolio_returns = portfolio_returns.loc[first_valid_idx:]
|
|
630
|
+
|
|
592
631
|
# Define stress event dates
|
|
593
632
|
stress_events = {
|
|
594
633
|
"Dotcom": ("2000-03-01", "2002-10-01"),
|
|
@@ -837,6 +876,11 @@ from plotly.subplots import make_subplots
|
|
|
837
876
|
|
|
838
877
|
|
|
839
878
|
def drawdown_plot(portfolio_returns):
|
|
879
|
+
# Find the first valid index
|
|
880
|
+
first_valid_idx = _get_first_valid_index(portfolio_returns)
|
|
881
|
+
if first_valid_idx is not None:
|
|
882
|
+
portfolio_returns = portfolio_returns.loc[first_valid_idx:]
|
|
883
|
+
|
|
840
884
|
# Calculate cumulative returns
|
|
841
885
|
cumulative_returns = (1 + portfolio_returns).cumprod()
|
|
842
886
|
|
|
@@ -1298,6 +1342,11 @@ import numpy as np
|
|
|
1298
1342
|
def create_weekly_returns_heatmap(portfolio_returns):
|
|
1299
1343
|
# Ensure the index is datetime
|
|
1300
1344
|
portfolio_returns.index = pd.to_datetime(portfolio_returns.index)
|
|
1345
|
+
|
|
1346
|
+
# Find the first valid index
|
|
1347
|
+
first_valid_idx = _get_first_valid_index(portfolio_returns)
|
|
1348
|
+
if first_valid_idx is not None:
|
|
1349
|
+
portfolio_returns = portfolio_returns.loc[first_valid_idx:]
|
|
1301
1350
|
|
|
1302
1351
|
# Get all unique years from the index
|
|
1303
1352
|
all_years = sorted(portfolio_returns.index.year.unique())
|
|
@@ -1413,7 +1462,11 @@ def calculate_turnover(df, mask):
|
|
|
1413
1462
|
def turnover_plot(df_balance, rebalance_mask):
|
|
1414
1463
|
# Calculate turnover percentages
|
|
1415
1464
|
turnover_df = calculate_turnover(df_balance, rebalance_mask)
|
|
1416
|
-
|
|
1465
|
+
|
|
1466
|
+
# Find the first valid index instead of using hardcoded date
|
|
1467
|
+
first_valid_idx = _get_first_valid_index(turnover_df)
|
|
1468
|
+
if first_valid_idx is not None:
|
|
1469
|
+
turnover_df = turnover_df.loc[first_valid_idx:]
|
|
1417
1470
|
|
|
1418
1471
|
# Find the max and min values
|
|
1419
1472
|
y_max = max(
|
|
@@ -1524,7 +1577,12 @@ def fast_rolling_autocorrelation(df, window):
|
|
|
1524
1577
|
def signal_correlation(df_signal):
|
|
1525
1578
|
window_size = 12
|
|
1526
1579
|
autocorrelation = fast_rolling_autocorrelation(df_signal, window_size)
|
|
1527
|
-
autocorrelation_single = autocorrelation.
|
|
1580
|
+
autocorrelation_single = autocorrelation.mean(axis=1)
|
|
1581
|
+
|
|
1582
|
+
# Find the first valid index instead of using hardcoded date
|
|
1583
|
+
first_valid_idx = _get_first_valid_index(autocorrelation_single)
|
|
1584
|
+
if first_valid_idx is not None:
|
|
1585
|
+
autocorrelation_single = autocorrelation_single.loc[first_valid_idx:]
|
|
1528
1586
|
|
|
1529
1587
|
mean_autocorrelation = np.mean(autocorrelation_single)
|
|
1530
1588
|
|
|
@@ -1615,6 +1673,12 @@ def decile_plots(df_signal, df_prices):
|
|
|
1615
1673
|
# Convert results to dictionaries
|
|
1616
1674
|
decile_returns = {decile: returns for decile, returns, _ in results}
|
|
1617
1675
|
decile_sharpes = {decile: sharpe for decile, _, sharpe in results}
|
|
1676
|
+
|
|
1677
|
+
# Find the first valid index across all decile returns
|
|
1678
|
+
all_returns = pd.DataFrame(decile_returns)
|
|
1679
|
+
first_valid_idx = _get_first_valid_index(all_returns)
|
|
1680
|
+
if first_valid_idx is not None:
|
|
1681
|
+
decile_returns = {decile: returns.loc[first_valid_idx:] for decile, returns in decile_returns.items()}
|
|
1618
1682
|
|
|
1619
1683
|
# Create the plot with secondary y-axis
|
|
1620
1684
|
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|