sovai 0.2.60__tar.gz → 0.2.62__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 (104) hide show
  1. {sovai-0.2.60 → sovai-0.2.62}/PKG-INFO +1 -1
  2. {sovai-0.2.60 → sovai-0.2.62}/pyproject.toml +1 -1
  3. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/pandas_extensions.py +96 -72
  4. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/time_decomposition.py +3 -1
  5. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/news/news_econometric_analysis.py +9 -2
  6. sovai-0.2.62/sovai/token_auth.py +25 -0
  7. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/client_side.py +20 -14
  8. sovai-0.2.60/sovai/token_auth.py +0 -15
  9. {sovai-0.2.60 → sovai-0.2.62}/LICENSE +0 -0
  10. {sovai-0.2.60 → sovai-0.2.62}/README.md +0 -0
  11. {sovai-0.2.60 → sovai-0.2.62}/data/codes.parq +0 -0
  12. {sovai-0.2.60 → sovai-0.2.62}/data/tickers.parq +0 -0
  13. {sovai-0.2.60 → sovai-0.2.62}/sovai/.DS_Store +0 -0
  14. {sovai-0.2.60 → sovai-0.2.62}/sovai/__init__.py +0 -0
  15. {sovai-0.2.60 → sovai-0.2.62}/sovai/api_config.py +0 -0
  16. {sovai-0.2.60 → sovai-0.2.62}/sovai/assets/dropdown.css +0 -0
  17. {sovai-0.2.60 → sovai-0.2.62}/sovai/assets/features_mapping.parq +0 -0
  18. {sovai-0.2.60 → sovai-0.2.62}/sovai/basic_auth.py +0 -0
  19. {sovai-0.2.60 → sovai-0.2.62}/sovai/computations/__init__.py +0 -0
  20. {sovai-0.2.60 → sovai-0.2.62}/sovai/computations/functions.py +0 -0
  21. {sovai-0.2.60 → sovai-0.2.62}/sovai/errors/__init__.py +0 -0
  22. {sovai-0.2.60 → sovai-0.2.62}/sovai/errors/sovai_errors.py +0 -0
  23. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/__init__.py +0 -0
  24. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/anomalies.py +0 -0
  25. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/ask_df_llm.py +0 -0
  26. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/change_point_generator.py +0 -0
  27. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/clustering.py +0 -0
  28. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/core_kshape.py +0 -0
  29. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/cum_sum_torch.py +0 -0
  30. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/cusum.py +0 -0
  31. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/dimensionality_reduction.py +0 -0
  32. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/feature_extraction.py +0 -0
  33. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/feature_importance.py +0 -0
  34. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/feature_neutralizer.py +0 -0
  35. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/filter_df.py +0 -0
  36. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/fractional_differencing.py +0 -0
  37. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/nowcasting.py +0 -0
  38. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/pairwise.py +0 -0
  39. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/parallel_functions.py +0 -0
  40. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/pfa_feature_selector.py +0 -0
  41. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/regime_change.py +0 -0
  42. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/regime_change_pca.py +0 -0
  43. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/shapley_global_importance.py +0 -0
  44. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/shapley_importance.py +0 -0
  45. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/signal_evaluation.py +0 -0
  46. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/technical_indicators.py +0 -0
  47. {sovai-0.2.60 → sovai-0.2.62}/sovai/extensions/weight_optimization.py +0 -0
  48. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_compute.py +0 -0
  49. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_data copy.py +0 -0
  50. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_data.py +0 -0
  51. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_plots.py +0 -0
  52. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_reports.py +0 -0
  53. {sovai-0.2.60 → sovai-0.2.62}/sovai/get_tools.py +0 -0
  54. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/__init__.py +0 -0
  55. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/accounting/__init__.py +0 -0
  56. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/accounting/accounting_plots.py +0 -0
  57. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/allocation/__init__.py +0 -0
  58. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/allocation/allocation_plots.py +0 -0
  59. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/bankruptcy/__init__.py +0 -0
  60. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  61. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/breakout/__init__.py +0 -0
  62. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/breakout/breakout_plots.py +0 -0
  63. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/corp_risk/__init__.py +0 -0
  64. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  65. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/earnings_surprise/__init__.py +0 -0
  66. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  67. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/insider/__init__.py +0 -0
  68. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/insider/insider_plots.py +0 -0
  69. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/institutional/__init__.py +0 -0
  70. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/institutional/institutional_plots.py +0 -0
  71. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/news/__init__.py +0 -0
  72. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/news/news_plots.py +0 -0
  73. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/ratios/__init__.py +0 -0
  74. {sovai-0.2.60 → sovai-0.2.62}/sovai/plots/ratios/ratios_plots.py +0 -0
  75. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/accounting/__init__.py +0 -0
  76. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  77. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/bankruptcy/__init__.py +0 -0
  78. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  79. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/general/__init__.py +0 -0
  80. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/general/general_plots.py +0 -0
  81. {sovai-0.2.60 → sovai-0.2.62}/sovai/reports/news/__inti__.py +0 -0
  82. {sovai-0.2.60 → sovai-0.2.62}/sovai/studies/nowcasting.py +0 -0
  83. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/authentication/__init__.py +0 -0
  84. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/authentication/authentication.py +0 -0
  85. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/sec/__init__.py +0 -0
  86. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/sec/graphs.py +0 -0
  87. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/sec/llm_code_generator.py +0 -0
  88. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  89. {sovai-0.2.60 → sovai-0.2.62}/sovai/tools/sec/sec_edgar_search.py +0 -0
  90. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/__init__.py +0 -0
  91. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/client_side_s3.py +0 -0
  92. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/client_side_s3_part_high copy 2.py +0 -0
  93. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/client_side_s3_part_high copy.py +0 -0
  94. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/client_side_s3_part_high.py +0 -0
  95. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/converter.py +0 -0
  96. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/datetime_formats.py +0 -0
  97. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/file_management.py +0 -0
  98. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/get_tickers.py +0 -0
  99. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/helpers.py +0 -0
  100. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/pandas_extensions copy.py +0 -0
  101. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/plot.py +0 -0
  102. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/port_manager.py +0 -0
  103. {sovai-0.2.60 → sovai-0.2.62}/sovai/utils/stream.py +0 -0
  104. {sovai-0.2.60 → sovai-0.2.62}/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.60
