diff --git a/package-lock.json b/package-lock.json index 8135a727a1..110a1c4e05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11011,12 +11011,6 @@ "node": ">=4.0.0" } }, - "node_modules/jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", - "peer": true - }, "node_modules/js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -12976,17 +12970,6 @@ "node": ">=6" } }, - "node_modules/popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -21714,8 +21697,7 @@ "@d3fc/d3fc-data-join": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@d3fc/d3fc-data-join/-/d3fc-data-join-6.0.3.tgz", - "integrity": "sha512-fd1D2Cl4YGjzl3gBhcrvTl/VxaSncY0ZcokWsN8ahtmk9DZK4DnAgHGrdecnXVLkOx+ANDcqxqscYz6MWXLbcA==", - "requires": {} + "integrity": "sha512-fd1D2Cl4YGjzl3gBhcrvTl/VxaSncY0ZcokWsN8ahtmk9DZK4DnAgHGrdecnXVLkOx+ANDcqxqscYz6MWXLbcA==" }, "@d3fc/d3fc-discontinuous-scale": { "version": "4.1.0", @@ -21733,14 +21715,12 @@ "@d3fc/d3fc-extent": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@d3fc/d3fc-extent/-/d3fc-extent-4.0.2.tgz", - "integrity": "sha512-m7w7Dof6KAIDtgzIsTcprWTEoiqExJGsGoQbb97bF+EwIkuEZWRUl1jkoeNL00efpX1o6zSdqSr6lojoR0aI/g==", - "requires": {} + "integrity": "sha512-m7w7Dof6KAIDtgzIsTcprWTEoiqExJGsGoQbb97bF+EwIkuEZWRUl1jkoeNL00efpX1o6zSdqSr6lojoR0aI/g==" }, "@d3fc/d3fc-financial-feed": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@d3fc/d3fc-financial-feed/-/d3fc-financial-feed-7.1.0.tgz", - "integrity": "sha512-K8jktdRJQAiJepglErsuY2ZMKsm0YFWTeuhYnTFb8rWmyhwoPeem9QW+e6xBTiAvbElJm4yTrkal09KmO2cLlQ==", - "requires": {} + "integrity": "sha512-K8jktdRJQAiJepglErsuY2ZMKsm0YFWTeuhYnTFb8rWmyhwoPeem9QW+e6xBTiAvbElJm4yTrkal09KmO2cLlQ==" }, "@d3fc/d3fc-group": { "version": "3.0.1", @@ -21799,8 +21779,7 @@ "@d3fc/d3fc-shape": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@d3fc/d3fc-shape/-/d3fc-shape-6.0.1.tgz", - "integrity": "sha512-/dD3S8BWrOjO2mSptUmwe38V7KG4Kw6liIE5NXZJjX/XidfZhuDu7WWuya3i90HeNYDZNcs6Z+4qM3FnvlZf8g==", - "requires": {} + "integrity": "sha512-/dD3S8BWrOjO2mSptUmwe38V7KG4Kw6liIE5NXZJjX/XidfZhuDu7WWuya3i90HeNYDZNcs6Z+4qM3FnvlZf8g==" }, "@d3fc/d3fc-technical-indicator": { "version": "8.1.0", @@ -22227,8 +22206,7 @@ "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" }, "acorn-walk": { "version": "7.2.0", @@ -22262,14 +22240,12 @@ "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "requires": {} + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" }, "alphanum-sort": { "version": "1.0.2", @@ -22671,8 +22647,7 @@ "babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "requires": {} + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==" }, "babel-eslint": { "version": "9.0.0", @@ -22790,8 +22765,7 @@ "babel-plugin-named-asset-import": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "requires": {} + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==" }, "babel-plugin-polyfill-corejs2": { "version": "0.3.2", @@ -23410,8 +23384,7 @@ "bootstrap": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", - "requires": {} + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==" }, "brace-expansion": { "version": "1.1.11", @@ -28660,8 +28633,7 @@ "jest-pnp-resolver": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.0.1.tgz", - "integrity": "sha512-kzhvJQp+9k0a/hpvIIzOJgOwfOqmnohdrAMZW2EscH3kxR2VWD7EcPa10cio8EK9V7PcD75bhG1pFnO70zGwSQ==", - "requires": {} + "integrity": "sha512-kzhvJQp+9k0a/hpvIIzOJgOwfOqmnohdrAMZW2EscH3kxR2VWD7EcPa10cio8EK9V7PcD75bhG1pFnO70zGwSQ==" }, "jest-regex-util": { "version": "23.3.0", @@ -28944,12 +28916,6 @@ "topo": "2.x.x" } }, - "jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", - "peer": true - }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -29046,8 +29012,7 @@ "ws": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "requires": {} + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==" } } }, @@ -30479,12 +30444,6 @@ "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.1.0.tgz", "integrity": "sha512-CPCdcFxx7fEcDMWTDjXe2Wypt4JuMt4q5Q2UrpTcyBBkLiCIyPEh/mCGmUWIcNkKGyXwQ9Y2wVhlKm6ketiBNQ==" }, - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "peer": true - }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", diff --git a/src/DataManipulator.ts b/src/DataManipulator.ts index 7f622955cc..3223c6b4c5 100644 --- a/src/DataManipulator.ts +++ b/src/DataManipulator.ts @@ -1,20 +1,32 @@ import { ServerRespond } from './DataStreamer'; export interface Row { - stock: string, - top_ask_price: number, + price_abc: number, + price_def: number, + ratio: number, timestamp: Date, + upper_bound: number, + lower_bound: number, + trigger_alert: number | undefined, } export class DataManipulator { - static generateRow(serverResponds: ServerRespond[]) { - return serverResponds.map((el: any) => { - return { - stock: el.stock, - top_ask_price: el.top_ask && el.top_ask.price || 0, - timestamp: el.timestamp, - }; - }) + static generateRow(serverRespond: ServerRespond[]): Row { + const priceABC = (serverRespond[0].top_ask.price + serverRespond[0].top_bid.price) / 2; + const priceDEF = (serverRespond[1].top_ask.price + serverRespond[1].top_bid.price) / 2; + const ratio = priceABC / priceDEF; + const upperBound = 1 + 0.05; + const lowerBound = 1 - 0.05; + return { + price_abc: priceABC, + price_def: priceDEF, + ratio, + timestamp: serverRespond[0].timestamp > serverRespond[1].timestamp ? + serverRespond[0].timestamp : serverRespond[1].timestamp, + upper_bound: upperBound, + lower_bound: lowerBound, + trigger_alert: (ratio > upperBound || ratio < lowerBound) ? ratio : undefined, + }; } } diff --git a/src/Graph.tsx b/src/Graph.tsx index 277797d933..58d98d01fa 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { Table } from '@finos/perspective'; +import { Table, TableData } from '@finos/perspective'; import { ServerRespond } from './DataStreamer'; import { DataManipulator } from './DataManipulator'; import './Graph.css'; @@ -23,10 +23,13 @@ class Graph extends Component { const elem = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement; const schema = { - stock: 'string', - top_ask_price: 'float', - top_bid_price: 'float', - timestamp: 'date', + price_abc: 'float', + price_def: 'float', + ratio: 'float', + timeStamp: 'date', + upper_bound: 'float', + lower_bound: 'float', + trigger_alert: 'float', }; if (window.perspective && window.perspective.worker()) { @@ -36,23 +39,25 @@ class Graph extends Component { // Load the `table` in the `` DOM reference. elem.load(this.table); elem.setAttribute('view', 'y_line'); - elem.setAttribute('column-pivots', '["stock"]'); elem.setAttribute('row-pivots', '["timestamp"]'); - elem.setAttribute('columns', '["top_ask_price"]'); + elem.setAttribute('columns', '["ratio", "lower_bound", "upper_bound", "trigger_alert"]'); elem.setAttribute('aggregates', JSON.stringify({ - stock: 'distinctcount', - top_ask_price: 'avg', - top_bid_price: 'avg', + price_abc: 'avg', + price_def: 'avg', + ratio: 'avg', timestamp: 'distinct count', + upper_bound: 'avg', + lower_bound: 'avg', + trigger_alert: 'avg', })); } } componentDidUpdate() { if (this.table) { - this.table.update( + this.table.update([ DataManipulator.generateRow(this.props.data), - ); + ] as unknown as TableData); } } }