`;
// Short Vol Card
html += ``;
html += `
`; // end grid
analysisReportDiv.innerHTML = html;
}
if (runAnalysisBtn) {
runAnalysisBtn.addEventListener('click', runFullAnalysis);
}
// --- PDF Download ---
function loadJsPdfIfNeeded(callback) {
if (jsPdfLoaded) { if (callback) callback(); return; }
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js';
script.onload = () => { jsPdfLoaded = true; console.log("jsPDF loaded dynamically."); if (callback) callback(); };
script.onerror = () => { console.error("Failed to load jsPDF."); alert("Error: Could not load PDF library."); };
document.head.appendChild(script);
}
function downloadAnalysisAsPdf() {
if (!jsPdfLoaded) { alert("PDF library not loaded."); return; }
if (!analysisResults) { alert("No analysis results to download. Please run the analysis first."); return; }
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ unit: 'pt', format: 'a4' });
const res = analysisResults;
const formatN = (num, dec = 2) => (typeof num === 'number' ? num.toFixed(dec) : 'N/A');
const formatC = (num) => `$${formatN(num, 2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`;
const pageMargin = 40;
const pageWidth = doc.internal.pageSize.getWidth() - 2 * pageMargin;
let y = pageMargin;
function addMainTitle(text) {
doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); // Primary
doc.text(text, doc.internal.pageSize.getWidth() / 2, y, { align: 'center' }); y += 35;
}
function addSectionTitle(text, color = [52, 152, 219]) { // Secondary
if (y > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); y = pageMargin; }
doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(color[0], color[1], color[2]);
doc.text(text, pageMargin, y); y += 25;
}
function addLine(key, value, indent = 0) {
if (y > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); y = pageMargin; }
doc.setFontSize(10);
doc.setFont(undefined, 'bold'); doc.setTextColor(52, 73, 94); // Darker text
doc.text(key, pageMargin + indent, y);
doc.setFont(undefined, 'normal');
const valueText = String(value);
doc.text(valueText, pageMargin + indent + 160, y, { align: 'left', maxWidth: pageWidth - 160 - indent - 5 });
y += 18;
}
function addInfo(text) {
if (y > doc.internal.pageSize.getHeight() - 50) { doc.addPage(); y = pageMargin; }
doc.setFontSize(8.5); doc.setFont(undefined, 'italic'); doc.setTextColor(127, 140, 141); // Asbestos
const splitText = doc.splitTextToSize(text, pageWidth);
doc.text(splitText, pageMargin, y);
y += (doc.getTextDimensions(splitText).h) + 10;
}
addMainTitle("Long vs. Short Volatility Performance Analysis");
addInfo(`Report Generated: ${new Date().toLocaleString()}`);
y += 10;
addSectionTitle("Common Backtest Parameters", [44, 62, 80]);
addLine("Period:", `${res.common.startDateStr} to ${res.common.endDateStr} (${res.common.numMonths} months)`);
addLine("Initial Capital per Strategy:", formatC(res.common.initialCapital));
addLine("Transaction Costs:", `${formatN(res.common.transactionCostPct, 2)}% per trade`);
addLine("Annual Risk-Free Rate:", `${formatN(res.common.riskFreeRateAnnualPct, 1)}%`);
y += 10;
// Long Vol Strategy Results
addSectionTitle("Long Volatility Strategy Performance", [46, 204, 113]); // Emerald
addLine("Entry VIX (>):", formatN(res.longVol.params.longVolEntryVix,1));
addLine("Holding Period (Months):", res.longVol.params.longVolHold);
addLine("Final Portfolio Value:", formatC(res.longVol.metrics.finalValue));
addLine("Total Return:", `${formatN(res.longVol.metrics.totalReturn)}%`);
addLine("Annualized Return:", `${formatN(res.longVol.metrics.annualizedReturn)}%`);
addLine("Annualized Volatility:", `${formatN(res.longVol.metrics.volatility)}%`);
addLine("Sharpe Ratio:", formatN(res.longVol.metrics.sharpeRatio));
addLine("Max Drawdown:", `${formatN(res.longVol.metrics.maxDrawdown)}%`);
addLine("Number of Trades:", res.longVol.metrics.trades);
y += 10;
// Short Vol Strategy Results
addSectionTitle("Short Volatility Strategy Performance", [231, 76, 60]); // Alizarin
addLine("Entry VIX (<):", formatN(res.shortVol.params.shortVolEntryVix,1));
addLine("Holding Period (Months):", res.shortVol.params.shortVolHold);
addLine("Stop Loss (% VIX Inc.):", `${formatN(res.shortVol.params.shortVolStopLossPct,0)}%`);
addLine("Final Portfolio Value:", formatC(res.shortVol.metrics.finalValue));
addLine("Total Return:", `${formatN(res.shortVol.metrics.totalReturn)}%`);
addLine("Annualized Return:", `${formatN(res.shortVol.metrics.annualizedReturn)}%`);
addLine("Annualized Volatility:", `${formatN(res.shortVol.metrics.volatility)}%`);
addLine("Sharpe Ratio:", formatN(res.shortVol.metrics.sharpeRatio));
addLine("Max Drawdown:", `${formatN(res.shortVol.metrics.maxDrawdown)}%`);
addLine("Number of Trades:", res.shortVol.metrics.trades);
y += 10;
addInfo("Disclaimer: This analysis is based on simplified strategy proxies and illustrative sample data. It is for educational purposes only and not financial advice. Actual market performance can vary significantly.");
// Footer
const pageCount = doc.internal.getNumberOfPages();
for (let i = 1; i <= pageCount; i++) {
doc.setPage(i);
doc.setFontSize(8); doc.setTextColor(149, 165, 166); // Concrete
doc.text(`Page ${i} of ${pageCount} - Volatility Strategy Analyzer`, pageMargin, doc.internal.pageSize.getHeight() - 20);
}
doc.save('Volatility_Strategy_Performance_Analysis.pdf');
}
if (downloadPdfBtn) {
downloadPdfBtn.addEventListener('click', () => loadJsPdfIfNeeded(downloadAnalysisAsPdf));
}
// --- Initialization ---
populateDateSelects();
showTab(0);
loadJsPdfIfNeeded();
});
Short Volatility Strategy
`; html += `Final Value: ${formatCurrency(results.shortVol.metrics.finalValue)}
`; html += `Total Return: ${formatNum(results.shortVol.metrics.totalReturn)}%
`; html += `Annualized Return: ${formatNum(results.shortVol.metrics.annualizedReturn)}%
`; html += `Annualized Volatility: ${formatNum(results.shortVol.metrics.volatility)}%
`; html += `Sharpe Ratio (Rf=${results.common.riskFreeRateAnnualPct}%): ${formatNum(results.shortVol.metrics.sharpeRatio)}
`; html += `Max Drawdown: ${formatNum(results.shortVol.metrics.maxDrawdown)}%
`; html += `Number of Trades: ${results.shortVol.metrics.trades}
`; html += `