`;
let weightsHtml = "";
let hasNegativeWeightPdf = false;
results.weights.forEach((w, index) => {
weightsHtml += `
`;
const interpretationNote_pdf = `This tool calculates unconstrained Minimum Variance Portfolio weights. Accuracy depends heavily on input quality (expected returns, volatilities, correlations). Negative weights imply short selling. This is a simplified model, not investment advice.`;
pdfContentEl.innerHTML = `
Weight ${inputs.sectors[index].name}: ${sso_formatPercentage(w)}
`; if (w < 0) hasNegativeWeightPdf = true; }); if (hasNegativeWeightPdf) { weightsHtml += `Note: Negative weights imply short selling. Long-only MVP would differ.
`; } const resultsSummaryHtml = `Expected Portfolio Return: ${sso_formatPercentage(results.portfolioReturn)}
Portfolio Volatility (Std. Dev.): ${sso_formatPercentage(results.portfolioVolatility)}
3-Sector Minimum Variance Portfolio Analysis
I. Input Parameters
${inputsHtml}
II. Minimum Variance Portfolio (Unconstrained)
Optimal Weights:
${weightsHtml}
Portfolio Characteristics:
${resultsSummaryHtml}
Important Notes: ${interpretationNote_pdf}
`;
document.body.appendChild(pdfContentEl);
html2canvas(pdfContentEl, { scale: 2, useCORS: true, logging:true, windowWidth: pdfContentEl.scrollWidth, windowHeight: pdfContentEl.scrollHeight }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
let numPages = Math.ceil(canvas.height / ( (pdfHeight - 40) * (canvas.width / (pdfWidth - 40)) ) );
let pageCanvasHeight = (pdfHeight - 40) * (canvas.width / (pdfWidth - 40));
for (let i = 0; i < numPages; i++) {
if (i > 0) pdf.addPage();
let sourceY = i * pageCanvasHeight;
let sourceHeight = Math.min(pageCanvasHeight, canvas.height - sourceY);
const tempCanvas = document.createElement('canvas');
tempCanvas.width = canvas.width;
tempCanvas.height = sourceHeight;
const ctx = tempCanvas.getContext('2d');
ctx.drawImage(canvas, 0, sourceY, canvas.width, sourceHeight, 0, 0, canvas.width, sourceHeight);
const pageImgData = tempCanvas.toDataURL('image/png');
const pageImgHeight = (sourceHeight * (pdfWidth - 40)) / canvas.width;
pdf.addImage(pageImgData, 'PNG', 20, 20, pdfWidth - 40, pageImgHeight, undefined, 'FAST');
}
pdf.save('3_Sector_MVP_Analysis.pdf');
if(document.body.contains(pdfContentEl)) document.body.removeChild(pdfContentEl);
}).catch(err => {
console.error("SSO PDF Error:", err); alert("Error generating PDF. See console.");
if(document.body.contains(pdfContentEl)) document.body.removeChild(pdfContentEl);
});
}
document.addEventListener('DOMContentLoaded', function() {
sso_updateCorrelationLabels(); // Initialize labels
// Add event listeners to update correlation labels when sector names change
['sso_sectorName_1', 'sso_sectorName_2', 'sso_sectorName_3'].forEach(id => {
const el = document.getElementById(id);
if(el) el.addEventListener('input', sso_updateCorrelationLabels);
});
// Set some default values for quicker testing
if (!document.getElementById('sso_sectorName_1').value) {
document.getElementById('sso_sectorName_1').value = 'US Equities';
document.getElementById('sso_expReturn_1').value = '9';
document.getElementById('sso_volatility_1').value = '15';
}
if (!document.getElementById('sso_sectorName_2').value) {
document.getElementById('sso_sectorName_2').value = 'Intl Equities';
document.getElementById('sso_expReturn_2').value = '7';
document.getElementById('sso_volatility_2').value = '18';
}
if (!document.getElementById('sso_sectorName_3').value) {
document.getElementById('sso_sectorName_3').value = 'Bonds';
document.getElementById('sso_expReturn_3').value = '4';
document.getElementById('sso_volatility_3').value = '6';
}
if (!document.getElementById('sso_corr12').value) document.getElementById('sso_corr12').value = '0.7';
if (!document.getElementById('sso_corr13').value) document.getElementById('sso_corr13').value = '0.2';
if (!document.getElementById('sso_corr23').value) document.getElementById('sso_corr23').value = '0.3';
sso_updateCorrelationLabels(); // Call again after setting defaults
if (!document.getElementById('sso_expReturn_1')) { // Check one critical input
console.error("Critical input 'sso_expReturn_1' not found.");
}
});
