From 9d3613242dfb82d4fd5641a9d74725984d9dc971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Wed, 27 Nov 2024 12:31:54 +0100 Subject: [PATCH 01/12] Fixed incorrect response from xray converter. --- demos/xray_wip/demo.css | 38 +++++++++++++++++++ demos/xray_wip/demo.html | 25 +++++++++++++ demos/xray_wip/demo.js | 77 +++++++++++++++++++++++++++++++++++++++ src/XRay/XRayConverter.ts | 12 ++++-- 4 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 demos/xray_wip/demo.css create mode 100644 demos/xray_wip/demo.html create mode 100644 demos/xray_wip/demo.js diff --git a/demos/xray_wip/demo.css b/demos/xray_wip/demo.css new file mode 100644 index 0000000..23cc8f9 --- /dev/null +++ b/demos/xray_wip/demo.css @@ -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; + } +} diff --git a/demos/xray_wip/demo.html b/demos/xray_wip/demo.html new file mode 100644 index 0000000..1a4444f --- /dev/null +++ b/demos/xray_wip/demo.html @@ -0,0 +1,25 @@ + + + + + + + + + + Highcharts Dashboards + Morningstar Portfolio Risk Score + + +

Highcharts Dashboards + Morningstar Portfolio Risk Score

+

+ Add your Postman environment file from Morningstar to start the demo: + +

