sovai 0.2.65__tar.gz → 0.2.67__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 (107) hide show
  1. {sovai-0.2.65 → sovai-0.2.67}/PKG-INFO +1 -1
  2. {sovai-0.2.65 → sovai-0.2.67}/pyproject.toml +1 -1
  3. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data.py +9 -0
  4. sovai-0.2.67/sovai/get_plots.py +362 -0
  5. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_reports.py +27 -16
  6. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/accounting/accounting_plots.py +3 -2
  7. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/news/news_plots.py +5 -3
  8. sovai-0.2.67/sovai/reports/accounting/accounting_balance_sheet.py +321 -0
  9. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side_s3_part_high.py +3 -3
  10. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/port_manager.py +3 -3
  11. sovai-0.2.65/sovai/get_plots.py +0 -311
  12. sovai-0.2.65/sovai/reports/accounting/accounting_balance_sheet.py +0 -306
  13. {sovai-0.2.65 → sovai-0.2.67}/LICENSE +0 -0
  14. {sovai-0.2.65 → sovai-0.2.67}/README.md +0 -0
  15. {sovai-0.2.65 → sovai-0.2.67}/data/codes.parq +0 -0
  16. {sovai-0.2.65 → sovai-0.2.67}/data/tickers.parq +0 -0
  17. {sovai-0.2.65 → sovai-0.2.67}/sovai/.DS_Store +0 -0
  18. {sovai-0.2.65 → sovai-0.2.67}/sovai/__init__.py +0 -0
  19. {sovai-0.2.65 → sovai-0.2.67}/sovai/api_config.py +0 -0
  20. {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/dropdown.css +0 -0
  21. {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/features_mapping.parq +0 -0
  22. {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/tickers.parq +0 -0
  23. {sovai-0.2.65 → sovai-0.2.67}/sovai/basic_auth.py +0 -0
  24. {sovai-0.2.65 → sovai-0.2.67}/sovai/computations/__init__.py +0 -0
  25. {sovai-0.2.65 → sovai-0.2.67}/sovai/computations/functions.py +0 -0
  26. {sovai-0.2.65 → sovai-0.2.67}/sovai/errors/__init__.py +0 -0
  27. {sovai-0.2.65 → sovai-0.2.67}/sovai/errors/sovai_errors.py +0 -0
  28. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/__init__.py +0 -0
  29. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/anomalies.py +0 -0
  30. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/ask_df_llm.py +0 -0
  31. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/change_point_generator copy.py +0 -0
  32. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/change_point_generator.py +0 -0
  33. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/clustering.py +0 -0
  34. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/core_kshape.py +0 -0
  35. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/cum_sum_torch.py +0 -0
  36. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/cusum.py +0 -0
  37. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/dimensionality_reduction.py +0 -0
  38. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_extraction.py +0 -0
  39. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_importance.py +0 -0
  40. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_neutralizer.py +0 -0
  41. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/filter_df.py +0 -0
  42. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/fractional_differencing.py +0 -0
  43. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/nowcasting.py +0 -0
  44. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pairwise.py +0 -0
  45. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pandas_extensions.py +0 -0
  46. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/parallel_functions.py +0 -0
  47. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pfa_feature_selector.py +0 -0
  48. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/regime_change.py +0 -0
  49. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/regime_change_pca.py +0 -0
  50. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/shapley_global_importance.py +0 -0
  51. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/shapley_importance.py +0 -0
  52. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/signal_evaluation.py +0 -0
  53. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/technical_indicators.py +0 -0
  54. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/time_decomposition.py +0 -0
  55. {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/weight_optimization.py +0 -0
  56. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_compute.py +0 -0
  57. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data copy 2.py +0 -0
  58. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data copy.py +0 -0
  59. {sovai-0.2.65 → sovai-0.2.67}/sovai/get_tools.py +0 -0
  60. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/__init__.py +0 -0
  61. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/accounting/__init__.py +0 -0
  62. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/allocation/__init__.py +0 -0
  63. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/allocation/allocation_plots.py +0 -0
  64. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/bankruptcy/__init__.py +0 -0
  65. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  66. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/breakout/__init__.py +0 -0
  67. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/breakout/breakout_plots.py +0 -0
  68. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/corp_risk/__init__.py +0 -0
  69. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  70. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/earnings_surprise/__init__.py +0 -0
  71. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  72. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/insider/__init__.py +0 -0
  73. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/insider/insider_plots.py +0 -0
  74. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/institutional/__init__.py +0 -0
  75. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/institutional/institutional_plots.py +0 -0
  76. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/news/__init__.py +0 -0
  77. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/ratios/__init__.py +0 -0
  78. {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/ratios/ratios_plots.py +0 -0
  79. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/accounting/__init__.py +0 -0
  80. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/bankruptcy/__init__.py +0 -0
  81. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  82. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/general/__init__.py +0 -0
  83. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/general/general_plots.py +0 -0
  84. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/news/__inti__.py +0 -0
  85. {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/news/news_econometric_analysis.py +0 -0
  86. {sovai-0.2.65 → sovai-0.2.67}/sovai/studies/nowcasting.py +0 -0
  87. {sovai-0.2.65 → sovai-0.2.67}/sovai/token_auth.py +0 -0
  88. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/authentication/__init__.py +0 -0
  89. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/authentication/authentication.py +0 -0
  90. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/__init__.py +0 -0
  91. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/graphs.py +0 -0
  92. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/llm_code_generator.py +0 -0
  93. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  94. {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/sec_edgar_search.py +0 -0
  95. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/__init__.py +0 -0
  96. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side.py +0 -0
  97. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side_s3.py +0 -0
  98. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/converter.py +0 -0
  99. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/datetime_formats.py +0 -0
  100. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/file_management.py +0 -0
  101. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/get_tickers.py +0 -0
  102. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/helpers.py +0 -0
  103. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/pandas_extensions copy.py +0 -0
  104. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/plot.py +0 -0
  105. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/port_manager copy.py +0 -0
  106. {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/stream.py +0 -0
  107. {sovai-0.2.65 → sovai-0.2.67}/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.65
3
+ Version: 0.2.67
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.65"
7
+ version = "0.2.67"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -493,7 +493,14 @@ ENDPOINT_ALIASES = {
493
493
  'trial_id', 'official_title', 'success_prediction',
494
494
  'economic_effect', 'duration_prediction', 'success_composite'
495
495
  ]
496
+ },
497
+ "insider/flow_prediction": {
498
+ "target_endpoint": "insider/trading",
499
+ "columns": [
500
+ 'flow_prediction'
501
+ ]
496
502
  }
503
+
497
504
  # --- Add other aliases here in the future ---
498
505
  # "some/alias": {
499
506
  # "target_endpoint": "real/endpoint",
@@ -502,6 +509,8 @@ ENDPOINT_ALIASES = {
502
509
  }
503
510
 
504
511
 
512
+
513
+
505
514
  # Define handlers for different endpoint types
506
515
  ENDPOINT_HANDLERS = [
507
516
  (CLIENT_SIDE_ENDPOINTS_GCS, client_side_frame, "Grabbing GCS client side"),
@@ -0,0 +1,362 @@
1
+ # Inside plot/get_plot.py
2
+ import inspect # Still useful for one specific check
3
+
4
+ # --- Top Level Imports (Keep lightweight) ---
5
+ from typing import Optional, Union, Tuple, List, Dict
6
+ import importlib # Needed for dynamic imports
7
+ # Keep pandas/plotly config at top level as they modify global state
8
+ import pandas as pd
9
+ import plotly.io as pio
10
+
11
+ # --- Global Settings ---
12
+ # Changing the default plotting backend to Plotly
13
+ # Ensure pandas is imported before using pd.options
14
+ pd.options.plotting.backend = "plotly"
15
+ pd.set_option("display.max_columns", None)
16
+ # Setting the default theme for Plotly to a dark mode
17
+ pio.templates.default = "plotly_dark"
18
+
19
+
20
+ # --- Helper Functions (Potentially moved or kept if simple) ---
21
+
22
+ def enable_plotly_in_cell():
23
+ # Lazy load IPython and plotly offline here
24
+ try:
25
+ import IPython
26
+ from IPython.display import display, HTML
27
+ from plotly.offline import init_notebook_mode
28
+
29
+ display(
30
+ HTML(
31
+ """<script src="/static/components/requirejs/require.js"></script>"""
32
+ )
33
+ )
34
+ init_notebook_mode(connected=False)
35
+ except ImportError:
36
+ print("Warning: IPython or plotly offline not available. Plotly may not render correctly in this environment.")
37
+
38
+
39
+ def _draw_graphs(data: Union[Dict, List[Dict]]):
40
+ """Helper to draw graphs from database results (if structure is consistent)."""
41
+ # Lazy load the actual plotting utility if needed
42
+ from sovai.utils.plot import plotting_data # Assuming this utility exists
43
+ if isinstance(data, list):
44
+ for plot_dict in data:
45
+ if isinstance(plot_dict, dict):
46
+ for _, val in plot_dict.items():
47
+ return plotting_data(val) # Plot first one found
48
+ elif isinstance(data, dict):
49
+ for _, val in data.items():
50
+ return plotting_data(val) # Plot first one found
51
+ else:
52
+ print(f"Warning: _draw_graphs received unexpected data type: {type(data)}")
53
+ return None
54
+
55
+
56
+ def generate_error_message(analysis_type, chart_type, source, verbose):
57
+ """Generates error message, potentially displaying Markdown."""
58
+ try:
59
+ from IPython.display import display, Markdown
60
+ if source == "local":
61
+ code_snippet = (
62
+ f"# Ensure sovai is imported, e.g., import sovai as sov\n"
63
+ f"dataset = sov.data('{analysis_type}/monthly') # Or appropriate frequency\n"
64
+ f"if dataset is not None and not dataset.empty:\n"
65
+ f" sov.plot('{analysis_type}', chart_type='{chart_type}', df=dataset)\n"
66
+ f"else:\n"
67
+ f" print('Failed to fetch data.')"
68
+ )
69
+ message = (
70
+ f"**Input DataFrame `df` is empty or None.** Please provide a valid DataFrame.\n"
71
+ f"If you intended to fetch data first, you could use:\n\n"
72
+ f"```python\n{code_snippet}\n```"
73
+ )
74
+ if verbose: # Only display if verbose is True
75
+ display(Markdown(message))
76
+ return "" # Return empty string as add_text no longer used this way
77
+ else:
78
+ display(Markdown("**An unknown error occurred.**")) # This part might be too generic
79
+ return ""
80
+ except ImportError:
81
+ # Fallback for non-IPython environments
82
+ text_message = ""
83
+ if source == "local":
84
+ text_message = f"Input DataFrame `df` is empty or None. Please fetch data first (e.g., using sov.data(...))."
85
+ else:
86
+ text_message = "An unknown error occurred."
87
+ if verbose: # Print simple text if verbose and IPython not available
88
+ print(text_message)
89
+ return ""
90
+
91
+
92
+ # --- Plot Function Mapper ---
93
+ PLOT_FUNCTION_MAPPER = {
94
+ # (dataset_name, chart_type, source, full_history_flag_or_None) : (module_path, function_name)
95
+ ("breakout", "predictions", "local", True): (".plots.breakout.breakout_plots", "get_predict_breakout_plot_for_ticker"),
96
+ ("breakout", "accuracy", "local", True): (".plots.breakout.breakout_plots", "interactive_plot_display_breakout_accuracy"),
97
+ ("accounting/weekly", "balance", "local", False): (".plots.accounting.accounting_plots", "get_balance_sheet_tree_plot_for_ticker"),
98
+ ("accounting", "cashflows", "local", True): (".plots.accounting.accounting_plots", "plot_cash_flows"),
99
+ ("accounting", "assets", "local", True): (".plots.accounting.accounting_plots", "plot_assets"),
100
+ ("ratios", "relative", "local", True): (".plots.ratios.ratios_plots", "plot_ratios_triple"),
101
+ ("ratios", "benchmark", "local", True): (".plots.ratios.ratios_plots", "plot_ratios_benchmark"),
102
+ ("institutional", "flows", "local", True): (".plots.institutional.institutional_plots", "institutional_flows_plot"),
103
+ ("institutional", "prediction", "local", True): (".plots.institutional.institutional_plots", "institutional_flow_predictions_plot"),
104
+ ("insider", "percentile", "local", True): (".plots.insider.insider_plots", "create_parallel_coordinates_plot_single_ticker"),
105
+ ("insider", "flows", "local", True): (".plots.insider.insider_plots", "insider_flows_plot"),
106
+ ("insider", "prediction", "local", True): (".plots.insider.insider_plots", "insider_flow_predictions_plot"),
107
+ ("news", "sentiment", "local", True): (".plots.news.news_plots", "plot_above_sentiment_returns"),
108
+ ("news", "strategy", "local", True): (".plots.news.news_plots", "plot_news_daily"),
109
+ ("news", "analysis", "local", True): (".plots.news.news_plots", "run_dash_news_ts"),
110
+ ("corprisk/risks", "line", "local", True): (".plots.corp_risk.corp_risk_plots", "plotting_corp_risk_line"),
111
+ ("allocation", "line", "local", True): (".plots.allocation.allocation_plots", "create_line_plot_allocation"),
112
+ ("allocation", "stacked", "local", True): (".plots.allocation.allocation_plots", "create_stacked_bar_plot_allocation"),
113
+ ("earnings/surprise", "line", "local", True): (".plots.earnings_surprise.earnings_surprise_plots", "create_earnings_surprise_plot"),
114
+ ("earnings/surprise", "tree", "local", True): (".plots.earnings_surprise.earnings_surprise_plots", "earnings_tree"),
115
+ ("bankruptcy", "compare", "local", True): (".plots.bankruptcy.bankruptcy_plots", "plot_bankruptcy_monthly_line"),
116
+ ("bankruptcy", "pca_clusters", "local", True): (".plots.bankruptcy.bankruptcy_plots", "plot_pca_clusters"),
117
+ ("bankruptcy", "predictions", "local", True): (".plots.bankruptcy.bankruptcy_plots", "plot_ticker_widget"),
118
+
119
+ # Database plots use the local _draw_graphs helper
120
+ ("bankruptcy", "shapley", "database"): (None, "_draw_graphs"),
121
+ ("bankruptcy", "pca", "database"): (None, "_draw_graphs"),
122
+ ("bankruptcy", "line", "database"): (None, "_draw_graphs"),
123
+ ("bankruptcy", "similar", "database"): (None, "_draw_graphs"),
124
+ ("bankruptcy", "facet", "database"): (None, "_draw_graphs"),
125
+ ("bankruptcy", "stack", "database"): (None, "_draw_graphs"),
126
+ ("bankruptcy", "box", "database"): (None, "_draw_graphs"),
127
+ ("bankruptcy", "waterfall", "database"): (None, "_draw_graphs"),
128
+ ("bankruptcy", "pca_relation", "database"): (None, "_draw_graphs"),
129
+ ("bankruptcy", "line_relation", "database"): (None, "_draw_graphs"),
130
+ ("bankruptcy", "facet_relation", "database"): (None, "_draw_graphs"),
131
+ ("bankruptcy", "time_global", "database"): (None, "_draw_graphs"),
132
+ ("bankruptcy", "stack_global", "database"): (None, "_draw_graphs"),
133
+ ("bankruptcy", "box_global", "database"): (None, "_draw_graphs"),
134
+ ("bankruptcy", "waterfall_global", "database"): (None, "_draw_graphs"),
135
+ ("bankruptcy", "confusion_global", "database"): (None, "_draw_graphs"),
136
+ ("bankruptcy", "classification_global", "database"): (None, "_draw_graphs"),
137
+ ("bankruptcy", "precision_global", "database"): (None, "_draw_graphs"),
138
+ ("bankruptcy", "lift_global", "database"): (None, "_draw_graphs"),
139
+ }
140
+
141
+
142
+ # --- Main Plot Function ---
143
+
144
+ def plot(
145
+ dataset_name,
146
+ chart_type=None,
147
+ df=None,
148
+ tickers: Optional[List[str]] = None,
149
+ ticker: Optional[str] = None,
150
+ verbose=False,
151
+ purge_cache=False,
152
+ **kwargs, # These are kwargs passed to the main sov.plot() call
153
+ ):
154
+ """
155
+ Generates plots based on dataset name and chart type.
156
+ Lazily loads required plotting modules.
157
+ """
158
+ from sovai import data as sovai_data
159
+
160
+ # Consolidate ticker/tickers from sov.plot() into lookup_tickers for sovai_data
161
+ # and also ensure they are present in kwargs for the plot_function if needed.
162
+ if ticker is not None:
163
+ if isinstance(ticker, str):
164
+ lookup_tickers = [ticker]
165
+ kwargs['ticker'] = ticker # Ensure 'ticker' is in kwargs for plot_func
166
+ elif isinstance(ticker, list):
167
+ lookup_tickers = ticker
168
+ if len(ticker) == 1: # If plot_func expects single 'ticker'
169
+ kwargs['ticker'] = ticker[0]
170
+ # If plot_func expects 'tickers' (list), it should already be in kwargs if passed as 'tickers='
171
+ else: # Should not happen
172
+ lookup_tickers = None
173
+ elif tickers is not None:
174
+ if isinstance(tickers, str):
175
+ lookup_tickers = [tickers]
176
+ kwargs['tickers'] = [tickers] # Ensure 'tickers' list is in kwargs
177
+ elif isinstance(tickers, list):
178
+ lookup_tickers = tickers
179
+ kwargs['tickers'] = tickers
180
+ else: # Should not happen
181
+ lookup_tickers = None
182
+ else:
183
+ lookup_tickers = None
184
+
185
+ enable_plotly_in_cell()
186
+
187
+ plot_info = None; source = None; full_history = None
188
+ key_local_4 = (dataset_name, chart_type, "local", True)
189
+ key_local_3 = (dataset_name, chart_type, "local", False)
190
+ key_db_3 = (dataset_name, chart_type, "database")
191
+
192
+ if key_local_4 in PLOT_FUNCTION_MAPPER:
193
+ source = "local"; full_history = True; plot_info = PLOT_FUNCTION_MAPPER[key_local_4]
194
+ elif key_local_3 in PLOT_FUNCTION_MAPPER:
195
+ source = "local"; full_history = False; plot_info = PLOT_FUNCTION_MAPPER[key_local_3]
196
+ elif key_db_3 in PLOT_FUNCTION_MAPPER:
197
+ source = "database"; plot_info = PLOT_FUNCTION_MAPPER[key_db_3]
198
+ else:
199
+ key_local_any_hist = (dataset_name, chart_type, "local")
200
+ possible_keys = [k for k in PLOT_FUNCTION_MAPPER if k[:3] == key_local_any_hist]
201
+ if possible_keys:
202
+ matched_key = possible_keys[0]
203
+ source = "local"; full_history = matched_key[3]; plot_info = PLOT_FUNCTION_MAPPER[matched_key]
204
+ else:
205
+ raise ValueError(f"Plotting function for dataset='{dataset_name}' with chart_type='{chart_type}' not found.")
206
+
207
+ module_path, function_name = plot_info
208
+
209
+ plot_function = None
210
+ if module_path:
211
+ try:
212
+ imported_module = importlib.import_module(module_path, package=__package__)
213
+ plot_function = getattr(imported_module, function_name)
214
+ except ImportError as e:
215
+ raise ImportError(f"Could not import plotting module '{module_path}' relative to {__package__}: {e}")
216
+ except AttributeError:
217
+ raise AttributeError(f"Function '{function_name}' not found in module '{module_path}'.")
218
+ elif function_name == "_draw_graphs":
219
+ plot_function = _draw_graphs
220
+ else:
221
+ raise ValueError(f"Invalid plot_info found in mapper: {plot_info} for {dataset_name}, {chart_type}")
222
+
223
+ if source == "local":
224
+ data_to_plot = df # User-provided DataFrame
225
+
226
+ # --- Conditional Data Fetching ---
227
+ # Check if the plot function seems to handle its own data via 'ticker' or 'tickers' params
228
+ # and if it doesn't explicitly take 'df' or a generic first positional for data.
229
+ skip_prefetch = False
230
+ try:
231
+ sig = inspect.signature(plot_function)
232
+ param_names = set(sig.parameters.keys())
233
+ # Heuristic: if it takes 'ticker' or 'tickers' but NOT 'df' or 'data' (common df names)
234
+ # AND doesn't seem to take a generic first positional argument for data (e.g. only has keyword args)
235
+ has_ticker_arg = 'ticker' in param_names or 'tickers' in param_names
236
+ has_df_arg = 'df' in param_names or 'data' in param_names or 'data_df' in param_names
237
+
238
+ first_param = next(iter(sig.parameters.values()), None)
239
+ is_first_pos_for_data = first_param and \
240
+ (first_param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD or \
241
+ first_param.kind == inspect.Parameter.POSITIONAL_ONLY) and \
242
+ first_param.name not in ('ticker', 'tickers') # Not 'ticker' itself
243
+
244
+ if has_ticker_arg and not has_df_arg and not is_first_pos_for_data :
245
+ skip_prefetch = True
246
+ if verbose: print(f"Plot function '{function_name}' seems to manage its own data via ticker/tickers; skipping dispatcher prefetch.")
247
+ except ValueError: # Built-in functions might not have inspectable signatures
248
+ pass # Proceed with default prefetch
249
+
250
+ if not skip_prefetch and (data_to_plot is None or data_to_plot.empty):
251
+ if verbose:
252
+ generate_error_message(dataset_name, chart_type, source, verbose)
253
+ print(f"Attempting to fetch data for {dataset_name} (tickers: {lookup_tickers}, full_history: {full_history})...")
254
+ try:
255
+ fetched_data = sovai_data(dataset_name, tickers=lookup_tickers, full_history=full_history)
256
+ if fetched_data is not None and not fetched_data.empty:
257
+ data_to_plot = fetched_data
258
+ if verbose: print(f"Successfully fetched data for {dataset_name}.")
259
+ else:
260
+ if verbose: print(f"Failed to fetch data or fetched empty data for {dataset_name}.")
261
+ except Exception as e:
262
+ if verbose: print(f"Error fetching data for {dataset_name}: {e}")
263
+
264
+ # --- Call plot function with refined try-except ---
265
+ try:
266
+ if verbose: print(f"Calling plot function '{function_name}'.")
267
+ return plot_function(data_to_plot, **kwargs)
268
+ except TypeError as te:
269
+ # Handle 0-argument function error
270
+ is_zero_arg_error = (
271
+ "takes 0 positional arguments" in str(te) and
272
+ "1 was given" in str(te)
273
+ )
274
+ if is_zero_arg_error:
275
+ if verbose: print(f"TypeError (0-arg): Retrying {function_name} with only kwargs.")
276
+ try:
277
+ return plot_function(**kwargs) # Retry with only kwargs
278
+ except Exception as e_fallback:
279
+ print(f"Original TypeError (0-arg) with {function_name}: {te}")
280
+ print(f"Error in 0-arg fallback for '{function_name}': {e_fallback}")
281
+ raise e_fallback
282
+
283
+ # Handle case where plot_function expects specific kwargs (like 'ticker')
284
+ # but received data_to_plot as an unwanted positional argument.
285
+ # This often happens if plot_function is like `def func(ticker=None):`
286
+ # and was called as `func(data_frame, ticker='val')`
287
+ else:
288
+ try:
289
+ sig = inspect.signature(plot_function)
290
+ # Filter kwargs to only those accepted by plot_function
291
+ accepted_kwargs = {
292
+ k: v for k, v in kwargs.items()
293
+ if k in sig.parameters or \
294
+ any(p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values())
295
+ }
296
+ # If data_to_plot was non-None and function has no clear positional data param,
297
+ # it might be the cause of the TypeError. Try without it.
298
+
299
+ # Heuristic: Does the function primarily expect keyword args like 'ticker'?
300
+ # And does not seem to want data_to_plot positionally?
301
+ param_names = set(sig.parameters.keys())
302
+ first_param = next(iter(sig.parameters.values()), None)
303
+ takes_pos_data = first_param and \
304
+ (first_param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD or \
305
+ first_param.kind == inspect.Parameter.POSITIONAL_ONLY) and \
306
+ first_param.name not in ('ticker', 'tickers') # and not 'df', 'data' etc.
307
+
308
+ if not takes_pos_data and ('ticker' in param_names or 'tickers' in param_names):
309
+ if verbose: print(f"TypeError (kwarg-focused func): Retrying {function_name} with accepted kwargs, no positional data.")
310
+ return plot_function(**accepted_kwargs)
311
+ else:
312
+ # Original TypeError was likely valid for other reasons
313
+ print(f"TypeError calling plot function '{function_name}': {te}. Args: {data_to_plot}, Kwargs: {kwargs}")
314
+ raise te
315
+ except Exception as e_inspect_fallback:
316
+ # If inspection or second attempt itself fails, raise original TypeError
317
+ print(f"Error during TypeError fallback for {function_name}: {e_inspect_fallback}")
318
+ print(f"Original TypeError calling plot function '{function_name}': {te}. Args: {data_to_plot}, Kwargs: {kwargs}")
319
+ raise te from None # Raise original te, suppress context from e_inspect_fallback
320
+ except Exception as e:
321
+ print(f"An unexpected error occurred while calling plot function '{function_name}': {e}")
322
+ raise e
323
+ elif source == "database":
324
+ try:
325
+ datasets = sovai_data(
326
+ dataset_name + "/charts",
327
+ chart=chart_type,
328
+ tickers=lookup_tickers,
329
+ purge_cache=purge_cache,
330
+ **kwargs,
331
+ )
332
+ except Exception as e:
333
+ if verbose: print(f"Error fetching database chart data for {dataset_name}: {e}")
334
+ return None
335
+
336
+ if datasets is None:
337
+ if verbose: print(f"Failed to retrieve data for {dataset_name}/charts with chart type {chart_type} and tickers {lookup_tickers}")
338
+ return None
339
+
340
+ try:
341
+ if isinstance(datasets, list):
342
+ if plot_function == _draw_graphs:
343
+ for dataset_item in datasets:
344
+ if dataset_item is not None:
345
+ fig = plot_function(dataset_item, **kwargs)
346
+ if fig: return fig
347
+ if verbose: print("No plottable data found in the list of datasets for _draw_graphs.")
348
+ return None
349
+ else:
350
+ if verbose: print("Warning: Received a list of datasets for database source, plotting first non-None item.")
351
+ for dataset_item in datasets:
352
+ if dataset_item is not None:
353
+ return plot_function(dataset_item, **kwargs)
354
+ if verbose: print("No non-None dataset found in the list to plot.")
355
+ return None
356
+ else:
357
+ return plot_function(datasets, **kwargs)
358
+ except Exception as e:
359
+ print(f"Error calling plot function '{function_name}' for database data: {e}")
360
+ raise e
361
+ else:
362
+ raise ValueError(f"Source '{source}' derived from mapper is not recognized.")
@@ -75,32 +75,43 @@ def report(dataset_name, report_type="sector-top", **kwargs):
75
75
 
76
76
  df = kwargs.get("df")
77
77
  if df is None:
78
+ # If df is not provided, try to fetch it.
79
+ # Crucially, pass along **kwargs from the report() call to data().
78
80
  try:
79
81
  if report_type == "ranking":
80
- df = data(dataset_name, frequency="latest")
82
+ df = data(dataset_name, frequency="latest", **kwargs)
81
83
  elif report_type == "change":
82
- print("change")
83
- df = data(dataset_name, frequency="difference")
84
+ # print("change") # Consider using logging instead of print
85
+ df = data(dataset_name, frequency="difference", **kwargs)
84
86
  elif report_type == "previous":
85
- df = data(dataset_name, frequency="previous")
87
+ df = data(dataset_name, frequency="previous", **kwargs)
86
88
  else:
87
- df = data(dataset_name)
88
- except:
89
- try:
90
- df = data(dataset_name)
91
- except:
92
- return report_function(*additional_args, **kwargs)
89
+ # This case applies to ("accounting", "balance_sheet")
90
+ # dataset_name will be "accounting"
91
+ # **kwargs will include {'ticker': 'MSFT'}
92
+ df = data(dataset_name, **kwargs)
93
+ except Exception as e_fetch:
94
+ # Handle cases where data fetching might fail.
95
+ # For reports like jupyter_html_assets that fetch their own data,
96
+ # this 'df' might not be strictly necessary.
97
+ print(f"Warning: Initial data fetch for report {dataset_name}/{report_type} failed. Error: {e_fetch}")
98
+ df = None # Set df to None if fetching fails
93
99
 
94
- # Use the correct report function based on the report type
95
- if report_type == "change":
96
- return general_ranking_change(df, *additional_args, **kwargs)
97
- elif report_type in ["ranking", "previous"]:
98
- return general_ranking(df, *additional_args, **kwargs)
100
+ # Decide how to call the actual report-generating function
101
+ if report_function in [jupyter_html_assets,create_interactive_report]:
102
+ # jupyter_html_assets expects 'ticker' from kwargs and fetches its own data.
103
+ # It does not use the 'df' fetched above.
104
+ return report_function(**kwargs)
105
+ # Add elif for other specific report functions if they have unique calling patterns
106
+ # elif report_function is some_other_report_function_expecting_only_kwargs:
107
+ # return report_function(**kwargs)
99
108
  else:
109
+ # Default assumption: the report function takes 'df' as its first argument.
110
+ # If df is None (due to fetch failure or if it was initially None and not fetched),
111
+ # it's passed as None, and the report_function must handle it.
100
112
  return report_function(df, *additional_args, **kwargs)
101
113
 
102
114
 
103
-
104
115
  # def report(dataset_name, report_type="sector-top", **kwargs):
105
116
  # # Extract the DataFrame from kwargs
106
117
  # df = kwargs.get('df')
@@ -18,10 +18,10 @@ import random
18
18
  from sovai.utils.port_manager import get_unique_port
19
19
 
20
20
 
21
- def get_balance_sheet_tree_plot_for_ticker(df_accounting=None, tickers="MSFT"):
21
+ def get_balance_sheet_tree_plot_for_ticker(df_accounting=None, ticker="MSFT"):
22
22
  # Assuming df_accounting is your DataFrame
23
23
  if df_accounting is None:
24
- df_accounting = data("accounting/weekly", tickers=tickers)
24
+ df_accounting = data("accounting/weekly", tickers=ticker)
25
25
 
26
26
  selected_data = df_accounting.iloc[-1]
27
27
 
@@ -124,6 +124,7 @@ def get_balance_sheet_tree_plot_for_ticker(df_accounting=None, tickers="MSFT"):
124
124
  {
125
125
  "level_1": "Total Liabilities & Equity",
126
126
  "level_2": "Total Equity",
127
+ "level_3": "Total Equity",
127
128
  "value": selected_data["equity_usd"],
128
129
  },
129
130
  {
@@ -476,6 +476,8 @@ def create_plot(df, ticker, column, long_ma, short_ma, threshold, future_days):
476
476
 
477
477
  def plot_news_daily(ticker='NVDA'):
478
478
  # Fetch and prepare data
479
+
480
+ print(ticker)
479
481
  df = fetch_and_prepare_data(ticker, ['tone', 'sentiment'])
480
482
 
481
483
  # Initialize the Dash app
@@ -778,9 +780,9 @@ def dash_news_ts_analysis(df_sentiment, df_polarity, df_topic):
778
780
 
779
781
  def run_dash_news_ts():
780
782
 
781
- df_sentiment = data("news/sentiment_score", full_history=True)
782
- df_polarity = data("news/polarity_score", full_history=True)
783
- df_topic = data("news/topic_probability", full_history=True)
783
+ df_sentiment = data("news/sentiment_score", full_history=True).reset_index()
784
+ df_polarity = data("news/polarity_score", full_history=True).reset_index()
785
+ df_topic = data("news/topic_probability", full_history=True).reset_index()
784
786
 
785
787
  app = dash_news_ts_analysis(df_sentiment, df_polarity, df_topic)
786
788
  app.run_server(debug=False, port=get_unique_port("news_topic_valuest"), jupyter_mode="inline", jupyter_height=1300)