sovai 0.2.1__tar.gz → 0.2.3__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 (91) hide show
  1. {sovai-0.2.1 → sovai-0.2.3}/PKG-INFO +3 -1
  2. {sovai-0.2.1 → sovai-0.2.3}/pyproject.toml +3 -1
  3. {sovai-0.2.1 → sovai-0.2.3}/sovai/__init__.py +10 -0
  4. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/pandas_extensions.py +13 -0
  5. sovai-0.2.3/sovai/extensions/technical_indicators.py +219 -0
  6. {sovai-0.2.1 → sovai-0.2.3}/sovai/get_data.py +118 -160
  7. {sovai-0.2.1 → sovai-0.2.3}/sovai/get_plots.py +10 -2
  8. {sovai-0.2.1 → sovai-0.2.3}/sovai/get_reports.py +5 -0
  9. sovai-0.2.3/sovai/get_tools.py +17 -0
  10. sovai-0.2.3/sovai/plots/earnings_surprise/__init__.py +1 -0
  11. sovai-0.2.3/sovai/plots/earnings_surprise/earnings_surprise_plots.py +135 -0
  12. sovai-0.2.3/sovai/plots/news/news_plots.py +795 -0
  13. sovai-0.2.3/sovai/reports/news/__inti__.py +1 -0
  14. sovai-0.2.3/sovai/reports/news/news_econometric_analysis.py +396 -0
  15. sovai-0.2.3/sovai/token_auth.py +15 -0
  16. sovai-0.2.3/sovai/tools/sec/sec_10_k_8_k_filings.py +535 -0
  17. sovai-0.2.3/sovai/tools/sec/sec_edgar_search.py +212 -0
  18. sovai-0.2.3/sovai/utils/__init__.py +0 -0
  19. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/client_side.py +2 -0
  20. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/file_management.py +2 -1
  21. sovai-0.2.1/data/tickers.parq +0 -0
  22. sovai-0.2.1/sovai/assets/tickers.parq +0 -0
  23. sovai-0.2.1/sovai/plots/news/news_plots.py +0 -116
  24. sovai-0.2.1/sovai/token_auth.py +0 -7
  25. {sovai-0.2.1 → sovai-0.2.3}/LICENSE +0 -0
  26. {sovai-0.2.1 → sovai-0.2.3}/README.md +0 -0
  27. {sovai-0.2.1 → sovai-0.2.3}/sovai/api_config.py +0 -0
  28. {sovai-0.2.1 → sovai-0.2.3}/sovai/assets/dropdown.css +0 -0
  29. {sovai-0.2.1 → sovai-0.2.3}/sovai/assets/features_mapping.parq +0 -0
  30. {sovai-0.2.1 → sovai-0.2.3}/sovai/basic_auth.py +0 -0
  31. {sovai-0.2.1 → sovai-0.2.3}/sovai/computations/__init__.py +0 -0
  32. {sovai-0.2.1 → sovai-0.2.3}/sovai/computations/functions.py +0 -0
  33. {sovai-0.2.1 → sovai-0.2.3}/sovai/errors/__init__.py +0 -0
  34. {sovai-0.2.1 → sovai-0.2.3}/sovai/errors/sovai_errors.py +0 -0
  35. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/__init__.py +0 -0
  36. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/anomalies.py +0 -0
  37. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/change_point_generator.py +0 -0
  38. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/clustering.py +0 -0
  39. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/core_kshape.py +0 -0
  40. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/cum_sum_torch.py +0 -0
  41. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/cusum.py +0 -0
  42. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/dimensionality_reduction.py +0 -0
  43. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/feature_extraction.py +0 -0
  44. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/feature_importance.py +0 -0
  45. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/feature_neutralizer.py +0 -0
  46. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/fractional_differencing.py +0 -0
  47. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/nowcasting.py +0 -0
  48. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/pairwise.py +0 -0
  49. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/parallel_functions.py +0 -0
  50. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/pfa_feature_selector.py +0 -0
  51. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/regime_change.py +0 -0
  52. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/regime_change_pca.py +0 -0
  53. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/shapley_global_importance.py +0 -0
  54. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/shapley_importance.py +0 -0
  55. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/signal_evaluation.py +0 -0
  56. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/time_decomposition.py +0 -0
  57. {sovai-0.2.1 → sovai-0.2.3}/sovai/extensions/weight_optimization.py +0 -0
  58. {sovai-0.2.1 → sovai-0.2.3}/sovai/get_compute.py +0 -0
  59. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/__init__.py +0 -0
  60. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/accounting/__init__.py +0 -0
  61. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/accounting/accounting_plots.py +0 -0
  62. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/allocation/__init__.py +0 -0
  63. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/allocation/allocation_plots.py +0 -0
  64. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/bankruptcy/__init__.py +0 -0
  65. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  66. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/breakout/__init__.py +0 -0
  67. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/breakout/breakout_plots.py +0 -0
  68. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/corp_risk/__init__.py +0 -0
  69. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  70. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/insider/__init__.py +0 -0
  71. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/insider/insider_plots.py +0 -0
  72. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/institutional/__init__.py +0 -0
  73. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/institutional/institutional_plots.py +0 -0
  74. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/news/__init__.py +0 -0
  75. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/ratios/__init__.py +0 -0
  76. {sovai-0.2.1 → sovai-0.2.3}/sovai/plots/ratios/ratios_plots.py +0 -0
  77. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/accounting/__inti__.py +0 -0
  78. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  79. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/bankruptcy/__inti__.py +0 -0
  80. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  81. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/general/__inti__.py +0 -0
  82. {sovai-0.2.1 → sovai-0.2.3}/sovai/reports/general/general_plots.py +0 -0
  83. {sovai-0.2.1 → sovai-0.2.3}/sovai/studies/nowcasting.py +0 -0
  84. /sovai-0.2.1/sovai/utils/__init__.py → /sovai-0.2.3/sovai/tools/sec/__inti__.py +0 -0
  85. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/converter.py +0 -0
  86. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/datetime_formats.py +0 -0
  87. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/get_tickers.py +0 -0
  88. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/helpers.py +0 -0
  89. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/pandas_extensions copy.py +0 -0
  90. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/plot.py +0 -0
  91. {sovai-0.2.1 → sovai-0.2.3}/sovai/utils/stream.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sovai
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  Author: Derek Snow
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Dist: boto3 (>=1.20)
15
15
  Requires-Dist: dash (>=2.0)