3
+ Version: 0.2.62
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  Author: Derek Snow
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "sovai"
7
- version = "0.2.60"
7
+ version = "0.2.62"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -1,7 +1,6 @@
1
1
  import pandas as pd
2
2
  import numpy as np
3
- import plotly.express as px
4
- from numpy.linalg import norm
3
+
5
4
 
6
5
  # from extensions.pfa_feature_selector import PFA ## # ## ###
7
6
 
@@ -11,72 +10,6 @@ pd.options.display.float_format = "{:.3f}".format
11
10
 
12
11
  # from sovai.extensions.shapley_importance import run_simulations_frame
13
12
 
14
- from sovai.extensions.feature_neutralizer import (
15
- neutralize_features_function,
16
- orthogonalize_features_function,
17
- )
18
-
19
- from sovai.extensions.fractional_differencing import fractional_diff
20
-
21
- from sovai.extensions.anomalies import (
22
- anomaly_scores,
23
- anomaly_global,
24
- anomaly_local,
25
- anomaly_cluster,
26
- anomaly_reconstruction,
27
- )
28
-
29
- from sovai.extensions.pairwise import distance_calc, relative_distance_calc
30
-
31
- from sovai.extensions.clustering import (
32
- cluster,
33
- cluster_summary,
34
- feature_cent,
35
- vizualisation_cluster,
36
- vizualisation_scatter,
37
- vizualisation_animation,
38
- )
39
-
40
- from sovai.extensions.nowcasting import nowcast_data_source, nowcast_plot_source
41
-
42
- from sovai.extensions.change_point_generator import (
43
- perform_cusum_analysis,
44
- run_cusum_dashboard,
45
- )
46
-
47
- from sovai.extensions.regime_change import (
48
- perform_regime_change_analysis,
49
- run_regime_change_dashboard,
50
- )
51
-
52
- from sovai.extensions.regime_change_pca import (
53
- perform_pca_regime_change_analysis,
54
- run_pca_regime_change_dashboard,
55
- )
56
-
57
- from sovai.extensions.time_decomposition import (
58
- perform_comprehensive_analysis,
59
- run_comprehensive_analysis_dashboard,
60
- )
61
-
62
- from sovai.extensions.feature_extraction import feature_extractor
63
-
64
- from sovai.extensions.dimensionality_reduction import dimensionality_reduction
65
-
66
- from sovai.extensions.feature_importance import (
67
- random_projection_importance,
68
- fast_nonlinear_diverse_selector,
69
- fast_ica_selector,
70
- truncated_svd_selector,
71
- sparse_random_projection_selector,
72
- )
73
-
74
- from sovai.extensions.weight_optimization import WeightOptimization
75
-
76
- from sovai.extensions.signal_evaluation import SignalEvaluator
77
-
78
- from sovai.extensions.technical_indicators import techn_indicators
79
-
80
13
 
