From 7777c9f704f88848d5bef159e88c84b334c1314e Mon Sep 17 00:00:00 2001 From: pawellysy Date: Tue, 19 Nov 2024 08:47:05 +0100 Subject: [PATCH 01/16] Implemented investment screener. --- .../InvestmentScreenerConnector.ts | 166 ++++++++++++++++++ .../InvestmentScreenerConverter.ts | 104 +++++++++++ .../InvestmentScreenerJSON.ts | 81 +++++++++ .../InvestmentScreenerOptions.ts | 57 ++++++ src/Screeners/InvestmentScreener/README.md | 2 + src/Screeners/InvestmentScreener/index.ts | 45 +++++ 6 files changed, 455 insertions(+) create mode 100644 src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts create mode 100644 src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts create mode 100644 src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts create mode 100644 src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts create mode 100644 src/Screeners/InvestmentScreener/README.md create mode 100644 src/Screeners/InvestmentScreener/index.ts diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts new file mode 100644 index 0000000..f0c0363 --- /dev/null +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts @@ -0,0 +1,166 @@ +/* * + * + * (c) 2009-2024 Highsoft AS + * + * License: www.highcharts.com/license + * + * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! + * + * Authors: + * - Pawel Lysy + * + * */ + +'use strict'; + +/* * + * + * Imports + * + * */ + +import type InvestmentScreenerOptions from './InvestmentScreenerOptions'; +import type { InvestmentScreenerFilter, InvestmentScreenerMetadata } from './InvestmentScreenerOptions'; +import External from '../../Shared/External'; +import MorningstarAPI from '../../Shared/MorningstarAPI'; +import MorningstarConnector from '../../Shared/MorningstarConnector'; +import InvestmentScreenerConverter from './InvestmentScreenerConverter'; +import MorningstarURL from '../../Shared/MorningstarURL'; + +/* * + * + * Constants + * + * */ + +const UTF_PIPE = '%7C'; +const UTF_COLON = '%3A'; + +/* * + * + * Class + * + * */ +export class InvestmentScreenerConnector extends MorningstarConnector { + public constructor ( + options: InvestmentScreenerOptions = { universeIds: [] } + ) { + super(options); + + this.converter = new InvestmentScreenerConverter(options.converter); + this.metadata = this.converter.metadata; + this.options = options; + } + + public override readonly converter: InvestmentScreenerConverter; + + public override readonly options: InvestmentScreenerOptions; + + public override readonly metadata: InvestmentScreenerMetadata; + + public override async load ( + options?: InvestmentScreenerOptions + ): Promise { + await super.load(); + + const userOptions = { ...this.options, ...options }; + this.api ??= new MorningstarAPI(userOptions.api); + const api = this.api; + const url = new MorningstarURL('ecint/v1/screener', api.baseURL); + const searchParams = url.searchParams; + + searchParams.set('outputType', 'json'); + searchParams.set('universeIds', userOptions.universeIds.join(UTF_PIPE)); + + if (userOptions.securityDataPoints) { + searchParams.set( + 'securityDataPoints', + userOptions.securityDataPoints.join(UTF_PIPE) + ); + } + + if (userOptions.filters) { + const filters = userOptions.filters.reduce( + (prev, curr) => prev + UTF_PIPE + this.getFilter(curr), + '' + ); + searchParams.set('filters', filters); + } + + if (userOptions.ignoreRestructure) { + searchParams.set( + 'ignoreRestructure', + `${userOptions.ignoreRestructure}` + ); + } + + if (userOptions.term) { + searchParams.set('term', userOptions.term); + } + + if (userOptions.applyTrackRecordExtension) { + searchParams.set( + 'applyTrackRecordExtension', + `${userOptions.applyTrackRecordExtension}` + ); + } + + if (userOptions.page) { + searchParams.set('page', `${userOptions.page}`); + } + + if (userOptions.pageSize) { + searchParams.set('pageSize', `${userOptions.pageSize || 1}`); + } + + if (userOptions.sortOrder) { + searchParams.set('sortOrder', userOptions.sortOrder); + } + + if (userOptions.countryId) { + searchParams.set('countryId', userOptions.countryId); + } + + if (userOptions.currencyId) { + searchParams.set('currencyId', userOptions.currencyId); + } + + const response = await api.fetch(url); + const json = (await response.json()) as unknown; + + this.converter.parse({ json }); + this.table.deleteColumns(); + this.table.setColumns(this.converter.getTable().getColumns()); + + return this; + } + + private getFilter (filter: InvestmentScreenerFilter): string { + return `${filter.dataPointId}${UTF_COLON}${filter.comparatorCode}${UTF_COLON}${filter.value}`; + } +} + +/* * + * + * Registry + * + * */ + +declare module '@highcharts/dashboards/es-modules/Data/Connectors/DataConnectorType' { + interface DataConnectorTypes { + MorningstarInvestmentScreener: typeof InvestmentScreenerConnector; + } +} + +External.DataConnector.registerType( + 'MorningstarInvestmentScreener', + InvestmentScreenerConnector +); + +/* * + * + * Default Export + * + * */ + +export default InvestmentScreenerConnector; diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts new file mode 100644 index 0000000..452a15b --- /dev/null +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts @@ -0,0 +1,104 @@ +/* * + * + * (c) 2009-2024 Highsoft AS + * + * License: www.highcharts.com/license + * + * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! + * + * Authors: + * - Pawel Lysy + * + * */ + +'use strict'; + +/* * + * + * Imports + * + * */ + +import type { InvestmentScreenerConverterOptions, InvestmentScreenerMetadata } from './InvestmentScreenerOptions'; + +import MorningstarConverter from '../../Shared/MorningstarConverter'; +import InvestmentScreenerJSON from './InvestmentScreenerJSON'; + +/* * + * + * Class + * + * */ + +export class InvestmentScreenerConverter extends MorningstarConverter { + public constructor (options?: InvestmentScreenerConverterOptions) { + super(options); + + this.metadata = { + columns: {} + }; + } + /* * + * + * Properties + * + * */ + + public path: string; + + public readonly metadata: InvestmentScreenerMetadata; + + /* * + * + * Functions + * + * */ + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public parse (options: InvestmentScreenerConverterOptions): void { + const metadata = this.metadata; + const table = this.table; + const userOptions = { + ...this.options, + ...options + }; + const json = userOptions.json; + + // Validate JSON + + if (!InvestmentScreenerJSON.isInvestmentScreenerResponse(json)) { + throw new Error('Invalid data'); + } + + // Prepare table + table.deleteColumns(); + const rows = json.rows; + if (rows.length > 0) { + const row = rows[0]; + for (const element of Object.keys(row)) { + table.setColumn(`InvestmentScreeeer_${element}`); + } + + for (let i = 0; i < rows.length; i++) { + for (const [key, val] of Object.entries(rows[i])) { + table.setCell( + `InvestmentScreeeer_${key}`, + i, + `InvestmentScreeeer_${val}` + ); + } + } + metadata.page = json.page; + metadata.total = json.total; + metadata.pageSize = json.pageSize; + } + } +} + +/* * + * + * Default Export + * + * */ + +export default InvestmentScreenerConverter; diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts new file mode 100644 index 0000000..368e574 --- /dev/null +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts @@ -0,0 +1,81 @@ +/* * + * + * (c) 2009-2024 Highsoft AS + * + * License: www.highcharts.com/license + * + * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! + * + * Authors: + * - Pawel Lysy + * + * */ + +'use strict'; + +/* * + * + * Namespace + * + * */ + +namespace InvestmentScreenerJSON { + export interface Response { + InvestmentScreener: InvestmentScreenerResponse; + } + + export interface InvestmentScreenerResponse { + total: number; + page: number; + pageSize: number; + rows: InvestmentScreenerRow[]; + } + + export interface InvestmentScreenerRow { + [key: string]: any; + } + + /* * + * + * Functions + * + * */ + + export function isResponse (json?: unknown): json is Response { + return ( + !!json && + typeof json === 'object' && + typeof (json as Response).InvestmentScreener === 'object' && + isInvestmentScreenerResponse((json as Response).InvestmentScreener) + ); + } + + export function isInvestmentScreenerResponse ( + json?: unknown + ): json is InvestmentScreenerResponse { + return ( + !!json && + typeof json === 'object' && + typeof (json as InvestmentScreenerResponse).rows === 'object' && + (json as InvestmentScreenerResponse).rows instanceof Array && + ((json as InvestmentScreenerResponse).rows.length === 0 || + isInvestmentScreenerRow( + (json as InvestmentScreenerResponse).rows[0] + )) + ); + } + + export function isInvestmentScreenerRow ( + json?: unknown + ): json is InvestmentScreenerRow { + return !!json && typeof json === 'object'; + } +} + +/* * + * + * Default Export + * + * */ + +export default InvestmentScreenerJSON; diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts new file mode 100644 index 0000000..7b62189 --- /dev/null +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts @@ -0,0 +1,57 @@ +import type { + MorningstarConverterOptions, + MorningstarMetadata, + MorningstarOptions +} from '../../Shared/MorningstarOptions'; +export interface InvestmentScreenerOptions extends MorningstarOptions { + applyTrackRecordExtension?: boolean; + countryId?: string; + currencyId?: string; + filterDataPoints?: string[]; + filters?: InvestmentScreenerFilter[]; + ignoreRestructure?: boolean; + page?: number; + pageSize?: number; + securityDataPoints?: SecurityDataPointType[]; + sortOrder?: string; + term?: string; + universeIds: string[]; +} + +export interface InvestmentScreenerFilter { + dataPointId: string; + comparatorCode: ComparatorCode; + value: any; +} + +export interface InvestmentScreenerMetadata extends MorningstarMetadata { + page?: number; + total?: number; + pageSize?: number; +} + +export interface InvestmentScreenerConverterOptions + extends MorningstarConverterOptions { + // Nothing to add yet +} + +export type ComparatorCode = + | 'IN' + | 'NIN' + | 'EQ' + | 'NE' + | 'GT' + | 'GTN' + | 'GTE' + | 'GTEN' + | 'LT' + | 'LTN' + | 'LTE' + | 'LTEN' + | 'CONTAINS' + | 'BTW' + | 'STARTSWITH'; + +export type SecurityDataPointType = string; + +export default InvestmentScreenerOptions; diff --git a/src/Screeners/InvestmentScreener/README.md b/src/Screeners/InvestmentScreener/README.md new file mode 100644 index 0000000..e044a88 --- /dev/null +++ b/src/Screeners/InvestmentScreener/README.md @@ -0,0 +1,2 @@ +Morningstar Investment Screener Connector +================================ diff --git a/src/Screeners/InvestmentScreener/index.ts b/src/Screeners/InvestmentScreener/index.ts new file mode 100644 index 0000000..c12dac7 --- /dev/null +++ b/src/Screeners/InvestmentScreener/index.ts @@ -0,0 +1,45 @@ +/* * + * + * (c) 2009-2024 Highsoft AS + * + * License: www.highcharts.com/license + * + * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! + * + * Authors: + * - Pawel Lysy + * + * */ + +'use strict'; + +/* * + * + * Imports + * + * */ + +import InvestmentScreenerConnector from './InvestmentScreenerConnector'; + + +/* * + * + * Exports + * + * */ + + +export * from './InvestmentScreenerConnector'; +export * from './InvestmentScreenerConverter'; +export * as InvestmentScreenerConverters from './Converters/index'; +export * from './InvestmentScreenerOptions'; + + +/* * + * + * Default Export + * + * */ + + +export default InvestmentScreenerConnector; From bc275d76e932dffe5f14096724b9257a1aa13e22 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Thu, 21 Nov 2024 11:18:56 +0100 Subject: [PATCH 02/16] Implemented InvestmentScreenerConnector together with the demo. --- demos/dashboards-investment-screener/demo.css | 47 +++++ .../dashboards-investment-screener/demo.html | 34 ++++ demos/dashboards-investment-screener/demo.js | 192 ++++++++++++++++++ .../InvestmentScreenerConnector.ts | 16 +- .../InvestmentScreenerConverter.ts | 13 +- src/Screeners/InvestmentScreener/index.ts | 2 +- src/index.ts | 10 +- 7 files changed, 292 insertions(+), 22 deletions(-) create mode 100644 demos/dashboards-investment-screener/demo.css create mode 100644 demos/dashboards-investment-screener/demo.html create mode 100644 demos/dashboards-investment-screener/demo.js diff --git a/demos/dashboards-investment-screener/demo.css b/demos/dashboards-investment-screener/demo.css new file mode 100644 index 0000000..5ac69fb --- /dev/null +++ b/demos/dashboards-investment-screener/demo.css @@ -0,0 +1,47 @@ +@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; + } +} + +.filters-row { + flex-direction: row; + justify-content: space-evenly; +} + +#dashboard-col-1 { + height: 500px; +} diff --git a/demos/dashboards-investment-screener/demo.html b/demos/dashboards-investment-screener/demo.html new file mode 100644 index 0000000..a1cc7be --- /dev/null +++ b/demos/dashboards-investment-screener/demo.html @@ -0,0 +1,34 @@ + + + + + + + + + + + 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/dashboards-investment-screener/demo.js b/demos/dashboards-investment-screener/demo.js new file mode 100644 index 0000000..7fa866a --- /dev/null +++ b/demos/dashboards-investment-screener/demo.js @@ -0,0 +1,192 @@ +const loadingLabel = document.getElementById('loading-label'); + +function displayInvestmentScreener (postmanJSON) { + const secIds = [ + 'secId', + 'tenforeId', + 'name', + 'closePrice', + 'ongoingCharge', + 'initialPurchase', + 'maxFrontEndLoad', + 'analystRatingScale', + 'average12MonthCarbonRiskScore', + 'investmentType', + 'holdingTypeId', + 'universe' + ]; + const cols = {}; + for (const id of secIds) { + cols[`InvestmentScreener_${id}`] = { headerFormat: id }; + } + + const board = Dashboards.board('container', { + dataPool: { + connectors: [ + { + id: 'investment-screener', + type: 'MorningstarInvestmentScreener', + options: { + page: 1, + pageSize: 20, + langageId: 'en-GB', + currencyId: 'USD', + securityDataPoints: secIds, + universeIds: ['FOALL$$ALL'], + postman: { + environmentJSON: postmanJSON + } + } + } + ] + }, + components: [ + { + renderTo: 'dashboard-col-1', + connector: { + id: 'investment-screener' + }, + type: 'DataGrid', + + dataGridOptions: { + editable: false, + columns: cols + }, + title: 'Investment Screener' + } + ] + }); + + board.dataPool.getConnector('investment-screener').then(connector => { + loadingLabel.style.display = 'none'; + document.getElementById('total').innerHTML = + `total - ${connector.metadata.total}`; + document.getElementById('page').innerHTML = + `page - ${connector.metadata.page}`; + document.getElementById('total-pages').innerHTML = + `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; + }); + + function setFilter (filters) { + loadingLabel.style.display = 'block'; + board.dataPool.getConnector('investment-screener').then(connector => { + const options = { + filters + }; + connector.load(options).then(() => { + loadingLabel.style.display = 'none'; + }); + document.getElementById('total').innerHTML = + `total - ${connector.metadata.total}`; + document.getElementById('page').innerHTML = + `page - ${connector.metadata.page}`; + document.getElementById('total-pages').innerHTML = + `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; + }); + } + + document.getElementById('filter-1').addEventListener('click', () => { + setFilter([ + { + dataPointId: 'StarRatingM255', + comparatorCode: 'IN', + value: 5 + }, + { + dataPointId: 'AnalystRatingScale', + comparatorCode: 'IN', + value: 5 + } + ]); + }); + + document.getElementById('filter-2').addEventListener('click', () => { + setFilter([ + { + dataPointId: 'GBRReturnM0', + comparatorCode: 'BTW', + value: '40:60' + } + ]); + }); + + document.getElementById('filter-3').addEventListener('click', () => { + setFilter([ + { + dataPointId: 'LowCarbonDesignation', + comparatorCode: 'IN', + value: 'TRUE' + }, + { + dataPointId: 'CarbonRiskScore', + comparatorCode: 'EQ', + value: 0 + }, + { + dataPointId: 'SustainabilityRank', + comparatorCode: 'IN', + value: 5 + } + ]); + }); + + document.getElementById('filter-4').addEventListener('click', () => { + setFilter([ + { + dataPointId: 'StarRatingM255', + comparatorCode: 'IN', + value: 5 + }, + { dataPointId: 'OngoingCharge', comparatorCode: 'LT', value: 0.5 }, + { + dataPointId: 'initialPurchase', + comparatorCode: 'LT', + value: 500000000 + }, + { dataPointId: 'maxFrontEndLoad', comparatorCode: 'LT', value: 5 }, + { dataPointId: 'maxDeferredLoad', comparatorCode: 'LT', value: 5 } + ]); + }); +} + +async function handleSelectEnvironment (evt) { + const target = evt.target; + const postmanJSON = await getPostmanJSON(target); + + if (!postmanJSON) { + loadingLabel.textContent = + 'The provided file is not a Postman Environment Configuration.'; + loadingLabel.style.display = 'block'; + + return; + } + + target.parentNode.style.display = 'none'; + + loadingLabel.style.display = 'block'; + loadingLabel.textContent = 'Loading data…'; + + displayInvestmentScreener(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/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts index f0c0363..066d746 100644 --- a/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerConnector.ts @@ -20,7 +20,10 @@ * */ import type InvestmentScreenerOptions from './InvestmentScreenerOptions'; -import type { InvestmentScreenerFilter, InvestmentScreenerMetadata } from './InvestmentScreenerOptions'; +import type { + InvestmentScreenerFilter, + InvestmentScreenerMetadata +} from './InvestmentScreenerOptions'; import External from '../../Shared/External'; import MorningstarAPI from '../../Shared/MorningstarAPI'; import MorningstarConnector from '../../Shared/MorningstarConnector'; @@ -33,8 +36,8 @@ import MorningstarURL from '../../Shared/MorningstarURL'; * * */ -const UTF_PIPE = '%7C'; -const UTF_COLON = '%3A'; +const UTF_PIPE = '|'; +const UTF_COLON = ':'; /* * * @@ -75,13 +78,16 @@ export class InvestmentScreenerConnector extends MorningstarConnector { if (userOptions.securityDataPoints) { searchParams.set( 'securityDataPoints', - userOptions.securityDataPoints.join(UTF_PIPE) + userOptions.securityDataPoints.join(',') ); } if (userOptions.filters) { const filters = userOptions.filters.reduce( - (prev, curr) => prev + UTF_PIPE + this.getFilter(curr), + (prev, curr) => + prev === '' ? + this.getFilter(curr) : + prev + UTF_PIPE + this.getFilter(curr), '' ); searchParams.set('filters', filters); diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts index 452a15b..3dfbd95 100644 --- a/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerConverter.ts @@ -20,6 +20,7 @@ * */ import type { InvestmentScreenerConverterOptions, InvestmentScreenerMetadata } from './InvestmentScreenerOptions'; +import type { DataTable } from '@highcharts/dashboards'; import MorningstarConverter from '../../Shared/MorningstarConverter'; import InvestmentScreenerJSON from './InvestmentScreenerJSON'; @@ -44,8 +45,6 @@ export class InvestmentScreenerConverter extends MorningstarConverter { * * */ - public path: string; - public readonly metadata: InvestmentScreenerMetadata; /* * @@ -64,27 +63,23 @@ export class InvestmentScreenerConverter extends MorningstarConverter { }; const json = userOptions.json; - // Validate JSON - if (!InvestmentScreenerJSON.isInvestmentScreenerResponse(json)) { throw new Error('Invalid data'); } - - // Prepare table table.deleteColumns(); const rows = json.rows; if (rows.length > 0) { const row = rows[0]; for (const element of Object.keys(row)) { - table.setColumn(`InvestmentScreeeer_${element}`); + table.setColumn(`InvestmentScreener_${element}`); } for (let i = 0; i < rows.length; i++) { for (const [key, val] of Object.entries(rows[i])) { table.setCell( - `InvestmentScreeeer_${key}`, + `InvestmentScreener_${key}`, i, - `InvestmentScreeeer_${val}` + val as DataTable.CellType ); } } diff --git a/src/Screeners/InvestmentScreener/index.ts b/src/Screeners/InvestmentScreener/index.ts index c12dac7..15dfb6f 100644 --- a/src/Screeners/InvestmentScreener/index.ts +++ b/src/Screeners/InvestmentScreener/index.ts @@ -31,10 +31,10 @@ import InvestmentScreenerConnector from './InvestmentScreenerConnector'; export * from './InvestmentScreenerConnector'; export * from './InvestmentScreenerConverter'; -export * as InvestmentScreenerConverters from './Converters/index'; export * from './InvestmentScreenerOptions'; + /* * * * Default Export diff --git a/src/index.ts b/src/index.ts index 86e2d76..83c0fc6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,35 +13,32 @@ * * */ - 'use strict'; - /* * * * Imports * * */ - import GoalAnalysis from './GoalAnalysis/index'; import SecurityDetails from './SecurityDetails/index'; import RNANews from './RNANews/index'; +import InvestmentScreener from './Screeners/InvestmentScreener/index'; import RiskScore from './RiskScore/index'; import * as Shared from './Shared/index'; import TimeSeries from './TimeSeries/index'; import { version } from './version'; import XRay from './XRay/index'; - /* * * * Exports * * */ - export * from './GoalAnalysis/index'; +export * from './Screeners/InvestmentScreener/index'; export * from './SecurityDetails/index'; export * from './RNANews/index'; export * from './RiskScore/index'; @@ -50,14 +47,12 @@ export * from './TimeSeries/index'; export { version } from './version'; export * from './XRay/index'; - /* * * * Default Export * * */ - export default { GoalAnalysis, SecurityDetails, @@ -66,5 +61,6 @@ export default { Shared, TimeSeries, XRay, + InvestmentScreener, version }; From d49c21cde4a89e650fe2de9dddde2d826d389106 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Thu, 21 Nov 2024 12:58:59 +0100 Subject: [PATCH 03/16] Fixed demo and changed the eslint config. --- .eslintrc | 1 - demos/dashboards-investment-screener/demo.css | 16 ++++++ .../dashboards-investment-screener/demo.html | 8 ++- demos/dashboards-investment-screener/demo.js | 50 ++++++++++++------- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/.eslintrc b/.eslintrc index e57cceb..ab2f84e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -34,7 +34,6 @@ "operator-linebreak": [2, "after"], "quotes": [2, "single"], "require-unicode-regexp": 1, - "space-before-function-paren": 2, "strict": 0 }, "overrides": [ diff --git a/demos/dashboards-investment-screener/demo.css b/demos/dashboards-investment-screener/demo.css index 5ac69fb..d3d6439 100644 --- a/demos/dashboards-investment-screener/demo.css +++ b/demos/dashboards-investment-screener/demo.css @@ -45,3 +45,19 @@ body { #dashboard-col-1 { height: 500px; } + +.filters-row>button { + background: #f2f2f2; + border: none; + border-radius: 4px; + cursor: pointer; + display: inline-block; + font-size: 0.8rem; + padding: 0.5rem 1.5rem; + margin: 0.5rem -5px 0.5rem 10px; + transition: background 250ms; +} + +.filters-row>button:hover { + background: #e6e6e6; +} diff --git a/demos/dashboards-investment-screener/demo.html b/demos/dashboards-investment-screener/demo.html index a1cc7be..ac9053a 100644 --- a/demos/dashboards-investment-screener/demo.html +++ b/demos/dashboards-investment-screener/demo.html @@ -8,10 +8,10 @@ - Highcharts Dashboards + Morningstar Portfolio Risk Score + Highcharts Dashboards + Morningstar Portfolio Investment Details -

Highcharts Dashboards + Morningstar Portfolio Risk Score

+

Highcharts Dashboards + Morningstar Portfolio Investment Details

Add your Postman environment file from Morningstar to start the demo: @@ -23,6 +23,10 @@

Highcharts Dashboards + Morningstar Portfolio Risk Score

+
+ Current filter: + +
diff --git a/demos/dashboards-investment-screener/demo.js b/demos/dashboards-investment-screener/demo.js index 7fa866a..ffc55d9 100644 --- a/demos/dashboards-investment-screener/demo.js +++ b/demos/dashboards-investment-screener/demo.js @@ -1,6 +1,6 @@ const loadingLabel = document.getElementById('loading-label'); -function displayInvestmentScreener (postmanJSON) { +function displayInvestmentScreener(postmanJSON) { const secIds = [ 'secId', 'tenforeId', @@ -15,10 +15,13 @@ function displayInvestmentScreener (postmanJSON) { 'holdingTypeId', 'universe' ]; - const cols = {}; - for (const id of secIds) { - cols[`InvestmentScreener_${id}`] = { headerFormat: id }; - } + + const columns = secIds.map(id => ({ + id: `InvestmentScreener_${id}`, + header: { + format: id + } + })); const board = Dashboards.board('container', { dataPool: { @@ -50,7 +53,7 @@ function displayInvestmentScreener (postmanJSON) { dataGridOptions: { editable: false, - columns: cols + columns }, title: 'Investment Screener' } @@ -67,7 +70,7 @@ function displayInvestmentScreener (postmanJSON) { `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; }); - function setFilter (filters) { + function setFilter(filters) { loadingLabel.style.display = 'block'; board.dataPool.getConnector('investment-screener').then(connector => { const options = { @@ -75,17 +78,20 @@ function displayInvestmentScreener (postmanJSON) { }; connector.load(options).then(() => { loadingLabel.style.display = 'none'; + document.getElementById('total').innerHTML = + `total - ${connector.metadata.total}`; + document.getElementById('page').innerHTML = + `page - ${connector.metadata.page}`; + document.getElementById('total-pages').innerHTML = + `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; }); - document.getElementById('total').innerHTML = - `total - ${connector.metadata.total}`; - document.getElementById('page').innerHTML = - `page - ${connector.metadata.page}`; - document.getElementById('total-pages').innerHTML = - `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; }); } - document.getElementById('filter-1').addEventListener('click', () => { + document.getElementById('filter-1').addEventListener('click', e => { + e.target.classList.add('button-active'); + document.getElementById('current-filter').innerHTML = + e.target.innerHTML; setFilter([ { dataPointId: 'StarRatingM255', @@ -100,7 +106,9 @@ function displayInvestmentScreener (postmanJSON) { ]); }); - document.getElementById('filter-2').addEventListener('click', () => { + document.getElementById('filter-2').addEventListener('click', e => { + document.getElementById('current-filter').innerHTML = + e.target.innerHTML; setFilter([ { dataPointId: 'GBRReturnM0', @@ -110,7 +118,9 @@ function displayInvestmentScreener (postmanJSON) { ]); }); - document.getElementById('filter-3').addEventListener('click', () => { + document.getElementById('filter-3').addEventListener('click', e => { + document.getElementById('current-filter').innerHTML = + e.target.innerHTML; setFilter([ { dataPointId: 'LowCarbonDesignation', @@ -130,7 +140,9 @@ function displayInvestmentScreener (postmanJSON) { ]); }); - document.getElementById('filter-4').addEventListener('click', () => { + document.getElementById('filter-4').addEventListener('click', e => { + document.getElementById('current-filter').innerHTML = + e.target.innerHTML; setFilter([ { dataPointId: 'StarRatingM255', @@ -149,7 +161,7 @@ function displayInvestmentScreener (postmanJSON) { }); } -async function handleSelectEnvironment (evt) { +async function handleSelectEnvironment(evt) { const target = evt.target; const postmanJSON = await getPostmanJSON(target); @@ -173,7 +185,7 @@ document .getElementById('postman-json') .addEventListener('change', handleSelectEnvironment); -async function getPostmanJSON (htmlInputFile) { +async function getPostmanJSON(htmlInputFile) { let file; let fileJSON; From e19197b245edc2e29a1e3ca4bf798c44264e7324 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 22 Nov 2024 12:26:25 +0100 Subject: [PATCH 04/16] Implemented investment screener tests. --- tests/Screeners/InvestmentScreener.test.ts | 76 ++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/Screeners/InvestmentScreener.test.ts diff --git a/tests/Screeners/InvestmentScreener.test.ts b/tests/Screeners/InvestmentScreener.test.ts new file mode 100644 index 0000000..37d0e52 --- /dev/null +++ b/tests/Screeners/InvestmentScreener.test.ts @@ -0,0 +1,76 @@ +import * as Assert from 'node:assert/strict'; +import * as MC from '../../code/connectors-morningstar.src'; +import InvestmentScreenerJSON from +'../../code/es-modules/Screeners/InvestmentScreener/InvestmentScreenerJSON'; + +export async function investmentScreenerLoad ( + api: MC.Shared.MorningstarAPIOptions +) { + const secIds = [ + 'secId', + 'tenforeId', + 'name', + 'closePrice', + 'ongoingCharge', + 'initialPurchase', + 'maxFrontEndLoad', + 'analystRatingScale', + 'average12MonthCarbonInvestmentScreener', + 'investmentType', + 'holdingTypeId', + 'universe' + ]; + const connector = new MC.InvestmentScreenerConnector({ + api, + page: 1, + pageSize: 20, + currencyId: 'USD', + securityDataPoints: secIds, + universeIds: ['FOALL$$ALL'] + }); + + Assert.ok( + connector instanceof MC.InvestmentScreenerConnector, + 'Connector should be instance of InvestmentScreenerConnector class.' + ); + + Assert.ok( + connector.converter instanceof MC.InvestmentScreenerConverter, + 'Converter should be instance of InvestmentScreenerConverter.' + ); + + await connector.load(); + + Assert.deepStrictEqual( + connector.table.getColumnNames(), + secIds.map(id => `InvestmentScreener_${id}`), + 'Connector table should exist of expected columns.' + ); + + Assert.strictEqual( + connector.table.getRowCount(), + 20, + 'Connector table should have 20 row.' + ); +} + +export function InvestmentScreenerResponseValidation () { + const exampleResponse = { + total: 3000, + page: 1, + pageSize: 20, + rows: [ + { + secId: 'F00000VCTT', + Name: 'TestPortfolio1', + riskRating: 4, + rating: 3 + } + ] + }; + + Assert.ok( + InvestmentScreenerJSON.isResponse(exampleResponse), + 'InvestmentScreenerJSON should validate correct response.' + ); +} From 060643d2f6cad80263164d43c7879663233f4427 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 22 Nov 2024 13:17:54 +0100 Subject: [PATCH 05/16] Fixed tests. --- src/Screeners/InvestmentScreener/README.md | 6 +++++ tests/Screeners/InvestmentScreener.test.ts | 28 ++++++++++------------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Screeners/InvestmentScreener/README.md b/src/Screeners/InvestmentScreener/README.md index e044a88..33837c1 100644 --- a/src/Screeners/InvestmentScreener/README.md +++ b/src/Screeners/InvestmentScreener/README.md @@ -1,2 +1,8 @@ Morningstar Investment Screener Connector ================================ + +This Highcharts Dashboards connector provides data from Morningstar’s [Investment Screener API]. The JSON from the API is converted into a DataTable. + + + +[Portfolio Risk Score API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/screener/investment-screener diff --git a/tests/Screeners/InvestmentScreener.test.ts b/tests/Screeners/InvestmentScreener.test.ts index 37d0e52..cc8af2f 100644 --- a/tests/Screeners/InvestmentScreener.test.ts +++ b/tests/Screeners/InvestmentScreener.test.ts @@ -1,6 +1,6 @@ import * as Assert from 'node:assert/strict'; import * as MC from '../../code/connectors-morningstar.src'; -import InvestmentScreenerJSON from +import InvestmentScreenerJSON from '../../code/es-modules/Screeners/InvestmentScreener/InvestmentScreenerJSON'; export async function investmentScreenerLoad ( @@ -8,17 +8,15 @@ export async function investmentScreenerLoad ( ) { const secIds = [ 'secId', - 'tenforeId', 'name', + 'investmentType', + 'holdingTypeId', + 'universe', + 'tenforeId', 'closePrice', 'ongoingCharge', 'initialPurchase', - 'maxFrontEndLoad', - 'analystRatingScale', - 'average12MonthCarbonInvestmentScreener', - 'investmentType', - 'holdingTypeId', - 'universe' + 'maxFrontEndLoad' ]; const connector = new MC.InvestmentScreenerConnector({ api, @@ -49,22 +47,22 @@ export async function investmentScreenerLoad ( Assert.strictEqual( connector.table.getRowCount(), - 20, - 'Connector table should have 20 row.' + 15, + 'Connector table should have 15 rows.' ); } export function InvestmentScreenerResponseValidation () { const exampleResponse = { - total: 3000, + total: 18238, page: 1, pageSize: 20, rows: [ { - secId: 'F00000VCTT', - Name: 'TestPortfolio1', - riskRating: 4, - rating: 3 + SecId: 'F000002PLH', + Name: '(LF)-Flexi Allocation Greece Eurobank', + riskrating: 4, + rating: 4 } ] }; From ad84bdf0eee3d39b0078b2a1ca6a04890d1ccf79 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 22 Nov 2024 14:41:58 +0100 Subject: [PATCH 06/16] Fixed test. --- .eslintrc | 1 + .../InvestmentScreener/InvestmentScreenerJSON.ts | 9 --------- tests/Screeners/InvestmentScreener.test.ts | 4 ++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.eslintrc b/.eslintrc index ab2f84e..e57cceb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -34,6 +34,7 @@ "operator-linebreak": [2, "after"], "quotes": [2, "single"], "require-unicode-regexp": 1, + "space-before-function-paren": 2, "strict": 0 }, "overrides": [ diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts index 368e574..4b479e0 100644 --- a/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerJSON.ts @@ -41,15 +41,6 @@ namespace InvestmentScreenerJSON { * * */ - export function isResponse (json?: unknown): json is Response { - return ( - !!json && - typeof json === 'object' && - typeof (json as Response).InvestmentScreener === 'object' && - isInvestmentScreenerResponse((json as Response).InvestmentScreener) - ); - } - export function isInvestmentScreenerResponse ( json?: unknown ): json is InvestmentScreenerResponse { diff --git a/tests/Screeners/InvestmentScreener.test.ts b/tests/Screeners/InvestmentScreener.test.ts index cc8af2f..31ae2c9 100644 --- a/tests/Screeners/InvestmentScreener.test.ts +++ b/tests/Screeners/InvestmentScreener.test.ts @@ -1,6 +1,6 @@ import * as Assert from 'node:assert/strict'; import * as MC from '../../code/connectors-morningstar.src'; -import InvestmentScreenerJSON from +import InvestmentScreenerJSON from '../../code/es-modules/Screeners/InvestmentScreener/InvestmentScreenerJSON'; export async function investmentScreenerLoad ( @@ -68,7 +68,7 @@ export function InvestmentScreenerResponseValidation () { }; Assert.ok( - InvestmentScreenerJSON.isResponse(exampleResponse), + InvestmentScreenerJSON.isInvestmentScreenerResponse(exampleResponse), 'InvestmentScreenerJSON should validate correct response.' ); } From cece1eee531e97aaa1119c6582ecae94d4e641ee Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 22 Nov 2024 14:49:29 +0100 Subject: [PATCH 07/16] Fixed linting errors. --- demos/dashboards-investment-screener/demo.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demos/dashboards-investment-screener/demo.js b/demos/dashboards-investment-screener/demo.js index ffc55d9..5ae987b 100644 --- a/demos/dashboards-investment-screener/demo.js +++ b/demos/dashboards-investment-screener/demo.js @@ -1,6 +1,6 @@ const loadingLabel = document.getElementById('loading-label'); -function displayInvestmentScreener(postmanJSON) { +function displayInvestmentScreener (postmanJSON) { const secIds = [ 'secId', 'tenforeId', @@ -70,7 +70,7 @@ function displayInvestmentScreener(postmanJSON) { `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; }); - function setFilter(filters) { + function setFilter (filters) { loadingLabel.style.display = 'block'; board.dataPool.getConnector('investment-screener').then(connector => { const options = { @@ -161,7 +161,7 @@ function displayInvestmentScreener(postmanJSON) { }); } -async function handleSelectEnvironment(evt) { +async function handleSelectEnvironment (evt) { const target = evt.target; const postmanJSON = await getPostmanJSON(target); @@ -185,7 +185,7 @@ document .getElementById('postman-json') .addEventListener('change', handleSelectEnvironment); -async function getPostmanJSON(htmlInputFile) { +async function getPostmanJSON (htmlInputFile) { let file; let fileJSON; From 66458d76f027937c6f86557921f368dcdc14323e Mon Sep 17 00:00:00 2001 From: pawellysy Date: Tue, 26 Nov 2024 08:03:13 +0100 Subject: [PATCH 08/16] Added investment screener demo to list of demos. --- demos/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/demos/index.html b/demos/index.html index 5fc4bcd..e0af18f 100644 --- a/demos/index.html +++ b/demos/index.html @@ -12,6 +12,7 @@

Morningstar Connectors Demos

  • Highcharts Stock + Morningstar OHLCV TimeSeries
  • Highcharts Stock + Morningstar Security Details
  • Highcharts Dashboards + Morningstar Risk Score
  • +
  • Highcharts Dashboards + Morningstar Investment Screener
  • From 1a872851a8a0f1133faf7e9ed86b9ccbebfe99d0 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Tue, 26 Nov 2024 11:34:38 +0100 Subject: [PATCH 09/16] Fixed typo --- demos/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/index.html b/demos/index.html index e0af18f..3255880 100644 --- a/demos/index.html +++ b/demos/index.html @@ -12,7 +12,7 @@

    Morningstar Connectors Demos

  • Highcharts Stock + Morningstar OHLCV TimeSeries
  • Highcharts Stock + Morningstar Security Details
  • Highcharts Dashboards + Morningstar Risk Score
  • -
  • Highcharts Dashboards + Morningstar Investment Screener
  • +
  • Highcharts Dashboards + Morningstar Investment Screener
  • From 6008978de52fa855d6de3be737befa3edadc3cc1 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Thu, 28 Nov 2024 07:41:23 +0100 Subject: [PATCH 10/16] Added docs for Investment Screener. --- .../screeners/investment-screener.md | 58 ++++++++++++++++ .../InvestmentScreenerOptions.ts | 66 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 docs/connectors/morningstar/screeners/investment-screener.md diff --git a/docs/connectors/morningstar/screeners/investment-screener.md b/docs/connectors/morningstar/screeners/investment-screener.md new file mode 100644 index 0000000..a692e67 --- /dev/null +++ b/docs/connectors/morningstar/screeners/investment-screener.md @@ -0,0 +1,58 @@ +Investment Screener connector +============================= + +Using Morningstar Investment Screener endpoint you are able filter Morningstar's database of global investments using hundreds of data points including Morningstar prorietary data. + + +How to use Investment Screener +---------------- + +Data can be filtered on any data point which is comprehensively covered by Morningstar, including proprietary data such as: + +Morningstar Sustainability Ratings +Analyst Rating +Fair Value +Style Box +With the solution, you can develop a sophisticated screening tool offering dozens of filters for advanced users. + +You can also use it to power predefined screeners for common investment research interests such as Top Fixed Income Funds, Top Rated US Bond Index Funds, Sustainable Investments, and so on. + +For more details, see [Morningstar's Investment Screener API]. + + +[Morningstar's Investment Screener API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/investment-screener + +this connector is designed to be interacted with using some external buttons, that might filter data on the backend, provide pagiantion as well as sorting. + +Here is an example of how to use the Investment Screener connector: +```js +const screenerConnector = MC.InvestmentScreenerConnector({ + page: 1, + pageSize: 20, + langageId: 'en-GB', + currencyId: 'USD', + securityDataPoints: [ + 'secId', + 'tenforeId', + 'name', + 'closePrice', + 'ongoingCharge', + 'initialPurchase', + 'maxFrontEndLoad', + 'analystRatingScale', + 'average12MonthCarbonRiskScore', + 'investmentType', + 'holdingTypeId', + 'universe' + ], + universeIds: ['FOALL$$ALL'], + postman: { + environmentJSON: postmanJSON + } +}); +``` + +For details see [Morningstar's Investment Screener API]. + + + diff --git a/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts b/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts index 7b62189..f4963f5 100644 --- a/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts +++ b/src/Screeners/InvestmentScreener/InvestmentScreenerOptions.ts @@ -5,22 +5,88 @@ import type { } from '../../Shared/MorningstarOptions'; export interface InvestmentScreenerOptions extends MorningstarOptions { applyTrackRecordExtension?: boolean; + /** + * + * ISO alpha-3 country code. + * + */ countryId?: string; + /** + * + * ISO alpha-3 currency code. + * The currency to be used for calculated data points such as performance + * returns. To return list of securities with a specific base currency, + * you must pass the following filter in the request: + * CURRENCY:EQ:{currency code}. For example: Currency:EQ:EUR. See the + * Filters section for more information. + */ currencyId?: string; + /** + * + * A list of filter data points. + * Multiple values must be separated by a pipe character ( | ) URL-encoded + * as “%7C”. In a UI screening tool, these values define the filters that + * are seen on the screen. Custom data points can be configured. See + * Filters for information about how to get a list of filter data points. + */ filterDataPoints?: string[]; + /** + * + * A list of criteria a security must meet to be included in the results. + */ filters?: InvestmentScreenerFilter[]; + /** + * + * When true returns will not be calculated using the restructure date. + * + */ ignoreRestructure?: boolean; + /** + * + * The number of output pages. + * + */ page?: number; + /** + * + * The number of rows per page. + * + */ pageSize?: number; + /** + * + * A list of security data points to return in the response. + * + */ securityDataPoints?: SecurityDataPointType[]; + /** + * + * Data points to sort on and the order in which results are sorted + * + */ sortOrder?: string; + /** + * + * Search string to use to search for securities by name, identifiers, or + * symbols. Can be used with filter to run a combined search. + * + */ term?: string; + /** + * + * A list of investment universe identifiers to query. Values may end with + * `:1` to signify that a custom universe is not only client funds. + * + */ universeIds: string[]; } export interface InvestmentScreenerFilter { + /** The data point to filter on. */ dataPointId: string; + /** The comparator to use. */ comparatorCode: ComparatorCode; + /** The value to compare against. */ value: any; } From db743a3809d3db1ca96bc5931043ba7e1d98ec79 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Thu, 28 Nov 2024 07:58:29 +0100 Subject: [PATCH 11/16] Added comments to demo. --- demos/dashboards-investment-screener/demo.js | 14 ++++++++++++++ src/api.d.ts | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/demos/dashboards-investment-screener/demo.js b/demos/dashboards-investment-screener/demo.js index 5ae987b..8d5a3dc 100644 --- a/demos/dashboards-investment-screener/demo.js +++ b/demos/dashboards-investment-screener/demo.js @@ -70,6 +70,11 @@ function displayInvestmentScreener (postmanJSON) { `out of ${Math.ceil(connector.metadata.total / connector.metadata.pageSize)}`; }); + /** + * Add filter to a connector + * + * @param {InvestmentScreenerFilter[]} filters + */ function setFilter (filters) { loadingLabel.style.display = 'block'; board.dataPool.getConnector('investment-screener').then(connector => { @@ -92,6 +97,8 @@ function displayInvestmentScreener (postmanJSON) { e.target.classList.add('button-active'); document.getElementById('current-filter').innerHTML = e.target.innerHTML; + // Create a filter that will check if the star rating is equal to 5 + // and if the analyst rating is equal to 5 setFilter([ { dataPointId: 'StarRatingM255', @@ -109,6 +116,8 @@ function displayInvestmentScreener (postmanJSON) { document.getElementById('filter-2').addEventListener('click', e => { document.getElementById('current-filter').innerHTML = e.target.innerHTML; + // Create a filter that will check if the GBR return is between + // 39 and 60 setFilter([ { dataPointId: 'GBRReturnM0', @@ -121,6 +130,9 @@ function displayInvestmentScreener (postmanJSON) { document.getElementById('filter-3').addEventListener('click', e => { document.getElementById('current-filter').innerHTML = e.target.innerHTML; + // Create a filter that will filter on the Low Carbon Designation + // and Carbon Risk Score. These Investments are considered highly + // sustainable setFilter([ { dataPointId: 'LowCarbonDesignation', @@ -143,6 +155,8 @@ function displayInvestmentScreener (postmanJSON) { document.getElementById('filter-4').addEventListener('click', e => { document.getElementById('current-filter').innerHTML = e.target.innerHTML; + // Create a filter that will check if the investment is considered + // as "low expenses" setFilter([ { dataPointId: 'StarRatingM255', diff --git a/src/api.d.ts b/src/api.d.ts index 6fdc664..b9d0844 100644 --- a/src/api.d.ts +++ b/src/api.d.ts @@ -24,7 +24,7 @@ import RiskScoreOptions from './RiskScore/RiskScoreOptions'; import RNANewsOptions from './RNANews/RNANewsOptions'; import TimeSeriesOptions from './TimeSeries/TimeSeriesOptions'; import XRayOptions from './XRay/XRayOptions'; - +import InvestmentScreenerOptions from './Screeners/InvestmentScreener/InvestmentScreenerOptions'; /* * * @@ -42,4 +42,5 @@ interface Options { RNANews: RNANewsOptions; TimeSeries: TimeSeriesOptions; XRay: XRayOptions; + InvestmentScreener: InvestmentScreenerOptions; } From dcda7a7b00248811ffd99f4a831de4043c0985cb Mon Sep 17 00:00:00 2001 From: pawellysy Date: Thu, 28 Nov 2024 14:02:12 +0100 Subject: [PATCH 12/16] Fixed docs. --- docs/connectors/morningstar.md | 1 + .../screeners/investment-screener.md | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/connectors/morningstar.md b/docs/connectors/morningstar.md index 800abc1..4aa6efe 100644 --- a/docs/connectors/morningstar.md +++ b/docs/connectors/morningstar.md @@ -54,3 +54,4 @@ types. * [Risk Score](morningstar/risk-score.md) * [TimeSeries](morningstar/time-series/time-series.md) * [XRay](morningstar/x-ray.md) +* [Investment Screener](morningstar/screeners/investment-screener.md) diff --git a/docs/connectors/morningstar/screeners/investment-screener.md b/docs/connectors/morningstar/screeners/investment-screener.md index a692e67..2507d8d 100644 --- a/docs/connectors/morningstar/screeners/investment-screener.md +++ b/docs/connectors/morningstar/screeners/investment-screener.md @@ -3,34 +3,41 @@ Investment Screener connector Using Morningstar Investment Screener endpoint you are able filter Morningstar's database of global investments using hundreds of data points including Morningstar prorietary data. - How to use Investment Screener ---------------- Data can be filtered on any data point which is comprehensively covered by Morningstar, including proprietary data such as: -Morningstar Sustainability Ratings -Analyst Rating -Fair Value -Style Box -With the solution, you can develop a sophisticated screening tool offering dozens of filters for advanced users. + * Morningstar Sustainability Ratings + * Analyst Rating + * Fair Value + * Style Box + * With the solution, you can develop a sophisticated screening tool offering dozens of filters for advanced users. You can also use it to power predefined screeners for common investment research interests such as Top Fixed Income Funds, Top Rated US Bond Index Funds, Sustainable Investments, and so on. For more details, see [Morningstar's Investment Screener API]. -[Morningstar's Investment Screener API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/investment-screener +[Morningstar's Investment Screener API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/screener/investment-screener this connector is designed to be interacted with using some external buttons, that might filter data on the backend, provide pagiantion as well as sorting. Here is an example of how to use the Investment Screener connector: + ```js const screenerConnector = MC.InvestmentScreenerConnector({ page: 1, pageSize: 20, langageId: 'en-GB', currencyId: 'USD', + filters: [ + { + dataPointId: 'StarRatingM255', + comparatorCode: 'IN', + value: 5 + } + ], securityDataPoints: [ 'secId', 'tenforeId', @@ -54,5 +61,3 @@ const screenerConnector = MC.InvestmentScreenerConnector({ For details see [Morningstar's Investment Screener API]. - - From e2e73ac217056bcf6d94efc8f70d78c5b9f9d757 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 29 Nov 2024 10:06:42 +0100 Subject: [PATCH 13/16] Fix typo --- docs/connectors/morningstar/screeners/investment-screener.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connectors/morningstar/screeners/investment-screener.md b/docs/connectors/morningstar/screeners/investment-screener.md index 2507d8d..a702b25 100644 --- a/docs/connectors/morningstar/screeners/investment-screener.md +++ b/docs/connectors/morningstar/screeners/investment-screener.md @@ -21,7 +21,7 @@ For more details, see [Morningstar's Investment Screener API]. [Morningstar's Investment Screener API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/screener/investment-screener -this connector is designed to be interacted with using some external buttons, that might filter data on the backend, provide pagiantion as well as sorting. +This connector is designed to be interacted with using some external buttons, that might filter data on the backend, provide pagiantion as well as sorting. Here is an example of how to use the Investment Screener connector: From 5ff969b680022cee0f07c27b7fd545aee9dea9d5 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 29 Nov 2024 11:53:05 +0100 Subject: [PATCH 14/16] Update docs/connectors/morningstar/screeners/investment-screener.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Musiałowski <105275628+kamil-musialowski@users.noreply.github.com> --- docs/connectors/morningstar/screeners/investment-screener.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connectors/morningstar/screeners/investment-screener.md b/docs/connectors/morningstar/screeners/investment-screener.md index a702b25..f6ebf19 100644 --- a/docs/connectors/morningstar/screeners/investment-screener.md +++ b/docs/connectors/morningstar/screeners/investment-screener.md @@ -1,7 +1,7 @@ Investment Screener connector ============================= -Using Morningstar Investment Screener endpoint you are able filter Morningstar's database of global investments using hundreds of data points including Morningstar prorietary data. +Using Morningstar Investment Screener endpoint allows you to filter Morningstar's database of global investments using hundreds of data points including Morningstar proprietary data. How to use Investment Screener ---------------- From c91c62b7c425e98f0d34179d24a85ab574cc5894 Mon Sep 17 00:00:00 2001 From: pawellysy Date: Fri, 29 Nov 2024 11:55:25 +0100 Subject: [PATCH 15/16] Added console warn on error in demo. --- demos/dashboards-investment-screener/demo.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demos/dashboards-investment-screener/demo.js b/demos/dashboards-investment-screener/demo.js index 8d5a3dc..777b671 100644 --- a/demos/dashboards-investment-screener/demo.js +++ b/demos/dashboards-investment-screener/demo.js @@ -210,7 +210,8 @@ async function getPostmanJSON (htmlInputFile) { break; } } catch (error) { - // fail silently + // eslint-disable-next-line no-console + console.warn(error); } } From 546d9d117087fe110763a4a42fb0e7b2de20dabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Musia=C5=82owski?= Date: Fri, 29 Nov 2024 13:07:33 +0100 Subject: [PATCH 16/16] Added missing typo fixes. --- .../connectors/morningstar/screeners/investment-screener.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/connectors/morningstar/screeners/investment-screener.md b/docs/connectors/morningstar/screeners/investment-screener.md index f6ebf19..74e245e 100644 --- a/docs/connectors/morningstar/screeners/investment-screener.md +++ b/docs/connectors/morningstar/screeners/investment-screener.md @@ -1,4 +1,4 @@ -Investment Screener connector +Investment Screener ============================= Using Morningstar Investment Screener endpoint allows you to filter Morningstar's database of global investments using hundreds of data points including Morningstar proprietary data. @@ -21,7 +21,7 @@ For more details, see [Morningstar's Investment Screener API]. [Morningstar's Investment Screener API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/screener/investment-screener -This connector is designed to be interacted with using some external buttons, that might filter data on the backend, provide pagiantion as well as sorting. +This connector is designed to be interacted with using external buttons, that might filter data on the backend, provide pagination as well as sorting. Here is an example of how to use the Investment Screener connector: @@ -29,7 +29,7 @@ Here is an example of how to use the Investment Screener connector: const screenerConnector = MC.InvestmentScreenerConnector({ page: 1, pageSize: 20, - langageId: 'en-GB', + languageId: 'en-GB', currencyId: 'USD', filters: [ {