16
16
  Requires-Dist: great-tables (>=0.9)
17
+ Requires-Dist: ipywidgets (>=8.1.3,<9.0.0)
17
18
  Requires-Dist: joblib (>=1.0)
18
19
  Requires-Dist: lightgbm (>=4.5.0,<5.0.0)
19
20
  Requires-Dist: matplotlib (>=3.0)
@@ -25,6 +26,7 @@ Requires-Dist: pandas (>=1.0)
25
26
  Requires-Dist: pexpect (>=4.9.0,<5.0.0)
26
27
  Requires-Dist: plotly (>=5.0)
27
28
  Requires-Dist: polars (>=0.20.30)
29
+ Requires-Dist: polars-talib (==0.1.3)
28
30
  Requires-Dist: pyarrow (>=5.0)
29
31
  Requires-Dist: python-dateutil (>=2.8)
30
32
  Requires-Dist: python-dotenv (>=0.10)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "sovai"
3
- version = "0.2.1"
3
+ version = "0.2.3"
4
4
  description = "python for asset management"
5
5
  authors = ["Derek Snow <d.snow@outlook.com>"]
6
6
  license = "Proprietary License"
@@ -56,6 +56,8 @@ openai = ">=1.0"
56
56
  mfles = ">=0.2"
57
57
  pexpect = "^4.9.0"
58
58
  lightgbm = "^4.5.0"
59
+ ipywidgets = "^8.1.3"
60
+ polars-talib = "0.1.3"
59
61
 
60
62
  [build-system]
61
63
  requires = ["poetry-core"]
@@ -19,6 +19,16 @@ from .extensions.pandas_extensions import CustomDataFrame as extension
19
19
  from .utils.file_management import save_or_update_tickers
20
20
 
21
21
 
22
+
23
+ from .get_tools import sec_search
24
+
25
+ from .get_tools import sec_filing
26
+
27
+
28
+
29
+
30
+
31
+
22
32
  # Call the function to ensure tickers data is up-to-date
23
33
  save_or_update_tickers()
24
34
 
@@ -76,6 +76,8 @@ from sovai.extensions.weight_optimization import WeightOptimization
76
76
 
77
77
  from sovai.extensions.signal_evaluation import SignalEvaluator
78
78
 
79
+ from sovai.extensions.technical_indicators import techn_indicators
80
+
79
81
 
80
82
  import warnings
81
83
 
@@ -908,6 +910,17 @@ class CustomDataFrame(pd.DataFrame):
908
910
  )
909
911
 
910
912
  return CustomDataFrame(avg_shap_values)
913
+
914
+ def technical_indicators(self):
915
+ """
916
+ Computes feature importance using SHAP values based on multiple simulations.
917
+
918
+ :param num_simulations: The number of simulations to run (default 4).
919
+ :param clustering_method: The clustering method to use ('OPTICS' or 'KMeans').
920
+ :return: A DataFrame with average SHAP values per feature.
921
+ """
922
+
923
+ return CustomDataFrame(techn_indicators(self))
911
924
 
912
925
 
913
926
  # # Example usage