+ +
+
+
+
+ + + diff --git a/demos/xray_wip/demo.js b/demos/xray_wip/demo.js new file mode 100644 index 0000000..9694075 --- /dev/null +++ b/demos/xray_wip/demo.js @@ -0,0 +1,77 @@ +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' + } + ] + } + }] + }, + components: [ + { + renderTo: 'dashboard-col-1', + connector: { + id: 'xray' + }, + type: 'DataGrid', + title: 'RiskScore' + } + ] +}); + +board.dataPool + .getConnectorTable('xray') + .then(() => {}); + +} + +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 (Connectors.Morningstar.isPostmanEnvironmentJSON(fileJSON)) { + break; + } + } catch (error) { + // fail silently + } + } + + return fileJSON; +} diff --git a/src/XRay/XRayConverter.ts b/src/XRay/XRayConverter.ts index 5441749..cfe4194 100644 --- a/src/XRay/XRayConverter.ts +++ b/src/XRay/XRayConverter.ts @@ -125,12 +125,18 @@ export class XRayConverter extends MorningstarConverter { ): void { const table = this.table; + table.setColumn(`${benchmarkId}_Values`); + for (const asset of json.assetAllocation) { - const rowId = `${benchmarkId}_${asset.type}_${asset.salePosition}`; + const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`; + table.setColumn(columnName); const values = asset.values; - for (let i = 1; i < 100; ++i) { - table.setCell(rowId, i - 1, values[i]); + const valueIndex = Object.keys(values); + + for (let i = 0; i < valueIndex.length; i++) { + table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(columnName, i, values[parseInt(valueIndex[i])]); } } From 991dd395bf25d3eda54739b1bdc88e412cd90402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 28 Nov 2024 13:59:39 +0100 Subject: [PATCH 02/12] Fixed missing params in requests. --- demos/xray_wip/demo.js | 4 +++- src/Shared/MorningstarOptions.ts | 10 ++++++++++ src/XRay/XRayConnector.ts | 8 ++++++-- src/XRay/XRayJSON.ts | 22 +++++++++++++++++----- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/demos/xray_wip/demo.js b/demos/xray_wip/demo.js index 9694075..2ae5b72 100644 --- a/demos/xray_wip/demo.js +++ b/demos/xray_wip/demo.js @@ -22,7 +22,9 @@ async function displaySecurityDetails (postmanJSON) { id: 'F0GBR052QA', idType: 'MSID', type: 'FO', - weight: '100' + weight: '100', + name: 'BlackRock Income and Growth Ord', + holdingType: 'weight' } ] } diff --git a/src/Shared/MorningstarOptions.ts b/src/Shared/MorningstarOptions.ts index 22b58a1..831e418 100644 --- a/src/Shared/MorningstarOptions.ts +++ b/src/Shared/MorningstarOptions.ts @@ -210,6 +210,16 @@ interface MorningstarSecurityOptionsGeneric { */ type?: (string|MorningstarSecurityType); + /** + * Type of holding. + */ + holdingType?: string; + + /** + * Weight of holding. + */ + weight?: (number|string); + } diff --git a/src/XRay/XRayConnector.ts b/src/XRay/XRayConnector.ts index 52a8bfa..d33f0e7 100644 --- a/src/XRay/XRayConnector.ts +++ b/src/XRay/XRayConnector.ts @@ -47,7 +47,7 @@ interface XRayHoldingObject { amount?: string; identifier: string; identifierType: string; - holdingType: number; + holdingType: string|number; name?: string; securityType?: string; weight?: string; @@ -78,7 +78,7 @@ function convertHoldings ( const holding: XRayHoldingObject = { identifier: security.id, identifierType: security.idType, - holdingType + holdingType: security.holdingType || holdingType }; if (security.name) { @@ -89,6 +89,10 @@ function convertHoldings ( holding.securityType = security.type; } + if (security.weight) { + holding.weight = security.weight.toString(); + } + return holding; }); } diff --git a/src/XRay/XRayJSON.ts b/src/XRay/XRayJSON.ts index 45b8c81..e439d3b 100644 --- a/src/XRay/XRayJSON.ts +++ b/src/XRay/XRayJSON.ts @@ -149,6 +149,21 @@ namespace XRayJSON { ); } + function checkRegionalExposure ( + regionalExposureArray?: unknown + ): regionalExposureArray is Array { + return ( + !!regionalExposureArray && + typeof regionalExposureArray === 'object' && + regionalExposureArray instanceof Array && + ( + regionalExposureArray && + regionalExposureArray.length === 0 || + isRegionalExposure(regionalExposureArray[0]) + ) + ); + } + function isBreakdowns ( json?: unknown @@ -156,15 +171,12 @@ namespace XRayJSON { return ( !!json && typeof json === 'object' && + (json as Breakdowns).assetAllocation instanceof Array && ( (json as Breakdowns).assetAllocation.length === 0 || isAssetAllocation((json as Breakdowns).assetAllocation[0]) - ) && - ( - typeof (json as Breakdowns).regionalExposure === 'undefined' || - isRegionalExposure((json as Breakdowns).regionalExposure) - ) + ) && checkRegionalExposure((json as Breakdowns).regionalExposure) ); } From 168d8303b45569a8372d1da66bb103376f72c10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Tue, 3 Dec 2024 13:13:53 +0100 Subject: [PATCH 03/12] Improved regionalExposure. --- demos/xray_wip/demo.css | 4 ++++ demos/xray_wip/demo.html | 1 - demos/xray_wip/demo.js | 2 +- src/XRay/XRayConverter.ts | 9 ++++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/demos/xray_wip/demo.css b/demos/xray_wip/demo.css index 23cc8f9..6d7744e 100644 --- a/demos/xray_wip/demo.css +++ b/demos/xray_wip/demo.css @@ -2,6 +2,10 @@ @import url("https://code.highcharts.com/css/highcharts.css"); @import url("https://code.highcharts.com/dashboards/css/dashboards.css"); +#container { + height: 1000px; +} + body { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, sans-serif; } diff --git a/demos/xray_wip/demo.html b/demos/xray_wip/demo.html index 1a4444f..58b649f 100644 --- a/demos/xray_wip/demo.html +++ b/demos/xray_wip/demo.html @@ -18,7 +18,6 @@

Highcharts Dashboards + Morningstar Portfolio Risk Score

