Portfolio Proposal
Compares current and proposed portfolio allocations with performance and risk metrics for decision-making.
HTML
<script src="https://code.highcharts.com/maps/highmaps.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/dumbbell.js"></script>
<script src="https://code.highcharts.com/modules/series-label.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@highcharts/grid-pro/grid-pro.js"></script>
<script src="https://code.highcharts.com/connectors/morningstar/connectors-morningstar.js"></script>
<header>
<h1>Portfolio Proposal</h1>
<p>Current vs. proposed allocation, risk and historical performance</p>
</header>
<div class="chart-row">
<div class="chart-container" id="stress-chart"></div>
<div class="chart-container" id="growth-chart"></div>
</div>
<div class="chart-row">
<div class="chart-container risk-return">
<div id="risk-return-wrapper">
<div id="risk-return-chart"></div>
</div>
<div class="data-grids">
<div class="data-grid" id="assets-grid"></div>
<div class="data-grid" id="models-grid"></div>
</div>
</div>
<div class="chart-container holdings-container">
<div id="current-holdings-chart"></div>
<div id="proposed-holdings-chart"></div>
</div>
</div>
<div class="chart-row">
<div class="chart-container" id="portfolio-chart"></div>
<div class="chart-container" id="portfolio-grid"></div>
</div>
<div class="chart-row">
<div class="chart-container" id="map-chart"></div>
</div>
<div class="loading-overlay" id="loading-overlay">
<div class="loading-spinner"></div>
</div>
CSS
@import url("https://cdn.jsdelivr.net/npm/@highcharts/grid-pro/css/grid-pro.css");
:root {
color-scheme: light dark;
--page-background: light-dark(#f4f3ee, #1b1b1b);
--card-background: light-dark(#fff, #141414);
--card-border: light-dark(#dcdbd2, #2c2c2c);
--text-color: light-dark(#1e1e1e, #d0d0d0);
--muted-text-color: light-dark(#5a5d5c, #a1a1a1);
--card-shadow: light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4));
}
body {
display: flex;
flex-direction: column;
margin: 0;
font-family: Arial, sans-serif;
gap: 16px;
background-color: var(--page-background);
color: var(--text-color);
padding: 24px;
}
header {
display: flex;
flex-direction: column;
gap: 4px;
}
h1 {
margin: 0;
font-size: 23px;
font-weight: 600;
color: var(--text-color);
}
header p {
margin: 0;
font-size: 15px;
color: var(--muted-text-color);
}
.chart-row {
display: flex;
flex-direction: row;
gap: 16px;
}
.chart-row div {
flex: 1 0 0;
}
#portfolio-grid .hcg-container div {
flex: none;
}
#stress-chart,
#growth-chart,
#risk-return-chart,
#current-holdings-chart,
#proposed-holdings-chart,
#portfolio-chart,
#map-chart {
min-height: 400px;
}
#portfolio-grid {
min-height: 400px !important;
}
.chart-container {
flex: 1;
background: var(--card-background);
border: 1px solid var(--card-border);
border-radius: 10px;
box-shadow: 0 2px 1px var(--card-shadow);
padding: 20px;
}
.chart-container.risk-return {
display: flex;
flex-direction: row;
}
.holdings-container {
display: flex;
min-width: 0;
flex: 1 0 0;
}
.holdings-container #current-holdings-chart {
min-width: 0;
flex: 1;
}
.theme-custom {
--hcg-font-size: 15px;
--hcg-color: var(--text-color);
--hcg-header-color: light-dark(#474554, #a1a1a1);
--hcg-header-padding: 14px;
--hcg-background: var(--card-background);
--hcg-padding: 10px;
...
JavaScript
Highcharts.SVGRenderer.prototype.symbols.triangleLeft = (x, y, w, h) => [
['M', x, y + h / 2],
['L', x + w, y],
['L', x + w, y + h],
['Z']
];
Highcharts.SVGRenderer.prototype.symbols.triangleRight = (x, y, w, h) => [
['M', x + w, y + h / 2],
['L', x, y],
['L', x, y + h],
['Z']
];
// Health is calculated as DividendGrowth 1y vs 3y
const healthMap = {
up: '▲', // "📈",
down: '▼', // "📉",
unchanged: ''
};
// Define constants and utility functions
const predefinedHoldings = [
// Cash assets
{
id: 'US0250818038',
idType: 'ISIN',
type: 'FO',
weight: 15,
name: 'American Century Capital Preservation Fund Investor Class',
symbol: 'CPFXX',
proposedWeight: 12,
// Performance is based on Security Performance M0-M255, without current
// price
performance: [
3.489756,
1.578978,
2.406443,
4.033827,
4.424365,
2.000312,
0.962403,
0.341273,
1.482696
],
health: 0, // No dividend
rating: 5
},
// Bonds
{
id: 'US61747C7074', // Morgan Stanley Instl Liquidity Govt Portfolio
idType: 'ISIN',
type: 'FO',
weight: 10,
name: 'Morgan Stanley Instl Liquidity Govt Portfolio',
symbol: 'MSILX',
proposedWeight: 8,
performance: [
6.441144,
2.326492,
11.612653,
8.407705,
7.397144,
14.58974,
4.214963,
10.441094,
14.269209
],
health: 0, // No dividend
rating: 4
},
{
id: 'US46637K2814', // JPMorgan Hedged Equity Fund Class I
idType: 'ISIN',
type: 'FO',
weight: 8,
name: 'JPMorgan Hedged Equity Fund Class I',
symbol: 'JHEQX',
proposedWeight: 10,
performance: [
...