ml4t-diagnostic 0.1.0a1__py3-none-any.whl
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.
- ml4t/diagnostic/AGENT.md +25 -0
- ml4t/diagnostic/__init__.py +166 -0
- ml4t/diagnostic/backends/__init__.py +10 -0
- ml4t/diagnostic/backends/adapter.py +192 -0
- ml4t/diagnostic/backends/polars_backend.py +899 -0
- ml4t/diagnostic/caching/__init__.py +40 -0
- ml4t/diagnostic/caching/cache.py +331 -0
- ml4t/diagnostic/caching/decorators.py +131 -0
- ml4t/diagnostic/caching/smart_cache.py +339 -0
- ml4t/diagnostic/config/AGENT.md +24 -0
- ml4t/diagnostic/config/README.md +267 -0
- ml4t/diagnostic/config/__init__.py +219 -0
- ml4t/diagnostic/config/barrier_config.py +277 -0
- ml4t/diagnostic/config/base.py +301 -0
- ml4t/diagnostic/config/event_config.py +148 -0
- ml4t/diagnostic/config/feature_config.py +404 -0
- ml4t/diagnostic/config/multi_signal_config.py +55 -0
- ml4t/diagnostic/config/portfolio_config.py +215 -0
- ml4t/diagnostic/config/report_config.py +391 -0
- ml4t/diagnostic/config/sharpe_config.py +202 -0
- ml4t/diagnostic/config/signal_config.py +206 -0
- ml4t/diagnostic/config/trade_analysis_config.py +310 -0
- ml4t/diagnostic/config/validation.py +279 -0
- ml4t/diagnostic/core/__init__.py +29 -0
- ml4t/diagnostic/core/numba_utils.py +315 -0
- ml4t/diagnostic/core/purging.py +372 -0
- ml4t/diagnostic/core/sampling.py +471 -0
- ml4t/diagnostic/errors/__init__.py +205 -0
- ml4t/diagnostic/evaluation/AGENT.md +26 -0
- ml4t/diagnostic/evaluation/__init__.py +437 -0
- ml4t/diagnostic/evaluation/autocorrelation.py +531 -0
- ml4t/diagnostic/evaluation/barrier_analysis.py +1050 -0
- ml4t/diagnostic/evaluation/binary_metrics.py +910 -0
- ml4t/diagnostic/evaluation/dashboard.py +715 -0
- ml4t/diagnostic/evaluation/diagnostic_plots.py +1037 -0
- ml4t/diagnostic/evaluation/distribution/__init__.py +499 -0
- ml4t/diagnostic/evaluation/distribution/moments.py +299 -0
- ml4t/diagnostic/evaluation/distribution/tails.py +777 -0
- ml4t/diagnostic/evaluation/distribution/tests.py +470 -0
- ml4t/diagnostic/evaluation/drift/__init__.py +139 -0
- ml4t/diagnostic/evaluation/drift/analysis.py +432 -0
- ml4t/diagnostic/evaluation/drift/domain_classifier.py +517 -0
- ml4t/diagnostic/evaluation/drift/population_stability_index.py +310 -0
- ml4t/diagnostic/evaluation/drift/wasserstein.py +388 -0
- ml4t/diagnostic/evaluation/event_analysis.py +647 -0
- ml4t/diagnostic/evaluation/excursion.py +390 -0
- ml4t/diagnostic/evaluation/feature_diagnostics.py +873 -0
- ml4t/diagnostic/evaluation/feature_outcome.py +666 -0
- ml4t/diagnostic/evaluation/framework.py +935 -0
- ml4t/diagnostic/evaluation/metric_registry.py +255 -0
- ml4t/diagnostic/evaluation/metrics/AGENT.md +23 -0
- ml4t/diagnostic/evaluation/metrics/__init__.py +133 -0
- ml4t/diagnostic/evaluation/metrics/basic.py +160 -0
- ml4t/diagnostic/evaluation/metrics/conditional_ic.py +469 -0
- ml4t/diagnostic/evaluation/metrics/feature_outcome.py +475 -0
- ml4t/diagnostic/evaluation/metrics/ic_statistics.py +446 -0
- ml4t/diagnostic/evaluation/metrics/importance_analysis.py +338 -0
- ml4t/diagnostic/evaluation/metrics/importance_classical.py +375 -0
- ml4t/diagnostic/evaluation/metrics/importance_mda.py +371 -0
- ml4t/diagnostic/evaluation/metrics/importance_shap.py +715 -0
- ml4t/diagnostic/evaluation/metrics/information_coefficient.py +527 -0
- ml4t/diagnostic/evaluation/metrics/interactions.py +772 -0
- ml4t/diagnostic/evaluation/metrics/monotonicity.py +226 -0
- ml4t/diagnostic/evaluation/metrics/risk_adjusted.py +324 -0
- ml4t/diagnostic/evaluation/multi_signal.py +550 -0
- ml4t/diagnostic/evaluation/portfolio_analysis/__init__.py +83 -0
- ml4t/diagnostic/evaluation/portfolio_analysis/analysis.py +734 -0
- ml4t/diagnostic/evaluation/portfolio_analysis/metrics.py +589 -0
- ml4t/diagnostic/evaluation/portfolio_analysis/results.py +334 -0
- ml4t/diagnostic/evaluation/report_generation.py +824 -0
- ml4t/diagnostic/evaluation/signal_selector.py +452 -0
- ml4t/diagnostic/evaluation/stat_registry.py +139 -0
- ml4t/diagnostic/evaluation/stationarity/__init__.py +97 -0
- ml4t/diagnostic/evaluation/stationarity/analysis.py +518 -0
- ml4t/diagnostic/evaluation/stationarity/augmented_dickey_fuller.py +296 -0
- ml4t/diagnostic/evaluation/stationarity/kpss_test.py +308 -0
- ml4t/diagnostic/evaluation/stationarity/phillips_perron.py +365 -0
- ml4t/diagnostic/evaluation/stats/AGENT.md +43 -0
- ml4t/diagnostic/evaluation/stats/__init__.py +191 -0
- ml4t/diagnostic/evaluation/stats/backtest_overfitting.py +219 -0
- ml4t/diagnostic/evaluation/stats/bootstrap.py +228 -0
- ml4t/diagnostic/evaluation/stats/deflated_sharpe_ratio.py +591 -0
- ml4t/diagnostic/evaluation/stats/false_discovery_rate.py +295 -0
- ml4t/diagnostic/evaluation/stats/hac_standard_errors.py +108 -0
- ml4t/diagnostic/evaluation/stats/minimum_track_record.py +408 -0
- ml4t/diagnostic/evaluation/stats/moments.py +164 -0
- ml4t/diagnostic/evaluation/stats/rademacher_adjustment.py +436 -0
- ml4t/diagnostic/evaluation/stats/reality_check.py +155 -0
- ml4t/diagnostic/evaluation/stats/sharpe_inference.py +219 -0
- ml4t/diagnostic/evaluation/themes.py +330 -0
- ml4t/diagnostic/evaluation/threshold_analysis.py +957 -0
- ml4t/diagnostic/evaluation/trade_analysis.py +1136 -0
- ml4t/diagnostic/evaluation/trade_dashboard/__init__.py +32 -0
- ml4t/diagnostic/evaluation/trade_dashboard/app.py +315 -0
- ml4t/diagnostic/evaluation/trade_dashboard/export/__init__.py +18 -0
- ml4t/diagnostic/evaluation/trade_dashboard/export/csv.py +82 -0
- ml4t/diagnostic/evaluation/trade_dashboard/export/html.py +276 -0
- ml4t/diagnostic/evaluation/trade_dashboard/io.py +166 -0
- ml4t/diagnostic/evaluation/trade_dashboard/normalize.py +304 -0
- ml4t/diagnostic/evaluation/trade_dashboard/stats.py +386 -0
- ml4t/diagnostic/evaluation/trade_dashboard/style.py +79 -0
- ml4t/diagnostic/evaluation/trade_dashboard/tabs/__init__.py +21 -0
- ml4t/diagnostic/evaluation/trade_dashboard/tabs/patterns.py +354 -0
- ml4t/diagnostic/evaluation/trade_dashboard/tabs/shap_analysis.py +280 -0
- ml4t/diagnostic/evaluation/trade_dashboard/tabs/stat_validation.py +186 -0
- ml4t/diagnostic/evaluation/trade_dashboard/tabs/worst_trades.py +236 -0
- ml4t/diagnostic/evaluation/trade_dashboard/types.py +129 -0
- ml4t/diagnostic/evaluation/trade_shap/__init__.py +102 -0
- ml4t/diagnostic/evaluation/trade_shap/alignment.py +188 -0
- ml4t/diagnostic/evaluation/trade_shap/characterize.py +413 -0
- ml4t/diagnostic/evaluation/trade_shap/cluster.py +302 -0
- ml4t/diagnostic/evaluation/trade_shap/explain.py +208 -0
- ml4t/diagnostic/evaluation/trade_shap/hypotheses/__init__.py +23 -0
- ml4t/diagnostic/evaluation/trade_shap/hypotheses/generator.py +290 -0
- ml4t/diagnostic/evaluation/trade_shap/hypotheses/matcher.py +251 -0
- ml4t/diagnostic/evaluation/trade_shap/hypotheses/templates.yaml +467 -0
- ml4t/diagnostic/evaluation/trade_shap/models.py +386 -0
- ml4t/diagnostic/evaluation/trade_shap/normalize.py +116 -0
- ml4t/diagnostic/evaluation/trade_shap/pipeline.py +263 -0
- ml4t/diagnostic/evaluation/trade_shap_dashboard.py +283 -0
- ml4t/diagnostic/evaluation/trade_shap_diagnostics.py +588 -0
- ml4t/diagnostic/evaluation/validated_cv.py +535 -0
- ml4t/diagnostic/evaluation/visualization.py +1050 -0
- ml4t/diagnostic/evaluation/volatility/__init__.py +45 -0
- ml4t/diagnostic/evaluation/volatility/analysis.py +351 -0
- ml4t/diagnostic/evaluation/volatility/arch.py +258 -0
- ml4t/diagnostic/evaluation/volatility/garch.py +460 -0
- ml4t/diagnostic/integration/__init__.py +48 -0
- ml4t/diagnostic/integration/backtest_contract.py +671 -0
- ml4t/diagnostic/integration/data_contract.py +316 -0
- ml4t/diagnostic/integration/engineer_contract.py +226 -0
- ml4t/diagnostic/logging/__init__.py +77 -0
- ml4t/diagnostic/logging/logger.py +245 -0
- ml4t/diagnostic/logging/performance.py +234 -0
- ml4t/diagnostic/logging/progress.py +234 -0
- ml4t/diagnostic/logging/wandb.py +412 -0
- ml4t/diagnostic/metrics/__init__.py +9 -0
- ml4t/diagnostic/metrics/percentiles.py +128 -0
- ml4t/diagnostic/py.typed +1 -0
- ml4t/diagnostic/reporting/__init__.py +43 -0
- ml4t/diagnostic/reporting/base.py +130 -0
- ml4t/diagnostic/reporting/html_renderer.py +275 -0
- ml4t/diagnostic/reporting/json_renderer.py +51 -0
- ml4t/diagnostic/reporting/markdown_renderer.py +117 -0
- ml4t/diagnostic/results/AGENT.md +24 -0
- ml4t/diagnostic/results/__init__.py +105 -0
- ml4t/diagnostic/results/barrier_results/__init__.py +36 -0
- ml4t/diagnostic/results/barrier_results/hit_rate.py +304 -0
- ml4t/diagnostic/results/barrier_results/precision_recall.py +266 -0
- ml4t/diagnostic/results/barrier_results/profit_factor.py +297 -0
- ml4t/diagnostic/results/barrier_results/tearsheet.py +397 -0
- ml4t/diagnostic/results/barrier_results/time_to_target.py +305 -0
- ml4t/diagnostic/results/barrier_results/validation.py +38 -0
- ml4t/diagnostic/results/base.py +177 -0
- ml4t/diagnostic/results/event_results.py +349 -0
- ml4t/diagnostic/results/feature_results.py +787 -0
- ml4t/diagnostic/results/multi_signal_results.py +431 -0
- ml4t/diagnostic/results/portfolio_results.py +281 -0
- ml4t/diagnostic/results/sharpe_results.py +448 -0
- ml4t/diagnostic/results/signal_results/__init__.py +74 -0
- ml4t/diagnostic/results/signal_results/ic.py +581 -0
- ml4t/diagnostic/results/signal_results/irtc.py +110 -0
- ml4t/diagnostic/results/signal_results/quantile.py +392 -0
- ml4t/diagnostic/results/signal_results/tearsheet.py +456 -0
- ml4t/diagnostic/results/signal_results/turnover.py +213 -0
- ml4t/diagnostic/results/signal_results/validation.py +147 -0
- ml4t/diagnostic/signal/AGENT.md +17 -0
- ml4t/diagnostic/signal/__init__.py +69 -0
- ml4t/diagnostic/signal/_report.py +152 -0
- ml4t/diagnostic/signal/_utils.py +261 -0
- ml4t/diagnostic/signal/core.py +275 -0
- ml4t/diagnostic/signal/quantile.py +148 -0
- ml4t/diagnostic/signal/result.py +214 -0
- ml4t/diagnostic/signal/signal_ic.py +129 -0
- ml4t/diagnostic/signal/turnover.py +182 -0
- ml4t/diagnostic/splitters/AGENT.md +19 -0
- ml4t/diagnostic/splitters/__init__.py +36 -0
- ml4t/diagnostic/splitters/base.py +501 -0
- ml4t/diagnostic/splitters/calendar.py +421 -0
- ml4t/diagnostic/splitters/calendar_config.py +91 -0
- ml4t/diagnostic/splitters/combinatorial.py +1064 -0
- ml4t/diagnostic/splitters/config.py +322 -0
- ml4t/diagnostic/splitters/cpcv/__init__.py +57 -0
- ml4t/diagnostic/splitters/cpcv/combinations.py +119 -0
- ml4t/diagnostic/splitters/cpcv/partitioning.py +263 -0
- ml4t/diagnostic/splitters/cpcv/purge_engine.py +379 -0
- ml4t/diagnostic/splitters/cpcv/windows.py +190 -0
- ml4t/diagnostic/splitters/group_isolation.py +329 -0
- ml4t/diagnostic/splitters/persistence.py +316 -0
- ml4t/diagnostic/splitters/utils.py +207 -0
- ml4t/diagnostic/splitters/walk_forward.py +757 -0
- ml4t/diagnostic/utils/__init__.py +42 -0
- ml4t/diagnostic/utils/config.py +542 -0
- ml4t/diagnostic/utils/dependencies.py +318 -0
- ml4t/diagnostic/utils/sessions.py +127 -0
- ml4t/diagnostic/validation/__init__.py +54 -0
- ml4t/diagnostic/validation/dataframe.py +274 -0
- ml4t/diagnostic/validation/returns.py +280 -0
- ml4t/diagnostic/validation/timeseries.py +299 -0
- ml4t/diagnostic/visualization/AGENT.md +19 -0
- ml4t/diagnostic/visualization/__init__.py +223 -0
- ml4t/diagnostic/visualization/backtest/__init__.py +98 -0
- ml4t/diagnostic/visualization/backtest/cost_attribution.py +762 -0
- ml4t/diagnostic/visualization/backtest/executive_summary.py +895 -0
- ml4t/diagnostic/visualization/backtest/interactive_controls.py +673 -0
- ml4t/diagnostic/visualization/backtest/statistical_validity.py +874 -0
- ml4t/diagnostic/visualization/backtest/tearsheet.py +565 -0
- ml4t/diagnostic/visualization/backtest/template_system.py +373 -0
- ml4t/diagnostic/visualization/backtest/trade_plots.py +1172 -0
- ml4t/diagnostic/visualization/barrier_plots.py +782 -0
- ml4t/diagnostic/visualization/core.py +1060 -0
- ml4t/diagnostic/visualization/dashboards/__init__.py +36 -0
- ml4t/diagnostic/visualization/dashboards/base.py +582 -0
- ml4t/diagnostic/visualization/dashboards/importance.py +801 -0
- ml4t/diagnostic/visualization/dashboards/interaction.py +263 -0
- ml4t/diagnostic/visualization/dashboards.py +43 -0
- ml4t/diagnostic/visualization/data_extraction/__init__.py +48 -0
- ml4t/diagnostic/visualization/data_extraction/importance.py +649 -0
- ml4t/diagnostic/visualization/data_extraction/interaction.py +504 -0
- ml4t/diagnostic/visualization/data_extraction/types.py +113 -0
- ml4t/diagnostic/visualization/data_extraction/validation.py +66 -0
- ml4t/diagnostic/visualization/feature_plots.py +888 -0
- ml4t/diagnostic/visualization/interaction_plots.py +618 -0
- ml4t/diagnostic/visualization/portfolio/__init__.py +41 -0
- ml4t/diagnostic/visualization/portfolio/dashboard.py +514 -0
- ml4t/diagnostic/visualization/portfolio/drawdown_plots.py +341 -0
- ml4t/diagnostic/visualization/portfolio/returns_plots.py +487 -0
- ml4t/diagnostic/visualization/portfolio/risk_plots.py +301 -0
- ml4t/diagnostic/visualization/report_generation.py +1343 -0
- ml4t/diagnostic/visualization/signal/__init__.py +103 -0
- ml4t/diagnostic/visualization/signal/dashboard.py +911 -0
- ml4t/diagnostic/visualization/signal/event_plots.py +514 -0
- ml4t/diagnostic/visualization/signal/ic_plots.py +635 -0
- ml4t/diagnostic/visualization/signal/multi_signal_dashboard.py +974 -0
- ml4t/diagnostic/visualization/signal/multi_signal_plots.py +603 -0
- ml4t/diagnostic/visualization/signal/quantile_plots.py +625 -0
- ml4t/diagnostic/visualization/signal/turnover_plots.py +400 -0
- ml4t/diagnostic/visualization/trade_shap/__init__.py +90 -0
- ml4t_diagnostic-0.1.0a1.dist-info/METADATA +1044 -0
- ml4t_diagnostic-0.1.0a1.dist-info/RECORD +242 -0
- ml4t_diagnostic-0.1.0a1.dist-info/WHEEL +4 -0
- ml4t_diagnostic-0.1.0a1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Trade SHAP diagnostics dashboard package.
|
|
2
|
+
|
|
3
|
+
This package provides an interactive Streamlit dashboard for visualizing
|
|
4
|
+
Trade-SHAP analysis results, including statistical validation, worst trades,
|
|
5
|
+
SHAP explanations, and error patterns.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
>>> from ml4t.diagnostic.evaluation.trade_dashboard import run_diagnostics_dashboard
|
|
9
|
+
>>> run_diagnostics_dashboard(result)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.app import run_dashboard
|
|
15
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.normalize import normalize_result
|
|
16
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.types import (
|
|
17
|
+
DashboardBundle,
|
|
18
|
+
DashboardConfig,
|
|
19
|
+
ReturnSummary,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Backward compatibility alias
|
|
23
|
+
run_diagnostics_dashboard = run_dashboard
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"DashboardBundle",
|
|
27
|
+
"DashboardConfig",
|
|
28
|
+
"ReturnSummary",
|
|
29
|
+
"normalize_result",
|
|
30
|
+
"run_dashboard",
|
|
31
|
+
"run_diagnostics_dashboard", # Backward compat alias
|
|
32
|
+
]
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""Dashboard application orchestrator.
|
|
2
|
+
|
|
3
|
+
Main entry point for the Trade-SHAP diagnostics dashboard.
|
|
4
|
+
Handles page configuration, data loading, and tab routing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
import traceback
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ml4t.diagnostic.evaluation.trade_shap.models import TradeShapResult
|
|
16
|
+
|
|
17
|
+
# Module-level load time tracking for styled mode
|
|
18
|
+
_LOAD_START_TIME: float | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _measure_load_time_start() -> None:
|
|
22
|
+
"""Start measuring load time."""
|
|
23
|
+
global _LOAD_START_TIME
|
|
24
|
+
_LOAD_START_TIME = time.time()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _measure_load_time_end() -> float:
|
|
28
|
+
"""End load time measurement and return elapsed seconds."""
|
|
29
|
+
global _LOAD_START_TIME
|
|
30
|
+
if _LOAD_START_TIME is None:
|
|
31
|
+
return 0.0
|
|
32
|
+
elapsed = time.time() - _LOAD_START_TIME
|
|
33
|
+
_LOAD_START_TIME = None
|
|
34
|
+
return elapsed
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def run_dashboard(
|
|
38
|
+
result: TradeShapResult | dict[str, Any] | None = None,
|
|
39
|
+
title: str = "Trade-SHAP Diagnostics Dashboard",
|
|
40
|
+
styled: bool = False,
|
|
41
|
+
allow_pickle_upload: bool = False,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Run the Streamlit diagnostics dashboard.
|
|
44
|
+
|
|
45
|
+
This is the main entry point for the dashboard. It can be called
|
|
46
|
+
programmatically with a result object, or run as a standalone app
|
|
47
|
+
that allows file uploads.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
result : TradeShapResult or dict, optional
|
|
52
|
+
Pre-loaded analysis result. If None, dashboard will show file upload.
|
|
53
|
+
title : str, default "Trade-SHAP Diagnostics Dashboard"
|
|
54
|
+
Dashboard title.
|
|
55
|
+
styled : bool, default False
|
|
56
|
+
Enable professional styling with custom CSS, load time tracking,
|
|
57
|
+
spinners, export buttons, and enhanced error handling.
|
|
58
|
+
allow_pickle_upload : bool, default False
|
|
59
|
+
Allow pickle file uploads. SECURITY WARNING: Pickle files can
|
|
60
|
+
execute arbitrary code. Only enable for trusted sources.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
Programmatic usage:
|
|
65
|
+
>>> from ml4t.diagnostic.evaluation import TradeShapAnalyzer
|
|
66
|
+
>>> from ml4t.diagnostic.evaluation.trade_dashboard import run_dashboard
|
|
67
|
+
>>>
|
|
68
|
+
>>> analyzer = TradeShapAnalyzer(model, features_df, shap_values)
|
|
69
|
+
>>> result = analyzer.explain_worst_trades(worst_trades)
|
|
70
|
+
>>> run_dashboard(result)
|
|
71
|
+
|
|
72
|
+
Styled mode with professional theme:
|
|
73
|
+
>>> run_dashboard(result, styled=True)
|
|
74
|
+
|
|
75
|
+
Standalone app:
|
|
76
|
+
$ streamlit run -m ml4t.diagnostic.evaluation.trade_dashboard.app
|
|
77
|
+
"""
|
|
78
|
+
# Lazy import streamlit
|
|
79
|
+
try:
|
|
80
|
+
import streamlit as st
|
|
81
|
+
except ImportError:
|
|
82
|
+
raise ImportError(
|
|
83
|
+
"streamlit is required for dashboard functionality. Install with: pip install streamlit"
|
|
84
|
+
) from None
|
|
85
|
+
|
|
86
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.io import (
|
|
87
|
+
PickleDisabledError,
|
|
88
|
+
load_result_from_upload,
|
|
89
|
+
)
|
|
90
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.normalize import normalize_result
|
|
91
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.style import STYLED_CSS
|
|
92
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.tabs import (
|
|
93
|
+
patterns,
|
|
94
|
+
shap_analysis,
|
|
95
|
+
stat_validation,
|
|
96
|
+
worst_trades,
|
|
97
|
+
)
|
|
98
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.types import DashboardConfig
|
|
99
|
+
|
|
100
|
+
# Start load time measurement in styled mode
|
|
101
|
+
if styled:
|
|
102
|
+
_measure_load_time_start()
|
|
103
|
+
|
|
104
|
+
# Page config
|
|
105
|
+
page_config: dict[str, Any] = {
|
|
106
|
+
"page_title": title,
|
|
107
|
+
"page_icon": "📊",
|
|
108
|
+
"layout": "wide",
|
|
109
|
+
"initial_sidebar_state": "expanded",
|
|
110
|
+
}
|
|
111
|
+
if styled:
|
|
112
|
+
page_config["menu_items"] = {
|
|
113
|
+
"Get Help": "https://github.com/ml4t/ml4t-diagnostic",
|
|
114
|
+
"Report a bug": "https://github.com/ml4t/ml4t-diagnostic/issues",
|
|
115
|
+
"About": "# Trade-SHAP Diagnostics\nSystematic trade debugging for ML strategies",
|
|
116
|
+
}
|
|
117
|
+
st.set_page_config(**page_config)
|
|
118
|
+
|
|
119
|
+
# Apply professional CSS in styled mode
|
|
120
|
+
if styled:
|
|
121
|
+
st.markdown(STYLED_CSS, unsafe_allow_html=True)
|
|
122
|
+
|
|
123
|
+
# Title and description
|
|
124
|
+
st.title(title)
|
|
125
|
+
st.markdown(
|
|
126
|
+
"""
|
|
127
|
+
**Systematic trade debugging and continuous improvement for ML trading strategies**
|
|
128
|
+
|
|
129
|
+
This dashboard visualizes Trade-SHAP analysis results to help you:
|
|
130
|
+
- Identify why specific trades failed
|
|
131
|
+
- Discover recurring error patterns
|
|
132
|
+
- Get actionable recommendations for improvement
|
|
133
|
+
"""
|
|
134
|
+
)
|
|
135
|
+
st.divider()
|
|
136
|
+
|
|
137
|
+
# Sidebar for data loading
|
|
138
|
+
with st.sidebar:
|
|
139
|
+
st.header("Configuration")
|
|
140
|
+
|
|
141
|
+
st.subheader("Data Loading")
|
|
142
|
+
|
|
143
|
+
if result is None:
|
|
144
|
+
# File upload mode
|
|
145
|
+
file_types = ["json"]
|
|
146
|
+
if allow_pickle_upload:
|
|
147
|
+
file_types.extend(["pkl", "pickle"])
|
|
148
|
+
|
|
149
|
+
uploaded_file = st.file_uploader(
|
|
150
|
+
"Upload TradeShapResult",
|
|
151
|
+
type=file_types,
|
|
152
|
+
help="Upload a JSON file containing TradeShapResult"
|
|
153
|
+
+ (" (or pickle if enabled)" if allow_pickle_upload else ""),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if uploaded_file is not None:
|
|
157
|
+
try:
|
|
158
|
+
with st.spinner("Loading data..."):
|
|
159
|
+
result = load_result_from_upload(
|
|
160
|
+
uploaded_file,
|
|
161
|
+
allow_pickle=allow_pickle_upload,
|
|
162
|
+
)
|
|
163
|
+
st.success("Data loaded successfully!")
|
|
164
|
+
except PickleDisabledError as e:
|
|
165
|
+
st.error(str(e))
|
|
166
|
+
return
|
|
167
|
+
except Exception as e:
|
|
168
|
+
st.error(f"Failed to load data: {e}")
|
|
169
|
+
if styled:
|
|
170
|
+
with st.expander("Error Details"):
|
|
171
|
+
st.code(traceback.format_exc())
|
|
172
|
+
return
|
|
173
|
+
else:
|
|
174
|
+
st.info("Upload a file to get started")
|
|
175
|
+
if not allow_pickle_upload:
|
|
176
|
+
st.caption(
|
|
177
|
+
"Pickle uploads disabled for security. Use JSON format for data transfer."
|
|
178
|
+
)
|
|
179
|
+
st.stop()
|
|
180
|
+
else:
|
|
181
|
+
st.success("Data loaded programmatically")
|
|
182
|
+
|
|
183
|
+
# Normalize result once for all tabs
|
|
184
|
+
if result is not None:
|
|
185
|
+
config = DashboardConfig(
|
|
186
|
+
allow_pickle_upload=allow_pickle_upload,
|
|
187
|
+
styled=styled,
|
|
188
|
+
title=title,
|
|
189
|
+
)
|
|
190
|
+
bundle = normalize_result(result, config)
|
|
191
|
+
|
|
192
|
+
# Display data summary in sidebar
|
|
193
|
+
_display_sidebar_summary(st, bundle, styled)
|
|
194
|
+
|
|
195
|
+
# Main content - tabs
|
|
196
|
+
tab1, tab2, tab3, tab4 = st.tabs(
|
|
197
|
+
[
|
|
198
|
+
"Statistical Validation",
|
|
199
|
+
"Worst Trades",
|
|
200
|
+
"SHAP Analysis",
|
|
201
|
+
"Patterns",
|
|
202
|
+
]
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
if styled:
|
|
206
|
+
with tab1, st.spinner("Loading statistical validation..."):
|
|
207
|
+
stat_validation.render_tab(st, bundle)
|
|
208
|
+
|
|
209
|
+
with tab2, st.spinner("Loading worst trades..."):
|
|
210
|
+
worst_trades.render_tab(st, bundle)
|
|
211
|
+
|
|
212
|
+
with tab3, st.spinner("Loading SHAP analysis..."):
|
|
213
|
+
shap_analysis.render_tab(st, bundle)
|
|
214
|
+
|
|
215
|
+
with tab4, st.spinner("Loading error patterns..."):
|
|
216
|
+
patterns.render_tab(st, bundle)
|
|
217
|
+
|
|
218
|
+
# Show load time
|
|
219
|
+
load_time = _measure_load_time_end()
|
|
220
|
+
if load_time > 0:
|
|
221
|
+
if load_time < 5.0:
|
|
222
|
+
st.sidebar.success(f"Loaded in {load_time:.2f}s")
|
|
223
|
+
else:
|
|
224
|
+
st.sidebar.warning(f"Loaded in {load_time:.2f}s (>5s target)")
|
|
225
|
+
else:
|
|
226
|
+
with tab1:
|
|
227
|
+
stat_validation.render_tab(st, bundle)
|
|
228
|
+
|
|
229
|
+
with tab2:
|
|
230
|
+
worst_trades.render_tab(st, bundle)
|
|
231
|
+
|
|
232
|
+
with tab3:
|
|
233
|
+
shap_analysis.render_tab(st, bundle)
|
|
234
|
+
|
|
235
|
+
with tab4:
|
|
236
|
+
patterns.render_tab(st, bundle)
|
|
237
|
+
else:
|
|
238
|
+
st.info("Please load data from the sidebar to begin analysis.")
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _display_sidebar_summary(st: Any, bundle: Any, styled: bool) -> None:
|
|
242
|
+
"""Display data summary in sidebar."""
|
|
243
|
+
with st.sidebar:
|
|
244
|
+
st.divider()
|
|
245
|
+
st.subheader("Data Summary")
|
|
246
|
+
|
|
247
|
+
col1, col2 = st.columns(2)
|
|
248
|
+
with col1:
|
|
249
|
+
st.metric("Trades Analyzed", bundle.n_trades_analyzed)
|
|
250
|
+
with col2:
|
|
251
|
+
st.metric("Trades Explained", bundle.n_trades_explained)
|
|
252
|
+
|
|
253
|
+
if bundle.n_trades_failed > 0:
|
|
254
|
+
st.warning(f"{bundle.n_trades_failed} trades failed explanation")
|
|
255
|
+
|
|
256
|
+
n_patterns = len(bundle.patterns_df) if not bundle.patterns_df.empty else 0
|
|
257
|
+
st.metric("Patterns Found", n_patterns)
|
|
258
|
+
|
|
259
|
+
# Export buttons (styled mode)
|
|
260
|
+
if styled:
|
|
261
|
+
st.divider()
|
|
262
|
+
st.subheader("Export")
|
|
263
|
+
_render_export_buttons(st, bundle)
|
|
264
|
+
|
|
265
|
+
# Display options
|
|
266
|
+
st.divider()
|
|
267
|
+
st.subheader("Display Options")
|
|
268
|
+
st.checkbox("Show timestamps", value=True, key="show_timestamps")
|
|
269
|
+
st.checkbox("Show confidence scores", value=True, key="show_confidence")
|
|
270
|
+
|
|
271
|
+
# Footer
|
|
272
|
+
st.divider()
|
|
273
|
+
st.caption(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
274
|
+
if styled:
|
|
275
|
+
st.caption("Dashboard v2.0 (Modular)")
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _render_export_buttons(st: Any, bundle: Any) -> None:
|
|
279
|
+
"""Render export buttons in sidebar."""
|
|
280
|
+
try:
|
|
281
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.export import (
|
|
282
|
+
export_html_report,
|
|
283
|
+
export_trades_csv,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# CSV export
|
|
287
|
+
csv_data = export_trades_csv(bundle)
|
|
288
|
+
if csv_data:
|
|
289
|
+
st.download_button(
|
|
290
|
+
label="Download Trades CSV",
|
|
291
|
+
data=csv_data,
|
|
292
|
+
file_name=f"trades_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
|
|
293
|
+
mime="text/csv",
|
|
294
|
+
use_container_width=True,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# HTML report export
|
|
298
|
+
html_data = export_html_report(bundle)
|
|
299
|
+
if html_data:
|
|
300
|
+
st.download_button(
|
|
301
|
+
label="Download HTML Report",
|
|
302
|
+
data=html_data,
|
|
303
|
+
file_name=f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html",
|
|
304
|
+
mime="text/html",
|
|
305
|
+
use_container_width=True,
|
|
306
|
+
)
|
|
307
|
+
except ImportError:
|
|
308
|
+
st.caption("Export modules not available")
|
|
309
|
+
except Exception as e:
|
|
310
|
+
st.error(f"Export error: {e}")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# Allow running as a standalone Streamlit app
|
|
314
|
+
if __name__ == "__main__":
|
|
315
|
+
run_dashboard()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Dashboard export modules.
|
|
2
|
+
|
|
3
|
+
Provides CSV and HTML export functionality for dashboard data.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.export.csv import (
|
|
9
|
+
export_patterns_csv,
|
|
10
|
+
export_trades_csv,
|
|
11
|
+
)
|
|
12
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.export.html import export_html_report
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"export_html_report",
|
|
16
|
+
"export_patterns_csv",
|
|
17
|
+
"export_trades_csv",
|
|
18
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""CSV export functions for dashboard data."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from ml4t.diagnostic.evaluation.trade_dashboard.types import DashboardBundle
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def export_trades_csv(bundle: DashboardBundle) -> str:
|
|
12
|
+
"""Export trades with SHAP values to CSV format.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
bundle : DashboardBundle
|
|
17
|
+
Normalized dashboard data.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
str
|
|
22
|
+
CSV formatted string with trade data.
|
|
23
|
+
"""
|
|
24
|
+
if bundle.trades_df.empty:
|
|
25
|
+
return ""
|
|
26
|
+
|
|
27
|
+
# Select columns for export
|
|
28
|
+
export_columns = [
|
|
29
|
+
"trade_id",
|
|
30
|
+
"symbol",
|
|
31
|
+
"entry_time",
|
|
32
|
+
"exit_time",
|
|
33
|
+
"pnl",
|
|
34
|
+
"return_pct",
|
|
35
|
+
"duration_days",
|
|
36
|
+
"entry_price",
|
|
37
|
+
"exit_price",
|
|
38
|
+
"top_feature",
|
|
39
|
+
"top_shap_value",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# Only include columns that exist
|
|
43
|
+
available_columns = [c for c in export_columns if c in bundle.trades_df.columns]
|
|
44
|
+
|
|
45
|
+
df = bundle.trades_df[available_columns].copy()
|
|
46
|
+
|
|
47
|
+
return df.to_csv(index=False)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def export_patterns_csv(bundle: DashboardBundle) -> str:
|
|
51
|
+
"""Export error patterns to CSV format.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
bundle : DashboardBundle
|
|
56
|
+
Normalized dashboard data.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
str
|
|
61
|
+
CSV formatted string with pattern data.
|
|
62
|
+
"""
|
|
63
|
+
if bundle.patterns_df.empty:
|
|
64
|
+
return ""
|
|
65
|
+
|
|
66
|
+
# Select columns for export
|
|
67
|
+
export_columns = [
|
|
68
|
+
"cluster_id",
|
|
69
|
+
"n_trades",
|
|
70
|
+
"description",
|
|
71
|
+
"hypothesis",
|
|
72
|
+
"confidence",
|
|
73
|
+
"separation_score",
|
|
74
|
+
"distinctiveness",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
# Only include columns that exist
|
|
78
|
+
available_columns = [c for c in export_columns if c in bundle.patterns_df.columns]
|
|
79
|
+
|
|
80
|
+
df = bundle.patterns_df[available_columns].copy()
|
|
81
|
+
|
|
82
|
+
return df.to_csv(index=False)
|