-
diff --git a/demos/xray_wip/demo.js b/demos/xray_wip/demo.js index 2ae5b72..a8b5f20 100644 --- a/demos/xray_wip/demo.js +++ b/demos/xray_wip/demo.js @@ -32,7 +32,7 @@ async function displaySecurityDetails (postmanJSON) { }, components: [ { - renderTo: 'dashboard-col-1', + renderTo: 'dashboard-col-0', connector: { id: 'xray' }, diff --git a/src/XRay/XRayConverter.ts b/src/XRay/XRayConverter.ts index cfe4194..7fc1d7f 100644 --- a/src/XRay/XRayConverter.ts +++ b/src/XRay/XRayConverter.ts @@ -142,11 +142,14 @@ export class XRayConverter extends MorningstarConverter { if (json.regionalExposure) { for (const exposure of json.regionalExposure) { - const rowId = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`; + const columnName = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`; + table.setColumn(columnName); const values = exposure.values; + const valueIndex = Object.keys(values); - for (let i = 1; i < 100; ++i) { - table.setCell(rowId, i - 1, values[i] || 0); + for (let i = 0; i < valueIndex.length; i++) { + table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(columnName, i, values[parseInt(valueIndex[i])]); } } } From 23f3c0a5cab44bd8f2c09cee111deff5367fe3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 5 Dec 2024 14:04:37 +0100 Subject: [PATCH 04/12] Added if handler for portfolio returns. --- src/XRay/XRayJSON.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/XRay/XRayJSON.ts b/src/XRay/XRayJSON.ts index e439d3b..f3d4d65 100644 --- a/src/XRay/XRayJSON.ts +++ b/src/XRay/XRayJSON.ts @@ -176,7 +176,10 @@ namespace XRayJSON { ( (json as Breakdowns).assetAllocation.length === 0 || isAssetAllocation((json as Breakdowns).assetAllocation[0]) - ) && checkRegionalExposure((json as Breakdowns).regionalExposure) + ) && ( + !(json as Breakdowns).regionalExposure || + checkRegionalExposure((json as Breakdowns).regionalExposure) + ) ); } From 974e4066b349ec4e41efa49b0c6bf926a8f1ca0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 5 Dec 2024 14:18:44 +0100 Subject: [PATCH 05/12] WIP demo namespace change. --- demos/xray_wip/demo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/xray_wip/demo.js b/demos/xray_wip/demo.js index a8b5f20..9d2d5ea 100644 --- a/demos/xray_wip/demo.js +++ b/demos/xray_wip/demo.js @@ -67,7 +67,7 @@ async function getPostmanJSON (htmlInputFile) { for (file of htmlInputFile.files) { try { fileJSON = JSON.parse(await file.text()); - if (Connectors.Morningstar.isPostmanEnvironmentJSON(fileJSON)) { + if (HighchartsConnectors.Morningstar.isPostmanEnvironmentJSON(fileJSON)) { break; } } catch (error) { From eb83551f5fac590291c091b29424e99e8efee80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Mon, 9 Dec 2024 20:17:52 +0100 Subject: [PATCH 06/12] Added support for GlobalStockSector in XRay. --- src/XRay/XRayConverter.ts | 32 ++++++++++++++++++++++++-------- src/XRay/XRayJSON.ts | 22 +++++++++++++++++++++- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/XRay/XRayConverter.ts b/src/XRay/XRayConverter.ts index 7fc1d7f..0a157b4 100644 --- a/src/XRay/XRayConverter.ts +++ b/src/XRay/XRayConverter.ts @@ -127,16 +127,18 @@ export class XRayConverter extends MorningstarConverter { table.setColumn(`${benchmarkId}_Values`); - for (const asset of json.assetAllocation) { - const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`; - table.setColumn(columnName); - const values = asset.values; + if (json.assetAllocation) { + for (const asset of json.assetAllocation) { + const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`; + table.setColumn(columnName); + const values = asset.values; - const valueIndex = Object.keys(values); + const valueIndex = Object.keys(values); - for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); - table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + for (let i = 0; i < valueIndex.length; i++) { + table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + } } } @@ -154,6 +156,20 @@ export class XRayConverter extends MorningstarConverter { } } + if (json.globalStockSector) { + for (const sector of json.globalStockSector) { + const columnName = `${benchmarkId}_GlobalStockSector_${sector.salePosition}`; + table.setColumn(columnName); + const values = sector.values; + const valueIndex = Object.keys(values); + + for (let i = 0; i < valueIndex.length; i++) { + table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + } + } + } + } protected parseHistoricalPerformance ( diff --git a/src/XRay/XRayJSON.ts b/src/XRay/XRayJSON.ts index f3d4d65..45eed62 100644 --- a/src/XRay/XRayJSON.ts +++ b/src/XRay/XRayJSON.ts @@ -49,6 +49,7 @@ namespace XRayJSON { export interface Breakdowns { assetAllocation: Array; regionalExposure?: Array; + globalStockSector?: Array; } @@ -72,6 +73,11 @@ namespace XRayJSON { values: Record; } + export interface GlobalStockSector { + salePosition: string; + values: Record; + } + export interface Response { XRay: Array; @@ -127,6 +133,17 @@ namespace XRayJSON { ); } + function isGlobalStockSector ( + json?: unknown + ): json is GlobalStockSector { + return ( + !!json && + typeof json === 'object' && + typeof (json as GlobalStockSector).salePosition === 'string' && + typeof (json as GlobalStockSector).values === 'object' + ); + } + function isBenchmark ( json?: unknown @@ -176,9 +193,12 @@ namespace XRayJSON { ( (json as Breakdowns).assetAllocation.length === 0 || isAssetAllocation((json as Breakdowns).assetAllocation[0]) - ) && ( + ) || ( !(json as Breakdowns).regionalExposure || checkRegionalExposure((json as Breakdowns).regionalExposure) + ) || ( + !(json as Breakdowns).globalStockSector || + isGlobalStockSector((json as Breakdowns).globalStockSector?.[0]) ) ); } From 657adf69589a318e6eea94ee52c42307c0eb2dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Tue, 31 Dec 2024 12:32:06 +0100 Subject: [PATCH 07/12] Changed values structure in xRay table. --- src/XRay/XRayConverter.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/XRay/XRayConverter.ts b/src/XRay/XRayConverter.ts index 0a157b4..b162679 100644 --- a/src/XRay/XRayConverter.ts +++ b/src/XRay/XRayConverter.ts @@ -125,18 +125,17 @@ export class XRayConverter extends MorningstarConverter { ): void { const table = this.table; - table.setColumn(`${benchmarkId}_Values`); - if (json.assetAllocation) { for (const asset of json.assetAllocation) { const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`; + table.setColumn(`${columnName}_Values`); table.setColumn(columnName); const values = asset.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, valueIndex[i]); table.setCell(columnName, i, values[parseInt(valueIndex[i])]); } } @@ -145,12 +144,13 @@ export class XRayConverter extends MorningstarConverter { if (json.regionalExposure) { for (const exposure of json.regionalExposure) { const columnName = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`; + table.setColumn(`${columnName}_Values`); table.setColumn(columnName); const values = exposure.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, valueIndex[i]); table.setCell(columnName, i, values[parseInt(valueIndex[i])]); } } @@ -159,12 +159,13 @@ export class XRayConverter extends MorningstarConverter { if (json.globalStockSector) { for (const sector of json.globalStockSector) { const columnName = `${benchmarkId}_GlobalStockSector_${sector.salePosition}`; + table.setColumn(`${columnName}_Values`); table.setColumn(columnName); const values = sector.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${benchmarkId}_Values`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, valueIndex[i]); table.setCell(columnName, i, values[parseInt(valueIndex[i])]); } } From 0218e5a9a60be9170ca33ff47a98abfff4d6afcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 2 Jan 2025 17:28:52 +0100 Subject: [PATCH 08/12] New dashboards demo for Morningstar XRay connector. --- demos/{xray_wip => dashboards-xray}/demo.css | 0 demos/{xray_wip => dashboards-xray}/demo.html | 2 ++ demos/{xray_wip => dashboards-xray}/demo.js | 31 +++++++++++++++++-- demos/index.html | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) rename demos/{xray_wip => dashboards-xray}/demo.css (100%) rename demos/{xray_wip => dashboards-xray}/demo.html (90%) rename demos/{xray_wip => dashboards-xray}/demo.js (63%) diff --git a/demos/xray_wip/demo.css b/demos/dashboards-xray/demo.css similarity index 100% rename from demos/xray_wip/demo.css rename to demos/dashboards-xray/demo.css diff --git a/demos/xray_wip/demo.html b/demos/dashboards-xray/demo.html similarity index 90% rename from demos/xray_wip/demo.html rename to demos/dashboards-xray/demo.html index 58b649f..1275b34 100644 --- a/demos/xray_wip/demo.html +++ b/demos/dashboards-xray/demo.html @@ -18,6 +18,8 @@

Highcharts Dashboards + Morningstar Portfolio Risk Score

+
+
diff --git a/demos/xray_wip/demo.js b/demos/dashboards-xray/demo.js similarity index 63% rename from demos/xray_wip/demo.js rename to demos/dashboards-xray/demo.js index 9d2d5ea..42d5b3e 100644 --- a/demos/xray_wip/demo.js +++ b/demos/dashboards-xray/demo.js @@ -37,7 +37,34 @@ async function displaySecurityDetails (postmanJSON) { id: 'xray' }, type: 'DataGrid', - title: 'RiskScore' + title: 'GlobalStockSector', + dataGridOptions: { + header: ['XRay_GlobalStockSector_N_Values', 'XRay_GlobalStockSector_N'] + } + }, { + renderTo: 'dashboard-col-1', + connector: { + id: 'xray' + }, + type: 'DataGrid', + title: 'MorningstarEUR3', + dataGridOptions: { + header: [ + 'XRay_MorningstarEUR3_L_Values', 'XRay_MorningstarEUR3_L', + 'XRay_MorningstarEUR3_N_Values', 'XRay_MorningstarEUR3_N', + 'XRay_MorningstarEUR3_S_Values', 'XRay_MorningstarEUR3_S' + ] + } + }, { + renderTo: 'dashboard-col-2', + connector: { + id: 'xray' + }, + type: 'DataGrid', + title: 'RegionalExposure', + dataGridOptions: { + header: ['XRay_RegionalExposure_N_Values', 'XRay_RegionalExposure_N'] + } } ] }); @@ -67,7 +94,7 @@ async function getPostmanJSON (htmlInputFile) { for (file of htmlInputFile.files) { try { fileJSON = JSON.parse(await file.text()); - if (HighchartsConnectors.Morningstar.isPostmanEnvironmentJSON(fileJSON)) { + if (HighchartsConnectors.Shared.Morningstar.isPostmanEnvironmentJSON(fileJSON)) { break; } } catch (error) { diff --git a/demos/index.html b/demos/index.html index 836ac72..0131f9a 100644 --- a/demos/index.html +++ b/demos/index.html @@ -8,6 +8,7 @@

Morningstar Connectors Demos

  • Highcharts Dashboards + Morningstar RNA News
  • +
  • Highcharts Dashboards + Morningstar XRay Connector
  • Highcharts Stock + Morningstar TimeSeries
  • Highcharts Stock + Morningstar OHLCV TimeSeries
  • Highcharts Stock + Morningstar Security Details
  • From 54c7da5b8f8f00d2885816c53fabb89f0dbe029d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Fri, 3 Jan 2025 15:16:08 +0100 Subject: [PATCH 09/12] Improved categories and values naming --- demos/dashboards-xray/demo.css | 4 ---- demos/dashboards-xray/demo.js | 40 ++++++++++++++++++++++++++++------ src/XRay/XRayConverter.ts | 18 +++++++-------- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/demos/dashboards-xray/demo.css b/demos/dashboards-xray/demo.css index 6d7744e..23cc8f9 100644 --- a/demos/dashboards-xray/demo.css +++ b/demos/dashboards-xray/demo.css @@ -2,10 +2,6 @@ @import url("https://code.highcharts.com/css/highcharts.css"); @import url("https://code.highcharts.com/dashboards/css/dashboards.css"); -#container { - height: 1000px; -} - body { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, sans-serif; } diff --git a/demos/dashboards-xray/demo.js b/demos/dashboards-xray/demo.js index 42d5b3e..6edc5db 100644 --- a/demos/dashboards-xray/demo.js +++ b/demos/dashboards-xray/demo.js @@ -39,7 +39,13 @@ async function displaySecurityDetails (postmanJSON) { type: 'DataGrid', title: 'GlobalStockSector', dataGridOptions: { - header: ['XRay_GlobalStockSector_N_Values', 'XRay_GlobalStockSector_N'] + header: [{ + format: 'Net', + columnId: 'XRay_GlobalStockSector_N_Categories' + }, { + format: 'Values', + columnId: 'XRay_GlobalStockSector_N_Values' + }] } }, { renderTo: 'dashboard-col-1', @@ -49,11 +55,25 @@ async function displaySecurityDetails (postmanJSON) { type: 'DataGrid', title: 'MorningstarEUR3', dataGridOptions: { - header: [ - 'XRay_MorningstarEUR3_L_Values', 'XRay_MorningstarEUR3_L', - 'XRay_MorningstarEUR3_N_Values', 'XRay_MorningstarEUR3_N', - 'XRay_MorningstarEUR3_S_Values', 'XRay_MorningstarEUR3_S' - ] + 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' + }] } }, { renderTo: 'dashboard-col-2', @@ -63,7 +83,13 @@ async function displaySecurityDetails (postmanJSON) { type: 'DataGrid', title: 'RegionalExposure', dataGridOptions: { - header: ['XRay_RegionalExposure_N_Values', 'XRay_RegionalExposure_N'] + header: [{ + format: 'Net', + columnId: 'XRay_RegionalExposure_N_Categories' + }, { + format: 'Values', + columnId: 'XRay_RegionalExposure_N_Values' + }] } } ] diff --git a/src/XRay/XRayConverter.ts b/src/XRay/XRayConverter.ts index b162679..f4bd819 100644 --- a/src/XRay/XRayConverter.ts +++ b/src/XRay/XRayConverter.ts @@ -128,15 +128,15 @@ export class XRayConverter extends MorningstarConverter { if (json.assetAllocation) { for (const asset of json.assetAllocation) { const columnName = `${benchmarkId}_${asset.type}_${asset.salePosition}`; + table.setColumn(`${columnName}_Categories`); table.setColumn(`${columnName}_Values`); - table.setColumn(columnName); const values = asset.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${columnName}_Values`, i, valueIndex[i]); - table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + table.setCell(`${columnName}_Categories`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]); } } } @@ -144,14 +144,14 @@ export class XRayConverter extends MorningstarConverter { if (json.regionalExposure) { for (const exposure of json.regionalExposure) { const columnName = `${benchmarkId}_RegionalExposure_${exposure.salePosition}`; + table.setColumn(`${columnName}_Categories`); table.setColumn(`${columnName}_Values`); - table.setColumn(columnName); const values = exposure.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${columnName}_Values`, i, valueIndex[i]); - table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + table.setCell(`${columnName}_Categories`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]); } } } @@ -159,14 +159,14 @@ export class XRayConverter extends MorningstarConverter { if (json.globalStockSector) { for (const sector of json.globalStockSector) { const columnName = `${benchmarkId}_GlobalStockSector_${sector.salePosition}`; + table.setColumn(`${columnName}_Categories`); table.setColumn(`${columnName}_Values`); - table.setColumn(columnName); const values = sector.values; const valueIndex = Object.keys(values); for (let i = 0; i < valueIndex.length; i++) { - table.setCell(`${columnName}_Values`, i, valueIndex[i]); - table.setCell(columnName, i, values[parseInt(valueIndex[i])]); + table.setCell(`${columnName}_Categories`, i, valueIndex[i]); + table.setCell(`${columnName}_Values`, i, values[parseInt(valueIndex[i])]); } } } From 4f5c372e1f9e3644b329d6a6eb1ec3e6f870f909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Wed, 8 Jan 2025 13:08:12 +0100 Subject: [PATCH 10/12] Improved XRay Dashboards demo. --- demos/dashboards-xray/demo.html | 4 +- demos/dashboards-xray/demo.js | 87 +++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/demos/dashboards-xray/demo.html b/demos/dashboards-xray/demo.html index 1275b34..40e6dbf 100644 --- a/demos/dashboards-xray/demo.html +++ b/demos/dashboards-xray/demo.html @@ -7,10 +7,10 @@ - Highcharts Dashboards + Morningstar Portfolio Risk Score + Highcharts Dashboards DataGrid + Morningstar XRay Connector -

    Highcharts Dashboards + Morningstar Portfolio Risk Score

    +

    Highcharts Dashboards DataGrid + Morningstar XRay Connector

    Add your Postman environment file from Morningstar to start the demo: diff --git a/demos/dashboards-xray/demo.js b/demos/dashboards-xray/demo.js index 6edc5db..421f45a 100644 --- a/demos/dashboards-xray/demo.js +++ b/demos/dashboards-xray/demo.js @@ -1,3 +1,46 @@ +const globalStockSectorMap = { + 99: 'Other', // ?? + 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: 'Equity', + 2: 'Property', + 3: 'Cash', + 4: 'Other', + 99: 'Fixed Income' +}; + +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: { @@ -37,7 +80,7 @@ async function displaySecurityDetails (postmanJSON) { id: 'xray' }, type: 'DataGrid', - title: 'GlobalStockSector', + title: 'Global Stock Sector', dataGridOptions: { header: [{ format: 'Net', @@ -45,6 +88,14 @@ async function displaySecurityDetails (postmanJSON) { }, { format: 'Values', columnId: 'XRay_GlobalStockSector_N_Values' + }], + columns: [{ + id: 'XRay_GlobalStockSector_N_Categories', + cells: { + formatter: function () { + return globalStockSectorMap[this.value] + } + } }] } }, { @@ -53,7 +104,7 @@ async function displaySecurityDetails (postmanJSON) { id: 'xray' }, type: 'DataGrid', - title: 'MorningstarEUR3', + title: 'Morningstar EUR3', dataGridOptions: { header: [{ format: 'Long', @@ -73,6 +124,28 @@ async function displaySecurityDetails (postmanJSON) { }, { format: 'Values', columnId: 'XRay_MorningstarEUR3_S_Values' + }], + columns: [{ + id: 'XRay_MorningstarEUR3_L_Categories', + cells: { + formatter: function () { + return assetAllocationMap[this.value] + } + } + }, { + id: 'XRay_MorningstarEUR3_N_Categories', + cells: { + formatter: function () { + return assetAllocationMap[this.value] + } + } + }, { + id: 'XRay_MorningstarEUR3_S_Categories', + cells: { + formatter: function () { + return assetAllocationMap[this.value] + } + } }] } }, { @@ -81,7 +154,7 @@ async function displaySecurityDetails (postmanJSON) { id: 'xray' }, type: 'DataGrid', - title: 'RegionalExposure', + title: 'Regional Exposure', dataGridOptions: { header: [{ format: 'Net', @@ -89,6 +162,14 @@ async function displaySecurityDetails (postmanJSON) { }, { format: 'Values', columnId: 'XRay_RegionalExposure_N_Values' + }], + columns: [{ + id: 'XRay_RegionalExposure_N_Categories', + cells: { + formatter: function () { + return regionalExposureMap[this.value] + } + } }] } } From abdc9a921f73d3ab645b1ab59a00d302123bd7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 9 Jan 2025 12:10:37 +0100 Subject: [PATCH 11/12] Added requested changes. --- demos/dashboards-xray/demo.html | 5 ++--- demos/dashboards-xray/demo.js | 29 ++++++++++++++++------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/demos/dashboards-xray/demo.html b/demos/dashboards-xray/demo.html index 40e6dbf..b5ea433 100644 --- a/demos/dashboards-xray/demo.html +++ b/demos/dashboards-xray/demo.html @@ -3,9 +3,8 @@ - - - + + Highcharts Dashboards DataGrid + Morningstar XRay Connector diff --git a/demos/dashboards-xray/demo.js b/demos/dashboards-xray/demo.js index 421f45a..06dd06d 100644 --- a/demos/dashboards-xray/demo.js +++ b/demos/dashboards-xray/demo.js @@ -1,5 +1,5 @@ const globalStockSectorMap = { - 99: 'Other', // ?? + 99: 'Not Classified', 101: 'Basic Materials', 102: 'Consumer Staples', 103: 'Financial Services', @@ -14,11 +14,11 @@ const globalStockSectorMap = { }; const assetAllocationMap = { - 1: 'Equity', - 2: 'Property', + 1: 'Stock', + 2: 'Bond', 3: 'Cash', 4: 'Other', - 99: 'Fixed Income' + 99: 'Not Classified' }; const regionalExposureMap = { @@ -38,7 +38,7 @@ const regionalExposureMap = { 14: 'Emerging Market', 15: 'Developed Country', 16: 'Not Classified', - 99: 'Other' // ?? + 99: 'Other' } async function displaySecurityDetails (postmanJSON) { @@ -93,7 +93,8 @@ async function displaySecurityDetails (postmanJSON) { id: 'XRay_GlobalStockSector_N_Categories', cells: { formatter: function () { - return globalStockSectorMap[this.value] + return this.value !== void 0 ? + globalStockSectorMap[this.value] : ''; } } }] @@ -129,21 +130,24 @@ async function displaySecurityDetails (postmanJSON) { id: 'XRay_MorningstarEUR3_L_Categories', cells: { formatter: function () { - return assetAllocationMap[this.value] + return this.value !== void 0 ? + assetAllocationMap[this.value] : ''; } } }, { id: 'XRay_MorningstarEUR3_N_Categories', cells: { formatter: function () { - return assetAllocationMap[this.value] + return this.value !== void 0 ? + assetAllocationMap[this.value] : ''; } } }, { id: 'XRay_MorningstarEUR3_S_Categories', cells: { formatter: function () { - return assetAllocationMap[this.value] + return this.value !== void 0 ? + assetAllocationMap[this.value] : ''; } } }] @@ -167,7 +171,8 @@ async function displaySecurityDetails (postmanJSON) { id: 'XRay_RegionalExposure_N_Categories', cells: { formatter: function () { - return regionalExposureMap[this.value] + return this.value !== void 0 ? + regionalExposureMap[this.value] : ''; } } }] @@ -176,9 +181,7 @@ async function displaySecurityDetails (postmanJSON) { ] }); -board.dataPool - .getConnectorTable('xray') - .then(() => {}); + board.dataPool.getConnectorTable('xray'); } From 6adef11c1690d1dd09411951df894bb7ec07f390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Thu, 9 Jan 2025 12:11:30 +0100 Subject: [PATCH 12/12] Remove .src from HTML --- demos/dashboards-xray/demo.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/dashboards-xray/demo.html b/demos/dashboards-xray/demo.html index b5ea433..58fa1c7 100644 --- a/demos/dashboards-xray/demo.html +++ b/demos/dashboards-xray/demo.html @@ -3,8 +3,8 @@ - - + + Highcharts Dashboards DataGrid + Morningstar XRay Connector