diff --git a/src/DataManipulator.ts b/src/DataManipulator.ts index 7f622955cc..40247be59f 100644 --- a/src/DataManipulator.ts +++ b/src/DataManipulator.ts @@ -1,20 +1,33 @@ 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(serverResponds: ServerRespond[]): Row[] { + const priceABC = serverResponds.find(d => d.stock === 'ABC')?.top_ask.price; + const priceDEF = serverResponds.find(d => d.stock === 'DEF')?.top_ask.price; + const ratio = priceABC && priceDEF ? priceABC / priceDEF : 0; + const upperBound = 1.05; + const lowerBound = 0.95; + const triggerAlert = (ratio > upperBound || ratio < lowerBound) ? ratio : undefined; + + return serverResponds.map((el: any) => ({ + price_abc: el.stock === 'ABC' ? el.top_ask.price : priceABC || 0, + price_def: el.stock === 'DEF' ? el.top_ask.price : priceDEF || 0, + ratio, + timestamp: el.timestamp, + upper_bound: upperBound, + lower_bound: lowerBound, + trigger_alert: triggerAlert, + })); } } + diff --git a/src/Graph.tsx b/src/Graph.tsx index 277797d933..cd4cb78ac0 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -11,6 +11,7 @@ interface IProps { interface PerspectiveViewerElement extends HTMLElement { load: (table: Table) => void, } + class Graph extends Component { table: Table | undefined; @@ -20,13 +21,19 @@ class Graph extends Component { componentDidMount() { // Get element from the DOM. - const elem = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement; + const elem = document.getElementsByTagName('perspective-viewer')[0] as PerspectiveViewerElement; const schema = { stock: 'string', top_ask_price: 'float', top_bid_price: 'float', timestamp: 'date', + price_abc: 'float', + price_def: 'float', + ratio: 'float', + upper_bound: 'float', + lower_bound: 'float', + trigger_alert: 'float', }; if (window.perspective && window.perspective.worker()) { @@ -35,15 +42,22 @@ class Graph extends Component { if (this.table) { // Load the `table` in the `` DOM reference. elem.load(this.table); + + // Set Perspective configurations 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', + stock: 'distinct count', top_ask_price: 'avg', top_bid_price: 'avg', timestamp: 'distinct count', + price_abc: 'avg', + price_def: 'avg', + ratio: 'avg', + upper_bound: 'avg', + lower_bound: 'avg', + trigger_alert: 'avg', })); } }