Costumize indicators from stock tools - javascript

I'm trying to implement some technical indicators series and add them to the indicators popop from stock tools. If I import highcharts/indicators/indicators-all I end up getting dozens of indicators, so I figured to import only the ones I need, so far I wasn't able to achieve that, if I import highcharts/indicators/indicators I end up getting only SMA, I tried to import other technical indicators via highcharts/indicators/indicators-INDICATOR-NAME but it didn't work.
Besides that I'd like to create a technical indicator/function such as Linear Regression (from this example) and attach them to the indicators popup as well.
function getLinearRegression(xData, yData) {
var sumX = 0,
sumY = 0,
sumXY = 0,
sumX2 = 0,
linearData = [],
linearXData = [],
linearYData = [],
n = xData.length,
alpha,
beta,
i,
x,
y;
// Get sums:
for (i = 0; i < n; i++) {
x = xData[i];
y = yData[i];
sumX += x;
sumY += y;
sumXY += x * y;
sumX2 += x * x;
}
// Get slope and offset:
alpha = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
if (isNaN(alpha)) {
alpha = 0;
}
beta = (sumY - alpha * sumX) / n;
// Calculate linear regression:
for (i = 0; i < n; i++) {
x = xData[i];
y = alpha * x + beta;
// Prepare arrays required for getValues() method
linearData[i] = [x, y];
linearXData[i] = x;
linearYData[i] = y;
}
return {
xData: linearXData,
yData: linearYData,
values: linearData
};
}
Is that even possible?
Live Demo
EDIT
To add a specific technical indicator you should add as an import highcharts/indicators/NAME (highcharts/indicators/ema,
highcharts/indicators/rsi e.g.)

