From 009daff46663fed6576f12fe4cd23f59b0441dc7 Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 01:22:49 +0530 Subject: [PATCH 1/5] Update App.css --- src/App.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/App.css b/src/App.css index 1a8747ad99..f5098640dc 100755 --- a/src/App.css +++ b/src/App.css @@ -35,10 +35,17 @@ .Graph { min-height: 50vh; - width: 700px; + width: 700px; /* Fixed width */ margin-bottom: 12px; } +/* Responsive design for screens smaller than 768px */ +@media (max-width: 768px) { + .Graph { + width: 90%; /* Adjust width to be responsive */ + } +} + @keyframes App-logo-spin { from { transform: rotate(0deg); From 32aa3551190aa1308927637e1132df5ed748c44c Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 01:23:09 +0530 Subject: [PATCH 2/5] Update App.tsx --- src/App.tsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 274d20b0a0..1d430c37a2 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,6 +9,8 @@ interface IState { } class App extends Component<{}, IState> { + private intervalId: NodeJS.Timeout | undefined; + constructor(props: {}) { super(props); this.state = { @@ -17,15 +19,23 @@ class App extends Component<{}, IState> { }; } + componentWillUnmount() { + // Clear the interval if the component is unmounted + if (this.intervalId) { + clearInterval(this.intervalId); + } + } + renderGraph() { if (this.state.showGraph) { - return () + return (); } + return null; } getDataFromServer() { let x = 0; - const interval = setInterval(() => { + this.intervalId = setInterval(() => { DataStreamer.getData((serverResponds: ServerRespond[]) => { this.setState({ data: serverResponds, @@ -34,7 +44,10 @@ class App extends Component<{}, IState> { }); x++; if (x > 1000) { - clearInterval(interval); + // Stop fetching after 1000 intervals + if (this.intervalId) { + clearInterval(this.intervalId); + } } }, 100); } @@ -52,7 +65,7 @@ class App extends Component<{}, IState> { - ) + ); } } From a06d2df97153cb2df98ac30766e98d8125451f5c Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 01:23:32 +0530 Subject: [PATCH 3/5] Update DataManipulator.ts --- src/DataManipulator.ts | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/DataManipulator.ts b/src/DataManipulator.ts index 7f622955cc..77798b89ae 100644 --- a/src/DataManipulator.ts +++ b/src/DataManipulator.ts @@ -1,20 +1,34 @@ import { ServerRespond } from './DataStreamer'; export interface Row { - stock: string, - top_ask_price: number, + price_abc: number, + price_def: number, + ratio: number, + upper_bound: number, + lower_bound: number, + trigger_alert: number | undefined, timestamp: Date, } - export class DataManipulator { - static generateRow(serverResponds: ServerRespond[]) { - return serverResponds.map((el: any) => { + static generateRow(serverResponds: ServerRespond[]): Row[] { + // Generate an array of rows + return serverResponds.map((serverRespond) => { + const priceABC = (serverRespond.top_ask.price + serverRespond.top_bid.price) / 2; + const priceDEF = (serverRespond.top_ask.price + serverRespond.top_bid.price) / 2; + const ratio = priceABC / priceDEF; + const upperBound = 1 + 0.05; + const lowerBound = 1 - 0.05; + return { - stock: el.stock, - top_ask_price: el.top_ask && el.top_ask.price || 0, - timestamp: el.timestamp, + price_abc: priceABC, + price_def: priceDEF, + ratio, + timestamp: serverRespond.timestamp, + upper_bound: upperBound, + lower_bound: lowerBound, + trigger_alert: (ratio > upperBound || ratio < lowerBound) ? ratio : undefined, }; - }) + }); } } From f5a2d5526250da2ef492ad9fb9c74bb6af21e98c Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 01:23:58 +0530 Subject: [PATCH 4/5] Update DataStreamer.ts --- src/DataStreamer.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/DataStreamer.ts b/src/DataStreamer.ts index 9d9eca7897..805185de6c 100644 --- a/src/DataStreamer.ts +++ b/src/DataStreamer.ts @@ -2,6 +2,7 @@ export interface Order { price: number, size: number, } + export interface ServerRespond { stock: string, top_bid: Order, @@ -12,20 +13,20 @@ export interface ServerRespond { class DataStreamer { static API_URL: string = 'http://localhost:8080/query?id=1'; - static getData(callback: (data: ServerRespond[]) => void): void { - const request = new XMLHttpRequest(); - request.open('GET', DataStreamer.API_URL, false); - - request.onload = () => { - if (request.status === 200) { - callback(JSON.parse(request.responseText)); + static async getData(callback: (data: ServerRespond[]) => void): Promise { + try { + const response = await fetch(DataStreamer.API_URL); + + if (response.ok) { + const data = await response.json(); + callback(data); } else { - alert ('Request failed'); + console.error(`Request failed with status ${response.status}`); } + } catch (error) { + console.error('Error fetching data:', error); } - - request.send(); } } -export default DataStreamer; \ No newline at end of file +export default DataStreamer; From bda4c85bf3b2e8067fae9e818eb2cd51c6114d01 Mon Sep 17 00:00:00 2001 From: Tunir Wabhitkar Date: Thu, 29 Aug 2024 01:24:14 +0530 Subject: [PATCH 5/5] Update Graph.tsx --- src/Graph.tsx | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/Graph.tsx b/src/Graph.tsx index 277797d933..e010a86b36 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'; @@ -11,6 +11,7 @@ interface IProps { interface PerspectiveViewerElement extends HTMLElement { load: (table: Table) => void, } + class Graph extends Component { table: Table | undefined; @@ -23,26 +24,32 @@ 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', + 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()) { + if (window.perspective) { this.table = window.perspective.worker().table(schema); } + 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('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', + upper_bound: 'avg', + lower_bound: 'avg', + trigger_alert: 'avg', timestamp: 'distinct count', })); } @@ -50,9 +57,8 @@ class Graph extends Component { componentDidUpdate() { if (this.table) { - this.table.update( - DataManipulator.generateRow(this.props.data), - ); + // Update the table with new data + this.table.update(DataManipulator.generateRow(this.props.data) as unknown as TableData); } } }