diff --git a/requirements.txt b/datafeed/requirements.txt similarity index 100% rename from requirements.txt rename to datafeed/requirements.txt diff --git a/server.py b/datafeed/server3.py similarity index 100% rename from server.py rename to datafeed/server3.py diff --git a/src/DataManipulator.ts b/src/DataManipulator.ts index 7f622955cc..0f8fe6de36 100644 --- a/src/DataManipulator.ts +++ b/src/DataManipulator.ts @@ -1,20 +1,36 @@ -import { ServerRespond } from './DataStreamer'; +import { ServerRespond } from "./DataStreamer"; export interface Row { - stock: string, - top_ask_price: number, - timestamp: Date, + 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..cc8dba4a79 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -1,32 +1,37 @@ -import React, { Component } from 'react'; -import { Table } from '@finos/perspective'; -import { ServerRespond } from './DataStreamer'; -import { DataManipulator } from './DataManipulator'; -import './Graph.css'; +import React, { Component } from "react"; +import { Table, TableData } from "@finos/perspective"; +import { ServerRespond } from "./DataStreamer"; +import { DataManipulator } from "./DataManipulator"; +import "./Graph.css"; interface IProps { - data: ServerRespond[], + data: ServerRespond[]; } interface PerspectiveViewerElement extends HTMLElement { - load: (table: Table) => void, + load: (table: Table) => void; } class Graph extends Component { table: Table | undefined; render() { - return React.createElement('perspective-viewer'); + return React.createElement("perspective-viewer"); } 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 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()) { @@ -35,24 +40,32 @@ class Graph extends Component { if (this.table) { // 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('aggregates', JSON.stringify({ - stock: 'distinctcount', - top_ask_price: 'avg', - top_bid_price: 'avg', - timestamp: 'distinct count', - })); + elem.setAttribute("view", "y_line"); + elem.setAttribute("row-pivots", '["timestamp"]'); + elem.setAttribute( + "columns", + '["ratio","lower_bound","upper_bound","trigger_alert"]' + ); + elem.setAttribute( + "aggregates", + JSON.stringify({ + 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); } } }