sovai 0.2.71__tar.gz → 0.2.72__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.
Files changed (106) hide show
  1. {sovai-0.2.71 → sovai-0.2.72}/PKG-INFO +1 -1
  2. {sovai-0.2.71 → sovai-0.2.72}/pyproject.toml +1 -1
  3. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/signal_evaluation.py +66 -2
  4. {sovai-0.2.71 → sovai-0.2.72}/LICENSE +0 -0
  5. {sovai-0.2.71 → sovai-0.2.72}/README.md +0 -0
  6. {sovai-0.2.71 → sovai-0.2.72}/data/codes.parq +0 -0
  7. {sovai-0.2.71 → sovai-0.2.72}/data/tickers.parq +0 -0
  8. {sovai-0.2.71 → sovai-0.2.72}/sovai/.DS_Store +0 -0
  9. {sovai-0.2.71 → sovai-0.2.72}/sovai/__init__.py +0 -0
  10. {sovai-0.2.71 → sovai-0.2.72}/sovai/api_config.py +0 -0
  11. {sovai-0.2.71 → sovai-0.2.72}/sovai/assets/dropdown.css +0 -0
  12. {sovai-0.2.71 → sovai-0.2.72}/sovai/assets/features_mapping.parq +0 -0
  13. {sovai-0.2.71 → sovai-0.2.72}/sovai/assets/tickers.parq +0 -0
  14. {sovai-0.2.71 → sovai-0.2.72}/sovai/basic_auth.py +0 -0
  15. {sovai-0.2.71 → sovai-0.2.72}/sovai/computations/__init__.py +0 -0
  16. {sovai-0.2.71 → sovai-0.2.72}/sovai/computations/functions.py +0 -0
  17. {sovai-0.2.71 → sovai-0.2.72}/sovai/errors/__init__.py +0 -0
  18. {sovai-0.2.71 → sovai-0.2.72}/sovai/errors/sovai_errors.py +0 -0
  19. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/__init__.py +0 -0
  20. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/anomalies.py +0 -0
  21. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/ask_df_llm.py +0 -0
  22. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/change_point_generator copy.py +0 -0
  23. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/change_point_generator.py +0 -0
  24. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/clustering.py +0 -0
  25. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/core_kshape.py +0 -0
  26. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/cum_sum_torch.py +0 -0
  27. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/cusum.py +0 -0
  28. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/dimensionality_reduction.py +0 -0
  29. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/feature_extraction.py +0 -0
  30. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/feature_importance.py +0 -0
  31. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/feature_neutralizer.py +0 -0
  32. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/filter_df.py +0 -0
  33. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/fractional_differencing.py +0 -0
  34. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/nowcasting.py +0 -0
  35. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/pairwise.py +0 -0
  36. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/pandas_extensions.py +0 -0
  37. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/parallel_functions.py +0 -0
  38. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/pfa_feature_selector.py +0 -0
  39. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/regime_change.py +0 -0
  40. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/regime_change_pca.py +0 -0
  41. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/shapley_global_importance.py +0 -0
  42. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/shapley_importance.py +0 -0
  43. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/technical_indicators.py +0 -0
  44. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/time_decomposition.py +0 -0
  45. {sovai-0.2.71 → sovai-0.2.72}/sovai/extensions/weight_optimization.py +0 -0
  46. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_compute.py +0 -0
  47. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_data copy 2.py +0 -0
  48. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_data copy.py +0 -0
  49. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_data.py +0 -0
  50. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_plots.py +0 -0
  51. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_reports.py +0 -0
  52. {sovai-0.2.71 → sovai-0.2.72}/sovai/get_tools.py +0 -0
  53. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/__init__.py +0 -0
  54. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/accounting/__init__.py +0 -0
  55. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/accounting/accounting_plots.py +0 -0
  56. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/allocation/__init__.py +0 -0
  57. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/allocation/allocation_plots.py +0 -0
  58. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/bankruptcy/__init__.py +0 -0
  59. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  60. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/breakout/__init__.py +0 -0
  61. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/breakout/breakout_plots.py +0 -0
  62. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/corp_risk/__init__.py +0 -0
  63. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  64. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/earnings_surprise/__init__.py +0 -0
  65. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  66. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/insider/__init__.py +0 -0
  67. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/insider/insider_plots.py +0 -0
  68. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/institutional/__init__.py +0 -0
  69. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/institutional/institutional_plots.py +0 -0
  70. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/news/__init__.py +0 -0
  71. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/news/news_plots.py +0 -0
  72. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/ratios/__init__.py +0 -0
  73. {sovai-0.2.71 → sovai-0.2.72}/sovai/plots/ratios/ratios_plots.py +0 -0
  74. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/accounting/__init__.py +0 -0
  75. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  76. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/bankruptcy/__init__.py +0 -0
  77. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  78. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/general/__init__.py +0 -0
  79. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/general/general_plots.py +0 -0
  80. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/news/__inti__.py +0 -0
  81. {sovai-0.2.71 → sovai-0.2.72}/sovai/reports/news/news_econometric_analysis.py +0 -0
  82. {sovai-0.2.71 → sovai-0.2.72}/sovai/studies/nowcasting.py +0 -0
  83. {sovai-0.2.71 → sovai-0.2.72}/sovai/token_auth.py +0 -0
  84. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/authentication/__init__.py +0 -0
  85. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/authentication/authentication.py +0 -0
  86. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/sec/__init__.py +0 -0
  87. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/sec/graphs.py +0 -0
  88. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/sec/llm_code_generator.py +0 -0
  89. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  90. {sovai-0.2.71 → sovai-0.2.72}/sovai/tools/sec/sec_edgar_search.py +0 -0
  91. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/__init__.py +0 -0
  92. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/client_side.py +0 -0
  93. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/client_side_s3.py +0 -0
  94. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/client_side_s3_part_high.py +0 -0
  95. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/converter.py +0 -0
  96. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/datetime_formats.py +0 -0
  97. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/file_management copy.py +0 -0
  98. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/file_management.py +0 -0
  99. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/get_tickers.py +0 -0
  100. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/helpers.py +0 -0
  101. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/pandas_extensions copy.py +0 -0
  102. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/plot.py +0 -0
  103. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/port_manager copy.py +0 -0
  104. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/port_manager.py +0 -0
  105. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/stream.py +0 -0
  106. {sovai-0.2.71 → sovai-0.2.72}/sovai/utils/verbose_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sovai
3
- Version: 0.2.71
3
+ Version: 0.2.72
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  License-File: LICENSE
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "sovai"
7
- version = "0.2.71"
7
+ version = "0.2.72"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -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
- turnover_df = turnover_df.query("index >= '1999-01-01'")
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.query("date >='1999-01-01'").mean(axis=1)
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