81
14
  import warnings
82
15
 
@@ -98,8 +31,8 @@ import pandas as pd
98
31
 
99
32
  import pandas as pd
100
33
  from typing import Union, List
101
- from sovai.extensions.ask_df_llm import Ask
102
- from sovai.extensions.filter_df import Filter
34
+ # from sovai.extensions.ask_df_llm import Ask
35
+
103
36
  import pandas as pd
104
37
  from functools import lru_cache
105
38
  import re
@@ -124,6 +57,9 @@ class CustomDataFrame(pd.DataFrame):
124
57
  :param verbose: If True, print detailed information about the filtering process.
125
58
  :return: A filtered CustomDataFrame.
126
59
  """
60
+
61
+ from sovai.extensions.filter_df import Filter
62
+
127
63
  filtered_df = Filter.filter(conditions, df_multi=self, verbose=verbose)
128
64
  return CustomDataFrame(filtered_df)
129
65
 
@@ -230,6 +166,7 @@ class CustomDataFrame(pd.DataFrame):
230
166
  return CustomDataFrame(latest_data)
231
167
 
232
168
  def plot_line(self, column=None, tickers=None, n=50):
169
+ import plotly.express as px
233
170
  # Your plot_line implementation
234
171
  if isinstance(self.index, pd.MultiIndex):
235
172
  df = self.reset_index()
@@ -308,6 +245,9 @@ class CustomDataFrame(pd.DataFrame):
308
245
  metric="pearson",
309
246
  calculations=["mean"],
310
247
  ):
248
+
249
+ from sovai.extensions.pairwise import distance_calc
250
+
311
251
  result = distance_calc(
312
252
  self,
313
253
  orient=orient,
@@ -326,6 +266,9 @@ class CustomDataFrame(pd.DataFrame):
326
266
  metric="pearson",
327
267
  calculations=["mean"],
328
268
  ):
269
+
270
+ from sovai.extensions.pairwise import distance_calc, relative_distance_calc
271
+
329
272
  result = relative_distance_calc(
330
273
  self,
331
274
  orient=orient,
@@ -337,6 +280,15 @@ class CustomDataFrame(pd.DataFrame):
337
280
  return CustomDataFrame(result)
338
281
 
339
282
  def cluster(self, orient="cluster", features=None):
283
+
284
+ from sovai.extensions.clustering import (
285
+ cluster,
286
+ cluster_summary,
287
+ feature_cent,
288
+ vizualisation_cluster,
289
+ vizualisation_scatter,
290
+ vizualisation_animation,
291
+ )
340
292
  if orient == "cluster":
341
293
  result = cluster(self, features)
342
294
  elif orient == "summary":
@@ -358,10 +310,10 @@ class CustomDataFrame(pd.DataFrame):
358
310
 
359
311
  import numpy as np
360
312
  import pandas as pd
361
- from numpy.linalg import norm
362
313
 
363
314
 
364
315
  def cointegration(self, on="ticker", shift=12):
316
+
365
317
  """
