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.
- {sovai-0.2.65 → sovai-0.2.67}/PKG-INFO +1 -1
- {sovai-0.2.65 → sovai-0.2.67}/pyproject.toml +1 -1
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data.py +9 -0
- sovai-0.2.67/sovai/get_plots.py +362 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_reports.py +27 -16
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/accounting/accounting_plots.py +3 -2
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/news/news_plots.py +5 -3
- sovai-0.2.67/sovai/reports/accounting/accounting_balance_sheet.py +321 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side_s3_part_high.py +3 -3
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/port_manager.py +3 -3
- sovai-0.2.65/sovai/get_plots.py +0 -311
- sovai-0.2.65/sovai/reports/accounting/accounting_balance_sheet.py +0 -306
- {sovai-0.2.65 → sovai-0.2.67}/LICENSE +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/README.md +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/data/codes.parq +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/data/tickers.parq +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/.DS_Store +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/api_config.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/assets/tickers.parq +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/basic_auth.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/computations/functions.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/change_point_generator copy.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pandas_extensions.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/signal_evaluation.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_compute.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data copy 2.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_data copy.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/get_tools.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/token_auth.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/converter.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/file_management.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/plot.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/port_manager copy.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/stream.py +0 -0
- {sovai-0.2.65 → sovai-0.2.67}/sovai/utils/verbose_utils.py +0 -0
|
@@ -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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
df = data(dataset_name)
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
#
|
|
95
|
-
if
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return
|
|
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,
|
|
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=
|
|
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)
|