@@ -0,0 +1,219 @@
1
+ import polars as pl
2
+ import polars_talib as plta
3
+ import warnings
4
+ warnings.filterwarnings("ignore", category=DeprecationWarning)
5
+
6
+ def func_ts_date(df_group: pl.DataFrame) -> pl.DataFrame:
7
+ # Ensure the data is sorted by date
8
+ df_group = df_group.sort("date")
9
+
10
+ # Calculate technical indicators
11
+ df_group = df_group.with_columns([
12
+ plta.bbands(timeperiod=20, nbdevup=2, nbdevdn=2).alias('BBANDS'),
13
+ plta.ema(timeperiod=20).alias('EMA_20'),
14
+ plta.macd(fastperiod=12, slowperiod=26, signalperiod=9).alias('MACD'),
15
+ plta.adx(timeperiod=14).alias('ADX_14'),
16
+ plta.cci(timeperiod=14).alias('CCI_14'),
17
+ plta.mfi(timeperiod=14).alias('MFI_14'),
18
+ plta.mom(timeperiod=10).alias('MOM_10'),
19
+ plta.stoch(fastk_period=5, slowk_period=3, slowd_period=3).alias('STOCH'),
20
+ plta.willr(timeperiod=14).alias('WILLR_14'),
21
+ plta.atr(timeperiod=14).alias('ATR_14'),
22
+ plta.obv().alias('OBV'),
23
+ plta.ad().alias('AD'),
24
+ plta.aroon(timeperiod=14).alias('AROON_14'),
25
+ plta.bop().alias('BOP'),
26
+ plta.cmo(timeperiod=14).alias('CMO_14'),
27
+ plta.dx(timeperiod=14).alias('DX_14'),
28
+ plta.kama(timeperiod=30).alias('KAMA_30'),
29
+ plta.ppo().alias('PPO'),
30
+ plta.rocr(timeperiod=10).alias('ROCR_10'),
31
+ plta.trix(timeperiod=30).alias('TRIX_30'),
32
+ plta.ultosc().alias('ULTOSC'),
33
+ plta.natr(timeperiod=14).alias('NATR_14'),
34
+ plta.ht_dcperiod().alias('HT_DCPERIOD'),
35
+ plta.ht_dcphase().alias('HT_DCPHASE'),
36
+ plta.ht_phasor().alias('HT_PHASOR'),
37
+ plta.ht_sine().alias('HT_SINE'),
38
+ plta.ht_trendmode().alias('HT_TRENDMODE'),
39
+ plta.avgprice().alias('AVGPRICE'),
40
+ plta.medprice().alias('MEDPRICE'),
41
+ plta.typprice().alias('TYPPRICE'),
42
+ plta.wclprice().alias('WCLPRICE'),
43
+ plta.beta(timeperiod=5).alias('BETA_5'),
44
+ plta.correl(timeperiod=30).alias('CORREL_30'),
45
+ plta.linearreg(timeperiod=14).alias('LINEARREG_14'),
46
+ plta.linearreg_angle(timeperiod=14).alias('LINEARREG_ANGLE_14'),
47
+ plta.linearreg_intercept(timeperiod=14).alias('LINEARREG_INTERCEPT_14'),
48
+ plta.linearreg_slope(timeperiod=14).alias('LINEARREG_SLOPE_14'),
49
+ plta.tsf(timeperiod=14).alias('TSF_14'),
50
+ plta.var(timeperiod=5).alias('VAR_5'),
51
+ plta.sar(acceleration=0.02, maximum=0.2).alias('SAR'),
52
+ plta.adxr(timeperiod=14).alias('ADXR_14'),
53
+ plta.apo(fastperiod=12, slowperiod=26, matype=0).alias('APO'),
54
+ plta.aroonosc(timeperiod=14).alias('AROONOSC_14'),
55
+ plta.dema(timeperiod=30).alias('DEMA_30'),
56
+ plta.ht_trendline().alias('HT_TRENDLINE'),
57
+ plta.ma(timeperiod=30, matype=0).alias('MA_30'),
58
+ plta.mama().alias('MAMA'),
59
+ plta.mavp(periods=pl.col("volume"), minperiod=2, maxperiod=30, matype=0).alias('MAVP'),
60
+ plta.midpoint(timeperiod=14).alias('MIDPOINT_14'),
61
+ plta.midprice(timeperiod=14).alias('MIDPRICE_14'),
62
+ plta.sarext().alias('SAREXT'),
63
+ plta.sma(timeperiod=30).alias('SMA_30'),
64
+ plta.t3(timeperiod=5, vfactor=0.7).alias('T3_5'),
65
+ plta.tema(timeperiod=30).alias('TEMA_30'),
66
+ plta.trima(timeperiod=30).alias('TRIMA_30'),
67
+ plta.wma(timeperiod=30).alias('WMA_30'),
68
+ plta.cdl2crows().alias('CDL2CROWS'),
69
+ plta.cdl3blackcrows().alias('CDL3BLACKCROWS'),
70
+ plta.cdl3inside().alias('CDL3INSIDE'),
71
+ plta.cdl3linestrike().alias('CDL3LINESTRIKE'),
72
+ plta.cdl3outside().alias('CDL3OUTSIDE'),
73
+ plta.cdl3starsinsouth().alias('CDL3STARSINSOUTH'),
74
+ plta.cdl3whitesoldiers().alias('CDL3WHITESOLDIERS'),
75
+ plta.cdlabandonedbaby().alias('CDLABANDONEDBABY'),
76
+ plta.cdladvanceblock().alias('CDLADVANCEBLOCK'),
77
+ plta.cdlbelthold().alias('CDLBELTHOLD'),
78
+ plta.cdlbreakaway().alias('CDLBREAKAWAY'),
79
+ plta.cdlclosingmarubozu().alias('CDLCLOSINGMARUBOZU'),
80
+ plta.cdlconcealbabyswall().alias('CDLCONCEALBABYSWALL'),
81
+ plta.cdlcounterattack().alias('CDLCOUNTERATTACK'),
82
+ plta.cdldarkcloudcover().alias('CDLDARKCLOUDCOVER'),
83
+ plta.cdldoji().alias('CDLDOJI'),
84
+ plta.cdldojistar().alias('CDLDOJISTAR'),
85
+ plta.cdldragonflydoji().alias('CDLDRAGONFLYDOJI'),
86
+ plta.cdlengulfing().alias('CDLENGULFING'),
87
+ plta.cdleveningdojistar().alias('CDLEVENINGDOJISTAR'),
88
+ plta.cdleveningstar().alias('CDLEVENINGSTAR'),
89
+ plta.cdlgapsidesidewhite().alias('CDLGAPSIDESIDEWHITE'),
90
+ plta.cdlgravestonedoji().alias('CDLGRAVESTONEDOJI'),
91
+ plta.cdlhammer().alias('CDLHAMMER'),
92
+ plta.cdlhangingman().alias('CDLHANGINGMAN'),
93
+ plta.cdlharami().alias('CDLHARAMI'),
94
+ plta.cdlharamicross().alias('CDLHARAMICROSS'),
95
+ plta.cdlhighwave().alias('CDLHIGHWAVE'),
96
+ plta.cdlhikkake().alias('CDLHIKKAKE'),
97
+ plta.cdlhikkakemod().alias('CDLHIKKAKEMOD'),
98
+ plta.cdlhomingpigeon().alias('CDLHOMINGPIGEON'),
99
+ plta.cdlidentical3crows().alias('CDLIDENTICAL3CROWS'),
100
+ plta.cdlinneck().alias('CDLINNECK'),
101
+ plta.cdlinvertedhammer().alias('CDLINVERTEDHAMMER'),
102
+ plta.cdlkicking().alias('CDLKICKING'),
103
+ plta.cdlkickingbylength().alias('CDLKICKINGBYLENGTH'),
104
+ plta.cdlladderbottom().alias('CDLLADDERBOTTOM'),
105
+ plta.cdllongleggeddoji().alias('CDLLONGLEGGEDDOJI'),
106
+ plta.cdllongline().alias('CDLLONGLINE'),
107
+ plta.cdlmarubozu().alias('CDLMARUBOZU'),
108
+ plta.cdlmatchinglow().alias('CDLMATCHINGLOW'),
109
+ plta.cdlmathold().alias('CDLMATHOLD'),
110
+ plta.cdlmorningdojistar().alias('CDLMORNINGDOJISTAR'),
111
+ plta.cdlmorningstar().alias('CDLMORNINGSTAR'),
112
+ plta.cdlonneck().alias('CDLONNECK'),
113
+ plta.cdlpiercing().alias('CDLPIERCING'),
114
+ plta.cdlrickshawman().alias('CDLRICKSHAWMAN'),
115
+ plta.cdlrisefall3methods().alias('CDLRISEFALL3METHODS'),
116
+ plta.cdlseparatinglines().alias('CDLSEPARATINGLINES'),
117
+ plta.cdlshootingstar().alias('CDLSHOOTINGSTAR'),
118
+ plta.cdlshortline().alias('CDLSHORTLINE'),
119
+ plta.cdlspinningtop().alias('CDLSPINNINGTOP'),
120
+ plta.cdlstalledpattern().alias('CDLSTALLEDPATTERN'),
121
+ plta.cdlsticksandwich().alias('CDLSTICKSANDWICH'),
122
+ plta.cdltakuri().alias('CDLTAKURI'),
123
+ plta.cdltasukigap().alias('CDLTASUKIGAP'),
124
+ plta.cdlthrusting().alias('CDLTHRUSTING'),
125
+ plta.cdltristar().alias('CDLTRISTAR'),
126
+ plta.cdlunique3river().alias('CDLUNIQUE3RIVER'),
127
+ plta.cdlupsidegap2crows().alias('CDLUPSIDEGAP2CROWS'),
128
+ plta.cdlxsidegap3methods().alias('CDLXSIDEGAP3METHODS'),
129
+ plta.trange().alias('TRANGE'),
130
+ plta.adosc(fastperiod=3, slowperiod=10).alias('ADOSC'),
131
+ plta.roc(timeperiod=10).alias('ROC_10'),
132
+ plta.rocp(timeperiod=10).alias('ROCP_10'),
133
+ plta.rocr100(timeperiod=10).alias('ROCR100_10'),
134
+ plta.rsi(timeperiod=14).alias('RSI_14'),
135
+ plta.stochf(fastk_period=5, fastd_period=3, fastd_matype=0).alias('STOCHF'),
136
+ plta.stochrsi(timeperiod=14, fastk_period=5, fastd_period=3, fastd_matype=0).alias('STOCHRSI'),
137
+ plta.add(pl.col("high")).alias('ADD'),
138
+ plta.div(pl.col("high")).alias('DIV'),
139
+ plta.max(timeperiod=30).alias('MAX_30'),
140
+ plta.maxindex(timeperiod=30).alias('MAXINDEX_30'),
141
+ plta.min(timeperiod=30).alias('MIN_30'),
142
+ plta.minindex(timeperiod=30).alias('MININDEX_30'),
143
+ plta.minmax(timeperiod=30).alias('MINMAX_30'),
144
+ plta.minmaxindex(timeperiod=30).alias('MINMAXINDEX_30'),
145
+ plta.mult(pl.col("high")).alias('MULT'),
146
+ plta.sub(pl.col("high")).alias('SUB'),
147
+ plta.sum(timeperiod=30).alias('SUM_30'),
148
+ plta.acos().alias('ACOS'),
149
+ plta.asin().alias('ASIN'),
150
+ plta.atan().alias('ATAN'),
151
+ plta.ceil().alias('CEIL'),
152
+ plta.cos().alias('COS'),
153
+ plta.cosh().alias('COSH'),
154
+ plta.exp().alias('EXP'),
155
+ plta.floor().alias('FLOOR'),
156
+ plta.ln().alias('LN'),
157
+ plta.log10().alias('LOG10'),
158
+ plta.sin().alias('SIN'),
159
+ plta.sinh().alias('SINH'),
160
+ plta.sqrt().alias('SQRT'),
161
+ plta.tan().alias('TAN'),
162
+ plta.tanh().alias('TANH'),
163
+ plta.stddev(timeperiod=5).alias('STDDEV_5'),
164
+ ])
165
+
166
+ # Handle multi-value returns
167
+ df_group = df_group.with_columns([
168
+ pl.col('BBANDS').struct.field('upperband').alias('BBANDS_upper'),
169
+ pl.col('BBANDS').struct.field('middleband').alias('BBANDS_middle'),
170
+ pl.col('BBANDS').struct.field('lowerband').alias('BBANDS_lower'),
171
+ pl.col('MACD').struct.field('macd').alias('MACD_macd'),
172
+ pl.col('MACD').struct.field('macdsignal').alias('MACD_signal'),
173
+ pl.col('MACD').struct.field('macdhist').alias('MACD_hist'),
174
+ pl.col('STOCH').struct.field('slowk').alias('STOCH_slowk'),
175
+ pl.col('STOCH').struct.field('slowd').alias('STOCH_slowd'),
176
+ pl.col('AROON_14').struct.field('aroondown').alias('AROON_down'),
177
+ pl.col('AROON_14').struct.field('aroonup').alias('AROON_up'),
178
+ pl.col('HT_PHASOR').struct.field('inphase').alias('HT_PHASOR_inphase'),
179
+ pl.col('HT_PHASOR').struct.field('quadrature').alias('HT_PHASOR_quadrature'),
180
+ pl.col('HT_SINE').struct.field('sine').alias('HT_SINE_sine'),
181
+ pl.col('HT_SINE').struct.field('leadsine').alias('HT_SINE_leadsine'),
182
+ pl.col('MAMA').struct.field('mama').alias('MAMA_mama'),
183
+ pl.col('MAMA').struct.field('fama').alias('MAMA_fama'),
184
+ pl.col('STOCHF').struct.field('fastk').alias('STOCHF_fastk'),
185
+ pl.col('STOCHF').struct.field('fastd').alias('STOCHF_fastd'),
186
+ pl.col('STOCHRSI').struct.field('fastk').alias('STOCHRSI_fastk'),
187
+ pl.col('STOCHRSI').struct.field('fastd').alias('STOCHRSI_fastd'),
188
+ pl.col('MINMAX_30').struct.field('min').alias('MINMAX_30_min'),
189
+ pl.col('MINMAX_30').struct.field('max').alias('MINMAX_30_max'),
190
+ pl.col('MINMAXINDEX_30').struct.field('minidx').alias('MINMAXINDEX_30_minidx'),
191
+ pl.col('MINMAXINDEX_30').struct.field('maxidx').alias('MINMAXINDEX_30_maxidx'),
192
+ ])
193
+
194
+
195
+ # Drop the original struct columns
196
+ df_group = df_group.drop(['BBANDS', 'MACD', 'STOCH', 'AROON_14', 'HT_PHASOR', 'HT_SINE','MAMA','STOCHF','MINMAX_30','MINMAXINDEX_30'])
197
+
198
+ return df_group
199
+
200
+
201
+ def techn_indicators(df_price):
202
+ # Assuming df_polars is your initial DataFrame
203
+ df_polars = pl.from_pandas(df_price.reset_index())
204
+ df_polars = df_polars.group_by("ticker").map_groups(func_ts_date).to_pandas().set_index(["ticker","date"]).sort_index()
205
+
206
+ # List of columns to remove
207
+ columns_to_remove = [
208
+ 'OBV', 'AD', 'ADOSC', 'VAR_5', 'TRANGE',
209
+ 'STOCHRSI',
210
+ 'DIV', 'LN', 'LOG10',
211
+ 'COS',
212
+ 'EMA_20', 'MOM_10', 'AVGPRICE', 'MEDPRICE', 'TYPPRICE', 'WCLPRICE',
213
+ 'BETA_5', 'CORREL_30', 'LINEARREG_14', 'TSF_14', 'SAR', 'MAVP', 'SAREXT'
214
+ ]
215
+
216
+ # Remove problematic columns
217
+ df_polars = df_polars.drop(columns=[col for col in columns_to_remove if col in df_polars.columns])
218
+
219
+ return df_polars
@@ -21,7 +21,8 @@ import boto3
21
21
  from io import BytesIO