366
318
  Calculate an approximate cointegration proxy using shifted cosine similarity.
367
319
 
@@ -370,6 +322,9 @@ class CustomDataFrame(pd.DataFrame):
370
322
  :param shift: The number of periods to shift for lagged comparison (default 1 month).
371
323
  :return: DataFrame of shifted cosine similarities.
372
324
  """
325
+
326
+ from numpy.linalg import norm
327
+
373
328
  # Shift the DataFrame by the specified lag
374
329
  shifted_df = self.groupby(level=on).shift(-shift)
375
330
 
@@ -462,6 +417,8 @@ class CustomDataFrame(pd.DataFrame):
462
417
  # return CustomDataFrame(avg_shap_values)
463
418
 
464
419
  def orthogonalize_features(self, method="gram_schmidt"):
420
+ from sovai.extensions.feature_neutralizer import orthogonalize_features_function
421
+
465
422
  return CustomDataFrame(orthogonalize_features_function(self, method))
466
423
 
467
424
  def importance_reorder(self):
@@ -469,6 +426,7 @@ class CustomDataFrame(pd.DataFrame):
469
426
 
470
427
 
471
428
  def neutralize_features(self, method="pca"):
429
+ from sovai.extensions.feature_neutralizer import neutralize_features_function
472
430
  return CustomDataFrame(neutralize_features_function(self, method))
473
431
 
474
432
  def ticker(self, ticker="AAPL"):
@@ -710,6 +668,8 @@ class CustomDataFrame(pd.DataFrame):
710
668
  return CustomDataFrame(df_merge)
711
669
 
712
670
  def fractional_difference(self, d=0.845, m=100, groupby_column="ticker"):
671
+ from sovai.extensions.fractional_differencing import fractional_diff
672
+
713
673
  """
714
674
  Apply fractional differencing to each group for all columns, or to the entire DataFrame if groupby_column is not present.
715
675
  :param d: Differencing parameter.
@@ -740,6 +700,14 @@ class CustomDataFrame(pd.DataFrame):
740
700
 
741
701
  def anomalies(self, method="scores", ticker=None):
742
702
 
703
+ from sovai.extensions.anomalies import (
704
+ anomaly_scores,
705
+ anomaly_global,
706
+ anomaly_local,
707
+ anomaly_cluster,
708
+ anomaly_reconstruction,
709
+ )
710
+
743
711
  if method == "scores":
744
712
  return CustomDataFrame(anomaly_scores(self, ticker=ticker))
745
713
  elif method == "global":
@@ -759,6 +727,15 @@ class CustomDataFrame(pd.DataFrame):
759
727
 
760
728
  from sovai.extensions.shapley_global_importance import run_simulations_global_importance
761
729
 
730
+ from sovai.extensions.feature_importance import (
731
+ random_projection_importance,
732
+ fast_nonlinear_diverse_selector,
733
+ fast_ica_selector,
734
+ truncated_svd_selector,
735
+ sparse_random_projection_selector,
736
+ )
737
+
738
+
762
739
  if method == "random_projection":
763
740
  return random_projection_importance(self)
764
741
  elif method == "fourier":
@@ -781,15 +758,26 @@ class CustomDataFrame(pd.DataFrame):
781
758
 
782
759
  def nowcast_data(self, feature=None):
783
760
 
761
+ from sovai.extensions.nowcasting import nowcast_data_source
762
+
763
+
784
764
  return CustomDataFrame(nowcast_data_source(self, selected_feature=feature))
785
765
 
786
766
 
787
767
  def nowcast_plot(self, feature=None):
788
768
 
769
+ from sovai.extensions.nowcasting import nowcast_plot_source
770
+
789
771
  return nowcast_plot_source(self, feature=feature)
790
772
 
791
773
 
792
774
  def change_point(self, method="data", ticker=None, feature=None):