That feature is not implemented in stock tools, but it could be very useful so you can create a new feature request here: https://github.com/highcharts/highcharts/issues/new/choose
Workaround:
All indicator series from plot options are added to stock tools, so you can customize chart.options.plotOptions, for example in load event:
chart: {
events: {
load: function() {
var plotOptions = this.options.plotOptions,
filteredSeries = {};
Highcharts.objectEach(plotOptions, function(option, key) {
if (!option.params || key === 'dema' || key === 'customlinearregression') {
filteredSeries[key] = option;
}
});
this.options.plotOptions = filteredSeries;
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/xwec9hr7/2/
Useful example: https://www.highcharts.com/stock/demo/stock-tools-custom-gui
Code reference: https://github.com/highcharts/highcharts/blob/371424be0b168de96aa6a58b81ce0b2b7f40d5c5/ts/annotations/popup.ts#L783

Related

NVD3 Toggle Streams

Does anyone know how to disable a stream after drawing?
I'm looking to modify the active streams after the page has loaded, and the user has clicked on a button in a different part of the page.
I've been working on code to simulate a click event after it determines it's state, but that seems kind of clunky and slow.
EDIT:
As requested, here's an example of an NVD3 chart with multiple streams (data series found in the legend).
After chart render, I am looking for a function that can enable / disable multiple streams (data 0, data 1, etc. on the example) in a single call.
I was working on something that dispatches click events to the labels, but thought there must be a better way.
<div id="chart">
<svg></svg>
</div>
var data = function() {
return stream_layers(4,10+Math.random()*10,.1).map(function(data, i) {
return {
key: 'Data ' + i,
values: data
};
});
}
function stream_layers(n, m, o) {
if (arguments.length < 3) o = 0;
function bump(a) {
var x = 1 / (.1 + Math.random()),
y = 2 * Math.random() - .5,
z = 10 / (.1 + Math.random());
for (var i = 0; i < m; i++) {
var w = (i / m - y) * z;
a[i] += x * Math.exp(-w * w);
}
}
return d3.range(n).map(function () {
var a = [],
i;
for (i = 0; i < m; i++) a[i] = o + o * Math.random();
for (i = 0; i < 5; i++) bump(a);
return a.map(stream_index);
});
}
function stream_index(d, i) {
return {
x: i,
y: Math.max(0, d)
};
}
nv.addGraph(function () {
var chart = nv.models.multiBarChart();
chart.multibar.stacked(false);
chart.showControls(false);
chart.showLegend(true);
chart.reduceXTicks(false);
d3.select('#chart svg')
.datum(data())
.transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
Found my answer..
The following works
chartData[i].disabled = true; // chartData = original data object fed to NVD3 chart
chartData[i].userDisabled = true;
chart.update(); // chart = a reference to your NVD3 chart instance.

why is this not working (js)

can someone tell why this does not work?
the code does print "generating fish" but than not printing enything...
function fish(x, y, degree, genes, Snumber) {
this.x = x;
this.y = y;
this.dgree = degree;
this.energy = 50;
this.genes = genes;
this.Snumber = Snumber;
}
fishs = new Array(10);
Snumber = 0;
document.writeln("generating fish");
for (i = 0; i < 10; i++) {
x = Math.round(Math.random * 600);
y = Math.round(Math.random * 600);
degree = Math.round(Math.random * 360);
genes + new Array(12);
for (j = 0; j < 12; j++) {
genes[j] = Math.random * 2 - 1;
}
fishs[i] = new fish(x, y, degree, genes, Snumber);
Snumber++;
document.writeln("genarating fish num" + i);
}
You have couple of errors and warnings in your code:
1.) You don't user the var keyword, so you automatically put the variables on the global scope.
2.) You use a + operator instead of an = in the line:
genes + new Array(12);
3.) You use Math.random (wich returns the random function, not a random number) instead of the function in 3 places.
4.) You use document.write(ln), which is deprecated. Use console.log instead (which prints to the console, hit F12 to see it)

How to reduce a data graph but keeping the extremes

I have a database that has got a month full of datasets in 10min intervals. (So a dataset for every 10min)
Now I want to show that data on three graphs: last 24 hours, last 7 days and last 30 days.
The data looks like this:
{ "data" : 278, "date" : ISODate("2016-08-31T01:51:05.315Z") }
{ "data" : 627, "date" : ISODate("2016-08-31T01:51:06.361Z") }
{ "data" : 146, "date" : ISODate("2016-08-31T01:51:07.938Z") }
// etc
For the 24h graph I simply output the data for the last 24h, that's easy.
For the other graphs I thin the data:
const data = {}; //data from database
let newData = [];
const interval = 7; //for 7 days the interval is 7, for 30 days it's 30
for( let i = 0; i < data.length; i += interval ) {
newData.push( data[ i ] );
};
This works fine but extreme events where data is 0 or differs greatly from the other values average, can be lost depending on what time you search the data. Not thinning out the data however will result in a large sum of data points that are sent over the pipe and have to be processed on the front end. I'd like to avoid that.
Now to my question
How can I reduce the data for a 7 day period while keeping extremes in it? What's the most efficient way here?
Additions:
In essence I think I'm trying to simplify a graph to reduce points but keep the overall shape. (If you look at it from a pure image perspective)
Something like an implementation of Douglas–Peucker algorithm in node?
As you mention in the comments, the Ramer-Douglas-Peucker (RDP) algorithm is used to process data points in 2D figures but you want to use it for graph data where X values are fixed. I modified this Javascript implementation of the algorithm provided by M Oehm to consider only the vertical (Y) distance in the calculations.
On the other hand, data smoothing is often suggested to reduce the number of data points in a graph (see this post by csgillespie).
In order to compare the two methods, I made a small test program. The Reset button creates new test data. An algorithm can be selected and applied to obtain a reduced number of points, separated by the specified interval. In the case of the RDP algorithm however, the resulting points are not evenly spaced. To get the same number of points as for the specified interval, I run the calculations iteratively, adjusting the espilon value each time until the correct number of points is reached.
From my tests, the RDP algorithm gives much better results. The only downside is that the spacing between points varies. I don't think that this can be avoided, given that we want to keep the extreme points which are not evenly distributed in the original data.
Here is the code snippet, which is better seen in Full Page mode:
var svgns = 'http://www.w3.org/2000/svg';
var graph = document.getElementById('graph1');
var grpRawData = document.getElementById('grpRawData');
var grpCalculatedData = document.getElementById('grpCalculatedData');
var btnReset = document.getElementById('btnReset');
var cmbMethod = document.getElementById('cmbMethod');
var btnAddCalculated = document.getElementById('btnAddCalculated');
var btnClearCalculated = document.getElementById('btnClearCalculated');
var data = [];
var calculatedCount = 0;
var colors = ['black', 'red', 'green', 'blue', 'orange', 'purple'];
var getPeriod = function () {
return parseInt(document.getElementById('txtPeriod').value, 10);
};
var clearGroup = function (grp) {
while (grp.lastChild) {
grp.removeChild(grp.lastChild);
}
};
var showPoints = function (grp, pts, markerSize, color) {
var i, point;
for (i = 0; i < pts.length; i++) {
point = pts[i];
var marker = document.createElementNS(svgns, 'circle');
marker.setAttributeNS(null, 'cx', point.x);
marker.setAttributeNS(null, 'cy', point.y);
marker.setAttributeNS(null, 'r', markerSize);
marker.setAttributeNS(null, 'fill', color);
grp.appendChild(marker);
}
};
// Create and display test data
var showRawData = function () {
var i, x, y;
var r = 0;
data = [];
for (i = 1; i < 500; i++) {
x = i;
r += 15.0 * (Math.random() * Math.random() - 0.25);
y = 150 + 30 * Math.sin(x / 200) * Math.sin((x - 37) / 61) + 2 * Math.sin((x - 7) / 11) + r;
data.push({ x: x, y: y });
}
showPoints(grpRawData, data, 1, '#888');
};
// Gaussian kernel smoother
var createGaussianKernelData = function () {
var i, x, y;
var r = 0;
var result = [];
var period = getPeriod();
for (i = Math.floor(period / 2) ; i < data.length; i += period) {
x = data[i].x;
y = gaussianKernel(i);
result.push({ x: x, y: y });
}
return result;
};
var gaussianKernel = function (index) {
var halfRange = Math.floor(getPeriod() / 2);
var distance, factor;
var totalValue = 0;
var totalFactor = 0;
for (i = index - halfRange; i <= index + halfRange; i++) {
if (0 <= i && i < data.length) {
distance = Math.abs(i - index);
factor = Math.exp(-Math.pow(distance, 2));
totalFactor += factor;
totalValue += data[i].y * factor;
}
}
return totalValue / totalFactor;
};
// Ramer-Douglas-Peucker algorithm
var ramerDouglasPeuckerRecursive = function (pts, first, last, eps) {
if (first >= last - 1) {
return [pts[first]];
}
var slope = (pts[last].y - pts[first].y) / (pts[last].x - pts[first].x);
var x0 = pts[first].x;
var y0 = pts[first].y;
var iMax = first;
var max = -1;
var p, dy;
// Calculate vertical distance
for (var i = first + 1; i < last; i++) {
p = pts[i];
y = y0 + slope * (p.x - x0);
dy = Math.abs(p.y - y);
if (dy > max) {
max = dy;
iMax = i;
}
}
if (max < eps) {
return [pts[first]];
}
var p1 = ramerDouglasPeuckerRecursive(pts, first, iMax, eps);
var p2 = ramerDouglasPeuckerRecursive(pts, iMax, last, eps);
return p1.concat(p2);
}
var internalRamerDouglasPeucker = function (pts, eps) {
var p = ramerDouglasPeuckerRecursive(data, 0, pts.length - 1, eps);
return p.concat([pts[pts.length - 1]]);
}
var createRamerDouglasPeuckerData = function () {
var finalPointCount = Math.round(data.length / getPeriod());
var epsilon = getPeriod();
var pts = internalRamerDouglasPeucker(data, epsilon);
var iteration = 0;
// Iterate until the correct number of points is obtained
while (pts.length != finalPointCount && iteration++ < 20) {
epsilon *= Math.sqrt(pts.length / finalPointCount);
pts = internalRamerDouglasPeucker(data, epsilon);
}
return pts;
};
// Event handlers
btnReset.addEventListener('click', function () {
calculatedCount = 0;
clearGroup(grpRawData);
clearGroup(grpCalculatedData);
showRawData();
});
btnClearCalculated.addEventListener('click', function () {
calculatedCount = 0;
clearGroup(grpCalculatedData);
});
btnAddCalculated.addEventListener('click', function () {
switch (cmbMethod.value) {
case "Gaussian":
showPoints(grpCalculatedData, createGaussianKernelData(), 2, colors[calculatedCount++]);
break;
case "RDP":
showPoints(grpCalculatedData, createRamerDouglasPeuckerData(), 2, colors[calculatedCount++]);
return;
}
});
showRawData();
div
{
margin-bottom: 6px;
}
<div>
<button id="btnReset">Reset</button>
<select id="cmbMethod">
<option value="RDP">Ramer-Douglas-Peucker</option>
<option value="Gaussian">Gaussian kernel</option>
</select>
<label for="txtPeriod">Interval: </label>
<input id="txtPeriod" type="text" style="width: 36px;" value="7" />
</div>
<div>
<button id="btnAddCalculated">Add calculated points</button>
<button id="btnClearCalculated">Clear calculated points</button>
</div>
<svg id="svg1" width="765" height="450" viewBox="0 0 510 300">
<g id="graph1" transform="translate(0,300) scale(1,-1)">
<rect width="500" height="300" stroke="black" fill="#eee"></rect>
<g id="grpRawData"></g>
<g id="grpCalculatedData"></g>
</g>
</svg>

Callstack overflow, works only on small array pairs, how would I make it take 10k array pairs?

I am attempting to do some data processing on the client side but it has proven to be more difficult than I originally thought.
I use a double for loop so it will call the following function 31^2 times and store a table of promises.
var getPearsonsCorrelation = function(x, y){
// var deferred = $q.defer();
//I commented the promise statements out
//so you can copy paste into your own browser to try a small array
var shortestArrayLength = 0;
if(x.length === y.length){shortestArrayLength = x.length;}
else if(x.length > y.length || y.length < x.length){
deferred.reject('array lenghts are not the same size');
}
var xy = [];
var x2 = [];
var y2 = [];
var sumX = 0;
var sumY = 0;
var sumXy = 0;
var sumX2 = 0;
var sumY2 = 0;
var partOneCounter = 0;
var partTwoCounter = 0;
function partThree(sumX, sumY, sumXy, sumX2, sumY2){
var step1 = (shortestArrayLength * sumXy) - (sumX * sumY);
var step2 = (shortestArrayLength * sumX2) - (sumX * sumX);
var step3 = (shortestArrayLength * sumY2) - (sumY * sumY);
var step4 = Math.sqrt(step2 * step3);
var answer = step1 / step4;
console.log(answer);
//deferred.resolve(answer);
}
function partTwo(xy, x2, y2){
if(partTwoCounter>= shortestArrayLength){
partThree(sumX, sumY, sumXy, sumX2, sumY2);
}else{
sumX += x[partTwoCounter];
sumY += y[partTwoCounter];
sumXy += xy[partTwoCounter];
sumX2 += x2[partTwoCounter];
sumY2 += y2[partTwoCounter];
setTimeout(partTwo(xy, x2, y2), 0);
partTwoCounter++;
}
}
function partOne(partTwo){
if(partOneCounter>=shortestArrayLength){
partTwo(xy, x2, y2);
}else{
xy.push(x[partOneCounter] * y[partOneCounter]);
x2.push(x[partOneCounter] * x[partOneCounter]);
y2.push(y[partOneCounter] * y[partOneCounter]);
setTimeout(partOne(partTwo), 0);
partOneCounter++;
}
}
partOne(partTwo);
//return deferred.promise;
};
I got this script from stevegardner, however as it currently is it is blocking javascript.
http://stevegardner.net/2012/06/11/javascript-code-to-calculate-the-pearson-correlation-coefficient/
In my attempt to make it async javascript, I now get callstack overflow errors instead. Is there some work around for this?
Appreciate it!
When you want to use setTimeout do not invoke the function. You should pass a noninvoked function.
calculate function(){
/* --- */
}
setTimeout(calculate(),0) //wrong
setTimeout(calculate,0) //right
//And if you want to pass in params into the setTimeout
setTimeout(function(){
calculate(params)
},0)
#Benjamin Gruenbaum thanks!

Linear Regression in Javascript [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I want to do Least Squares Fitting in Javascript in a web browser.
Currently users enter data point information using HTML text inputs and then I grab that data with jQuery and graph it with Flot.
After the user had entered in their data points I would like to present them with a "line of best fit". I imagine I would calculate the linear, polynomial, exponential and logarithmic equations and then choose the one with the highest R^2 value.
I can't seem to find any libraries that will help me to do this though. I stumbled upon jStat, but it is completely missing documentation (as far as I can find) and after digging through the the source code it doesn't seem to have any linear regression functionality built in--I'm basing this purely on function names however.
Does anyone know any Javascript libraries that offer simple regression analysis?
The hope would be that I could use the library like so...
If I had some set of scatter points in an array var points = [[3,4],[15,45],...[23,78]], I would be able to hand that to some function like lin_reg(points) and it would return something like [7.12,3] if the linear equation was y = 7.12 x + 3.
What kind of linear regression? For something simple like least squares, I'd just program it myself:
http://mathworld.wolfram.com/LeastSquaresFitting.html
The math is not too hard to follow there, give it a shot for an hour or so and let me know if it's too hard, I can try it.
EDIT:
Found someone that did it:
http://dracoblue.net/dev/linear-least-squares-in-javascript/159/
The simplest solution I found for the question at hand can be found in the following post:
http://trentrichardson.com/2010/04/06/compute-linear-regressions-in-javascript/
Note that in addition to the linear equation, it also returns the R2 score, which can be useful.
** EDIT **
Here is the actual code snippet:
function linearRegression(y,x){
var lr = {};
var n = y.length;
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var sum_yy = 0;
for (var i = 0; i < y.length; i++) {
sum_x += x[i];
sum_y += y[i];
sum_xy += (x[i]*y[i]);
sum_xx += (x[i]*x[i]);
sum_yy += (y[i]*y[i]);
}
lr['slope'] = (n * sum_xy - sum_x * sum_y) / (n*sum_xx - sum_x * sum_x);
lr['intercept'] = (sum_y - lr.slope * sum_x)/n;
lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y)/Math.sqrt((n*sum_xx-sum_x*sum_x)*(n*sum_yy-sum_y*sum_y)),2);
return lr;
}
To use this you just need to pass it two arrays, known_y's and known_x's, so this is what you might pass:
var known_y = [1, 2, 3, 4];
var known_x = [5.2, 5.7, 5.0, 4.2];
var lr = linearRegression(known_y, known_x);
// now you have:
// lr.slope
// lr.intercept
// lr.r2
I found this great JavaScript library.
It's very simple, and seems to work perfectly.
I also can't recommend Math.JS enough.
Simple linear regression with measures of variation ( Total sum of squares = Regression sum of squares + Error sum of squares ), Standard error of estimate SEE (Residual standard error), and coefficients of determination R2 and correlation R.
const regress = (x, y) => {
const n = y.length;
let sx = 0;
let sy = 0;
let sxy = 0;
let sxx = 0;
let syy = 0;
for (let i = 0; i < n; i++) {
sx += x[i];
sy += y[i];
sxy += x[i] * y[i];
sxx += x[i] * x[i];
syy += y[i] * y[i];
}
const mx = sx / n;
const my = sy / n;
const yy = n * syy - sy * sy;
const xx = n * sxx - sx * sx;
const xy = n * sxy - sx * sy;
const slope = xy / xx;
const intercept = my - slope * mx;
const r = xy / Math.sqrt(xx * yy);
const r2 = Math.pow(r,2);
let sst = 0;
for (let i = 0; i < n; i++) {
sst += Math.pow((y[i] - my), 2);
}
const sse = sst - r2 * sst;
const see = Math.sqrt(sse / (n - 2));
const ssr = sst - sse;
return {slope, intercept, r, r2, sse, ssr, sst, sy, sx, see};
}
regress([1, 2, 3, 4, 5], [1, 2, 3, 4, 3]);
Check out
https://web.archive.org/web/20150523035452/https://cgwb.nci.nih.gov/cgwbreg.html (javascript regression calculator) - pure JavaScript, not CGI calls to server. The data and processing remains on your computer. Complete R style results and R code to check the work and a visualization of the results.
See the source code for the embedded JavaScript implementations of OLS and statistics associated with the results.
The code is my effort to port the GSL library functions to JavaScript.
The codes is released under GPL because it's basically line for line porting of GPL licensed Gnu Scientific Library (GSL) code.
EDIT: Paul Lutus also provides some GPL code for regression at: http://arachnoid.com/polysolve/index.html
Here is a snippet that will take an array of triplets (x, y, r) where r is the weight of the (x, y) data point and return [a, b] such that Y = a*X + b approximate the data.
// return (a, b) that minimize
// sum_i r_i * (a*x_i+b - y_i)^2
function linear_regression( xyr )
{
var i,
x, y, r,
sumx=0, sumy=0, sumx2=0, sumy2=0, sumxy=0, sumr=0,
a, b;
for(i=0;i<xyr.length;i++)
{
// this is our data pair
x = xyr[i][0]; y = xyr[i][1];
// this is the weight for that pair
// set to 1 (and simplify code accordingly, ie, sumr becomes xy.length) if weighting is not needed
r = xyr[i][2];
// consider checking for NaN in the x, y and r variables here
// (add a continue statement in that case)
sumr += r;
sumx += r*x;
sumx2 += r*(x*x);
sumy += r*y;
sumy2 += r*(y*y);
sumxy += r*(x*y);
}
// note: the denominator is the variance of the random variable X
// the only case when it is 0 is the degenerate case X==constant
b = (sumy*sumx2 - sumx*sumxy)/(sumr*sumx2-sumx*sumx);
a = (sumr*sumxy - sumx*sumy)/(sumr*sumx2-sumx*sumx);
return [a, b];
}
Somewhat based on Nic Mabon's answer.
function linearRegression(x, y)
{
var xs = 0; // sum(x)
var ys = 0; // sum(y)
var xxs = 0; // sum(x*x)
var xys = 0; // sum(x*y)
var yys = 0; // sum(y*y)
var n = 0;
for (; n < x.length && n < y.length; n++)
{
xs += x[n];
ys += y[n];
xxs += x[n] * x[n];
xys += x[n] * y[n];
yys += y[n] * y[n];
}
var div = n * xxs - xs * xs;
var gain = (n * xys - xs * ys) / div;
var offset = (ys * xxs - xs * xys) / div;
var correlation = Math.abs((xys * n - xs * ys) / Math.sqrt((xxs * n - xs * xs) * (yys * n - ys * ys)));
return { gain: gain, offset: offset, correlation: correlation };
}
Then y' = x * gain + offset.

Categories

Resources