AG-420 Improve React implementation
This commit is contained in:
18
package.json
18
package.json
@@ -6,7 +6,9 @@
|
||||
"scripts": {
|
||||
"full-width": "webpack-dev-server --config webpack.config.full-width.js --progress --colors --hot --inline",
|
||||
"standard": "webpack-dev-server --config webpack.config.standard.js --progress --colors --hot --inline",
|
||||
"hoc": "webpack-dev-server --config webpack.config.hoc.js --progress --colors --hot --inline",
|
||||
"grouped": "webpack-dev-server --config webpack.config.grouped.js --progress --colors --hot --inline",
|
||||
"trader": "webpack-dev-server --content-base src-trader-dashboard/ --config webpack.config.trader.js --progress --colors --hot --inline",
|
||||
"large": "webpack-dev-server --config webpack.config.large.js --progress --colors --hot --inline",
|
||||
"clean": "rimraf dist",
|
||||
"build-standard": "npm run clean && webpack --config webpack.config.standard.js --progress --profile --bail"
|
||||
@@ -28,23 +30,25 @@
|
||||
},
|
||||
"homepage": "http://www.ag-grid.com/",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.0.0",
|
||||
"babel-loader": "6.2.1",
|
||||
"babel-preset-es2015": "6.3.13",
|
||||
"babel-preset-react": "6.3.13",
|
||||
"babel-core": "^6.0.0",
|
||||
"babel-preset-stage-1": "^6.24.1",
|
||||
"css-loader": "0.23.1",
|
||||
"style-loader": "0.13.0",
|
||||
"webpack": "1.12.11",
|
||||
"webpack-dev-server": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"rimraf": "2.5.x",
|
||||
"react": "0.14.6",
|
||||
"react-dom": "0.14.6",
|
||||
"ag-grid": "9.1.x",
|
||||
"ag-grid-api": "file:../ag-grid-api",
|
||||
"ag-grid-enterprise": "9.1.x",
|
||||
"ag-grid-react": "9.1.x"
|
||||
"ag-grid-react": "9.1.x",
|
||||
"d3": "^4.9.1",
|
||||
"lodash": "^4.17.4",
|
||||
"react": "15.5.x",
|
||||
"react-dom": "15.5.x",
|
||||
"rimraf": "2.5.x"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import MyApp from './myApp.jsx';
|
||||
// is there a better way of doing this?
|
||||
|
||||
import 'ag-grid-root/dist/styles/ag-grid.css';
|
||||
import 'ag-grid-root/dist/styles/theme-fresh.css';
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@ import ColDefFactory from "./ColDefFactory.jsx";
|
||||
import MyReactDateComponent from "./MyReactDateComponent.jsx";
|
||||
import MyReactHeaderComponent from "./MyReactHeaderComponent.jsx";
|
||||
import "./myApp.css";
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
export default class MyApp extends React.Component {
|
||||
|
||||
@@ -40,20 +39,24 @@ export default class MyApp extends React.Component {
|
||||
// what you want!
|
||||
this.gridOptions = {
|
||||
//We register the react date component that ag-grid will use to render
|
||||
dateComponentFramework:MyReactDateComponent,
|
||||
dateComponentFramework: MyReactDateComponent,
|
||||
// this is how you listen for events using gridOptions
|
||||
onModelUpdated: function () {
|
||||
console.log('event onModelUpdated received');
|
||||
},
|
||||
defaultColDef : {
|
||||
headerComponentFramework : MyReactHeaderComponent,
|
||||
headerComponentParams : {
|
||||
defaultColDef: {
|
||||
headerComponentFramework: MyReactHeaderComponent,
|
||||
headerComponentParams: {
|
||||
menuIcon: 'fa-bars'
|
||||
}
|
||||
},
|
||||
// this is a simple property
|
||||
rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.onRowSelected = this.onRowSelected.bind(this);
|
||||
this.onCellClicked = this.onCellClicked.bind(this);
|
||||
}
|
||||
|
||||
onShowGrid(show) {
|
||||
@@ -108,7 +111,7 @@ export default class MyApp extends React.Component {
|
||||
componentInstance.helloFromSkillsFilter();
|
||||
}
|
||||
|
||||
dobFilter () {
|
||||
dobFilter() {
|
||||
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
||||
dateFilterComponent.setFilterType('equals');
|
||||
dateFilterComponent.setDateFrom('2000-01-01');
|
||||
@@ -181,9 +184,9 @@ export default class MyApp extends React.Component {
|
||||
gridOptions={this.gridOptions}
|
||||
|
||||
// listening for events
|
||||
onGridReady={this.onGridReady.bind(this)}
|
||||
onRowSelected={this.onRowSelected.bind(this)}
|
||||
onCellClicked={this.onCellClicked.bind(this)}
|
||||
onGridReady={this.onGridReady}
|
||||
onRowSelected={this.onRowSelected}
|
||||
onCellClicked={this.onCellClicked}
|
||||
|
||||
// binding to simple properties
|
||||
showToolPanel={this.state.showToolPanel}
|
||||
|
||||
28
src-trader-dashboard/components/ControlPanel.jsx
Normal file
28
src-trader-dashboard/components/ControlPanel.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onExchangeChanged = this.onExchangeChanged.bind(this);
|
||||
}
|
||||
|
||||
onExchangeChanged(event) {
|
||||
this.props.onExchangeChanged(event.target.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span style={{marginRight: 15}}>Control Panel</span>
|
||||
<select value={this.props.selectedExchange.symbol} onChange={this.onExchangeChanged}>
|
||||
{
|
||||
this.props.exchanges.map((exchange) => {
|
||||
return <option key={exchange.symbol} value={exchange.symbol}>{exchange.name}</option>
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
159
src-trader-dashboard/components/LiveUpdatesGrid.jsx
Normal file
159
src-trader-dashboard/components/LiveUpdatesGrid.jsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import React, {Component} from "react";
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
import map from "lodash/map";
|
||||
import difference from "lodash/difference";
|
||||
import forEach from "lodash/forEach";
|
||||
import includes from "lodash/includes";
|
||||
import assign from "lodash/assign";
|
||||
|
||||
import ExchangeService from "../services/ExchangeService.jsx";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
columnDefs: [
|
||||
{
|
||||
field: 'symbol',
|
||||
headerName: 'Symbol',
|
||||
sort: 'asc'
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
headerName: 'Price',
|
||||
cellFormatter: this.numberFormatter,
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellStyle: {'text-align': 'right'}
|
||||
},
|
||||
{
|
||||
field: 'bid',
|
||||
headerName: 'Bid',
|
||||
cellFormatter: this.numberFormatter,
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellStyle: {'text-align': 'right'}
|
||||
},
|
||||
{
|
||||
field: 'ask',
|
||||
headerName: 'Ask',
|
||||
cellFormatter: this.numberFormatter,
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellStyle: {'text-align': 'right'}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.exchangeService = new ExchangeService();
|
||||
|
||||
// grid events
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
|
||||
// component events
|
||||
this.updateQuote = this.updateQuote.bind(this);
|
||||
}
|
||||
|
||||
numberFormatter(params) {
|
||||
if (typeof params.value === 'number') {
|
||||
return params.value.toFixed(2);
|
||||
} else {
|
||||
return params.value;
|
||||
}
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.addItems(map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol)));
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.props.selectedExchange.supportedStocks.forEach(symbol => {
|
||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.exchangeService.removeSubscribers();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.selectedExchange.supportedStocks !== this.props.selectedExchange.supportedStocks) {
|
||||
if (!this.gridApi) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentSymbols = this.props.selectedExchange.supportedStocks;
|
||||
const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
||||
|
||||
// Unsubscribe to current ones that will be removed
|
||||
const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
||||
forEach(symbolsRemoved, symbol => {
|
||||
this.exchangeService.removeSubscriber(this.updateQuote, symbol);
|
||||
});
|
||||
|
||||
// Subscribe to new ones that need to be added
|
||||
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
||||
forEach(symbolsAdded, symbol => {
|
||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
||||
});
|
||||
|
||||
// Remove ag-grid nodes as necessary
|
||||
const nodesToRemove = [];
|
||||
this.gridApi.forEachNode(node => {
|
||||
const {data} = node;
|
||||
if (includes(symbolsRemoved, data.symbol)) {
|
||||
nodesToRemove.push(node);
|
||||
}
|
||||
});
|
||||
this.gridApi.removeItems(nodesToRemove);
|
||||
|
||||
// Insert new ag-grid nodes as necessary
|
||||
this.gridApi.addItems(map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol)));
|
||||
}
|
||||
}
|
||||
|
||||
updateQuote(quote) {
|
||||
if (!this.gridApi) {
|
||||
// the grid isn't ready yet
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedNodes = [];
|
||||
const updatedCols = [];
|
||||
|
||||
this.gridApi.forEachNode(node => {
|
||||
const {data} = node;
|
||||
if (data.symbol === quote.symbol) {
|
||||
for (const def of this.state.columnDefs) {
|
||||
if (data[def.field] !== quote[def.field]) {
|
||||
updatedCols.push(def.field);
|
||||
}
|
||||
}
|
||||
assign(data, quote);
|
||||
updatedNodes.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
this.gridApi.refreshCells(updatedNodes, updatedCols);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 800}}
|
||||
className="ag-fresh">
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
enableSorting="true"
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
23
src-trader-dashboard/components/StockDetailPanel.jsx
Normal file
23
src-trader-dashboard/components/StockDetailPanel.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import StockPriceDeltaPanel from "./StockPriceDeltaPanel.jsx";
|
||||
import StockTimestampPanel from "./StockTimestampPanel.jsx";
|
||||
import StockSummaryPanel from "./StockSummaryPanel.jsx";
|
||||
import StockHistoricalChartPanel from "./StockHistoricalChartPanel.jsx";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<StockPriceDeltaPanel />
|
||||
<StockTimestampPanel />
|
||||
<StockSummaryPanel />
|
||||
<StockHistoricalChartPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
3014
src-trader-dashboard/components/StockHistoricalChartPanel.jsx
Normal file
3014
src-trader-dashboard/components/StockHistoricalChartPanel.jsx
Normal file
File diff suppressed because it is too large
Load Diff
23
src-trader-dashboard/components/StockPanel.jsx
Normal file
23
src-trader-dashboard/components/StockPanel.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import LiveUpdatesGrid from "./LiveUpdatesGrid.jsx";
|
||||
import StockDetailPanel from "./StockDetailPanel.jsx";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div style={{float: "left", marginRight: 25}}>
|
||||
<LiveUpdatesGrid selectedExchange={this.props.selectedExchange}></LiveUpdatesGrid>
|
||||
</div>
|
||||
<div style={{float: "left"}}>
|
||||
<StockDetailPanel></StockDetailPanel>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
49
src-trader-dashboard/components/StockPriceDeltaPanel.jsx
Normal file
49
src-trader-dashboard/components/StockPriceDeltaPanel.jsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let containerStyle = {
|
||||
display: "inline-block"
|
||||
};
|
||||
|
||||
let priceStyle = {
|
||||
fontSize: "2.6em",
|
||||
fontWeight: "bold",
|
||||
marginRight: 10
|
||||
};
|
||||
|
||||
let deltaStyle = {
|
||||
fontWeight: "normal",
|
||||
fontSize: "1.8em",
|
||||
verticalAlign: "bottom"
|
||||
};
|
||||
|
||||
let negativeSwingStyle = {
|
||||
color: "#d14836",
|
||||
marginRight: 5
|
||||
};
|
||||
|
||||
let positiveSwingStyle = {
|
||||
color: "#093",
|
||||
marginRight: 5
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span style={priceStyle}>
|
||||
155.47
|
||||
</span>
|
||||
<div style={containerStyle}>
|
||||
<span style={deltaStyle}>
|
||||
<span style={negativeSwingStyle}>-0.23</span>
|
||||
<span style={negativeSwingStyle}>(-0.15%)</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
94
src-trader-dashboard/components/StockSummaryPanel.jsx
Normal file
94
src-trader-dashboard/components/StockSummaryPanel.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let containerStyle = {
|
||||
fontSize: 13
|
||||
};
|
||||
|
||||
let tableStyle = {
|
||||
display: "inline-block",
|
||||
verticalAlign: "top",
|
||||
borderCollapse:"collapse"
|
||||
|
||||
};
|
||||
|
||||
let keyStyle = {
|
||||
color: "#666"
|
||||
};
|
||||
|
||||
let valueStyle = {
|
||||
textAlign: "right"
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={containerStyle}>
|
||||
<table style={tableStyle}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={keyStyle}>Range
|
||||
</td>
|
||||
<td style={valueStyle}>154.72 - 156.06
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>52 week
|
||||
</td>
|
||||
<td style={valueStyle}>91.50 - 156.65
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>Open
|
||||
</td>
|
||||
<td style={valueStyle}>155.94
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>
|
||||
Vol / Avg.
|
||||
</td>
|
||||
<td style={valueStyle}>15,931.00/24.94M
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table style={tableStyle}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={keyStyle}>
|
||||
Div/yield
|
||||
</td>
|
||||
<td style={valueStyle}>0.63/1.62
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>
|
||||
EPS
|
||||
</td>
|
||||
<td style={valueStyle}>8.55
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>
|
||||
Shares
|
||||
</td>
|
||||
<td style={valueStyle}>5,213.84M
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={keyStyle}>
|
||||
Mkt cap
|
||||
</td>
|
||||
<td style={valueStyle}>808,518.60M
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
46
src-trader-dashboard/components/StockTimestampPanel.jsx
Normal file
46
src-trader-dashboard/components/StockTimestampPanel.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let containerStyle = {
|
||||
display: "inline-block"
|
||||
};
|
||||
|
||||
let priceStyle = {
|
||||
fontSize: "2.6em",
|
||||
fontWeight: "bold",
|
||||
marginRight: 10
|
||||
};
|
||||
|
||||
let minorStyle = {
|
||||
fontSize: 11,
|
||||
color: "#6F6F6F"
|
||||
};
|
||||
|
||||
let negativeSwingStyle = {
|
||||
color: "#d14836",
|
||||
marginRight: 5
|
||||
};
|
||||
|
||||
let positiveSwingStyle = {
|
||||
color: "#093",
|
||||
marginRight: 5
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id="ref_304466804484872_elt">
|
||||
May 17, 6:17am GMT-4
|
||||
<div style={minorStyle}>
|
||||
<span>NASDAQ</span>
|
||||
<div>Currency in USD</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
43
src-trader-dashboard/components/TraderDashboard.jsx
Normal file
43
src-trader-dashboard/components/TraderDashboard.jsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import ExchangeService from "../services/ExchangeService.jsx";
|
||||
|
||||
import ControlPanel from "./ControlPanel.jsx";
|
||||
import StockPanel from "./StockPanel.jsx";
|
||||
|
||||
|
||||
export default class TraderDashboard extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.exchangeService = new ExchangeService();
|
||||
|
||||
this.state = {
|
||||
selectedExchange: this.exchangeService.getExchangeInformation("NASDAQ"),
|
||||
exchanges: this.exchangeService.getExchanges()
|
||||
};
|
||||
|
||||
this.onExchangeChanged = this.onExchangeChanged.bind(this);
|
||||
}
|
||||
|
||||
onExchangeChanged(selectedExchange) {
|
||||
this.setState({
|
||||
selectedExchange: this.exchangeService.getExchangeInformation(selectedExchange)
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div style={{marginTop: 25, marginBottom: 25}}>
|
||||
<ControlPanel
|
||||
exchanges={this.state.exchanges}
|
||||
selectedExchange={this.state.selectedExchange}
|
||||
onExchangeChanged={this.onExchangeChanged}>
|
||||
</ControlPanel>
|
||||
</div>
|
||||
<StockPanel selectedExchange={this.state.selectedExchange}></StockPanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
18
src-trader-dashboard/index.html
Normal file
18
src-trader-dashboard/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="dist/bundle.js" charset="utf-8"></script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="traderDashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
18
src-trader-dashboard/index.js
Normal file
18
src-trader-dashboard/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
import ReactDOM from "react-dom";
|
||||
import React from "react";
|
||||
|
||||
import TraderDashboard from "./components/TraderDashboard.jsx";
|
||||
|
||||
import "ag-grid-root/dist/styles/ag-grid.css";
|
||||
import "ag-grid-root/dist/styles/theme-fresh.css";
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
ReactDOM.render(
|
||||
React.createElement(TraderDashboard),
|
||||
document.querySelector('#traderDashboard')
|
||||
);
|
||||
});
|
||||
|
||||
234
src-trader-dashboard/services/ExchangeService.jsx
Normal file
234
src-trader-dashboard/services/ExchangeService.jsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import concat from "lodash/concat";
|
||||
import remove from "lodash/remove";
|
||||
import uniq from "lodash/uniq";
|
||||
import find from "lodash/find";
|
||||
import sampleSize from "lodash/sampleSize";
|
||||
import keys from "lodash/keys";
|
||||
|
||||
export default class {
|
||||
constructor() {
|
||||
this.subscribers = {};
|
||||
|
||||
this.exchanges = [
|
||||
{name: 'Nasdaq Stock Market', symbol: 'NASDAQ', supportedStocks: NASDAQ_SYMBOLS},
|
||||
{name: 'London Stock Exchange', symbol: 'LSE', supportedStocks: LSE_SYMBOLS},
|
||||
{name: 'Japan Exchange Group', symbol: 'JSE', supportedStocks: JSE_SYMBOLS},
|
||||
{name: 'Deutsche Börse', symbol: 'DE', supportedStocks: DE_SYMBOLS}
|
||||
];
|
||||
|
||||
this.initialiseTickerData();
|
||||
}
|
||||
|
||||
initialiseTickerData() {
|
||||
this.tickerData = {};
|
||||
|
||||
const allSymbols = uniq(concat(NASDAQ_SYMBOLS, LSE_SYMBOLS, JSE_SYMBOLS, DE_SYMBOLS));
|
||||
allSymbols.forEach((symbol) => {
|
||||
this.tickerData[symbol] = this.generateTickerRow(symbol);
|
||||
});
|
||||
}
|
||||
|
||||
generateTickerRow(symbol) {
|
||||
let price = this.random(10, 600);
|
||||
return {
|
||||
symbol,
|
||||
price,
|
||||
bid: price - this.random(1, 3),
|
||||
ask: price + this.random(1, 3)
|
||||
}
|
||||
}
|
||||
|
||||
random(min, max) {
|
||||
return parseFloat((Math.random() * (max - min + 1) + min))
|
||||
}
|
||||
|
||||
addSubscriber(subscriber, symbol) {
|
||||
if (!this.subscribers[symbol]) {
|
||||
this.subscribers[symbol] = [];
|
||||
}
|
||||
this.subscribers[symbol].push(subscriber);
|
||||
|
||||
if (!this.updateInterval) {
|
||||
this.updateInterval = setInterval(this.applyDeltasToTickerData.bind(this), 500);
|
||||
}
|
||||
}
|
||||
|
||||
applyDeltasToTickerData() {
|
||||
let symbols = keys(this.subscribers);
|
||||
let properties = ['price', 'bid', 'ask'];
|
||||
|
||||
let symbolsToAlter = sampleSize(symbols, symbols.length / 4);
|
||||
let propertyToAlter = sampleSize(properties, 1);
|
||||
|
||||
symbolsToAlter.forEach((symbol) => {
|
||||
this.tickerData[symbol] = {
|
||||
symbol,
|
||||
price: this.tickerData[symbol].price,
|
||||
bid: this.tickerData[symbol].bid,
|
||||
ask: this.tickerData[symbol].ask,
|
||||
};
|
||||
|
||||
this.tickerData[symbol][propertyToAlter] = +this.tickerData[symbol][propertyToAlter] + this.random(-2, 2);
|
||||
});
|
||||
|
||||
symbols.forEach((symbol) => {
|
||||
this.subscribers[symbol].forEach((subscriber) => {
|
||||
subscriber(this.tickerData[symbol]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeSubscriber(subscriber, symbol) {
|
||||
remove(this.subscribers[symbol], subscriber);
|
||||
}
|
||||
|
||||
getTicker(symbol) {
|
||||
return this.tickerData[symbol];
|
||||
}
|
||||
|
||||
getExchanges() {
|
||||
return this.exchanges;
|
||||
}
|
||||
|
||||
getExchangeInformation(exchangeName) {
|
||||
return find(this.exchanges, (exchange) => {
|
||||
return exchange.symbol === exchangeName;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const NASDAQ_SYMBOLS = [
|
||||
"SNCL.L",
|
||||
"RNK.L",
|
||||
"SWJ.L",
|
||||
"JDT.L",
|
||||
"UANC.L",
|
||||
"SDP.L",
|
||||
"HSBA.L",
|
||||
"XPL.L",
|
||||
"KLR.L",
|
||||
"SSE.L",
|
||||
"JSI.L",
|
||||
"UBMN.L",
|
||||
"WPC.L",
|
||||
"VTC.L",
|
||||
"UTG.L",
|
||||
"DOR.L",
|
||||
"44RS.L",
|
||||
"GPOR.L",
|
||||
"ASL.L",
|
||||
"40JP.L",
|
||||
"133716",
|
||||
"PJF.L",
|
||||
"MLC.L",
|
||||
"137817",
|
||||
"GHE.L",
|
||||
"PML.L",
|
||||
"SBRY.L",
|
||||
"LEN.L",
|
||||
"STS.L",
|
||||
"138654",
|
||||
"PTEC.L"
|
||||
];
|
||||
|
||||
const LSE_SYMBOLS = [
|
||||
"PVG.L",
|
||||
"SN.L,",
|
||||
"SWJ.L",
|
||||
"JDT.L",
|
||||
"UANC.L",
|
||||
"SDP.L",
|
||||
"HSBA.L",
|
||||
"XPL.L",
|
||||
"KLR.L",
|
||||
"SSE.L",
|
||||
"JSI.L",
|
||||
"UBMN.L",
|
||||
"DLN.L",
|
||||
"SIR.L",
|
||||
"SEC.L",
|
||||
"DOR.L",
|
||||
"44RS.L",
|
||||
"GPOR.L",
|
||||
"ASL.L",
|
||||
"40JP.L",
|
||||
"133716",
|
||||
"PJF.L",
|
||||
"MLC.L",
|
||||
"137817",
|
||||
"GHE.L",
|
||||
"PML.L",
|
||||
"SBRY.L",
|
||||
"LEN.L",
|
||||
"MAV4.L",
|
||||
"GLEN.L",
|
||||
"EDGD.L",
|
||||
];
|
||||
|
||||
const JSE_SYMBOLS = [
|
||||
"ECV.L",
|
||||
"MHN.L",
|
||||
"SWJ.L",
|
||||
"JDT.L",
|
||||
"UANC.L",
|
||||
"PLAZ.L",
|
||||
"CLDN.L",
|
||||
"XPL.L",
|
||||
"KLR.L",
|
||||
"SSE.L",
|
||||
"JSI.L",
|
||||
"UBMN.L",
|
||||
"WPC.L",
|
||||
"VTC.L",
|
||||
"UTG.L",
|
||||
"DOR.L",
|
||||
"44RS.L",
|
||||
"GPOR.L",
|
||||
"ASL.L",
|
||||
"40JP.L",
|
||||
"133716",
|
||||
"CRW.L",
|
||||
"JPR.L",
|
||||
"UTLC.L",
|
||||
"GHS.L",
|
||||
"PML.L",
|
||||
"SBRY.L",
|
||||
"LEN.L",
|
||||
"STS.L",
|
||||
"138654",
|
||||
"RWS.L"
|
||||
];
|
||||
|
||||
const DE_SYMBOLS = [
|
||||
"ECV.L",
|
||||
"MHN.L",
|
||||
"SWJ.L",
|
||||
"JDT.L",
|
||||
"UANC.L",
|
||||
"SDP.L",
|
||||
"KBC.L",
|
||||
"VM.L,",
|
||||
"KLR.L",
|
||||
"SSE.L",
|
||||
"JSI.L",
|
||||
"UBMN.L",
|
||||
"WPC.L",
|
||||
"VTC.L",
|
||||
"UTG.L",
|
||||
"DOR.L",
|
||||
"44RS.L",
|
||||
"GPOR.L",
|
||||
"ASL.L",
|
||||
"40JP.L",
|
||||
"133716",
|
||||
"PJF.L",
|
||||
"MLC.L",
|
||||
"DPV6.L",
|
||||
"LMIN.L",
|
||||
"PML.L",
|
||||
"SBRY.L",
|
||||
"LEN.L",
|
||||
"STS.L",
|
||||
"BKIR.L",
|
||||
"AFMF.L",
|
||||
];
|
||||
33
webpack.config.trader.js
Normal file
33
webpack.config.trader.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
|
||||
const SRC_DIR = path.resolve(__dirname, 'src-trader-dashboard');
|
||||
|
||||
module.exports = {
|
||||
entry: SRC_DIR + "/index.js",
|
||||
output: {
|
||||
path: __dirname,
|
||||
filename: "dist/bundle.js"
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: "style!css"
|
||||
},
|
||||
{
|
||||
test: /\.js$|\.jsx$/,
|
||||
include: SRC_DIR,
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: ['react', 'es2015']
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"ag-grid-root" : __dirname + "/node_modules/ag-grid"
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user