-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
.App { | ||
text-align: center; | ||
min-height: 100vh; | ||
} | ||
|
||
.App-logo { | ||
animation: App-logo-spin infinite 20s linear; | ||
height: 40vmin; | ||
} | ||
|
||
.App-header { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
font-size: calc(10px + 2vmin); | ||
margin-bottom: 12px; | ||
} | ||
|
||
.App-link { | ||
color: #61dafb; | ||
} | ||
|
||
.App-content { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
margin-bottom: 12px; | ||
} | ||
|
||
.Stream-button { | ||
margin-bottom: 12px; | ||
} | ||
|
||
.Graph { | ||
min-height: 50vh; | ||
width: 700px; | ||
margin-bottom: 12px; | ||
} | ||
|
||
@keyframes App-logo-spin { | ||
from { | ||
transform: rotate(0deg); | ||
} | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import App from './App'; | ||
|
||
it('renders without crashing', () => { | ||
const div = document.createElement('div'); | ||
ReactDOM.render(<App />, div); | ||
ReactDOM.unmountComponentAtNode(div); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React, { Component } from 'react'; | ||
import DataStreamer, { ServerRespond } from './DataStreamer'; | ||
import Graph from './Graph'; | ||
import './App.css'; | ||
|
||
interface IState { | ||
data: ServerRespond[], | ||
showGraph: boolean, | ||
} | ||
|
||
class App extends Component<{}, IState> { | ||
constructor(props: {}) { | ||
super(props); | ||
this.state = { | ||
data: [], | ||
showGraph: false, | ||
}; | ||
} | ||
|
||
renderGraph() { | ||
if (this.state.showGraph) { | ||
return (<Graph data={this.state.data}/>) | ||
} | ||
} | ||
|
||
getDataFromServer() { | ||
let x = 0; | ||
const interval = setInterval(() => { | ||
DataStreamer.getData((serverResponds: ServerRespond[]) => { | ||
this.setState({ | ||
data: serverResponds, | ||
showGraph: true, | ||
}); | ||
}); | ||
x++; | ||
if (x > 1000) { | ||
clearInterval(interval); | ||
} | ||
}, 100); | ||
} | ||
|
||
render() { | ||
return ( | ||
<div className="App"> | ||
<header className="App-header"> | ||
Bank Merge & Co Task 3 | ||
</header> | ||
<div className="App-content"> | ||
<button className="btn btn-primary Stream-button" onClick={() => {this.getDataFromServer()}}>Start Streaming Data</button> | ||
<div className="Graph"> | ||
{this.renderGraph()} | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { ServerRespond } from './DataStreamer'; | ||
|
||
export interface Row { | ||
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[]): Row { | ||
const priceABC = (serverResponds[0].top_ask.price + serverResponds[0].top_bid.price)/2; | ||
const priceDEF = (serverResponds[1].top_ask.price + serverResponds[1].top_bid.price)/2; | ||
const ratio = priceABC / priceDEF; | ||
const upper_bound = 1 + 0.01; | ||
const lower_bound = 1 - 0.01; | ||
return { | ||
price_abc: priceABC, | ||
price_def: priceDEF, | ||
ratio, | ||
timestamp: serverResponds[0].timestamp > serverResponds[1].timestamp ? | ||
serverResponds[0].timestamp : serverResponds[1].timestamp, | ||
upper_bound: upper_bound, | ||
lower_bound: lower_bound, | ||
trigger_alert: (ratio > upper_bound || ratio < lower_bound ) ? ratio : undefined, | ||
|
||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
export interface Order { | ||
price: number, | ||
size: number, | ||
} | ||
export interface ServerRespond { | ||
stock: string, | ||
top_bid: Order, | ||
top_ask: Order, | ||
timestamp: Date, | ||
} | ||
|
||
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)); | ||
} else { | ||
alert ('Request failed'); | ||
} | ||
} | ||
|
||
request.send(); | ||
} | ||
} | ||
|
||
export default DataStreamer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
perspective-viewer { | ||
height: 50vh; | ||
width: 700px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React, { Component } from 'react'; | ||
import { Table } from '@jpmorganchase/perspective'; | ||
import { ServerRespond } from './DataStreamer'; | ||
import { DataManipulator } from './DataManipulator'; | ||
import './Graph.css'; | ||
|
||
interface IProps { | ||
data: ServerRespond[], | ||
} | ||
|
||
interface PerspectiveViewerElement extends HTMLElement { | ||
load: (table: Table) => void, | ||
} | ||
class Graph extends Component<IProps, {}> { | ||
table: Table | undefined; | ||
|
||
render() { | ||
return React.createElement('perspective-viewer'); | ||
} | ||
|
||
componentDidMount() { | ||
// Get element from the DOM. | ||
const elem = document.getElementsByTagName('perspective-viewer')[0] as unknown as PerspectiveViewerElement; | ||
|
||
const schema = { | ||
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()) { | ||
this.table = window.perspective.worker().table(schema); | ||
} | ||
if (this.table) { | ||
// Load the `table` in the `<perspective-viewer>` DOM reference. | ||
elem.load(this.table); | ||
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', | ||
timestamp: 'distinct count', | ||
upper_bound: 'avg', | ||
lower_bound: 'avg', | ||
trigger_alert: 'avg', | ||
})); | ||
} | ||
} | ||
|
||
componentDidUpdate() { | ||
if (this.table) { | ||
this.table.update([ | ||
DataManipulator.generateRow(this.props.data), | ||
]); | ||
} | ||
} | ||
} | ||
|
||
export default Graph; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
body { | ||
margin: 0; | ||
padding: 0; | ||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", | ||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", | ||
sans-serif; | ||
-webkit-font-smoothing: antialiased; | ||
-moz-osx-font-smoothing: grayscale; | ||
} | ||
|
||
code { | ||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", | ||
monospace; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import App from './App'; | ||
import './index.css'; | ||
import 'bootstrap/dist/css/bootstrap.css'; | ||
|
||
declare global { | ||
interface Window { perspective: any; } | ||
} | ||
|
||
ReactDOM.render(<App />, document.getElementById('root')); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/// <reference types="react-scripts" /> |