775
+
776
+ from sovai.extensions.change_point_generator import (
777
+ perform_cusum_analysis,
778
+ run_cusum_dashboard,
779
+ )
780
+
793
781
  if ticker is None or feature is None:
794
782
  print("Ticker and/or feature not provided. We will choose on your behalf.")
795
783
  if ticker is None:
@@ -819,15 +807,26 @@ class CustomDataFrame(pd.DataFrame):
819
807
  print(f"Selected feature: {feature}")
820
808
 
821
809
  if method == "data":
810
+
811
+ from sovai.extensions.regime_change import perform_regime_change_analysis
812
+
822
813
  analysis_df = perform_regime_change_analysis(self, ticker, feature)
823
814
  result = CustomDataFrame(analysis_df)
824
815
  return result
825
816
  elif method == "plot":
817
+
818
+ from sovai.extensions.regime_change import run_regime_change_dashboard
826
819
  return run_regime_change_dashboard(self, ticker=ticker, feature=feature)
827
820
  else:
828
821
  raise ValueError("Invalid method. Choose from 'data', 'plot'")
829
822
 
830
823
  def pca_regime_change(self, method="data", ticker=None):
824
+
825
+
826
+ from sovai.extensions.regime_change_pca import (
827
+ perform_pca_regime_change_analysis,
828
+ run_pca_regime_change_dashboard,
829
+ )
831
830
  if ticker is None:
832
831
  print("Ticker not provided. We will choose on your behalf.")
833
832
  ticker = self.index.get_level_values("ticker").unique()[0]
@@ -841,6 +840,13 @@ class CustomDataFrame(pd.DataFrame):
841
840
  raise ValueError("Invalid method. Choose from 'data', 'plot'")
842
841
 
843
842
  def time_decomposition(self, method="data", ticker=None, feature=None):
843
+
844
+
845
+ from sovai.extensions.time_decomposition import (
846
+ perform_comprehensive_analysis,
847
+ run_comprehensive_analysis_dashboard,
848
+ )
849
+
844
850
  if ticker is None or feature is None:
845
851
  print("Ticker and/or feature not provided. We will choose on your behalf.")
846
852
  if ticker is None:
@@ -873,6 +879,8 @@ class CustomDataFrame(pd.DataFrame):
873
879
  """
874
880
  Extracts features from the CustomDataFrame and returns a new CustomDataFrame with the extracted features.
875
881
  """
882
+ from sovai.extensions.feature_extraction import feature_extractor
883
+
876
884
  result_pd = feature_extractor(
877
885
  self, entity_col, date_col, lookback, features, every, verbose
878
886
  )
@@ -894,6 +902,12 @@ class CustomDataFrame(pd.DataFrame):
894
902
  CustomDataFrame: Reduced data in panel format
895
903
  """
896
904
 
905
+
906
+
907
+ from sovai.extensions.dimensionality_reduction import dimensionality_reduction
908
+
909
+
910
+
897
911
  def print_status(message):
898
912
  if verbose:
899
913
  print(message)
@@ -929,6 +943,9 @@ class CustomDataFrame(pd.DataFrame):
929
943
  import pandas as pd
930
944
  import numpy as np
931
945
 
946
+
947
+ from sovai.extensions.weight_optimization import WeightOptimization
948
+
932
949
  # Check if self is a pandas DataFrame
933
950
  if not isinstance(self, pd.DataFrame):
934
951
  raise TypeError("Input must be a pandas DataFrame.")
@@ -974,6 +991,8 @@ class CustomDataFrame(pd.DataFrame):
974
991
  import pandas as pd
975
992
  import numpy as np
976
993
 
994
+ from sovai.extensions.signal_evaluation import SignalEvaluator
995
+
977
996
  # Check if self.df_factor is a pandas DataFrame
978
997
  if not isinstance(self, pd.DataFrame):
979
998
  raise TypeError("Input must be a pandas DataFrame.")
@@ -1024,6 +1043,9 @@ class CustomDataFrame(pd.DataFrame):
1024
1043
  return CustomDataFrame(avg_shap_values)
1025
1044
 
1026
1045
  def technical_indicators(self):
1046
+
1047
+ from sovai.extensions.technical_indicators import techn_indicators
1048
+
1027
1049
  """
