Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
713 lines (568 sloc) 19.6 KB
<!--
Copyright 2019 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
{% block body %}
<script src="https://code.jquery.com/jquery-3.1.1.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" rel="stylesheet" type="text/css" />
<script>
/**
* HashMap - HashMap Class for JavaScript
* @author Ariel Flesler <aflesler@gmail.com>
* @version 2.0.6
* Homepage: https://github.com/flesler/hashmap
*/
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else if (typeof module === 'object') {
// Node js environment
var HashMap = module.exports = factory();
// Keep it backwards compatible
HashMap.HashMap = HashMap;
} else {
// Browser globals (this is window)
this.HashMap = factory();
}
}(function() {
function HashMap(other) {
this.clear();
switch (arguments.length) {
case 0: break;
case 1: {
if ('length' in other) {
// Flatten 2D array to alternating key-value array
multi(this, Array.prototype.concat.apply([], other));
} else { // Assumed to be a HashMap instance
this.copy(other);
}
break;
}
default: multi(this, arguments); break;
}
}
var proto = HashMap.prototype = {
constructor:HashMap,
get:function(key) {
var data = this._data[this.hash(key)];
return data && data[1];
},
set:function(key, value) {
// Store original key as well (for iteration)
var hash = this.hash(key);
if ( !(hash in this._data) ) {
this.size++;
}
this._data[hash] = [key, value];
},
multi:function() {
multi(this, arguments);
},
copy:function(other) {
for (var hash in other._data) {
if ( !(hash in this._data) ) {
this.size++;
}
this._data[hash] = other._data[hash];
}
},
has:function(key) {
return this.hash(key) in this._data;
},
search:function(value) {
for (var key in this._data) {
if (this._data[key][1] === value) {
return this._data[key][0];
}
}
return null;
},
delete:function(key) {
var hash = this.hash(key);
if ( hash in this._data ) {
this.size--;
delete this._data[hash];
}
},
type:function(key) {
var str = Object.prototype.toString.call(key);
var type = str.slice(8, -1).toLowerCase();
// Some browsers yield DOMWindow or Window for null and undefined, works fine on Node
if (!key && (type === 'domwindow' || type === 'window')) {
return key + '';
}
return type;
},
keys:function() {
var keys = [];
this.forEach(function(_, key) { keys.push(key); });
return keys;
},
values:function() {
var values = [];
this.forEach(function(value) { values.push(value); });
return values;
},
entries:function() {
var entries = [];
this.forEach(function(value, key) { entries.push([key, value]); });
return entries;
},
// TODO: This is deprecated and will be deleted in a future version
count:function() {
return this.size;
},
clear:function() {
// TODO: Would Object.create(null) make any difference
this._data = {};
this.size = 0;
},
clone:function() {
return new HashMap(this);
},
hash:function(key) {
switch (this.type(key)) {
case 'undefined':
case 'null':
case 'boolean':
case 'number':
case 'regexp':
return key + '';
case 'date':
return '♣' + key.getTime();
case 'string':
return '♠' + key;
case 'array':
var hashes = [];
for (var i = 0; i < key.length; i++) {
hashes[i] = this.hash(key[i]);
}
return '♥' + hashes.join('⁞');
default:
// TODO: Don't use expandos when Object.defineProperty is not available?
if (!key.hasOwnProperty('_hmuid_')) {
key._hmuid_ = ++HashMap.uid;
hide(key, '_hmuid_');
}
return '♦' + key._hmuid_;
}
},
forEach:function(func, ctx) {
for (var key in this._data) {
var data = this._data[key];
func.call(ctx || this, data[1], data[0]);
}
}
};
HashMap.uid = 0;
//- Add chaining to all methods that don't return something
['set','multi','copy','delete','clear','forEach'].forEach(function(method) {
var fn = proto[method];
proto[method] = function() {
fn.apply(this, arguments);
return this;
};
});
//- Backwards compatibility
// TODO: remove() is deprecated and will be deleted in a future version
HashMap.prototype.remove = HashMap.prototype.delete;
//- Utils
function multi(map, args) {
for (var i = 0; i < args.length; i += 2) {
map.set(args[i], args[i+1]);
}
}
function hide(obj, prop) {
// Make non iterable if supported
if (Object.defineProperty) {
Object.defineProperty(obj, prop, {enumerable:false});
}
}
return HashMap;
}));
</script>
<p>
<label for="strategy">Graph options:</label>
<select id="strategy" name="strategy" class=" dropdown">
<option value="continuous" >Continuous (CPU intensive)</option>
<option value="discrete" >Discrete</option>
<option value="static" selected >Static</option>
</select>
</p>
<div style="display: none">
<div class="">
<table class="ui celled padded table">
<thead>
<tr><th class="single line">Predictor pair </th>
<th>Exchange</th>
<th>Predictor accuracy</th>
<th>Exchange -> BigTable latency avg. 5 mins</th>
<th>BigTable query latency avg. 5 mins</th>
<th>Graph update rate</th>
<th>Graph interval (sec)</th>
<th><a class="ui image label">
<img src="https://semantic-ui.com/images/avatar/small/steve.jpg">
DeLeo
</a>Second AI prediction </th>
<th><a class="ui image label">
<img src="https://semantic-ui.com/images/avatar/small/elliot.jpg">
Mike
</a>Minute AI prediction</th>
<th><a class="ui image label">
<img src="https://semantic-ui.com/images/avatar/small/helen.jpg">
Harish
</a>Hour AI prediction</th>
</tr></thead>
<tbody>
<tr>
<td>
<h2 class="ui center aligned header">BTC/USD</h2>
</td>
<td class="single line">
BitFinex
</td>
<td>
<div class="ui star rating" data-rating="3" data-max-rating="5"></div>
</td>
<td class="right aligned">
451 ms
</td>
<td class="right aligned">
10 ms
</td>
<td class="right aligned">
500 ms
</td>
<td class="right aligned">
300 s
</td>
<td>
+0.1%
<td>
+0.1%
</td>
<td>
-3.1%
</td>
</tr>
<tr>
<td>
<h2 class="ui center aligned header">BTC/USD</h2>
</td>
<td class="single line">
BitStamp
</td>
<td>
<div class="ui star rating" data-rating="4" data-max-rating="5"></div>
</td>
<td class="right aligned">
140 ms
</td>
<td class="right aligned">
10 ms
</td>
<td class="right aligned">
500 ms
</td>
<td class="right aligned">
300 s
</td>
<td>
-0.2%
<td>
+0.3%
</td>
<td>
-2.1%
</td>
</tr>
</tbody>
<tfoot>
<tr>
</tr></tfoot>
</table>
</div>
</div>
<span>
<div id="visualization"></div>
<div id="visualization2"></div>
<div id="visualization3"></div>
</span>
<script type='text/javascript'>//<![CDATA[
var DELAY = 500; // delay in ms to add new data points
var strategy = document.getElementById('strategy');
// create a graph2d with an (currently empty) dataset
var container = document.getElementById('visualization');
var container2 = document.getElementById('visualization2');
var container3 = document.getElementById('visualization3');
var dataset = new vis.DataSet();
var dataset2 = new vis.DataSet();
var dataset3 = new vis.DataSet();
var timeWindowSec = -300;
var dataHashMap = new HashMap();
var TTL = 7 * 1000; /* Time to keep the data in our sytem 3 sec */
var lock = false;
var familyname = "market";
var options = {
start: vis.moment().add(timeWindowSec, 'seconds'), // changed so its faster
end: vis.moment(),
dataAxis: {
left: {
}
},
drawPoints: {
style: 'circle' // square, circle
},
shaded: {
orientation: 'bottom' // top, bottom
},
legend:true,
height: '30%'
};
var options2 = {
style:'bar',
stack:true,
barChart: { align:'left'}, // align: left, center, right
drawPoints: false,
dataAxis: {
icons:false,
},
orientation:'top',
start: vis.moment().add(timeWindowSec, 'seconds'), // changed so its faster
end: vis.moment(),
height: '30%'
};
var options3 = {
style:'points',
stack:false,
barChart: { align:'left'}, // align: left, center, right
drawPoints: false,
dataAxis: {
icons:false,
},
orientation:'top',
start: vis.moment().add(timeWindowSec, 'seconds'), // changed so its faster
end: vis.moment(),
height: '30%'
};
var graph2d = new vis.Graph2d(container, dataset, options);
var graph2d2 = new vis.Graph2d(container2, dataset2, options2);
var graph2d3 = new vis.Graph2d(container3, dataset3, options3);
function renderStep() {
// move the window (you can think of different strategies).
var now = vis.moment();
var range = graph2d.getWindow();
var interval = range.end - range.start;
switch (strategy.value) {
case 'continuous':
// continuously move the window
graph2d.setWindow(now - interval, now, {animation: false});
requestAnimationFrame(renderStep);
break;
case 'discrete':
graph2d.setWindow(now - interval, now, {animation: false});
setTimeout(renderStep, DELAY);
break;
default: // 'static'
// move the window 90% to the left when now is larger than the end of the window
if (now > range.end) {
graph2d.setWindow(now - 0.1 * interval, now + 0.9 * interval);
}
setTimeout(renderStep, DELAY);
break;
}
}
renderStep();
function renderStep2() {
// move the window (you can think of different strategies).
var now = vis.moment();
var range = graph2d2.getWindow();
var interval = range.end - range.start;
switch (strategy.value) {
case 'continuous':
// continuously move the window
graph2d2.setWindow(now - interval, now, {animation: false});
requestAnimationFrame(renderStep2);
break;
case 'discrete':
graph2d2.setWindow(now - interval, now, {animation: false});
setTimeout(renderStep2, DELAY);
break;
default: // 'static'
// move the window 90% to the left when now is larger than the end of the window
if (now > range.end) {
graph2d2.setWindow(now - 0.1 * interval, now + 0.9 * interval);
}
setTimeout(renderStep2, DELAY);
break;
}
}
renderStep2();
function renderStep3() {
// move the window (you can think of different strategies).
var now = vis.moment();
var range = graph2d3.getWindow();
var interval = range.end - range.start;
switch (strategy.value) {
case 'continuous':
// continuously move the window
graph2d3.setWindow(now - interval, now, {animation: false});
requestAnimationFrame(renderStep3);
break;
case 'discrete':
graph2d3.setWindow(now - interval, now, {animation: false});
setTimeout(renderStep3, DELAY);
break;
default: // 'static'
// move the window 90% to the left when now is larger than the end of the window
if (now > range.end) {
graph2d3.setWindow(now - 0.1 * interval, now + 0.9 * interval);
}
setTimeout(renderStep3, DELAY);
break;
}
}
renderStep3();
/**
* Add a new datapoint to the graph
*/
function addDataPoint() {
// add a new data point to the dataset
var now = vis.moment();
var da;
try {
da = fetchData();
}
catch(err) {
console.log(err);
setTimeout(addDataPoint, DELAY/2);
return;
}
// console.log(startTime);
// console.log(endTime);
for (x in da['da'][0][familyname]['exchangeTime']) {
//if(da['da'][0][familyname]['orderType'][x] == "ASK") continue; // if you like only one channel
// check if does not exists
//if(typeof dataHashMap.get(da['da'][0][familyname]['key'][x]) != "undefined" ){ continue; }
if(dataHashMap.has(da['da'][0][familyname]['key'][x])){ continue; }
// object does not exist
dataHashMap.set(da['da'][0][familyname]['key'][x], new Date(parseInt(da['da'][0][familyname]['exchangeTime'][x])));
//console.log("it does not exist , adding " + da['da'][0][familyname]['key'][x])
var time11 = parseInt(da['da'][0][familyname]['exchangeTime'][x])
var tradeDate = vis.moment(time11);
dataset.add({
x: tradeDate,
y:parseFloat(da['da'][0][familyname]['price'][x]),
group: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
label: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
});
// graph asks volume negative
var voli = parseFloat(da['da'][0][familyname]['volume'][x]);
if(da['da'][0][familyname]['orderType'][x] == "ASK"){
if(voli>0) voli = voli * -1;
}
dataset2.add({
x: tradeDate,
y:voli,
group: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
label: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
});
dataset3.add({
x: tradeDate,
y:parseFloat(da['da'][0][familyname]['delta'][x]),
group: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
label: da['da'][0][familyname]['market'][x] + " - " + da['da'][0][familyname]['orderType'][x] ,
});
}
// remove all data points which are no longer visible
var range = graph2d.getWindow();
var interval = range.end - range.start;
var oldIds = dataset.getIds({
filter: function (item) {
return item.x < range.start - interval;
}
});
dataset.remove(oldIds);
var range2 = graph2d2.getWindow();
var interval = range2.end - range2.start;
var oldIds2 = dataset2.getIds({
filter: function (item) {
return item.x < range2.start - interval;
}
});
dataset2.remove(oldIds2);
var range3 = graph2d3.getWindow();
var interval = range3.end - range3.start;
var oldIds3 = dataset3.getIds({
filter: function (item) {
return item.x < range3.start - interval;
}
});
dataset3.remove(oldIds3);
dataHashMap.forEach(function(value, key) {
if(((new Date) - value) > TTL){ // remove if entries are older then TTL seconds
//console.log("deleting " + item);
dataHashMap.delete(key);
}
});
// garbage collector
/* for (let item of dataHashMap) {
if(((new Date) - item[1]) > TTL){ // remove if entries are older then TTL seconds
//console.log("deleting " + item);
dataHashMap.delete(item[0]);
}
// expected output: Array ["0", "foo"]
// expected output: Array [1, "bar"]
}*/
/*console.log("oldids:" + oldIds3);
console.log("interval:" + interval);
console.log("range3.start:" + range3.start);
console.log("range3.end:" + range3.end);
*/
setTimeout(addDataPoint, DELAY);
}
addDataPoint();
function fetchData(){
var jsonData = $.ajax({
url: "/getStreamingData",
dataType: "json",
async: false
}).responseText;
da = JSON.parse(JSON.parse(jsonData));
data_timestamp = da[0][familyname]['exchangeTime'][0];
data_pure = da[0][familyname]['delta'];
data_price = da[0][familyname]['price'];
data_volume = da[0][familyname]['volume'];
var arro = {};
for (x in data_pure) {
if(da[0][familyname]['market'][x] in arro) arro[da[0][familyname]['market'][x]]++
else arro[da[0][familyname]['market'][x]] = 1
}
exchangeNumber = 1;
orderMarkets = {};
Object.keys(arro).forEach(function(key) {
//data.addColumn('number', key);
//data.addColumn('number', key);
orderMarkets[key] = exchangeNumber;
exchangeNumber++;
});
reObject = {};
reObject['da'] = da;
reObject['orderMarkets'] = orderMarkets;
return reObject;
}
</script>
{% endblock %}
You can’t perform that action at this time.