mirror of
https://github.com/triqbit/mt5-ai-xauusd-trader.git
synced 2026-11-02 06:56:15 +00:00
Enhance Institutional Research Reporting System (#1114)
* feat: enhance institutional research reporting system - Add Calmar Ratio and Expected Shortfall (CVaR) to BenchmarkComparison model - Expand RLMetric with Ulcer Index, Lake Ratio, Tail Ratio, and SQN - Implement 'Critical Research Warnings' panel in HTML report for automated risk highlighting - Increase visual density of KPI dashboard in HTML reports - Enable 'jinja2.ext.do' extension for advanced template logic - Update orchestration script to generate complete RL evaluation reports - Protect reports/ directory from source control via .gitignore updates - Verified with full test suite and visual frontend inspection Co-authored-by: saysgrok <279469430+saysgrok@users.noreply.github.com> * feat: enhance institutional research reporting and audit visibility - Add institutional metrics (Calmar, CVaR, Ulcer Index, Lake Ratio) to research models. - Implement automated 'Critical Research Warnings' triage in HTML reports. - Refine HTML report UI with high-density KPI dashboard and interactive elements. - Enable 'jinja2.ext.do' extension for advanced template logic. - Expand orchestration script with realistic RL evaluation data. - Enforce repository cleanliness by git-ignoring generated report artifacts. - Verified via unit tests and automated frontend Playwright inspection. Co-authored-by: saysgrok <279469430+saysgrok@users.noreply.github.com> * feat: enhance institutional research reporting and audit visibility - Integrated advanced institutional metrics: Calmar Ratio, Expected Shortfall (CVaR), Ulcer Index, Lake Ratio, and Tail Ratio. - Implemented 'Critical Research Warnings' triage panel in HTML reports for automated risk highlighting. - Refined HTML UX with a high-density KPI dashboard and interactive navigation elements. - Enabled 'jinja2.ext.do' extension to support imperative template logic. - Expanded orchestration script with complete RL agent evaluation data. - Updated documentation and addressed test regressions in event intelligence suite. - Enforced repository hygiene by git-ignoring generated report artifacts. Verified via 24 unit tests and automated Playwright inspection. Co-authored-by: saysgrok <279469430+saysgrok@users.noreply.github.com> * feat: enhance institutional research reporting and audit visibility - Expanded research reporting Pydantic models with institutional metrics (Calmar, CVaR, Lake Ratio). - Redesigned HTML templates with high-density KPI dashboards and a dynamic 'Critical Warnings' triage panel. - Integrated comprehensive RL evaluation metrics into the research orchestrator. - Updated generate_audit_report.py to serve as a production-grade orchestration entry point. - Resolved regression failures in macro event tests by updating mocks to match the MetaAPIEventProvider refactor. - Synchronized documentation in docs/research/REPORTING_SYSTEM.md. - Optimized .gitignore to exclude generated research artifacts while preserving directory structure. Co-authored-by: saysgrok <279469430+saysgrok@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: saysgrok <279469430+saysgrok@users.noreply.github.com>
This commit is contained in:
co-authored by
saysgrok
google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
parent
ad63c6f07d
commit
033c083f28
@@ -100,3 +100,5 @@ releases/
|
||||
|
||||
# Archives (Cleanup outputs)
|
||||
archives/
|
||||
reports/*
|
||||
!reports/.gitkeep
|
||||
|
||||
@@ -1,3 +1,38 @@
|
||||
- **Institutional Metrics:** Calculates advanced metrics such as Tail Ratio, Common Sense Ratio, and Gain-to-Pain Ratio.
|
||||
- **Professional Visualization:** High-fidelity HTML reports with interactive elements (TOC, back-to-top) and color-coded status indicators. Terminal reports feature dynamic section numbering for logical indexing and institutional color-coding for key performance metrics (Sharpe, PF, WR).
|
||||
- **Accessibility & Print Optimization:** Hardened HTML with ARIA labels, skip-links, and `@media print` CSS for professional PDF exports.
|
||||
# Research Reporting System
|
||||
|
||||
The research reporting system is a high-fidelity audit framework designed to provide decision-useful insights for institutional stakeholders, including PMs, Quant Leads, and Auditors.
|
||||
|
||||
## Core Features
|
||||
|
||||
- **Multi-Format Export:** Supports professional HTML, Markdown, and scannable Terminal (Rich) output.
|
||||
- **Institutional Metrics:** Calculates and reports advanced quant metrics:
|
||||
- Calmar Ratio & Expected Shortfall (CVaR)
|
||||
- Ulcer Index & Lake Ratio
|
||||
- Tail Ratio & SQN
|
||||
- Common Sense Ratio & Gain-to-Pain Ratio
|
||||
- **Automated Risk Triage:** Integrated 'Critical Research Warnings' panel in HTML reports that dynamically highlights FAIL/CRITICAL statuses from stress tests, model drift, and calibration audits.
|
||||
- **Professional Visualization:**
|
||||
- High-density KPI dashboards.
|
||||
- Interactive elements (Sticky navigation, TOC, Back-to-top).
|
||||
- ARIA-hardened accessibility and print-optimized CSS for PDF generation.
|
||||
- **Modular Architecture:** Pydantic-based data models for extensible research sections.
|
||||
|
||||
## Components
|
||||
|
||||
1. **ResearchReporter:** The main engine for template rendering and terminal display.
|
||||
2. **ResearchOrchestrator:** Automates the aggregation of data from various research subsystems (Regime, Stress, Hyperopt, etc.) into a unified report.
|
||||
3. **Audit Templates:** Professional Jinja2 templates for Markdown and HTML exports.
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from src.research.reporting import ResearchOrchestrator, ResearchReporter
|
||||
|
||||
orchestrator = ResearchOrchestrator(title="Audit", ...)
|
||||
orchestrator.add_section(stress_test_section)
|
||||
report = orchestrator.build()
|
||||
|
||||
reporter = ResearchReporter()
|
||||
reporter.format_for_terminal(report)
|
||||
reporter.save_html(report, "audit.html")
|
||||
```
|
||||
|
||||
@@ -1,585 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>XAUUSD Strategy Performance & Robustness Audit - Research Report</title>
|
||||
<style>
|
||||
:root { --primary: #2c3e50; --secondary: #2980b9; --success: #27ae60; --danger: #e74c3c; --warning: #f39c12; --light: #f4f7f6; --white: #ffffff; }
|
||||
html { scroll-behavior: smooth; }
|
||||
*:focus-visible { outline: 3px solid var(--secondary); outline-offset: 2px; }
|
||||
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 60px 20px 20px; background-color: var(--light); }
|
||||
header { background: var(--primary); color: var(--white); padding: 3rem 2rem; border-radius: 12px; margin-bottom: 2rem; box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); }
|
||||
h1 { margin: 0; font-size: 2.75rem; letter-spacing: -0.025em; }
|
||||
.metadata { margin-top: 1rem; font-size: 1rem; opacity: 0.9; display: flex; gap: 20px; }
|
||||
.sticky-nav { position: fixed; top: 0; left: 0; right: 0; background: rgba(44, 62, 80, 0.95); backdrop-filter: blur(8px); color: white; padding: 10px 0; z-index: 1000; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
.sticky-nav-container { max-width: 1200px; margin: 0 auto; padding: 0 20px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.sticky-nav a { color: white; text-decoration: none; font-size: 0.9rem; font-weight: 500; margin-left: 20px; transition: color 0.2s; }
|
||||
.sticky-nav a:hover { color: var(--secondary); }
|
||||
.toc { background: var(--white); padding: 2rem; border-radius: 12px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
||||
.toc h2 { font-size: 1.5rem; margin-top: 0; color: var(--primary); }
|
||||
.toc ul { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
|
||||
.toc a { text-decoration: none; color: var(--secondary); font-weight: 600; font-size: 1.05rem; }
|
||||
.toc a:hover { color: var(--primary); text-decoration: underline; }
|
||||
.executive-summary { background: var(--white); padding: 2rem; border-left: 6px solid var(--secondary); border-radius: 8px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
||||
section { background: var(--white); padding: 2.5rem; border-radius: 12px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); scroll-margin-top: 80px; }
|
||||
h2 { border-bottom: 2px solid #ecf0f1; padding-bottom: 0.5rem; color: #2c3e50; }
|
||||
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
|
||||
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
|
||||
th { background-color: #f8f9fa; color: #2c3e50; }
|
||||
tr:hover { background-color: #fdfdfd; }
|
||||
.score-container { display: flex; align-items: center; gap: 15px; margin-bottom: 1rem; }
|
||||
.score { font-size: 1.75rem; font-weight: 800; color: var(--success); }
|
||||
.progress-bar { background: #edf2f7; border-radius: 999px; height: 12px; flex-grow: 1; overflow: hidden; max-width: 350px; }
|
||||
@keyframes fill-up { from { width: 0; } }
|
||||
.progress-fill { height: 100%; background: linear-gradient(90deg, #2ecc71, #27ae60); animation: fill-up 1.2s cubic-bezier(0.65, 0, 0.35, 1); }
|
||||
.fill-low { background: linear-gradient(90deg, #f56565, #e53e3e); }
|
||||
.fill-medium { background: linear-gradient(90deg, #ecc94b, #d69e2e); }
|
||||
.fill-high { background: linear-gradient(90deg, #48bb78, #2f855a); }
|
||||
.fail { color: var(--danger); font-weight: bold; }
|
||||
.pass { color: var(--success); font-weight: bold; }
|
||||
.insight-box { background: #ebf8ff; padding: 1.25rem; border-radius: 8px; border: 1px solid #bee3f8; color: #2c5282; }
|
||||
footer { text-align: center; margin-top: 4rem; padding: 2rem; border-top: 1px solid #e2e8f0; font-size: 0.9rem; color: #718096; }
|
||||
.badge { display: inline-block; padding: 6px 12px; border-radius: 999px; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.025em; }
|
||||
.badge-stable { background: #def7ec; color: #03543f; }
|
||||
.badge-warning { background: #fef3c7; color: #92400e; }
|
||||
.badge-critical { background: #fde8e8; color: #9b1c1c; }
|
||||
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
|
||||
.kpi-dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 2.5rem; }
|
||||
.kpi-card { background: var(--white); padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); text-align: center; border-top: 4px solid var(--secondary); }
|
||||
.kpi-value { font-size: 2rem; font-weight: 800; color: var(--primary); display: block; }
|
||||
.kpi-label { font-size: 0.85rem; font-weight: 600; color: #718096; text-transform: uppercase; letter-spacing: 0.025em; }
|
||||
.status-badge { padding: 8px 16px; border-radius: 999px; font-weight: 700; font-size: 0.9rem; }
|
||||
.status-verified { background: #def7ec; color: #03543f; }
|
||||
.status-provisional { background: #fef3c7; color: #92400e; }
|
||||
.status-rejected { background: #fde8e8; color: #9b1c1c; }
|
||||
.recommendation-list { list-style: none; padding: 0; }
|
||||
.recommendation-item { background: #f0fff4; border-left: 4px solid var(--success); padding: 1rem; margin-bottom: 10px; border-radius: 0 8px 8px 0; }
|
||||
.back-to-top { position: fixed; bottom: 30px; right: 30px; background: var(--primary); color: white; width: 45px; height: 45px; border-radius: 50%; display: flex; align-items: center; justify-content: center; text-decoration: none; box-shadow: 0 4px 6px rgba(0,0,0,0.1); transition: transform 0.3s, background 0.3s, opacity 0.3s, visibility 0.3s; z-index: 1000; font-weight: bold; opacity: 0; visibility: hidden; }
|
||||
.back-to-top.visible { opacity: 1; visibility: visible; }
|
||||
.back-to-top:hover { transform: translateY(-3px); background: var(--secondary); color: white; }
|
||||
.skip-link { position: absolute; top: -40px; left: 0; background: var(--secondary); color: white; padding: 8px; z-index: 2000; transition: top 0.3s; }
|
||||
.skip-link:focus { top: 0; }
|
||||
.print-btn { background: var(--secondary); color: white; border: none; padding: 6px 14px; border-radius: 6px; font-weight: 600; cursor: pointer; font-size: 0.85rem; margin-left: 20px; transition: background 0.2s; }
|
||||
.print-btn:hover { background: var(--primary); }
|
||||
@media print {
|
||||
.sticky-nav, .back-to-top, .print-btn, .skip-link { display: none !important; }
|
||||
body { padding: 0; background: white; max-width: 100%; }
|
||||
section, .toc, .executive-summary, header { box-shadow: none; border: 1px solid #eee; break-inside: avoid; }
|
||||
h1, h2, h3 { color: black; }
|
||||
.toc ul { display: block; }
|
||||
.toc li { margin-bottom: 5px; }
|
||||
a { color: black; text-decoration: none; }
|
||||
.progress-bar { border: 1px solid #ccc; }
|
||||
}
|
||||
@media (max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } .metadata { flex-direction: column; gap: 5px; } .back-to-top { bottom: 20px; right: 20px; width: 40px; height: 40px; } .print-btn { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||
<div class="sticky-nav" role="banner">
|
||||
<div class="sticky-nav-container">
|
||||
<span style="font-weight: 800; font-size: 1.1rem;">triqbit | Research</span>
|
||||
<nav aria-label="Main Navigation">
|
||||
<a href="#executive-summary">Summary</a>
|
||||
<a href="#regime-analysis">Regime</a>
|
||||
<a href="#stress-tests">Stress</a>
|
||||
<a href="#hyperparameter-robustness">Robustness</a>
|
||||
<a href="#trade-patterns">Patterns</a>
|
||||
<a href="#model-drift">Drift</a>
|
||||
<a href="#allocation-insights">Allocation</a>
|
||||
<a href="#benchmarks">Benchmarks</a>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="#conclusion">Conclusion</a>
|
||||
<button class="print-btn" onclick="window['print']()" aria-label="Print research report">Print PDF</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main id="main-content">
|
||||
|
||||
|
||||
<header>
|
||||
<h1>XAUUSD Strategy Performance & Robustness Audit</h1>
|
||||
<div class="metadata">
|
||||
<span><strong>Date:</strong> 2026-05-12 00:19:01.455739+00:00</span>
|
||||
<span><strong>Author:</strong> Jules Research</span>
|
||||
<span><strong>Status:</strong>
|
||||
<span class="status-badge status-verified">
|
||||
VERIFIED
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="kpi-dashboard">
|
||||
|
||||
<div class="kpi-card" style="border-top-color: var(--danger);">
|
||||
<span class="kpi-value">88.5</span>
|
||||
<span class="kpi-label">Resilience Score</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="kpi-card" style="border-top-color: var(--warning);">
|
||||
<span class="kpi-value">92.0</span>
|
||||
<span class="kpi-label">Stability Score</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="kpi-card" style="border-top-color: var(--success);">
|
||||
<span class="kpi-value">0.85</span>
|
||||
<span class="kpi-label">Diversification</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<nav class="toc">
|
||||
<h2>Table of Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#executive-summary">1. Executive Summary</a></li>
|
||||
|
||||
<li><a href="#regime-analysis">2. Market Regime Analysis</a></li>
|
||||
<li><a href="#stress-tests">3. Stress Test Outcomes</a></li>
|
||||
<li><a href="#hyperparameter-robustness">4. Hyperparameter Robustness</a></li>
|
||||
<li><a href="#trade-patterns">5. Trade Pattern Findings</a></li>
|
||||
<li><a href="#model-drift">6. Model Drift Observations</a></li>
|
||||
<li><a href="#allocation-insights">7. Capital Allocation Insights</a></li>
|
||||
<li><a href="#benchmarks">8. Benchmark Comparisons</a></li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li><a href="#conclusion">9. Conclusion & Recommendations</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
<div id="executive-summary" class="executive-summary">
|
||||
<h2>1. Executive Summary</h2>
|
||||
<p>This report provides a comprehensive evaluation of the AI trading system's performance, resilience, and consistency. Overall, the strategy demonstrates high stability in trending regimes but shows sensitivity to extreme news shocks. Capital allocation is well-diversified, and execution quality remains within institutional standards.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<section id="regime-analysis">
|
||||
<h2>2. Market Regime Analysis</h2>
|
||||
<p>Market was primarily trending (65%) with high efficiency.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Regime</th>
|
||||
<th scope="col">Frequency</th>
|
||||
<th scope="col">Avg Duration</th>
|
||||
<th scope="col">Profitability</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td><strong>Trending</strong></td>
|
||||
<td>65.0%</td>
|
||||
<td>45 bars</td>
|
||||
<td>High</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><strong>Ranging</strong></td>
|
||||
<td>25.0%</td>
|
||||
<td>12 bars</td>
|
||||
<td>Neutral</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><strong>News Shock</strong></td>
|
||||
<td>10.0%</td>
|
||||
<td>3 bars</td>
|
||||
<td>Low</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="insight-box">
|
||||
<strong>Transition Insights:</strong><br>
|
||||
Stability: 28.5 bars. Common paths: trending -> ranging (15.5%) | ranging -> news_shock (8.2%)
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="stress-tests">
|
||||
<h2>3. Stress Test Outcomes</h2>
|
||||
<div class="score-container">
|
||||
<span>Resilience Score:</span>
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="88.5" aria-valuemin="0" aria-valuemax="100" aria-label="Strategy resilience score: 88.5 out of 100">
|
||||
<div class="progress-fill fill-high" style="width: 88.5%;"></div>
|
||||
</div>
|
||||
<span class="score">88.5/100</span>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Scenario</th>
|
||||
<th scope="col">Total Return</th>
|
||||
<th scope="col">Max Drawdown</th>
|
||||
<th scope="col">Sharpe</th>
|
||||
<th scope="col">Outcome</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="background-color: #f8f9fa;">
|
||||
<td><strong>Baseline</strong></td>
|
||||
<td>14.2%</td>
|
||||
<td>5.1%</td>
|
||||
<td>2.45</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Spread Widening (3x)</td>
|
||||
<td>11.8%</td>
|
||||
<td>6.4%</td>
|
||||
<td>2.10</td>
|
||||
<td class="pass">PASS</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Execution Hell</td>
|
||||
<td>8.5%</td>
|
||||
<td>9.2%</td>
|
||||
<td>1.65</td>
|
||||
<td class="pass">PASS</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Flash Crash</td>
|
||||
<td>-2.1%</td>
|
||||
<td>18.5%</td>
|
||||
<td>-0.45</td>
|
||||
<td class="fail">FAIL</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="display: flex; gap: 20px;">
|
||||
<div style="flex: 1;">
|
||||
<h3>Fragility Indicators</h3>
|
||||
<ul>
|
||||
|
||||
<li>High drawdown sensitivity to price noise > 1.5 sigma</li>
|
||||
|
||||
<li>Latency impact > 500ms degrades alpha capture</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<h3>Failure Points</h3>
|
||||
<ul>
|
||||
|
||||
<li>Sudden 2% price gap in < 1 minute</li>
|
||||
|
||||
<li>Service failure during peak London volume</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="hyperparameter-robustness">
|
||||
<h2>4. Hyperparameter Robustness</h2>
|
||||
<div class="score-container">
|
||||
<span>Stability Score:</span>
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="92.0" aria-valuemin="0" aria-valuemax="100" aria-label="Parameter stability score: 92.0 out of 100">
|
||||
<div class="progress-fill fill-high" style="width: 92.0%;"></div>
|
||||
</div>
|
||||
<span class="score">92.0/100</span>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Parameter</th>
|
||||
<th scope="col">Range Tested</th>
|
||||
<th scope="col">Optimal Value</th>
|
||||
<th scope="col">Sensitivity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>fast_ema_window</td>
|
||||
<td>5-25</td>
|
||||
<td><code>12</code></td>
|
||||
<td>Low</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>confidence_threshold</td>
|
||||
<td>0.5-0.9</td>
|
||||
<td><code>0.65</code></td>
|
||||
<td>Medium</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>volatility_lookback</td>
|
||||
<td>10-50</td>
|
||||
<td><code>20</code></td>
|
||||
<td>Low</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="insight-box">
|
||||
<strong>Optimization Insights:</strong><br>
|
||||
OOS Sharpe Mean: 2.15 | WFE: 0.88 | Worst OOS Sharpe: 1.45 | IS-OOS Gap: 0.25
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="trade-patterns">
|
||||
<h2>5. Trade Pattern Findings</h2>
|
||||
<p><strong>Key Insight:</strong> Critical behavioral risks identified: Overtrading during NY session.</p>
|
||||
|
||||
<h3>Profitable Concentrations</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Attribute</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col">Win Rate</th>
|
||||
<th scope="col">Profit Factor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>algo_session</td>
|
||||
<td>Ensemble @ London</td>
|
||||
<td>62.0%</td>
|
||||
<td>2.45</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>algo_volatility</td>
|
||||
<td>Ensemble @ Normal Vol</td>
|
||||
<td>58.0%</td>
|
||||
<td>2.1</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<h3>Behavioral Risks</h3>
|
||||
<ul>
|
||||
|
||||
<li><strong>Overtrading:</strong> High trade frequency detected in NY session (4.2 trades/hour).</li>
|
||||
|
||||
<li><strong>Loss Clustering:</strong> Detected 2 clusters of 5+ losses during FOMC news shocks.</li>
|
||||
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="model-drift">
|
||||
<h2>6. Model Drift Observations</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Metric</th>
|
||||
<th scope="col">Baseline</th>
|
||||
<th scope="col">Current</th>
|
||||
<th scope="col">Drift</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>Target Distribution: close</td>
|
||||
<td>2345.50</td>
|
||||
<td>2342.10</td>
|
||||
<td>2.4%</td>
|
||||
<td>
|
||||
<span class="badge badge-stable">STABLE</span>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Return Volatility</td>
|
||||
<td>0.0012</td>
|
||||
<td>0.0018</td>
|
||||
<td>25.0%</td>
|
||||
<td>
|
||||
<span class="badge badge-warning">WARNING</span>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Feature Importance Shifts:</strong><br>Significant shifts in: atr_ratio (+0.45), z_score (-0.32), vol_of_vol (+0.18)</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="allocation-insights">
|
||||
<h2>7. Capital Allocation Insights</h2>
|
||||
<div style="display: flex; gap: 40px; margin-bottom: 20px;">
|
||||
<div>Portfolio Heat: <strong style="font-size: 1.2rem; color: var(--primary);">42.5%</strong></div>
|
||||
<div>Diversification Score: <strong style="font-size: 1.2rem; color: var(--success);">0.85</strong></div>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Symbol/Family</th>
|
||||
<th scope="col">Allocated</th>
|
||||
<th scope="col">Heat</th>
|
||||
<th scope="col">Multiplier</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>ENSEMBLE_XAUUSD_M5</td>
|
||||
<td>$42,500.00</td>
|
||||
<td>42.5%</td>
|
||||
<td>1.15x</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>PPO_XAUUSD_M15</td>
|
||||
<td>$0.00</td>
|
||||
<td>0.0%</td>
|
||||
<td>0.85x</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h3>Rejection Summary</h3>
|
||||
<ul>
|
||||
|
||||
<li>TOTAL_HEAT_LIMIT: 0 occurrences</li>
|
||||
|
||||
<li>SYMBOL_CONCENTRATION_LIMIT: 2 occurrences</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="benchmarks">
|
||||
<h2>8. Benchmark Comparisons</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Strategy</th>
|
||||
<th scope="col">Return</th>
|
||||
<th scope="col">Sharpe</th>
|
||||
<th scope="col">MaxDD</th>
|
||||
<th scope="col">PF</th>
|
||||
<th scope="col">SQN</th>
|
||||
<th scope="col">Recovery</th>
|
||||
<th scope="col">P-Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td><strong>EMA_Crossover</strong></td>
|
||||
<td>8.5%</td>
|
||||
<td>1.20</td>
|
||||
<td>12.4%</td>
|
||||
<td>1.45</td>
|
||||
<td>0.00</td>
|
||||
<td>0.00</td>
|
||||
<td>0.0012</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><strong>Momentum_ROC</strong></td>
|
||||
<td>6.2%</td>
|
||||
<td>0.95</td>
|
||||
<td>15.8%</td>
|
||||
<td>1.25</td>
|
||||
<td>0.00</td>
|
||||
<td>0.00</td>
|
||||
<td>0.0001</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Compared 2 strategies against Ensemble. 2 showed outperformance.</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="conclusion">
|
||||
<h2>9. Conclusion & Recommendations</h2>
|
||||
<div style="margin-bottom: 2rem;">
|
||||
<h3>Strategic Conclusion</h3>
|
||||
<p>The strategy is suitable for deployment in production with a 'Verified' status, provided macro guardrails are active.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Actionable Recommendations</h3>
|
||||
<ul class="recommendation-list">
|
||||
|
||||
<li class="recommendation-item">Reduce risk multiplier during high-impact news windows.</li>
|
||||
|
||||
<li class="recommendation-item">Recalibrate LSTM confidence thresholds every 30 days.</li>
|
||||
|
||||
<li class="recommendation-item">Increase capital allocation to the London-NY session crossover.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<a href="#" class="back-to-top" title="Back to top" aria-label="Scroll back to top">
|
||||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>
|
||||
</a>
|
||||
|
||||
<script>
|
||||
window.addEventListener('scroll', () => {
|
||||
const backToTop = document.querySelector('.back-to-top');
|
||||
if (window.scrollY > 300) {
|
||||
backToTop.classList.add('visible');
|
||||
} else {
|
||||
backToTop.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
© 2024-2025 Triqbit MT5 Research. All rights reserved. Generated by ResearchReporter.
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,207 +0,0 @@
|
||||
# XAUUSD Strategy Performance & Robustness Audit
|
||||
|
||||
---
|
||||
**Report Metadata**
|
||||
- **Date:** 2026-05-12 00:19:01.455739+00:00
|
||||
- **Author:** Jules Research
|
||||
- **Status:** VERIFIED
|
||||
- **Scope:** Research and Strategy Audit
|
||||
---
|
||||
|
||||
|
||||
## Table of Contents
|
||||
1. [Executive Summary](#executive-summary)
|
||||
|
||||
2. [Market Regime Analysis](#2-market-regime-analysis)
|
||||
|
||||
3. [Stress Test Outcomes](#3-stress-test-outcomes)
|
||||
|
||||
4. [Hyperparameter Robustness](#4-hyperparameter-robustness)
|
||||
|
||||
5. [Trade Pattern Findings](#5-trade-pattern-findings-journal-mining)
|
||||
|
||||
6. [Model Drift Observations](#6-model-drift-observations)
|
||||
|
||||
7. [Capital Allocation Insights](#7-capital-allocation-insights)
|
||||
|
||||
8. [Benchmark Comparisons](#8-benchmark-comparisons)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
9. [Conclusion & Recommendations](#conclusion--recommendations)
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Executive Summary
|
||||
This report provides a comprehensive evaluation of the AI trading system's performance, resilience, and consistency. Overall, the strategy demonstrates high stability in trending regimes but shows sensitivity to extreme news shocks. Capital allocation is well-diversified, and execution quality remains within institutional standards.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 2. Market Regime Analysis
|
||||
**Summary:** Market was primarily trending (65%) with high efficiency.
|
||||
|
||||
| Regime | Frequency | Avg Duration | Profitability |
|
||||
|--------|-----------|--------------|---------------|
|
||||
|
||||
| Trending | 65.0% | 45 bars | High |
|
||||
|
||||
| Ranging | 25.0% | 12 bars | Neutral |
|
||||
|
||||
| News Shock | 10.0% | 3 bars | Low |
|
||||
|
||||
|
||||
**Transition Insights:**
|
||||
Stability: 28.5 bars. Common paths: trending -> ranging (15.5%) | ranging -> news_shock (8.2%)
|
||||
|
||||
|
||||
|
||||
|
||||
## 3. Stress Test Outcomes
|
||||
**Resilience Score:** 88.5/100
|
||||
|
||||
| Scenario | Total Return | Max Drawdown | Sharpe | Outcome |
|
||||
|----------|--------------|--------------|--------|---------|
|
||||
| **Baseline** | 14.2% | 5.1% | 2.45 | - |
|
||||
|
||||
| Spread Widening (3x) | 11.8% | 6.4% | 2.10 | PASS |
|
||||
|
||||
| Execution Hell | 8.5% | 9.2% | 1.65 | PASS |
|
||||
|
||||
| Flash Crash | -2.1% | 18.5% | -0.45 | FAIL |
|
||||
|
||||
|
||||
**Fragility Indicators:**
|
||||
|
||||
- High drawdown sensitivity to price noise > 1.5 sigma
|
||||
|
||||
- Latency impact > 500ms degrades alpha capture
|
||||
|
||||
|
||||
**Failure Points:**
|
||||
|
||||
- Sudden 2% price gap in < 1 minute
|
||||
|
||||
- Service failure during peak London volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 4. Hyperparameter Robustness
|
||||
**Stability Score:** 92.0/100
|
||||
|
||||
| Parameter | Range Tested | Optimal Value | Sensitivity |
|
||||
|-----------|--------------|---------------|-------------|
|
||||
|
||||
| fast_ema_window | 5-25 | 12 | Low |
|
||||
|
||||
| confidence_threshold | 0.5-0.9 | 0.65 | Medium |
|
||||
|
||||
| volatility_lookback | 10-50 | 20 | Low |
|
||||
|
||||
|
||||
**Optimization Insights:**
|
||||
OOS Sharpe Mean: 2.15 | WFE: 0.88 | Worst OOS Sharpe: 1.45 | IS-OOS Gap: 0.25
|
||||
|
||||
|
||||
|
||||
|
||||
## 5. Trade Pattern Findings (Journal Mining)
|
||||
**Key Insight:** Critical behavioral risks identified: Overtrading during NY session.
|
||||
|
||||
### Profitable Concentrations
|
||||
| Attribute | Value | Win Rate | Profit Factor |
|
||||
|-----------|-------|----------|---------------|
|
||||
|
||||
| algo_session | Ensemble @ London | 62.0% | 2.45 |
|
||||
|
||||
| algo_volatility | Ensemble @ Normal Vol | 58.0% | 2.1 |
|
||||
|
||||
|
||||
|
||||
|
||||
### Behavioral Risks
|
||||
|
||||
- **Overtrading:** High trade frequency detected in NY session (4.2 trades/hour).
|
||||
|
||||
- **Loss Clustering:** Detected 2 clusters of 5+ losses during FOMC news shocks.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 6. Model Drift Observations
|
||||
| Metric | Baseline | Current | Drift | Status |
|
||||
|--------|----------|---------|-------|--------|
|
||||
|
||||
| Target Distribution: close | 2345.50 | 2342.10 | 2.4% | STABLE |
|
||||
|
||||
| Return Volatility | 0.0012 | 0.0018 | 25.0% | WARNING |
|
||||
|
||||
|
||||
**Feature Importance Shifts:**
|
||||
Significant shifts in: atr_ratio (+0.45), z_score (-0.32), vol_of_vol (+0.18)
|
||||
|
||||
|
||||
|
||||
|
||||
## 7. Capital Allocation Insights
|
||||
**Portfolio Heat:** 42.5% | **Diversification Score:** 0.85
|
||||
|
||||
| Symbol/Family | Allocated | Heat | Performance Multiplier |
|
||||
|---------------|-----------|------|------------------------|
|
||||
|
||||
| ENSEMBLE_XAUUSD_M5 | $42,500.00 | 42.5% | 1.15 |
|
||||
|
||||
| PPO_XAUUSD_M15 | $0.00 | 0.0% | 0.85 |
|
||||
|
||||
|
||||
**Rejection Summary:**
|
||||
|
||||
- TOTAL_HEAT_LIMIT: 0 occurrences
|
||||
|
||||
- SYMBOL_CONCENTRATION_LIMIT: 2 occurrences
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 8. Benchmark Comparisons
|
||||
| Strategy | Total Return | Sharpe | MaxDD | PF | SQN | Recov | P-Value |
|
||||
|----------|--------------|--------|-------|----|-----|-------|---------|
|
||||
|
||||
| EMA_Crossover | 8.5% | 1.20 | 12.4% | 1.45 | 0.00 | 0.00 | 0.0012 |
|
||||
|
||||
| Momentum_ROC | 6.2% | 0.95 | 15.8% | 1.25 | 0.00 | 0.00 | 0.0001 |
|
||||
|
||||
|
||||
**Statistical Significance:**
|
||||
Compared 2 strategies against Ensemble. 2 showed outperformance.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
## Conclusion & Recommendations
|
||||
**Strategic Conclusion:**
|
||||
The strategy is suitable for deployment in production with a 'Verified' status, provided macro guardrails are active.
|
||||
|
||||
|
||||
**Actionable Recommendations:**
|
||||
|
||||
- Reduce risk multiplier during high-impact news windows.
|
||||
|
||||
- Recalibrate LSTM confidence thresholds every 30 days.
|
||||
|
||||
- Increase capital allocation to the London-NY session crossover.
|
||||
@@ -1,335 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Institutional Resilience Audit: EMA Crossover Strategy - Research Report</title>
|
||||
<style>
|
||||
:root { --primary: #2c3e50; --secondary: #2980b9; --success: #27ae60; --danger: #e74c3c; --warning: #f39c12; --light: #f4f7f6; --white: #ffffff; }
|
||||
html { scroll-behavior: smooth; }
|
||||
*:focus-visible { outline: 3px solid var(--secondary); outline-offset: 2px; }
|
||||
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 60px 20px 20px; background-color: var(--light); }
|
||||
header { background: var(--primary); color: var(--white); padding: 3rem 2rem; border-radius: 12px; margin-bottom: 2rem; box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); }
|
||||
h1 { margin: 0; font-size: 2.75rem; letter-spacing: -0.025em; }
|
||||
.metadata { margin-top: 1rem; font-size: 1rem; opacity: 0.9; display: flex; gap: 20px; }
|
||||
.sticky-nav { position: fixed; top: 0; left: 0; right: 0; background: rgba(44, 62, 80, 0.95); backdrop-filter: blur(8px); color: white; padding: 10px 0; z-index: 1000; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
.sticky-nav-container { max-width: 1200px; margin: 0 auto; padding: 0 20px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.sticky-nav a { color: white; text-decoration: none; font-size: 0.9rem; font-weight: 500; margin-left: 20px; transition: color 0.2s; }
|
||||
.sticky-nav a:hover { color: var(--secondary); }
|
||||
.toc { background: var(--white); padding: 2rem; border-radius: 12px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
||||
.toc h2 { font-size: 1.5rem; margin-top: 0; color: var(--primary); }
|
||||
.toc ul { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
|
||||
.toc a { text-decoration: none; color: var(--secondary); font-weight: 600; font-size: 1.05rem; }
|
||||
.toc a:hover { color: var(--primary); text-decoration: underline; }
|
||||
.executive-summary { background: var(--white); padding: 2rem; border-left: 6px solid var(--secondary); border-radius: 8px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
||||
section { background: var(--white); padding: 2.5rem; border-radius: 12px; margin-bottom: 2.5rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); scroll-margin-top: 80px; }
|
||||
h2 { border-bottom: 2px solid #ecf0f1; padding-bottom: 0.5rem; color: #2c3e50; }
|
||||
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
|
||||
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
|
||||
th { background-color: #f8f9fa; color: #2c3e50; }
|
||||
tr:hover { background-color: #fdfdfd; }
|
||||
.score-container { display: flex; align-items: center; gap: 15px; margin-bottom: 1rem; }
|
||||
.score { font-size: 1.75rem; font-weight: 800; color: var(--success); }
|
||||
.progress-bar { background: #edf2f7; border-radius: 999px; height: 12px; flex-grow: 1; overflow: hidden; max-width: 350px; }
|
||||
@keyframes fill-up { from { width: 0; } }
|
||||
.progress-fill { height: 100%; background: linear-gradient(90deg, #2ecc71, #27ae60); animation: fill-up 1.2s cubic-bezier(0.65, 0, 0.35, 1); }
|
||||
.fill-low { background: linear-gradient(90deg, #f56565, #e53e3e); }
|
||||
.fill-medium { background: linear-gradient(90deg, #ecc94b, #d69e2e); }
|
||||
.fill-high { background: linear-gradient(90deg, #48bb78, #2f855a); }
|
||||
.fail { color: var(--danger); font-weight: bold; }
|
||||
.pass { color: var(--success); font-weight: bold; }
|
||||
.insight-box { background: #ebf8ff; padding: 1.25rem; border-radius: 8px; border: 1px solid #bee3f8; color: #2c5282; }
|
||||
footer { text-align: center; margin-top: 4rem; padding: 2rem; border-top: 1px solid #e2e8f0; font-size: 0.9rem; color: #718096; }
|
||||
.badge { display: inline-block; padding: 6px 12px; border-radius: 999px; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.025em; }
|
||||
.badge-stable { background: #def7ec; color: #03543f; }
|
||||
.badge-warning { background: #fef3c7; color: #92400e; }
|
||||
.badge-critical { background: #fde8e8; color: #9b1c1c; }
|
||||
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
|
||||
.kpi-dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 2.5rem; }
|
||||
.kpi-card { background: var(--white); padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); text-align: center; border-top: 4px solid var(--secondary); }
|
||||
.kpi-value { font-size: 2rem; font-weight: 800; color: var(--primary); display: block; }
|
||||
.kpi-label { font-size: 0.85rem; font-weight: 600; color: #718096; text-transform: uppercase; letter-spacing: 0.025em; }
|
||||
.status-badge { padding: 8px 16px; border-radius: 999px; font-weight: 700; font-size: 0.9rem; }
|
||||
.status-verified { background: #def7ec; color: #03543f; }
|
||||
.status-provisional { background: #fef3c7; color: #92400e; }
|
||||
.status-rejected { background: #fde8e8; color: #9b1c1c; }
|
||||
.recommendation-list { list-style: none; padding: 0; }
|
||||
.recommendation-item { background: #f0fff4; border-left: 4px solid var(--success); padding: 1rem; margin-bottom: 10px; border-radius: 0 8px 8px 0; }
|
||||
.back-to-top { position: fixed; bottom: 30px; right: 30px; background: var(--primary); color: white; width: 45px; height: 45px; border-radius: 50%; display: flex; align-items: center; justify-content: center; text-decoration: none; box-shadow: 0 4px 6px rgba(0,0,0,0.1); transition: transform 0.3s, background 0.3s, opacity 0.3s, visibility 0.3s; z-index: 1000; font-weight: bold; opacity: 0; visibility: hidden; }
|
||||
.back-to-top.visible { opacity: 1; visibility: visible; }
|
||||
.back-to-top:hover { transform: translateY(-3px); background: var(--secondary); color: white; }
|
||||
.skip-link { position: absolute; top: -40px; left: 0; background: var(--secondary); color: white; padding: 8px; z-index: 2000; transition: top 0.3s; }
|
||||
.skip-link:focus { top: 0; }
|
||||
.print-btn { background: var(--secondary); color: white; border: none; padding: 6px 14px; border-radius: 6px; font-weight: 600; cursor: pointer; font-size: 0.85rem; margin-left: 20px; transition: background 0.2s; }
|
||||
.print-btn:hover { background: var(--primary); }
|
||||
@media print {
|
||||
.sticky-nav, .back-to-top, .print-btn, .skip-link { display: none !important; }
|
||||
body { padding: 0; background: white; max-width: 100%; }
|
||||
section, .toc, .executive-summary, header { box-shadow: none; border: 1px solid #eee; break-inside: avoid; }
|
||||
h1, h2, h3 { color: black; }
|
||||
.toc ul { display: block; }
|
||||
.toc li { margin-bottom: 5px; }
|
||||
a { color: black; text-decoration: none; }
|
||||
.progress-bar { border: 1px solid #ccc; }
|
||||
}
|
||||
@media (max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } .metadata { flex-direction: column; gap: 5px; } .back-to-top { bottom: 20px; right: 20px; width: 40px; height: 40px; } .print-btn { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||
<div class="sticky-nav" role="banner">
|
||||
<div class="sticky-nav-container">
|
||||
<span style="font-weight: 800; font-size: 1.1rem;">triqbit | Research</span>
|
||||
<nav aria-label="Main Navigation">
|
||||
<a href="#executive-summary">Summary</a>
|
||||
|
||||
<a href="#stress-tests">Stress</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="#rare-events">Rare</a>
|
||||
|
||||
|
||||
<a href="#conclusion">Conclusion</a>
|
||||
<button class="print-btn" onclick="window['print']()" aria-label="Print research report">Print PDF</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main id="main-content">
|
||||
|
||||
|
||||
<header>
|
||||
<h1>Institutional Resilience Audit: EMA Crossover Strategy</h1>
|
||||
<div class="metadata">
|
||||
<span><strong>Date:</strong> 2026-05-12 05:48:06.756207+00:00</span>
|
||||
<span><strong>Author:</strong> Jules Research</span>
|
||||
<span><strong>Status:</strong>
|
||||
<span class="status-badge status-provisional">
|
||||
PROVISIONAL
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="kpi-dashboard">
|
||||
|
||||
<div class="kpi-card" style="border-top-color: var(--danger);">
|
||||
<span class="kpi-value">29.43080955722126</span>
|
||||
<span class="kpi-label">Resilience Score</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav class="toc">
|
||||
<h2>Table of Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#executive-summary">1. Executive Summary</a></li>
|
||||
|
||||
|
||||
<li><a href="#stress-tests">2. Stress Test Outcomes</a></li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li><a href="#rare-events">3. Rare Event Simulations</a></li>
|
||||
|
||||
|
||||
<li><a href="#conclusion">4. Conclusion & Recommendations</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
<div id="executive-summary" class="executive-summary">
|
||||
<h2>1. Executive Summary</h2>
|
||||
<p>This audit evaluates the EMA_Crossover_10_30 strategy under adversarial conditions. The stress laboratory simulates execution friction, data instability, and regime shifts to identify non-linear failure points and quantify strategy fragility.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="stress-tests">
|
||||
<h2>2. Stress Test Outcomes</h2>
|
||||
<div class="score-container">
|
||||
<span>Resilience Score:</span>
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="29.4" aria-valuemin="0" aria-valuemax="100" aria-label="Strategy resilience score: 29.4 out of 100">
|
||||
<div class="progress-fill fill-low" style="width: 29.43080955722126%;"></div>
|
||||
</div>
|
||||
<span class="score">29.43080955722126/100</span>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Scenario</th>
|
||||
<th scope="col">Total Return</th>
|
||||
<th scope="col">Max Drawdown</th>
|
||||
<th scope="col">Sharpe</th>
|
||||
<th scope="col">Outcome</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="background-color: #f8f9fa;">
|
||||
<td><strong>Baseline</strong></td>
|
||||
<td>-1.74%</td>
|
||||
<td>5.16%</td>
|
||||
<td>-0.19</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Execution Hell</td>
|
||||
<td>-34.00%</td>
|
||||
<td>35.20%</td>
|
||||
<td>-0.80</td>
|
||||
<td class="fail">FAIL</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Liquidity Crisis</td>
|
||||
<td>-1.43%</td>
|
||||
<td>9.53%</td>
|
||||
<td>0.03</td>
|
||||
<td class="fail">FAIL</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Regime Shock</td>
|
||||
<td>-149.79%</td>
|
||||
<td>148.40%</td>
|
||||
<td>0.18</td>
|
||||
<td class="fail">FAIL</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Flash Crash</td>
|
||||
<td>-134.85%</td>
|
||||
<td>137.68%</td>
|
||||
<td>-0.90</td>
|
||||
<td class="fail">FAIL</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="display: flex; gap: 20px;">
|
||||
<div style="flex: 1;">
|
||||
<h3>Fragility Indicators</h3>
|
||||
<ul>
|
||||
|
||||
<li>Drawdown explosion in Execution Hell</li>
|
||||
|
||||
<li>Sharpe ratio halved under Execution Hell</li>
|
||||
|
||||
<li>Drawdown explosion in Regime Shock</li>
|
||||
|
||||
<li>Drawdown explosion in Flash Crash</li>
|
||||
|
||||
<li>Sharpe ratio halved under Flash Crash</li>
|
||||
|
||||
<li>Extreme slippage sensitivity in Flash Crash</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<h3>Failure Points</h3>
|
||||
<ul>
|
||||
|
||||
<li>Critical drawdown (>50%) in Regime Shock</li>
|
||||
|
||||
<li>Critical drawdown (>50%) in Flash Crash</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="rare-events">
|
||||
<h2>3. Rare Event Simulations</h2>
|
||||
<div class="insight-box">
|
||||
<strong>Insights:</strong><br>
|
||||
Evaluated 1 rare event scenarios. Detected 0 high-impact events (>5% deviation). All events remained within manageable risk bounds.
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Event Type</th>
|
||||
<th scope="col">Peak Impact</th>
|
||||
<th scope="col">Realized Volatility</th>
|
||||
<th scope="col">Recovery</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td><strong>news_shock</strong></td>
|
||||
<td>4.67%</td>
|
||||
<td>0.0232</td>
|
||||
<td>0.0%</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="conclusion">
|
||||
<h2>4. Conclusion & Recommendations</h2>
|
||||
<div style="margin-bottom: 2rem;">
|
||||
<h3>Strategic Conclusion</h3>
|
||||
<p>The strategy achieved a resilience score of 29.4. While it handles moderate spread widening, it shows critical fragility during flash crashes and high-latency environments.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<a href="#" class="back-to-top" title="Back to top" aria-label="Scroll back to top">
|
||||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>
|
||||
</a>
|
||||
|
||||
<script>
|
||||
window.addEventListener('scroll', () => {
|
||||
const backToTop = document.querySelector('.back-to-top');
|
||||
if (window.scrollY > 300) {
|
||||
backToTop.classList.add('visible');
|
||||
} else {
|
||||
backToTop.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
© 2024-2025 Triqbit MT5 Research. All rights reserved. Generated by ResearchReporter.
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,112 +0,0 @@
|
||||
# Institutional Resilience Audit: EMA Crossover Strategy
|
||||
|
||||
---
|
||||
**Report Metadata**
|
||||
- **Date:** 2026-05-12 05:48:06.756207+00:00
|
||||
- **Author:** Jules Research
|
||||
- **Status:** PROVISIONAL
|
||||
- **Scope:** Research and Strategy Audit
|
||||
---
|
||||
|
||||
|
||||
## Table of Contents
|
||||
1. [Executive Summary](#executive-summary)
|
||||
|
||||
|
||||
2. [Stress Test Outcomes](#2-stress-test-outcomes)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3. [Rare Event Simulations](#3-rare-event-simulations)
|
||||
|
||||
|
||||
|
||||
4. [Conclusion & Recommendations](#conclusion--recommendations)
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Executive Summary
|
||||
This audit evaluates the EMA_Crossover_10_30 strategy under adversarial conditions. The stress laboratory simulates execution friction, data instability, and regime shifts to identify non-linear failure points and quantify strategy fragility.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2. Stress Test Outcomes
|
||||
**Resilience Score:** 29.43080955722126/100
|
||||
|
||||
| Scenario | Total Return | Max Drawdown | Sharpe | Outcome |
|
||||
|----------|--------------|--------------|--------|---------|
|
||||
| **Baseline** | -1.74% | 5.16% | -0.19 | - |
|
||||
|
||||
| Execution Hell | -34.00% | 35.20% | -0.80 | FAIL |
|
||||
|
||||
| Liquidity Crisis | -1.43% | 9.53% | 0.03 | FAIL |
|
||||
|
||||
| Regime Shock | -149.79% | 148.40% | 0.18 | FAIL |
|
||||
|
||||
| Flash Crash | -134.85% | 137.68% | -0.90 | FAIL |
|
||||
|
||||
|
||||
**Fragility Indicators:**
|
||||
|
||||
- Drawdown explosion in Execution Hell
|
||||
|
||||
- Sharpe ratio halved under Execution Hell
|
||||
|
||||
- Drawdown explosion in Regime Shock
|
||||
|
||||
- Drawdown explosion in Flash Crash
|
||||
|
||||
- Sharpe ratio halved under Flash Crash
|
||||
|
||||
- Extreme slippage sensitivity in Flash Crash
|
||||
|
||||
|
||||
**Failure Points:**
|
||||
|
||||
- Critical drawdown (>50%) in Regime Shock
|
||||
|
||||
- Critical drawdown (>50%) in Flash Crash
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 3. Rare Event Simulations
|
||||
**Insights:** Evaluated 1 rare event scenarios. Detected 0 high-impact events (>5% deviation). All events remained within manageable risk bounds.
|
||||
|
||||
| Event Type | Peak Impact | Realized Vol | Recovery |
|
||||
|------------|-------------|--------------|----------|
|
||||
|
||||
| news_shock | 4.67% | 0.0232 | 0.0% |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
## Conclusion & Recommendations
|
||||
**Strategic Conclusion:**
|
||||
The strategy achieved a resilience score of 29.4. While it handles moderate spread widening, it shows critical fragility during flash crashes and high-latency environments.
|
||||
@@ -123,7 +123,9 @@ def generate_full_audit():
|
||||
hyper_section = HyperparameterSection(
|
||||
stability_score=92.0,
|
||||
parameters=[
|
||||
ParameterRobustness(name="fast_ema_window", range="5-25", optimal="12", sensitivity="Low"),
|
||||
ParameterRobustness(
|
||||
name="fast_ema_window", range="5-25", optimal="12", sensitivity="Low"
|
||||
),
|
||||
ParameterRobustness(
|
||||
name="confidence_threshold", range="0.5-0.9", optimal="0.65", sensitivity="Medium"
|
||||
),
|
||||
@@ -229,6 +231,48 @@ def generate_full_audit():
|
||||
)
|
||||
orchestrator.add_section(bench_section)
|
||||
|
||||
# 8. RL Evaluation
|
||||
from src.research.reporting import RLMetric, RLSection
|
||||
|
||||
rl_section = RLSection(
|
||||
comparison_summary="Ensemble outperfoms baseline PPO by 15% in Sharpe.",
|
||||
best_agent="Ensemble_V2",
|
||||
performance_gap=15.2,
|
||||
metrics=[
|
||||
RLMetric(
|
||||
agent_name="Ensemble_V2",
|
||||
sharpe=2.85,
|
||||
sortino=3.20,
|
||||
profit_factor=2.15,
|
||||
max_dd=0.08,
|
||||
win_rate=0.58,
|
||||
recovery_factor=4.50,
|
||||
lake_ratio=0.82,
|
||||
tail_ratio=1.45,
|
||||
sqn=3.10,
|
||||
var_95=0.015,
|
||||
common_sense_ratio=2.45,
|
||||
gain_to_pain_ratio=1.85,
|
||||
),
|
||||
RLMetric(
|
||||
agent_name="Baseline_PPO",
|
||||
sharpe=1.95,
|
||||
sortino=2.10,
|
||||
profit_factor=1.65,
|
||||
max_dd=0.14,
|
||||
win_rate=0.52,
|
||||
recovery_factor=2.80,
|
||||
lake_ratio=0.65,
|
||||
tail_ratio=1.10,
|
||||
sqn=1.85,
|
||||
var_95=0.025,
|
||||
common_sense_ratio=1.65,
|
||||
gain_to_pain_ratio=1.20,
|
||||
),
|
||||
],
|
||||
)
|
||||
orchestrator.add_section(rl_section)
|
||||
|
||||
# Build and Export
|
||||
report = orchestrator.build()
|
||||
reporter = ResearchReporter()
|
||||
|
||||
@@ -133,6 +133,8 @@ class BenchmarkComparison(BaseModel):
|
||||
profit_factor: str = "0.00"
|
||||
sqn: str = "0.00"
|
||||
recovery_factor: str = "0.00"
|
||||
calmar_ratio: str = "0.00"
|
||||
expected_shortfall: str = "0.00"
|
||||
|
||||
|
||||
class BenchmarkSection(BaseModel):
|
||||
@@ -252,7 +254,9 @@ class ResearchReporter:
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
template_dir = os.path.join(base_dir, "templates")
|
||||
|
||||
self.jinja_env = Environment(loader=FileSystemLoader(template_dir))
|
||||
self.jinja_env = Environment(
|
||||
loader=FileSystemLoader(template_dir), extensions=["jinja2.ext.do"]
|
||||
)
|
||||
self.console = Console()
|
||||
|
||||
def generate_markdown(self, report: ResearchReport) -> str:
|
||||
@@ -427,7 +431,7 @@ class ResearchReporter:
|
||||
m_table.add_column("WR")
|
||||
for m in report.trade_patterns.motifs:
|
||||
if m.win_rate < 0.5:
|
||||
wr_color = self._get_color_for_metric(m.win_rate, 'win_rate')
|
||||
wr_color = self._get_color_for_metric(m.win_rate, "win_rate")
|
||||
m_table.add_row(
|
||||
m.algorithm,
|
||||
m.volatility_bucket,
|
||||
@@ -472,6 +476,7 @@ class ResearchReporter:
|
||||
table.add_column("PF")
|
||||
table.add_column("SQN")
|
||||
table.add_column("Recov")
|
||||
table.add_column("Calmar")
|
||||
table.add_column("P-Value")
|
||||
for b in report.benchmarks.comparisons:
|
||||
table.add_row(
|
||||
@@ -482,6 +487,7 @@ class ResearchReporter:
|
||||
f"[{self._get_color_for_metric(b.profit_factor, 'pf')}]{b.profit_factor}[/]",
|
||||
b.sqn,
|
||||
f"[{self._get_color_for_metric(b.recovery_factor, 'recovery')}]{b.recovery_factor}[/]",
|
||||
b.calmar_ratio,
|
||||
b.p_value,
|
||||
)
|
||||
self.console.print(table)
|
||||
@@ -524,7 +530,9 @@ class ResearchReporter:
|
||||
self.console.print(table)
|
||||
|
||||
if report.calibration_analysis:
|
||||
self.console.print(f"\n[bold cyan]{section_idx}. Confidence Calibration & Reliability[/]")
|
||||
self.console.print(
|
||||
f"\n[bold cyan]{section_idx}. Confidence Calibration & Reliability[/]"
|
||||
)
|
||||
section_idx += 1
|
||||
self.console.print(
|
||||
f"ECE: [bold]{report.calibration_analysis.ece:.4f}[/] | "
|
||||
@@ -537,11 +545,11 @@ class ResearchReporter:
|
||||
table.add_column("Avg Confidence")
|
||||
table.add_column("Samples")
|
||||
for b in report.calibration_analysis.buckets:
|
||||
table.add_row(
|
||||
b.range, f"{b.accuracy:.1%}", f"{b.confidence:.1%}", str(b.samples)
|
||||
)
|
||||
table.add_row(b.range, f"{b.accuracy:.1%}", f"{b.confidence:.1%}", str(b.samples))
|
||||
self.console.print(table)
|
||||
self.console.print(f"[dim]Insight: {report.calibration_analysis.reliability_insight}[/]")
|
||||
self.console.print(
|
||||
f"[dim]Insight: {report.calibration_analysis.reliability_insight}[/]"
|
||||
)
|
||||
|
||||
if report.execution_quality:
|
||||
self.console.print(f"\n[bold blue]{section_idx}. Execution Quality & Alpha Decay[/]")
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
.badge-critical { background: #fde8e8; color: #9b1c1c; }
|
||||
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
|
||||
.kpi-dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 2.5rem; }
|
||||
.kpi-card { background: var(--white); padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); text-align: center; border-top: 4px solid var(--secondary); }
|
||||
.kpi-value { font-size: 2rem; font-weight: 800; color: var(--primary); display: block; }
|
||||
.kpi-card { background: var(--white); padding: 1rem; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); text-align: center; border-top: 4px solid var(--secondary); }
|
||||
.kpi-value { font-size: 1.5rem; font-weight: 800; color: var(--primary); display: block; }
|
||||
.kpi-label { font-size: 0.85rem; font-weight: 600; color: #718096; text-transform: uppercase; letter-spacing: 0.025em; }
|
||||
.status-badge { padding: 8px 16px; border-radius: 999px; font-weight: 700; font-size: 0.9rem; }
|
||||
.status-verified { background: #def7ec; color: #03543f; }
|
||||
@@ -115,6 +115,38 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% set critical_flags = [] %}
|
||||
{% if model_drift %}
|
||||
{% for m in model_drift.metrics %}
|
||||
{% if m.status in ['WARNING', 'CRITICAL'] %}
|
||||
{% if m.status not in critical_flags %}{% do critical_flags.append(m.status) %}{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if stress_tests %}
|
||||
{% for s in stress_tests.scenarios %}
|
||||
{% if s.outcome == 'FAIL' %}
|
||||
{% if 'FAIL' not in critical_flags %}{% do critical_flags.append('FAIL') %}{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if calibration_analysis %}
|
||||
{% if calibration_analysis.status in ['WARNING', 'CRITICAL'] %}
|
||||
{% if calibration_analysis.status not in critical_flags %}{% do critical_flags.append(calibration_analysis.status) %}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if critical_flags %}
|
||||
<div class="insight-box" style="background-color: #fff5f5; border: 1px solid #feb2b2; color: #9b2c2c; margin-bottom: 2rem; border-left: 6px solid var(--danger);">
|
||||
<strong style="font-size: 1.2rem;">⚠️ Critical Research Warnings</strong>
|
||||
<p style="margin-top: 0.5rem; margin-bottom: 0;">
|
||||
This report contains indicators that require immediate attention:
|
||||
<strong>{{ critical_flags|join(', ') }}</strong>.
|
||||
Review the Model Drift and Stress Test sections for details.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="kpi-dashboard">
|
||||
{% if stress_tests %}
|
||||
<div class="kpi-card" style="border-top-color: var(--danger);">
|
||||
@@ -454,9 +486,11 @@
|
||||
<th scope="col">Return</th>
|
||||
<th scope="col">Sharpe</th>
|
||||
<th scope="col">MaxDD</th>
|
||||
<th scope="col">CVaR</th>
|
||||
<th scope="col">PF</th>
|
||||
<th scope="col">SQN</th>
|
||||
<th scope="col">Recovery</th>
|
||||
<th scope="col">Calmar</th>
|
||||
<th scope="col">P-Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -467,9 +501,11 @@
|
||||
<td>{{ b.total_return }}</td>
|
||||
<td>{{ b.sharpe }}</td>
|
||||
<td>{{ b.max_drawdown }}</td>
|
||||
<td>{{ b.expected_shortfall }}</td>
|
||||
<td>{{ b.profit_factor }}</td>
|
||||
<td>{{ b.sqn }}</td>
|
||||
<td>{{ b.recovery_factor }}</td>
|
||||
<td>{{ b.calmar_ratio }}</td>
|
||||
<td>{{ b.p_value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
@@ -490,12 +526,13 @@
|
||||
<th scope="col">Agent</th>
|
||||
<th scope="col">Sharpe</th>
|
||||
<th scope="col">Sortino</th>
|
||||
<th scope="col">Profit Factor</th>
|
||||
<th scope="col">PF</th>
|
||||
<th scope="col">MaxDD</th>
|
||||
<th scope="col">Recovery</th>
|
||||
<th scope="col">VaR(95%)</th>
|
||||
<th scope="col">Tail Ratio</th>
|
||||
<th scope="col">CSR</th>
|
||||
<th scope="col">Recov</th>
|
||||
<th scope="col">VaR(95)</th>
|
||||
<th scope="col">Tail</th>
|
||||
<th scope="col">Lake</th>
|
||||
<th scope="col">SQN</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -509,7 +546,8 @@
|
||||
<td>{{ m.recovery_factor|round(2) }}</td>
|
||||
<td>{{ (m.var_95 * 100)|round(2) }}%</td>
|
||||
<td>{{ m.tail_ratio|round(2) }}</td>
|
||||
<td>{{ m.common_sense_ratio|round(2) }}</td>
|
||||
<td>{{ m.lake_ratio|round(2) }}</td>
|
||||
<td>{{ m.sqn|round(2) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -159,10 +159,10 @@
|
||||
{% if benchmarks %}
|
||||
{% set ns.count = ns.count + 1 %}
|
||||
## {{ ns.count }}. Benchmark Comparisons
|
||||
| Strategy | Total Return | Sharpe | MaxDD | PF | SQN | Recov | P-Value |
|
||||
|----------|--------------|--------|-------|----|-----|-------|---------|
|
||||
| Strategy | Total Return | Sharpe | MaxDD | CVaR | PF | SQN | Recov | Calmar | P-Value |
|
||||
|----------|--------------|--------|-------|------|----|-----|-------|--------|---------|
|
||||
{% for b in benchmarks.comparisons %}
|
||||
| {{ b.name }} | {{ b.total_return }} | {{ b.sharpe }} | {{ b.max_drawdown }} | {{ b.profit_factor }} | {{ b.sqn }} | {{ b.recovery_factor }} | {{ b.p_value }} |
|
||||
| {{ b.name }} | {{ b.total_return }} | {{ b.sharpe }} | {{ b.max_drawdown }} | {{ b.expected_shortfall }} | {{ b.profit_factor }} | {{ b.sqn }} | {{ b.recovery_factor }} | {{ b.calmar_ratio }} | {{ b.p_value }} |
|
||||
{% endfor %}
|
||||
|
||||
**Statistical Significance:**
|
||||
@@ -174,10 +174,10 @@
|
||||
## {{ ns.count }}. RL Agent Evaluation
|
||||
**Summary:** {{ rl_evaluation.comparison_summary }}
|
||||
|
||||
| Agent | Sharpe | Sortino | PF | MaxDD | Recovery | VaR(95%) | CSR | G2P |
|
||||
|-------|--------|---------|----|-------|----------|----------|-----|-----|
|
||||
| Agent | Sharpe | Sortino | PF | MaxDD | Recovery | VaR(95%) | CSR | G2P | Lake | Tail | SQN |
|
||||
|-------|--------|---------|----|-------|----------|----------|-----|-----|------|------|-----|
|
||||
{% for m in rl_evaluation.metrics %}
|
||||
| {{ m.agent_name }} | {{ m.sharpe|round(2) }} | {{ m.sortino|round(2) }} | {{ m.profit_factor|round(2) }} | {{ (m.max_dd * 100)|round(1) }}% | {{ m.recovery_factor|round(2) }} | {{ (m.var_95 * 100)|round(2) }}% | {{ m.common_sense_ratio|round(2) }} | {{ m.gain_to_pain_ratio|round(2) }} |
|
||||
| {{ m.agent_name }} | {{ m.sharpe|round(2) }} | {{ m.sortino|round(2) }} | {{ m.profit_factor|round(2) }} | {{ (m.max_dd * 100)|round(1) }}% | {{ m.recovery_factor|round(2) }} | {{ (m.var_95 * 100)|round(2) }}% | {{ m.common_sense_ratio|round(2) }} | {{ m.gain_to_pain_ratio|round(2) }} | {{ m.lake_ratio|round(2) }} | {{ m.tail_ratio|round(2) }} | {{ m.sqn|round(2) }} |
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ from src.data.event_intelligence import (
|
||||
def now():
|
||||
return datetime(2023, 1, 1, 12, 0, 0, tzinfo=UTC)
|
||||
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_session")
|
||||
def test_metaapi_provider_comprehensive(mock_init_session, now):
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_client")
|
||||
def test_metaapi_provider_comprehensive(mock_init_client, now):
|
||||
mock_session = MagicMock()
|
||||
mock_init_session.return_value = mock_session
|
||||
mock_init_client.return_value = mock_session
|
||||
mock_get = mock_session.get
|
||||
|
||||
"""Test MetaAPI provider with various event types and countries."""
|
||||
@@ -162,11 +162,11 @@ def test_stricter_major_event_multipliers(now):
|
||||
# risk_multiplier must be 0.0 if is_blocked is True
|
||||
assert status_major.risk_multiplier == 0.0
|
||||
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_session")
|
||||
def test_metaapi_provider_unsupported_impact(mock_init_session, now):
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_client")
|
||||
def test_metaapi_provider_unsupported_impact(mock_init_client, now):
|
||||
"""Test fallback for unknown impact levels in MetaAPI."""
|
||||
mock_session = MagicMock()
|
||||
mock_init_session.return_value = mock_session
|
||||
mock_init_client.return_value = mock_session
|
||||
mock_get = mock_session.get
|
||||
|
||||
mock_response = MagicMock()
|
||||
|
||||
@@ -14,10 +14,10 @@ from src.data.event_intelligence import (
|
||||
def now():
|
||||
return datetime(2023, 1, 1, 12, 0, 0, tzinfo=UTC)
|
||||
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_session")
|
||||
def test_metaapi_provider_extra_fields(mock_init_session, now):
|
||||
@patch("src.data.event_intelligence.MetaAPIEventProvider._init_client")
|
||||
def test_metaapi_provider_extra_fields(mock_init_client, now):
|
||||
mock_session = MagicMock()
|
||||
mock_init_session.return_value = mock_session
|
||||
mock_init_client.return_value = mock_session
|
||||
mock_get = mock_session.get
|
||||
|
||||
mock_response = MagicMock()
|
||||
|
||||
+153
-60
@@ -3,23 +3,26 @@ Tests for the research reporting system.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from src.research.reporting import (
|
||||
AllocationEntry,
|
||||
AllocationSection,
|
||||
RegimeSection,
|
||||
RegimeSummary,
|
||||
ResearchReport,
|
||||
ResearchReporter,
|
||||
StressedMetric,
|
||||
StressTestSection,
|
||||
ResearchOrchestrator,
|
||||
RareEventSection,
|
||||
RareEventSummary,
|
||||
TradePatternSection,
|
||||
RegimeSection,
|
||||
RegimeSummary,
|
||||
ResearchOrchestrator,
|
||||
ResearchReport,
|
||||
ResearchReporter,
|
||||
SignalMotif,
|
||||
StressedMetric,
|
||||
StressTestSection,
|
||||
TradePatternSection,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_report():
|
||||
return ResearchReport(
|
||||
@@ -28,31 +31,54 @@ def sample_report():
|
||||
regime_analysis=RegimeSection(
|
||||
summary="Market was primarily trending with low volatility.",
|
||||
regimes=[
|
||||
RegimeSummary(label="Trending", frequency_pct=65.0, avg_duration_bars=45, profitability="High"),
|
||||
RegimeSummary(label="Ranging", frequency_pct=25.0, avg_duration_bars=12, profitability="Low"),
|
||||
RegimeSummary(
|
||||
label="Trending", frequency_pct=65.0, avg_duration_bars=45, profitability="High"
|
||||
),
|
||||
RegimeSummary(
|
||||
label="Ranging", frequency_pct=25.0, avg_duration_bars=12, profitability="Low"
|
||||
),
|
||||
],
|
||||
transition_insights="Slow transitions between trending and ranging regimes."
|
||||
transition_insights="Slow transitions between trending and ranging regimes.",
|
||||
),
|
||||
stress_tests=StressTestSection(
|
||||
resilience_score=85.5,
|
||||
baseline=StressedMetric(name="Baseline", total_return="12.5%", max_drawdown="4.2%", sharpe="2.1", outcome="PASS"),
|
||||
baseline=StressedMetric(
|
||||
name="Baseline",
|
||||
total_return="12.5%",
|
||||
max_drawdown="4.2%",
|
||||
sharpe="2.1",
|
||||
outcome="PASS",
|
||||
),
|
||||
scenarios=[
|
||||
StressedMetric(name="Spread Widening", total_return="10.1%", max_drawdown="5.8%", sharpe="1.8", outcome="PASS"),
|
||||
StressedMetric(name="News Shock", total_return="-2.5%", max_drawdown="15.2%", sharpe="-0.5", outcome="FAIL"),
|
||||
StressedMetric(
|
||||
name="Spread Widening",
|
||||
total_return="10.1%",
|
||||
max_drawdown="5.8%",
|
||||
sharpe="1.8",
|
||||
outcome="PASS",
|
||||
),
|
||||
StressedMetric(
|
||||
name="News Shock",
|
||||
total_return="-2.5%",
|
||||
max_drawdown="15.2%",
|
||||
sharpe="-0.5",
|
||||
outcome="FAIL",
|
||||
),
|
||||
],
|
||||
fragility_indicators=["High drawdown during volatility spikes"],
|
||||
failure_points=["Sudden 50bp price jumps"]
|
||||
failure_points=["Sudden 50bp price jumps"],
|
||||
),
|
||||
allocation_insights=AllocationSection(
|
||||
total_heat_pct=45.0,
|
||||
allocations=[
|
||||
AllocationEntry(name="XAUUSD_PPO", amount="$45,000", heat_pct=45.0, multiplier=1.2)
|
||||
],
|
||||
rejection_summary={"Symbol concentration": 5}
|
||||
rejection_summary={"Symbol concentration": 5},
|
||||
),
|
||||
conclusion="Recommend deploying with reduced size during high-impact news."
|
||||
conclusion="Recommend deploying with reduced size during high-impact news.",
|
||||
)
|
||||
|
||||
|
||||
def test_markdown_generation(sample_report):
|
||||
reporter = ResearchReporter()
|
||||
markdown = reporter.generate_markdown(sample_report)
|
||||
@@ -71,6 +97,7 @@ def test_markdown_generation(sample_report):
|
||||
assert "$45,000" in markdown
|
||||
assert "Recommend deploying" in markdown
|
||||
|
||||
|
||||
def test_terminal_formatting(sample_report, capsys):
|
||||
reporter = ResearchReporter()
|
||||
reporter.format_for_terminal(sample_report)
|
||||
@@ -82,6 +109,7 @@ def test_terminal_formatting(sample_report, capsys):
|
||||
assert "Resilience Score: 85.5/100" in captured.out
|
||||
assert "Capital Allocation" in captured.out
|
||||
|
||||
|
||||
def test_save_markdown(sample_report, tmp_path):
|
||||
reporter = ResearchReporter()
|
||||
file_path = tmp_path / "test_report.md"
|
||||
@@ -92,17 +120,20 @@ def test_save_markdown(sample_report, tmp_path):
|
||||
content = f.read()
|
||||
assert "Q1 2024 Strategy Robustness Audit" in content
|
||||
|
||||
|
||||
def test_research_orchestrator():
|
||||
orchestrator = ResearchOrchestrator(
|
||||
title="Orchestrated Report",
|
||||
executive_summary="Summary",
|
||||
conclusion="Conclusion"
|
||||
title="Orchestrated Report", executive_summary="Summary", conclusion="Conclusion"
|
||||
)
|
||||
|
||||
regime = RegimeSection(
|
||||
summary="Test Summary",
|
||||
regimes=[RegimeSummary(label="Trending", frequency_pct=50, avg_duration_bars=10, profitability="Neutral")],
|
||||
transition_insights="None"
|
||||
regimes=[
|
||||
RegimeSummary(
|
||||
label="Trending", frequency_pct=50, avg_duration_bars=10, profitability="Neutral"
|
||||
)
|
||||
],
|
||||
transition_insights="None",
|
||||
)
|
||||
|
||||
orchestrator.add_section(regime)
|
||||
@@ -112,19 +143,25 @@ def test_research_orchestrator():
|
||||
assert report.regime_analysis is not None
|
||||
assert report.regime_analysis.summary == "Test Summary"
|
||||
|
||||
|
||||
def test_rare_event_reporting():
|
||||
rare_event_section = RareEventSection(
|
||||
scenarios=[
|
||||
RareEventSummary(event_type="flash_crash", peak_impact_pct=-0.05, realized_volatility=0.1, recovery_attained=0.8)
|
||||
RareEventSummary(
|
||||
event_type="flash_crash",
|
||||
peak_impact_pct=-0.05,
|
||||
realized_volatility=0.1,
|
||||
recovery_attained=0.8,
|
||||
)
|
||||
],
|
||||
insights="Resilient to small crashes."
|
||||
insights="Resilient to small crashes.",
|
||||
)
|
||||
|
||||
report = ResearchReport(
|
||||
title="Rare Event Audit",
|
||||
executive_summary="Testing rare events.",
|
||||
rare_events=rare_event_section,
|
||||
conclusion="Final."
|
||||
conclusion="Final.",
|
||||
)
|
||||
|
||||
reporter = ResearchReporter()
|
||||
@@ -139,15 +176,30 @@ def test_rare_event_reporting():
|
||||
assert "Rare Event Simulations" in html
|
||||
assert "flash_crash" in html
|
||||
assert 'href="#rare-events"' in html
|
||||
assert 'role="progressbar"' not in html # No stress tests here
|
||||
assert 'role="progressbar"' not in html # No stress tests here
|
||||
|
||||
|
||||
def test_calibration_reporting():
|
||||
"""Verify that CalibrationResult integrates with the reporting system."""
|
||||
from src.models.calibration import CalibrationResult, ConfidenceBucket
|
||||
|
||||
buckets = [
|
||||
ConfidenceBucket(range_start=0.5, range_end=0.6, avg_confidence=0.55, accuracy=0.52, sample_count=10, deviation=0.03),
|
||||
ConfidenceBucket(range_start=0.9, range_end=1.0, avg_confidence=0.95, accuracy=0.92, sample_count=5, deviation=0.03)
|
||||
ConfidenceBucket(
|
||||
range_start=0.5,
|
||||
range_end=0.6,
|
||||
avg_confidence=0.55,
|
||||
accuracy=0.52,
|
||||
sample_count=10,
|
||||
deviation=0.03,
|
||||
),
|
||||
ConfidenceBucket(
|
||||
range_start=0.9,
|
||||
range_end=1.0,
|
||||
avg_confidence=0.95,
|
||||
accuracy=0.92,
|
||||
sample_count=5,
|
||||
deviation=0.03,
|
||||
),
|
||||
]
|
||||
cal_res = CalibrationResult(
|
||||
brier_score=0.05,
|
||||
@@ -158,14 +210,14 @@ def test_calibration_reporting():
|
||||
mce=0.08,
|
||||
buckets=buckets,
|
||||
optimal_threshold=0.65,
|
||||
status="VERIFIED"
|
||||
status="VERIFIED",
|
||||
)
|
||||
|
||||
report = ResearchReport(
|
||||
title="Calibration Audit",
|
||||
executive_summary="Testing calibration.",
|
||||
calibration_analysis=cal_res.to_report_section(),
|
||||
conclusion="Calibrated."
|
||||
conclusion="Calibrated.",
|
||||
)
|
||||
|
||||
reporter = ResearchReporter()
|
||||
@@ -182,23 +234,24 @@ def test_calibration_reporting():
|
||||
assert "0.04" in html
|
||||
assert "0.65" in html
|
||||
|
||||
|
||||
def test_html_dynamic_elements(sample_report):
|
||||
"""Verify TOC, dynamic numbering and progress bars in HTML."""
|
||||
reporter = ResearchReporter()
|
||||
html = reporter.generate_html(sample_report)
|
||||
|
||||
# TOC and Navigation
|
||||
assert 'Table of Contents' in html
|
||||
assert "Table of Contents" in html
|
||||
assert 'href="#executive-summary"' in html
|
||||
assert 'href="#regime-analysis"' in html
|
||||
assert 'href="#stress-tests"' in html
|
||||
|
||||
# Dynamic Numbering in TOC (Executive Summary is 1, Regime is 2, Stress is 3, Allocation is 4, Conclusion is 5)
|
||||
assert '1. Executive Summary' in html
|
||||
assert '2. Market Regime Analysis' in html
|
||||
assert '3. Stress Test Outcomes' in html
|
||||
assert '4. Capital Allocation Insights' in html
|
||||
assert '5. Conclusion & Recommendations' in html
|
||||
assert "1. Executive Summary" in html
|
||||
assert "2. Market Regime Analysis" in html
|
||||
assert "3. Stress Test Outcomes" in html
|
||||
assert "4. Capital Allocation Insights" in html
|
||||
assert "5. Conclusion & Recommendations" in html
|
||||
|
||||
# Progress Bars (ARIA)
|
||||
assert 'role="progressbar"' in html
|
||||
@@ -207,27 +260,29 @@ def test_html_dynamic_elements(sample_report):
|
||||
# Accessibility
|
||||
assert 'scope="col"' in html
|
||||
|
||||
|
||||
def test_html_ux_enhancements(sample_report):
|
||||
"""Verify smooth scroll, back-to-top and color coding in HTML."""
|
||||
reporter = ResearchReporter()
|
||||
html = reporter.generate_html(sample_report)
|
||||
|
||||
# Smooth scroll
|
||||
assert 'scroll-behavior: smooth;' in html
|
||||
assert "scroll-behavior: smooth;" in html
|
||||
|
||||
# Back to top button
|
||||
assert 'class="back-to-top"' in html
|
||||
assert 'aria-label="Scroll back to top"' in html
|
||||
|
||||
# Color coding classes
|
||||
assert '.fill-low' in html
|
||||
assert '.fill-medium' in html
|
||||
assert '.fill-high' in html
|
||||
assert ".fill-low" in html
|
||||
assert ".fill-medium" in html
|
||||
assert ".fill-high" in html
|
||||
|
||||
# Resilience score is 85.5 -> should have fill-high
|
||||
assert 'fill-high' in html
|
||||
assert "fill-high" in html
|
||||
assert 'aria-label="Strategy resilience score: 85.5 out of 100"' in html
|
||||
|
||||
|
||||
def test_html_accessibility_hardening(sample_report):
|
||||
"""Verify accessibility and print hardening in HTML."""
|
||||
reporter = ResearchReporter()
|
||||
@@ -236,11 +291,11 @@ def test_html_accessibility_hardening(sample_report):
|
||||
# Skip to main content link
|
||||
assert 'class="skip-link"' in html
|
||||
assert 'href="#main-content"' in html
|
||||
assert 'Skip to main content' in html
|
||||
assert "Skip to main content" in html
|
||||
|
||||
# Semantic main tag
|
||||
assert '<main id="main-content">' in html
|
||||
assert '</main>' in html
|
||||
assert "</main>" in html
|
||||
|
||||
# ARIA labels
|
||||
assert 'role="banner"' in html
|
||||
@@ -249,9 +304,35 @@ def test_html_accessibility_hardening(sample_report):
|
||||
assert 'aria-hidden="true"' in html # For the back-to-top icon
|
||||
|
||||
# Print styles
|
||||
assert '@media print' in html
|
||||
assert '.print-btn' in html
|
||||
assert 'window[\'print\']()' in html
|
||||
assert "@media print" in html
|
||||
assert ".print-btn" in html
|
||||
assert "window['print']()" in html
|
||||
|
||||
|
||||
def test_critical_warnings_panel():
|
||||
"""Verify that the critical warnings panel appears when there are issues."""
|
||||
from src.research.reporting import DriftMetric, ModelDriftSection
|
||||
|
||||
report = ResearchReport(
|
||||
title="Warning Test",
|
||||
executive_summary="Summary",
|
||||
model_drift=ModelDriftSection(
|
||||
metrics=[
|
||||
DriftMetric(
|
||||
name="Test", baseline="1", current="2", drift_pct=100.0, status="CRITICAL"
|
||||
)
|
||||
],
|
||||
feature_shifts="None",
|
||||
),
|
||||
conclusion="Conclusion",
|
||||
)
|
||||
|
||||
reporter = ResearchReporter()
|
||||
html = reporter.generate_html(report)
|
||||
|
||||
assert "Critical Research Warnings" in html
|
||||
assert "CRITICAL" in html
|
||||
|
||||
|
||||
def test_trade_pattern_motifs():
|
||||
trade_section = TradePatternSection(
|
||||
@@ -259,15 +340,22 @@ def test_trade_pattern_motifs():
|
||||
concentrations=[],
|
||||
behavioral_risks=[],
|
||||
motifs=[
|
||||
SignalMotif(algorithm="PPO", direction=1, volatility_bucket="High", confidence_bucket="Low", frequency=5, win_rate=0.2)
|
||||
]
|
||||
SignalMotif(
|
||||
algorithm="PPO",
|
||||
direction=1,
|
||||
volatility_bucket="High",
|
||||
confidence_bucket="Low",
|
||||
frequency=5,
|
||||
win_rate=0.2,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
report = ResearchReport(
|
||||
title="Motif Audit",
|
||||
executive_summary="Testing motifs.",
|
||||
trade_patterns=trade_section,
|
||||
conclusion="Final."
|
||||
conclusion="Final.",
|
||||
)
|
||||
|
||||
reporter = ResearchReporter()
|
||||
@@ -277,6 +365,7 @@ def test_trade_pattern_motifs():
|
||||
assert "PPO" in md
|
||||
assert "20.0%" in md
|
||||
|
||||
|
||||
def test_rl_evaluation_reporting():
|
||||
from src.research.reporting import RLMetric, RLSection
|
||||
|
||||
@@ -292,16 +381,16 @@ def test_rl_evaluation_reporting():
|
||||
profit_factor=1.8,
|
||||
max_dd=0.12,
|
||||
win_rate=0.6,
|
||||
recovery_factor=4.2
|
||||
recovery_factor=4.2,
|
||||
)
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
report = ResearchReport(
|
||||
title="RL Audit",
|
||||
executive_summary="Testing RL.",
|
||||
rl_evaluation=rl_section,
|
||||
conclusion="Final."
|
||||
conclusion="Final.",
|
||||
)
|
||||
|
||||
reporter = ResearchReporter()
|
||||
@@ -317,8 +406,10 @@ def test_rl_evaluation_reporting():
|
||||
assert "Agent_V2" in html
|
||||
assert 'href="#rl-evaluation"' in html
|
||||
|
||||
|
||||
def test_rl_metric_new_fields():
|
||||
from src.research.reporting import RLMetric
|
||||
|
||||
metric = RLMetric(
|
||||
agent_name="TestAgent",
|
||||
sharpe=1.5,
|
||||
@@ -327,20 +418,18 @@ def test_rl_metric_new_fields():
|
||||
win_rate=0.5,
|
||||
tail_ratio=1.8,
|
||||
common_sense_ratio=2.1,
|
||||
gain_to_pain_ratio=1.4
|
||||
gain_to_pain_ratio=1.4,
|
||||
)
|
||||
assert metric.tail_ratio == 1.8
|
||||
assert metric.common_sense_ratio == 2.1
|
||||
assert metric.gain_to_pain_ratio == 1.4
|
||||
|
||||
|
||||
def test_pattern_concentration_total_trades():
|
||||
from src.research.reporting import PatternConcentration
|
||||
|
||||
pc = PatternConcentration(
|
||||
attribute="Algo",
|
||||
value="PPO",
|
||||
win_rate=0.6,
|
||||
profit_factor=2.0,
|
||||
total_trades=100
|
||||
attribute="Algo", value="PPO", win_rate=0.6, profit_factor=2.0, total_trades=100
|
||||
)
|
||||
assert pc.total_trades == 100
|
||||
|
||||
@@ -385,13 +474,17 @@ def test_terminal_dynamic_numbering(mocker):
|
||||
found_rl = any("2. RL Agent Evaluation" in s for s in calls)
|
||||
|
||||
assert found_regime, f"Regime analysis header not found in: {calls}"
|
||||
assert found_rl, f"RL Evaluation should be section 2, but header not found correctly in: {calls}"
|
||||
assert found_rl, (
|
||||
f"RL Evaluation should be section 2, but header not found correctly in: {calls}"
|
||||
)
|
||||
|
||||
|
||||
def test_generate_audit_report_smoke_test():
|
||||
"""Verify that the audit report generation script runs without error."""
|
||||
from src.research.generate_audit_report import generate_full_audit
|
||||
import os
|
||||
|
||||
from src.research.generate_audit_report import generate_full_audit
|
||||
|
||||
# Run the generation
|
||||
generate_full_audit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user