1028
1050
  Computes feature importance using SHAP values based on multiple simulations.
1029
1051
 
@@ -1049,10 +1071,12 @@ class CustomDataFrame(pd.DataFrame):
1049
1071
  import polars as pl
1050
1072
  import pandas as pd
1051
1073
  import numpy as np
1052
- from numpy.linalg import norm
1053
1074
 
1054
1075
 
1055
1076
  def distance_pl(pandas_df, on="ticker"):
1077
+
1078
+ from numpy.linalg import norm
1079
+
1056
1080
  pl_df = pl.from_pandas(
1057
1081
  pandas_df.reset_index()
1058
1082
  if isinstance(pandas_df.index, pd.MultiIndex)
@@ -3,7 +3,7 @@ import pandas as pd
3
3
  import plotly.graph_objects as go
4
4
  from plotly.subplots import make_subplots
5
5
  from scipy import stats
6
- from statsforecast.models import MSTL
6
+
7
7
  import dash
8
8
  from dash import dcc, html
9
9
  from dash.dependencies import Input, Output
@@ -31,6 +31,8 @@ def categorize_trend(
31
31
 
32
32
 
33
33
  def perform_comprehensive_analysis(df_accounting, ticker, feature):
34
+ from statsforecast.models import MSTL
35
+
34
36
  df_signal = (
35
37
  df_accounting.query(f"ticker == '{ticker}'")
36
38
  .reset_index()
@@ -6,8 +6,6 @@ import logging
6
6
  import ipywidgets as widgets
7
7
  import pandas as pd
8
8
  import numpy as np
9
- from statsmodels.tsa.stattools import adfuller, coint, grangercausalitytests
10
- from statsmodels.tsa.vector_ar.vecm import VECM
11
9
  from IPython.display import display, HTML
12
10
  from scipy import stats
13
11
  import warnings
@@ -48,6 +46,8 @@ def prepare_data(ticker, variables):
48
46
 
49
47
 
50
48
  def adf_test(series):
49
+ from statsmodels.tsa.stattools import adfuller
50
+
51
51
  """Perform Augmented Dickey-Fuller test for stationarity."""
52
52
  result = adfuller(series)
53
53
  return pd.Series({
@@ -59,6 +59,9 @@ def adf_test(series):
59
59
  })
60
60
 
61
61
  def cointegration_test(series1, series2):
62
+
63
+ from statsmodels.tsa.stattools import coint
64
+
62
65
  """Perform cointegration test between two series."""
63
66
  _, p_value, _ = coint(series1, series2)
64
67
  return p_value
@@ -100,6 +103,8 @@ def interpret_vecm_coefficient(coef, p_value):
100
103
  return f"{strength.capitalize()} {direction} impact"
101
104
 
102
105
  def granger_causality(data, variables, max_lags=5):
106
+ from statsmodels.tsa.stattools import grangercausalitytests
107
+
103
108
  results = {}
104
109
  for v1 in variables:
105
110
  for v2 in variables:
@@ -189,6 +194,8 @@ def generate_dynamic_report(df_merged, ticker, variables):
189
194
  report.append("<p>VECM combines short-term dynamics with long-term equilibrium relationships. It's particularly useful when variables are cointegrated, as it can model both short-term adjustments and long-term convergence to equilibrium.</p>")
190
195
 
191
196
  try:
197
+ from statsmodels.tsa.vector_ar.vecm import VECM
198
+
192
199
  max_lags = 10 # Increase the number of lags considered
193
200
  logger.info(f"Fitting VECM model with {max_lags} lags")
194
201
  model = VECM(df_merged[all_variables], deterministic='co', k_ar_diff=max_lags)
@@ -0,0 +1,25 @@
1
+ from sovai.api_config import ApiConfig, save_key
2
+ # Removed verify_token import from top level
3
+ from sovai.errors.sovai_errors import InvalidCredentialsError
4
+
5
+
6
+ def token_auth(token: str):
7
+ """Authenticates using a token, saves it, and verifies it."""
8
+
9
+ # Lazy load verify_token here, just before use
10
+ from sovai.utils.client_side import verify_token
11
+
12
+ ApiConfig.token = token
13
+ ApiConfig.token_type = "Bearer"
14
+ save_key() # Assumes save_key doesn't trigger heavy imports
15
+
16
+ # Now call the imported function
17
+ is_valid, user_id = verify_token(verbose=False) # Uses lazy-loaded verify_token
18
+
19
+ if not is_valid:
20
+ # print('invalid') # Keep commented or use logging
21
+ raise InvalidCredentialsError("Invalid or expired token. Please authenticate.")
22
+
23
+ # Optionally, you could return something useful, like the validity or user_id
24
+ # print(f"Token verified successfully for user ID: {user_id}") # Or use logging
25
+ # return is_valid, user_id
@@ -7,13 +7,7 @@ from sovai.errors.sovai_errors import InvalidCredentialsError
7
7
  import requests
8
8
  from sovai.api_config import ApiConfig
9
9
 
10
- # Try to import CustomDataFrame, use regular DataFrame if not available
11
- try:
12
- from sovai.extensions.pandas_extensions import CustomDataFrame
13
- HAS_CUSTOM_DATAFRAME = True
14
- except ImportError:
15
- HAS_CUSTOM_DATAFRAME = False
16
- CustomDataFrame = pd.DataFrame # Fallback to regular DataFrame
10
+
17
11
 
18
12
 
19
13
  ## might do the same thing as token_auth, you might have recreated it.
@@ -224,15 +218,27 @@ def client_side_frame(endpoint, tickers, columns, start_date, end_date):
224
218
  name_file = config["name"]
225
219
  partitioned = config["partitioned"]
226
220
 
227
- # Load data
228
- df_percentiles = load_data_for_tickers(
221
+ # Load data - receives a standard pandas DataFrame
222
+ df_result = load_data_for_tickers(
229
223
  base_url, tickers, columns, start_date, end_date, name_file, partitioned
230
224
  )
231
-
232
- if HAS_CUSTOM_DATAFRAME:
233
- return CustomDataFrame(df_percentiles)
234
- else:
235
- return df_percentiles # Returns a regular pandas DataFrame if CustomDataFrame is not available
225
+
226
+ # --- Lazy Load CustomDataFrame Wrapper ---
227
+ # Try to import and wrap only if the import succeeds
228
+ try:
229
+ from sovai.extensions.pandas_extensions import CustomDataFrame
230
+ # If import successful, wrap the result
231
+ print("Wrapping result in CustomDataFrame.") # Optional: for debugging
232
+ return CustomDataFrame(df_result)
233
+ except ImportError:
234
+ # If import fails (lean install), return the standard DataFrame
235
+ print("CustomDataFrame not available (lean install?). Returning standard pandas DataFrame.") # Optional: for debugging
236
+ return df_result
237
+ except Exception as e:
238
+ # Catch other potential errors during wrapping
239
+ print(f"Error wrapping result in CustomDataFrame: {e}. Returning standard pandas DataFrame.")
240
+ return df_result
241
+
236
242
 
237
243
 
238
244
  # def client_side_frame(endpoint, tickers, columns, start_date, end_date):
@@ -1,15 +0,0 @@
1
- from sovai.api_config import ApiConfig, save_key
2
- from sovai.utils.client_side import verify_token
3
- from sovai.errors.sovai_errors import InvalidCredentialsError
4
-
5
-
6
- def token_auth(token: str):
7
- ApiConfig.token = token
8
- ApiConfig.token_type = "Bearer"
9
- save_key()
10
- is_valid, user_id = verify_token(verbose=False)
11
-
12
- if not is_valid:
13
- # print('invalid')
14
- raise InvalidCredentialsError("Invalid or expired token. Please authenticate.")
15
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes