Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix/xray-connector-invalid-response #56

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions demos/dashboards-xray/demo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import url("https://code.highcharts.com/dashboards/css/datagrid.css");
@import url("https://code.highcharts.com/css/highcharts.css");
@import url("https://code.highcharts.com/dashboards/css/dashboards.css");

body {
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, sans-serif;
}

.row {
display: flex;
flex-wrap: wrap;
}

.cell {
flex: 1;
min-width: 20px;
}

.cell > .highcharts-dashboards-component {
position: relative;
margin: 10px;
background-clip: border-box;
}

.highcharts-dashboards-component-title {
padding: 10px;
margin: 0;
background-color: var(--highcharts-neutral-color-5);
color: var(--highcharts-neutral-color-100);
border: solid 1px var(--highcharts-neutral-color-20);
border-bottom: none;
}

@media screen and (max-width: 1000px) {
.row {
flex-direction: column;
}
}
25 changes: 25 additions & 0 deletions demos/dashboards-xray/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="demo.css" />
<script src="https://code.highcharts.com/dashboards/datagrid.js"></script>
<script src="https://code.highcharts.com/dashboards/dashboards.js"></script>
<script src="../../code/connectors-morningstar.src.js"></script>
<title>Highcharts Dashboards DataGrid + Morningstar XRay Connector</title>
</head>
<body>
<h1>Highcharts Dashboards DataGrid + Morningstar XRay Connector</h1>
<p>
Add your Postman environment file from Morningstar to start the demo:
<input type="file" id="postman-json" accept=".json,application/json" />
</p>
<p id="loading-label" style="display: none;">Loading data…</p>
<div class="row" id="container">
<div class="cell" id="dashboard-col-0"></div>
<div class="cell" id="dashboard-col-1"></div>
<div class="cell" id="dashboard-col-2"></div>
</div>
<script src="./demo.js"></script>
</body>
</html>
216 changes: 216 additions & 0 deletions demos/dashboards-xray/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
const globalStockSectorMap = {
99: 'Not Classified',
101: 'Basic Materials',
102: 'Consumer Staples',
103: 'Financial Services',
104: 'Real Estate',
205: 'Consumer Defensive',
206: 'Healthcare',
207: 'Utilities',
308: 'Communication Services',
309: 'Energy',
310: 'Industrials',
311: 'Technology'
};

const assetAllocationMap = {
1: 'Stock',
2: 'Bond',
3: 'Cash',
4: 'Other',
99: 'Not Classified'
};

const regionalExposureMap = {
1: 'United States',
2: 'Canada',
3: 'Latin America',
4: 'United Kingdom',
5: 'Eurozone',
6: 'Europe - ex Euro',
7: 'Europe - Emerging',
8: 'Africa',
9: 'Middle East',
10: 'Japan',
11: 'Australasia',
12: 'Asia - Developed',
13: 'Asia - Emerging',
14: 'Emerging Market',
15: 'Developed Country',
16: 'Not Classified',
99: 'Other'
}

async function displaySecurityDetails (postmanJSON) {
const board = Dashboards.board('container', {
dataPool: {
connectors: [{
id: 'xray',
type: 'MorningstarXRay',
options: {
postman: {
environmentJSON: postmanJSON
},
currencyId: 'GBP',
dataPoints: {
type: 'portfolio',
dataPoints: [
'AssetAllocationMorningstarEUR3',
'GlobalStockSector',
'RegionalExposure'
]
},
holdings: [
{
id: 'F0GBR052QA',
idType: 'MSID',
type: 'FO',
weight: '100',
name: 'BlackRock Income and Growth Ord',
holdingType: 'weight'
}
]
}
}]
},
components: [
{
renderTo: 'dashboard-col-0',
connector: {
id: 'xray'
},
type: 'DataGrid',
title: 'Global Stock Sector',
dataGridOptions: {
header: [{
format: 'Net',
columnId: 'XRay_GlobalStockSector_N_Categories'
}, {
format: 'Values',
columnId: 'XRay_GlobalStockSector_N_Values'
}],
columns: [{
id: 'XRay_GlobalStockSector_N_Categories',
cells: {
formatter: function () {
return this.value !== void 0 ?
globalStockSectorMap[this.value] : '';
}
}
}]
}
}, {
renderTo: 'dashboard-col-1',
connector: {
id: 'xray'
},
type: 'DataGrid',
title: 'Morningstar EUR3',
dataGridOptions: {
header: [{
format: 'Long',
columnId: 'XRay_MorningstarEUR3_L_Categories'
}, {
format: 'Values',
columnId: 'XRay_MorningstarEUR3_L_Values'
}, {
format: 'Net',
columnId: 'XRay_MorningstarEUR3_N_Categories'
}, {
format: 'Values',
columnId: 'XRay_MorningstarEUR3_N_Values'
}, {
format: 'Short',
columnId: 'XRay_MorningstarEUR3_S_Categories'
}, {
format: 'Values',
columnId: 'XRay_MorningstarEUR3_S_Values'
}],
columns: [{
id: 'XRay_MorningstarEUR3_L_Categories',
cells: {
formatter: function () {
return this.value !== void 0 ?
assetAllocationMap[this.value] : '';
}
}
}, {
id: 'XRay_MorningstarEUR3_N_Categories',
cells: {
formatter: function () {
return this.value !== void 0 ?
assetAllocationMap[this.value] : '';
}
}
}, {
id: 'XRay_MorningstarEUR3_S_Categories',
cells: {
formatter: function () {
return this.value !== void 0 ?
assetAllocationMap[this.value] : '';
}
}
}]
}
}, {
renderTo: 'dashboard-col-2',
connector: {
id: 'xray'
},
type: 'DataGrid',
title: 'Regional Exposure',
dataGridOptions: {
header: [{
format: 'Net',
columnId: 'XRay_RegionalExposure_N_Categories'
}, {
format: 'Values',
columnId: 'XRay_RegionalExposure_N_Values'
}],
columns: [{
id: 'XRay_RegionalExposure_N_Categories',
cells: {
formatter: function () {
return this.value !== void 0 ?
regionalExposureMap[this.value] : '';
}
}
}]
}
}
]
});

board.dataPool.getConnectorTable('xray');

}

async function handleSelectEnvironment (evt) {
const target = evt.target;
const postmanJSON = await getPostmanJSON(target);

target.parentNode.style.display = 'none';

displaySecurityDetails(postmanJSON);
}

document.getElementById('postman-json')
.addEventListener('change', handleSelectEnvironment);

async function getPostmanJSON (htmlInputFile) {
let file;
let fileJSON;

for (file of htmlInputFile.files) {
try {
fileJSON = JSON.parse(await file.text());
if (HighchartsConnectors.Shared.Morningstar.isPostmanEnvironmentJSON(fileJSON)) {
break;
}
} catch (error) {
// fail silently
}
}

return fileJSON;
}
1 change: 1 addition & 0 deletions demos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<h1>Morningstar Connectors Demos</h1>
<ul>
<li><a href="dashboards-rna-news/demo.html">Highcharts Dashboards + Morningstar RNA News</a></li>
<li><a href="dashboards-xray/demo.html">Highcharts Dashboards + Morningstar XRay Connector</a></li>
<li><a href="stock-timeseries/demo.html">Highcharts Stock + Morningstar TimeSeries</a></li>
<li><a href="stock-ohlcv/demo.html">Highcharts Stock + Morningstar OHLCV TimeSeries</a></li>
<li><a href="stock-securitydetails/demo.html">Highcharts Stock + Morningstar Security Details</a></li>
Expand Down
10 changes: 10 additions & 0 deletions src/Shared/MorningstarOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ interface MorningstarSecurityOptionsGeneric<IDType> {
*/
type?: (string|MorningstarSecurityType);

/**
* Type of holding.
*/
holdingType?: string;

/**
* Weight of holding.
*/
weight?: (number|string);

}


Expand Down
8 changes: 6 additions & 2 deletions src/XRay/XRayConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ interface XRayHoldingObject {
amount?: string;
identifier: string;
identifierType: string;
holdingType: number;
holdingType: string|number;
name?: string;
securityType?: string;
weight?: string;
Expand Down Expand Up @@ -78,7 +78,7 @@ function convertHoldings (
const holding: XRayHoldingObject = {
identifier: security.id,
identifierType: security.idType,
holdingType
holdingType: security.holdingType || holdingType
};

if (security.name) {
Expand All @@ -89,6 +89,10 @@ function convertHoldings (
holding.securityType = security.type;
}

if (security.weight) {
holding.weight = security.weight.toString();
}

return holding;
});
}
Expand Down
44 changes: 35 additions & 9 deletions src/XRay/XRayConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,48 @@ export class XRayConverter extends MorningstarConverter {
): void {
const table = this.table;

for (const asset of json.assetAllocation) {
const rowId = `${benchmarkId}_${asset.type}_${asset.salePosition}`;
const values = asset.values;

for (let i = 1; i < 100; ++i) {
table.setCell(rowId, i - 1, values[i]);
if (json.assetAllocation) {
for (const asset of json.assetAllocation) {
const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`;
table.setColumn(`${columnName}_Categories`);
table.setColumn(`${columnName}_Values`);
const values = asset.values;

const valueIndex = Object.keys(values);

for (let i = 0; i < valueIndex.length; i++) {
table.setCell(`${columnName}_Categories`, i, valueIndex[i]);
table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]);
}
}
}

if (json.regionalExposure) {
for (const exposure of json.regionalExposure) {
const rowId = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`;
const columnName = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`;
table.setColumn(`${columnName}_Categories`);
table.setColumn(`${columnName}_Values`);
const values = exposure.values;
const valueIndex = Object.keys(values);

for (let i = 0; i < valueIndex.length; i++) {
table.setCell(`${columnName}_Categories`, i, valueIndex[i]);
table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]);
}
}
}

for (let i = 1; i < 100; ++i) {
table.setCell(rowId, i - 1, values[i] || 0);
if (json.globalStockSector) {
for (const sector of json.globalStockSector) {
const columnName = `${benchmarkId}_GlobalStockSector_${sector.salePosition}`;
table.setColumn(`${columnName}_Categories`);
table.setColumn(`${columnName}_Values`);
const values = sector.values;
const valueIndex = Object.keys(values);

for (let i = 0; i < valueIndex.length; i++) {
table.setCell(`${columnName}_Categories`, i, valueIndex[i]);
table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]);
}
}
}
Expand Down
Loading
Loading