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

Implement Morningstar Regulatory News Announcements connector #3

Merged
merged 15 commits into from
Jul 31, 2024
Merged
14 changes: 14 additions & 0 deletions demos/rna-news/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://code.highcharts.com/dashboards/2.2.0/css/dashboards.css" />
<script src="https://code.highcharts.com/dashboards/2.2.0/dashboards.src.js"></script>
<script src="../../code/morningstar-connectors.src.js"></script>
<title>RNA News Demo - Morningstar Connectors Demos</title>
</head>
<body>
<div id="container"></div>
<script src="./demo.js"></script>
</body>
</html>
141 changes: 141 additions & 0 deletions demos/rna-news/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
const board = Dashboards.board('container', {
dataPool: {
connectors: [{
id: 'rna',
type: 'MorningstarRNANews',
options: {
security: {
id: 'US0378331005'
},
postman: {
environmentURL: '/tmp/Environment.json'
}
}
},
{
id: 'rna-type-amount',
type: 'JSON',
options: {
columnNames: ['Type', 'Amount'],
data: [
[],
[]
],
orientation: 'columns',
firstRowAsNames: false
}
}
]
},
components: [
{
renderTo: 'dashboard-col-0',
connector: {
id: 'rna'
},
type: 'DataGrid',
title: 'News',
dataGridOptions: {
editable: false,
columns: {
Day: {
cellFormatter: function () {
return new Date(this.value)
.toISOString()
.substring(0, 10);
}
}
}
}
},
{
renderTo: 'dashboard-col-1',
connector: {
id: 'rna-type-amount',
columnAssignment: [{
seriesId: 'number-per-type',
data: ['Type', 'Amount']
}]
},
type: 'Highcharts',
chartOptions: {
chart: {
animation: false,
type: 'column'
},
title: {
text: 'Number of items per type'
},
subtitle: {
text: 'Shows number of news items of each kind'
},
series: [{
id: 'number-per-type',
name: 'Number per type'
}],
tooltip: {
shared: true,
split: true,
stickOnContact: true
},
lang: {
accessibility: {
chartContainerLabel:
'Shows number of news items of each kind'
}
},
xAxis: {
type: 'category',
accessibility: {
description: 'Kind of news annoucement'
}
},
yAxis: {
title: {
text: 'Number of announcements'
}
}
}
}
]
});

board.dataPool.getConnectorTable('rna')
.then(async table => {
const types = table.getColumn('Type');
const uniqueTypes = Array.from(new Set(types));
const numberPerType = uniqueTypes.map(type =>
types.reduce((previous, current) => {
if (current === type) {
return previous + 1;
}
return previous;
}, 0)
);

board.dataPool.setConnectorOptions({
id: 'rna-type-amount',
type: 'JSON',
options: {
columnNames: ['Type', 'Amount'],
orientation: 'columns',
firstRowAsNames: false,
data: [
uniqueTypes,
numberPerType
]
}
});

// Refresh the component after updating the table
await board.getComponentByCellId('dashboard-col-1').initConnectors();
await board.getComponentByCellId('dashboard-col-1').update({
connector: {
id: 'rna-type-amount',
columnAssignment: [{
seriesId: 'number-per-type',
data: ['Type', 'Amount']
}]
}
});
});
8 changes: 8 additions & 0 deletions src/RNANews/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Morningstar RNA News Connector
===================================================

This Highcharts Dashboards connector provides access to the [Morningstar RNANews API]. The JSON from the API is converted into a DataTable.

<!-- Link References -->

[Morningstar RNANews API]: https://developer.morningstar.com/direct-web-services/documentation/api-reference/time-series/regulatory-news-announcements
202 changes: 202 additions & 0 deletions src/RNANews/RNANewsConnector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/* *
*
* (c) 2009-2024 Highsoft AS
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* Authors:
* - Eskil Gjerde Sviggum
*
* */


'use strict';


/* *
*
* Imports
*
* */

import External from '../Shared/External';
import MorningstarConnector from '../Shared/MorningstarConnector';
import MorningstarAPI from '../Shared/MorningstarAPI';
import MorningstarURL from '../Shared/MorningstarURL';
import RNANewsOptions from './RNANewsOptions';
import RNANewsConverter from './RNANewsConverter';
import RNANewsJSON from './RNANewsJSON';

/* *
*
* Class
*
* */

class RNANewsConnector extends MorningstarConnector {

/**
* Constructs an instance of RNANewsConnector.
* @param {RNANewsOptions} [options]
* Options for the connector and converter.
*/
public constructor(
options: RNANewsOptions
) {
super(options);

this.converter = new RNANewsConverter(options);
this.options = options;
}

/* *
*
* Properties
*
* */


public override readonly converter: RNANewsConverter;


public override readonly options: RNANewsOptions;

/* *
*
* Functions
*
* */

/**
* Loads RNANews data from Morningstar.
*
* @return {Promise<this>}
* Same connector instance with modified table.
*/
public override async load(): Promise<this> {
const options = this.options;
const {
security,
startDate,
endDate,
maxStories,
localization
} = options;

if (!security) {
return this;
}

const url = new MorningstarURL('timeseries/rna-news');
const searchParams = url.searchParams;
const api = new MorningstarAPI(options.api);

searchParams.setSecurityOptions([security]);

if (startDate) {
const date = RNANewsConnector.validateAndFormatDate(startDate);
searchParams.set('startDate', date);
}

if (endDate) {
const date = RNANewsConnector.validateAndFormatDate(endDate);
searchParams.set('endDate', date);
}

if (maxStories) {
const numericMaxStories = Number(maxStories);
if (!Number.isInteger(numericMaxStories)) {
throw new Error(`Expected maxStories to be integer, but is instead ${maxStories}`);
}
searchParams.set('maxStories', '' + maxStories);
}

if (localization) {
searchParams.setLocalizationOptions(localization);
}

const response = await api.fetch(url);
const json = await response.json() as RNANewsJSON.Response;

this.converter.parse({ json });

this.table.deleteColumns();
this.table.setColumns(this.converter.getTable().getColumns());

return this;
}

}

/* *
*
* Class Namespace
*
* */

namespace RNANewsConnector {
/**
* If a number is provided, it is treated as a unix timestamp in
* milliseconds and converted to format `yyyy-MM-dd`.
* If a string is provided, it is validated to conform to the format.
* @private
* @param {number | string} date date as a timestamp of formatted string
* @return {string} date formatted as `yyyy-MM-dd`.
*/
export function validateAndFormatDate(date: number | string): string {
let timestamp: number;
if (typeof date === 'string') {
// Check if string is a number, likely a timestamp
if (!Number.isNaN(Number(date))) {
timestamp = Number(date);
} else {
const parsedDate = Date.parse(date);
if (Number.isNaN(parsedDate)) {
throw new Error(`The date ${date} is not a valid date.`);
}
timestamp = parsedDate;
}
} else if (typeof date === 'number') {
timestamp = date;
} else {
throw new Error(
'The provided date is not of type string, nor number.'
);
}

return new Date(timestamp)
.toISOString()
.substring(0, 10);
}
}

/* *
*
* Registry
*
* */


declare module '@highcharts/dashboards/es-modules/Data/Connectors/DataConnectorType' {
interface DataConnectorTypes {
MorningstarRNANews: typeof RNANewsConnector;
}
}


External.DataConnector.registerType(
'MorningstarRNANews',
RNANewsConnector
);


/* *
*
* Default Export
*
* */


export default RNANewsConnector;
Loading