22
22
  import json
23
23
 
24
- # from fastapi import HTTPException
24
+ # from fastapi import HTTPException ## Dee
25
+
25
26
  import pyarrow.parquet as pq
26
27
  import time
27
28
  import hashlib
@@ -105,7 +106,104 @@ def read_parquet(
105
106
  return pl.read_parquet(url)
106
107
  else:
107
108
  return CustomDataFrame(pd.read_parquet(url))
109
+
108
110
 
111
+ import pandas as pd
112
+ from typing import Union, List
113
+
114
+ def filter_data(
115
+ data: Union[pd.DataFrame, 'pl.DataFrame'],
116
+ columns: Union[str, List[str]] = None,
117
+ start_date: str = None,
118
+ end_date: str = None,
119
+ use_polars: bool = False
120
+ ) -> Union[pd.DataFrame, 'pl.DataFrame']:
121
+ """
122
+ Filter the data based on specified columns and date range.
123
+ Always includes 'ticker', 'date', and 'calculation' columns if they exist in the original DataFrame.
124
+
125
+ :param data: Input DataFrame (pandas or polars)
126
+ :param columns: Columns to select (string or list of strings)
127
+ :param start_date: Start date for filtering (string in 'YYYY-MM-DD' format)
128
+ :param end_date: End date for filtering (string in 'YYYY-MM-DD' format)
129
+ :param use_polars: Boolean indicating whether to use polars instead of pandas
130
+ :return: Filtered DataFrame
131
+ """
132
+ if use_polars:
133
+ import polars as pl
134
+
135
+ # Prepare columns list
136
+ if columns:
137
+ if isinstance(columns, str):
138
+ columns = columns.split(',')
139
+ columns = [col.strip() for col in columns]
140
+ else:
141
+ columns = data.columns.to_list()
142
+
143
+ # Always include 'ticker', 'date', and 'calculation' if they exist
144
+ for col in ['calculation', 'date', 'ticker']:
145
+ if col in data.columns and col not in columns:
146
+ columns.insert(0, col)
147
+
148
+ # Column filtering
149
+ data = data.select(columns)
150
+
151
+ # Date filtering
152
+ if start_date or end_date:
153
+ if 'date' in data.columns:
154
+ if start_date:
155
+ data = data.filter(pl.col('date') >= pl.Date.parse(start_date))
156
+ if end_date:
157
+ data = data.filter(pl.col('date') <= pl.Date.parse(end_date))
158
+ else:
159
+ # Assume date is in index if not in columns
160
+ data = data.with_row_count('temp_index')
161
+ if start_date:
162
+ data = data.filter(pl.col('temp_index').cast(pl.Date) >= pl.Date.parse(start_date))
163
+ if end_date:
164
+ data = data.filter(pl.col('temp_index').cast(pl.Date) <= pl.Date.parse(end_date))
165
+ data = data.drop('temp_index')
166
+
167
+ else:
168
+ # Prepare columns list
169
+ if columns:
170
+ if isinstance(columns, str):
171
+ columns = columns.split(',')
172
+ columns = [col.strip() for col in columns]
173
+ else:
174
+ columns = list(data.columns)
175
+
176
+ # Always include 'ticker', 'date', and 'calculation' if they exist
177
+ for col in ['calculation', 'date', 'ticker']:
178
+ if col in data.columns and col not in columns:
179
+ columns.insert(0, col)
180
+
181
+ # Column filtering
182
+ data = data[columns]
183
+
184
+ if start_date or end_date:
185
+ if 'date' in data.columns:
186
+ data['date'] = pd.to_datetime(data['date'])
187
+ if start_date:
188
+ data = data[data['date'] >= pd.to_datetime(start_date)]
189
+ if end_date:
190
+ data = data[data['date'] <= pd.to_datetime(end_date)]
191
+ elif isinstance(data.index, pd.DatetimeIndex):
192
+ if start_date:
193
+ data = data[data.index >= pd.to_datetime(start_date)]
194
+ if end_date:
195
+ data = data[data.index <= pd.to_datetime(end_date)]
196
+ elif isinstance(data.index, pd.MultiIndex) and any(isinstance(level, pd.DatetimeIndex) for level in data.index.levels):
197
+ date_level = next(level for level in data.index.levels if isinstance(level, pd.DatetimeIndex))
198
+ if start_date:
199
+ data = data[data.index.get_level_values(date_level.name) >= pd.to_datetime(start_date)]
200
+ if end_date:
201
+ data = data[data.index.get_level_values(date_level.name) <= pd.to_datetime(end_date)]
202
+ else:
203
+ print("Warning: Unable to filter by date. Date column or index not found.")
204
+
205
+
206
+ return data
109
207
 
110
208
  # Global cache
111
209
  _query_cache = {}
@@ -115,6 +213,9 @@ _query_cache = {}
115
213
  ## None means no ticker. "" Mean ticker but on parquet for all.
116
214
 
117
215
  endpoint_to_ticker = {
216
+ "/risks": "",
217
+ "/government/traffic/domains": "",
218
+ "/government/traffic/agencies": "",
118
219
  "/risks": "",
119
220
  "/bankruptcy": "",
120
221
  "/bankruptcy/shapleys": "",
@@ -172,7 +273,10 @@ endpoint_to_ticker = {
172
273
  "/complaints/public": "",
173
274
  "/short/over_shorted": "",
174
275
  "/earnings/surprise": "",
175
- "/market/closeadj": "",
276
+ "/news/sentiment_score": "",
277
+ "/news/topic_probability": "",
278
+ "/news/polarity_score": "",
279
+
176
280
  }
177
281
 
178
282
  ## There are give types of file retrievals
@@ -375,17 +479,24 @@ def data(
375
479
  _query_cache[cache_key] = data
376
480
  return data
377
481
 
482
+
483
+ # Example usage in your existing code:
378
484
  if is_all(tickers):
379
485
  verbose_mode.vprint("All ticker Initialized")
380
486
  url = res.text.strip('"')
381
487
  verbose_mode.vprint(url, " (download link)")
382
488
  data = read_parquet(url, use_polars=use_polars)
383
- _query_cache[cache_key] = data
384
- return data
489
+
490
+ # Apply filters
491
+ data = filter_data(data, columns=columns, start_date=start_date, end_date=end_date, use_polars=use_polars)
385
492
 
386
493
  verbose_mode.vprint("It reached the DF")
387
- data = CustomDataFrame(convert_data2df(res.json()))
388
- _query_cache[cache_key] = data
494
+ try:
495
+ data = CustomDataFrame(convert_data2df(res.json()))
496
+ _query_cache[cache_key] = data
497
+ except:
498
+ _query_cache[cache_key] = data
499
+
389
500
  verbose_mode.vprint("It passed the DF")
390
501
 
391
502
  if plot:
@@ -394,6 +505,7 @@ def data(
394
505
  return data
395
506
  except Exception as err:
396
507
  verbose_mode.vprint("An error occurred:", err)
508
+ return data
397
509
  if res.status_code == 404:
398
510
  msg = res.json()
399
511
  msg.update({"status_code": 404, "error": err.args[0]})
@@ -401,160 +513,6 @@ def data(
401
513
  return None
402
514
 
403
515
 
404
- # def print_tickers_value(tickers):
405
- # if tickers is None:
406
- # print("tickers is None")
407
- # elif tickers is False:
408
- # print("tickers is False")
409
- # else:
410
- # print(f"tickers is: {tickers}")
411
-
412
- # # Example usage
413
-
414
- # def data(
415
- # endpoint: str,
416
- # tickers: Union[str, list, None] = None,
417
- # chart: Optional[str] = None,
418
- # columns_name: Optional[str] = None,
419
- # version: Optional[str] = None,
420
- # start_date: Optional[str] = None,
421
- # end_date: Optional[str] = None,
422
- # predict: bool = False,
423
- # plot: bool = False,
424
- # rows: Optional[int] = None,
425
- # limit: Optional[int] = None,
426
- # params: Optional[dict] = None,
427
- # body: Optional[dict] = None,
428
- # use_polars: bool = False,
429
- # purge_cache: bool = False,
430
- # parquet: bool = True,
431
- # ) -> Union[pd.DataFrame, None]:
432
- # params = params or {}
433
- # params.update(
434
- # _prepare_params(
435
- # tickers=tickers,
436
- # chart=chart,
437
- # version=version,
438
- # from_date=start_date,
439
- # to_date=end_date,
440
- # limit=rows or limit,
441
- # predict=predict,
442
- # columns=columns_name,
443
- # )
444
- # )
445
- # endpoint, params = _prepare_endpoint(endpoint, params)
446
- # print(endpoint)
447
- # params = params or None
448
- # headers = {"Authorization": f"Bearer {ApiConfig.token}"}
449
- # url = ApiConfig.base_url + endpoint
450
-
451
- # print(f"Requesting URL: {url} with params: {params}")
452
-
453
- # # Create a unique cache key
454
- # cache_key = hashlib.sha256(json.dumps([url, params], sort_keys=True).encode()).hexdigest()
455
-
456
- # # Check if the result is already in the cache
457
- # # Purge cache if requested
458
- # if purge_cache and cache_key in _query_cache:
459
- # del _query_cache[cache_key]
460
- # print("Cache entry purged.")
461
-
462
- # # Check if the result is already in the cache
463
- # if not purge_cache and cache_key in _query_cache:
464
- # print("Returning cached data")
465
- # return _query_cache[cache_key]
466
-
467
- # try:
468
- # res = requests.get(
469
- # url=url,
470
- # headers=headers,
471
- # data=body,
472
- # params=params,
473
- # stream=True,
474
- # verify=ApiConfig.verify_ssl,
475
- # )
476
- # res.raise_for_status()
477
- # print(f"Response Status: {res.status_code}")
478
- # print(f"Response Content-Type: {res.headers.get('content-type')}")
479
-
480
- # # Print a small part of the response for preview
481
- # # response_preview = res.text[:2] # Adjust the number of characters as needed
482
- # # print(f"Response Preview: {response_preview}")
483
- # print_tickers_value(tickers)
484
-
485
- # print(params)
486
-
487
- # # print("Before check..")
488
- # # print(is_all(tickers))
489
- # # if is_all(tickers):
490
- # # response_dict = res.json()
491
- # # print("this is loading parquet")
492
- # # # Assuming response_dict is a dictionary containing the required keys
493
- # # print("Bucket Name:", response_dict["bucket_name"])
494
- # # print("File Name:", response_dict["file_name"])
495
- # # print("Access Key:", response_dict["access_key"])
496
- # # print("Secret Key:", response_dict["secret_key"])
497
-
498
- # # return load_df_from_wasabi(response_dict["bucket_name"], response_dict["file_name"], response_dict["access_key"], response_dict["secret_key"])
499
-
500
- # tickers = get_ticker_from_endpoint(endpoint, tickers, endpoint_to_ticker)
501
-
502
- # print_tickers_value(tickers)
503
-
504
-
505
- # data_format = res.headers.get("X-Data-Format")
506
- # content_type = res.headers["content-type"]
507
-
508
- # if content_type == "application/octet-stream":
509
- # if data_format == "pyarrow":
510
- # data = CustomDataFrame(stream_data_pyarrow(res))
511
- # else:
512
- # data = CustomDataFrame(stream_data(res))
513
- # _query_cache[cache_key] = data
514
- # return data
515
-
516
-
517
- # if is_all(tickers):
518
- # print("All ticker Initialized")
519
- # url = res.text.strip('"')
520
- # print(url, " (download link)", )
521
- # data = read_parquet(url, use_polars=use_polars)
522
- # _query_cache[cache_key] = data
523
-
524
- # return data
525
-
526
-
527
- # print("It reached the DF")
528
- # data = CustomDataFrame(convert_data2df(res.json()))
529
- # _query_cache[cache_key] = data
530
- # print("It passsed the DF")
531
-
532
- # if plot:
533
- # _draw_graphs(data)
534
- # return None
535
- # return data
536
- # except Exception as err:
537
- # print("An error occurred:", err)
538
- # if res.status_code == 404:
539
- # msg = res.json()
540
- # msg.update({"status_code": 404, "error": err.args[0]})
541
- # raise InvalidInputData(str(msg))
542
- # return None
543
-
544
-
545
- # def _prepare_params(**kwargs):
546
- # finish_params = {}
547
- # if isinstance(kwargs["tickers"], list):
548
- # kwargs["tickers"] = ",".join(kwargs["tickers"])
549
- # if isinstance(kwargs["columns"], list):
550
- # kwargs["columns"] = ",".join(kwargs["columns"])
551
- # for server_param, client_param in kwargs.items():
552
- # if client_param:
553
- # finish_params[server_param] = str(client_param)
554
-
555
- # return finish_params
556
-
557
-
558
516
  def _prepare_params(**kwargs):
559
517
  finish_params = {}
560
518
 
@@ -5,11 +5,12 @@ from .plots.breakout.breakout_plots import *
5
5
  from .plots.accounting.accounting_plots import *
6
6
  from .plots.ratios.ratios_plots import *
7
7
  from .plots.institutional.institutional_plots import *
8
- from .plots.news.news_plots import *
8
+ from .plots.news.news_plots import plot_news_daily, create_plot_news_sent_price, plot_above_sentiment_returns, run_dash_news_ts
9
9
  from .plots.corp_risk.corp_risk_plots import *
10
10
 
11
11
  from .plots.insider.insider_plots import *
12
12
  from .plots.allocation.allocation_plots import *
13
+ from .plots.earnings_surprise.earnings_surprise_plots import *
13
14
 
14
15
  from sovai.utils.plot import plotting_data
15
16
  from typing import Optional, Union, Tuple, List, Dict
@@ -70,6 +71,7 @@ def generate_error_message(analysis_type, chart_type, source, verbose):
70
71
  else:
71
72
  display(Markdown("**An unknown error occurred.**"))
72
73
 
74
+ ##
73
75
 
74
76
  plot_ticker_widget
75
77
 
@@ -110,9 +112,15 @@ PLOT_FUNCTION_MAPPER = {
110
112
  ("insider", "flows", "local"): insider_flows_plot,
111
113
  ("insider", "prediction", "local"): insider_flow_predictions_plot,
112
114
  ("news", "sentiment", "local"): plot_above_sentiment_returns,
115
+ ("news", "strategy", "local"): plot_news_daily,
116
+ ("news", "analysis", "local"): run_dash_news_ts,
113
117
  ("corprisk/risks", "line", "local"): plotting_corp_risk_line,
114
118
  ("allocation", "line", "local"): create_line_plot_allocation,
115
119
  ("allocation", "stacked", "local"): create_stacked_bar_plot_allocation,
120
+ ("earnings", "line", "local"): create_earnings_surprise_plot,
121
+
122
+
123
+
116
124
 
117
125
  # Add other mappings as needed
118
126
  }
@@ -120,7 +128,7 @@ PLOT_FUNCTION_MAPPER = {
120
128
 
121
129
  def plot(
122
130
  dataset_name,
123
- chart_type="line",
131
+ chart_type=None,
124
132
  df=None,
125
133
  tickers: Optional[List[str]] = None,
126
134
  verbose=False,