Problem calculating RSI from the Binance node API - javascript

I have written a program in javascript (Node) that is supposed to calculate the RSI using the Binance api.
The only thing is that my program does not calculate the "real" RSI. For example, if i set my period to be 14 days, as the formula says - I get an RSI value equal to ~28 and the real RSI being 38.
If i change the period and set it to 20, i get an RSI pretty close to the real one, with mine being 39 and the real one being 38.
I can't figure it out.what am i doing wrong. Any suggestion?
Here is my code :
const binance = require('node-binance-api')().options({
APIKEY: 'xxx',
APISECRET: 'xxx',
useServerTime: true,
test: true // True = SandboxMode
});
/* VARIABLES */
let listClose = [];
let changeUp = 0;
let changeDown = 0;
let last_closeHigh = 0;
let last_closeLow = 0;
let current_time = Date.now();
let period = 20;
function calculateRSI() {
console.log("Generating RSI");
binance.candlesticks("ETHBTC", "1d", (error, ticks, symbol) => {
for (i = 0; i < ticks.length; i++) {
let last_tick = ticks[i];
let [time, open, high, low, close, volume, closeTime, assetVolume, trades, buyBaseVolume, buyAssetVolume, ignored] = last_tick;
listClose.push(close);
if (i == ticks.length -1 ) {
for (x = 0; x < ticks.length; x++) {
previous_close = (parseFloat(listClose[x-1]));
current_close = (parseFloat(listClose[x]));
// HIGH
if (current_close > previous_close) {
upChange = current_close - previous_close;
changeUp += upChange;
if (x == ticks.length -1) {
last_closeHigh = current_close - previous_close;
}
}
// LOW
if (previous_close > current_close) {
downChange = previous_close - current_close;
changeDown += downChange;
if (x == ticks.length - 1) {
last_closeLow = previous_close - current_close;
}
}
if (x == ticks.length-1) {
AVGHigh = changeUp / period;
AVGLow = changeDown / period;
Upavg = (AVGHigh * (period -1) + last_closeHigh) / (period);
Downavg = (AVGLow * (period -1) + last_closeLow) / (period);
RS = Upavg / Downavg;
RSI = (100 - (100 / (1 + RS)));
console.log(RSI);
return RSI;
}
}
}
}
}, {
limit: period,
endTime: current_time
});
}
calculateRSI();

Sorry for jumping on this late...but the reason for this is using the Sandbox.
Binance Sandbox is awful and should never be used, it gives bad values.

Related

Randomising arrays to form an highly entropic grid

I am attempting to make a 5x5 grid using arrays with the following limitations
Should not exceed more than 4 check marks per grid
Should not have 2 consecutive check marks
This is what I have come up with so far, I would appreciate if someone could help me figure out how would I achieve the latter condition
let emoji = {
0: '✅',
1: '❓',
}
let grid = []
let checkmarks = 0
for (let i = 0; i < 5; i++) {
let row = []
for (let j = 0; j < 5; j++) {
let random = crypto.randomInt(0, 1000) % 2
if (random == 0) {
if(checkmarks < 4) {
row.push(emoji[0])
checkmarks++
}
else {
row.push(emoji[1])
}
} else {
row.push(emoji[1])
}
}
grid.push(row)
}
I am attempting to make it as random as possible.
I'm posting this answer because the accepted answer doesn't seem to produce a consistent result. I agree with most of the approach, but result just wasn't always returning 4 checkmarks (because it seems to reset after each iteration, which can increase the maximum number of loops needed).
But ultimately, the idea is to fill the 5x5 array with the ❓ character first, randomly select a location, verify the surrounding blocks are not ✅, and then place a ✅ if these conditions are met. If not, I instead just select a new position but keep the existing results until the needed number of ✅ have been set.
let grid = [],
rows = 5,
cols = 5,
maxChecks = 4,
totalChecks = 0,
emoji = {
0: '✅',
1: '❓',
};
const _RandomChecks = () => {
grid = [];
totalChecks = 0;
for(let i = 0; i < rows; i++) {
grid[i] = [];
for(let j = 0; j < cols; j++) {
grid[i] = [...grid[i], emoji[1]];
}
}
while(totalChecks < maxChecks) {
let rndRow = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % rows,
rndCol = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % cols,
valid = (grid[rndRow][rndCol] == emoji[1]) ? true : false;
if(grid[rndRow-1]?.[rndCol] && valid) valid = (grid[rndRow-1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow+1]?.[rndCol] && valid) valid = (grid[rndRow+1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol-1] && valid) valid = (grid[rndRow][rndCol-1] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol+1] && valid) valid = (grid[rndRow][rndCol+1] == emoji[1]) ? true : false;
if(valid) {
grid[rndRow][rndCol] = emoji[0];
totalChecks++;
}
}
console.log(grid.map(row => row.join('')).join('\n'));
}
_RandomChecks();
Instead of randomly determining if a cell should be a checkmark I would rather randomly find cells that should be a checkmark.
Your current solution decreases the chance of getting a checkmark with each cell.
Created some example code for you:
const emojis = ['✅', '❓']
const size = 5
const checkmarks = []
for (let i = 0; i < 4; i += 1) {
while (true) {
// get random x and y
const x = Math.random() * size | 0
const y = Math.random() * size | 0
// check if x and y are far enough from existing checkmarks
const areNeighbours = checkmarks.some(c => {
if (c.x === x) {
return Math.abs(c.y - y) <= 1
}
if (c.y === y) {
return Math.abs(c.x - x) <= 1
}
return false
})
if (!areNeighbours) {
checkmarks.push({
x,
y
})
break
}
}
}
const grid = []
for (let y = 0; y < size; y += 1) {
grid.push([])
for (let x = 0; x < size; x += 1) {
const checkmark = checkmarks.find(c => c.x === x && c.y === y)
grid[y][x] = checkmark ? emojis[0] : emojis[1]
}
}
console.log(grid.map(row => row.join('')).join('\n'))
Imagine a 5x5 board initially filled by ❓.
Next you toss 4 coins at once, each coin will landed in one cell, head or tail.
If head, place a ✅ in the cell.
Now check if non-consecutive ✅ condition is met. If not start over.
Solution:
const emojis = ['✅', '❓'];
function randomInt(min, max) {
return min + Math.floor(Math.random() * (max - min));
}
function tossCoins(checkmarkLimit, size) {
const positions = Array.from({ length: checkmarkLimit }, () => {
const pos = randomInt(0, size * size);
const tail = Math.random() > 0.5;
if (tail) return null;
const x = pos % 5;
const y = (pos - x) / 5;
return [x, y];
})
return positions.filter(Boolean);
}
function checkNonConsecutive(positions) {
for (let i = 0; i < positions.length; i++) {
const p = positions[i];
for (let j = 0; j < positions.length; j++) {
if (i == j) continue;
const o = positions[j];
const distance = Math.abs(p[0] - o[0]) + Math.abs(p[1] - o[1])
if (distance <= 1) {
return false;
}
}
}
return true;
}
function main() {
const checkmarkLimit = 4;
const size = 5;
const grid = Array.from({ length: size }, () => Array.from({ length: size }, () => emojis[1]));
let positions = tossCoins(checkmarkLimit, size);
while (!checkNonConsecutive(positions)) {
positions = tossCoins(checkmarkLimit, size);
}
positions.forEach(([x, y]) => {
grid[y][x] = emojis[0];
});
return grid;
}
for (let n=0; n < 10; n++) {
console.log('round: ' + n);
console.log(main().map(row => row.join('')).join('\n'));
}

Problems trying to compare two negative numbers

I have this function below, i am trying to compare negative numbers, I'm using unix time so the time difference is negative because the date has already passed, but I still want to use it, when the within5Days variable is a negative four(-4) the within5DaysBoolean variable is not set to false, it is still being set to true, I don't know what I'm missing here, any help
function timeDifference2(next, now) {
var sPerMinute = 60;
var sPerHour = sPerMinute * 60;
var sPerDay = sPerHour * 24;
var sPerMonth = sPerDay * 30;
var sPerYear = sPerDay * 365;
var sPerTwoDays = sPerDay * 2;
var elapsed = next - now;
return Math.floor(elapsed / 3600);
}
var within5Days = timeDifference2(unixTime, currentUnixTime);
if (within5Days < 120 && within5Days > -2) {
var within5DaysValue = within5Days;
var within5DaysBoolean = true;
} else if (within5Days > 120 || within5Days < -2) {
var within5DaysValue = within5Days;
var within5DaysBoolean = false;
}
you may try as follows using parseFloat
if((parseFloat(within5Days) < 120 && parseFloat(within5Days) > -2)) {
var within5DaysValue = within5Days;
var within5DaysBoolean = true;
} else if ((parseFloat(within5Days) > 120) || parseFloat(within5Days) < -2)) {
var within5DaysValue = within5Days;
var within5DaysBoolean = false;
}

Memory issues in recursion

I'm trying to solve this leetcode problem here: https://leetcode.com/problems/next-closest-time/description/.
Simply my solution is to try every combination that is valid and then set my ans variable to the one that is closest to the original time. It does print out all the combinations however the diff variable never changes. In the for loop after (if cur.length ==4) it prints every possible combination because it still thinks that diff is 9007199254740991. Also when I assign ans to cur.slice(), I receive a blank array. Even when I uncomment it in the nextClosestTime function I still have the same issue.
/**
* #param {string} time
* #return {string}
*/
var diff = 9007199254740991;
function calcSeconds(digits) {
var hours = (digits[0] * 10) + digits[1];
var seconds = (digits[2] * 10) + digits[3];
return (hours * 3600) + (seconds * 60);
}
function nextClosestTime(time) {
var digits = [];
// diff = 9007199254740991;
var cur = [];
var ans = [];
for (var i = 0; i < time.length; i++) {
if (isFinite(time.charAt(i))) {
digits.push(parseInt(time.charAt(i)));
}
}
var target = calcSeconds(digits);
nch(digits, cur, diff, target, ans);
return ans;
};
function nch(digits, cur, diff, target, ans) {
if (cur.length == 4) {
var curSec = calcSeconds(cur);
if (Math.abs(curSec - target) < diff) {
console.log(cur);
diff = Math.abs(calcSeconds(digits) - calcSeconds(cur));
//ans = cur.slice();
}
return;
}
for (var i = 0; i < digits.length; i++) {
if ((((cur[0] * 10) + cur[1]) >= 24) || (((cur[2] * 10) + cur[3]) >= 60)) {
return;
}
cur.push(digits[i]);
nch(digits, cur, diff, target, ans);
cur.pop()
}
}

Creating svg paths with javascript(shape morphing)

So I have this class which is used for shape morphing:
class ShapeOverlays {
constructor(elm) {
this.elm = elm;
this.path = elm.querySelectorAll('path');
this.numPoints = 18;
this.duration = 600;
this.delayPointsArray = [];
this.delayPointsMax = 300;
this.delayPerPath = 100;
this.timeStart = Date.now();
this.isOpened = false;
this.isAnimating = false;
}
toggle() {
this.isAnimating = true;
const range = 4 * Math.random() + 6;
for (var i = 0; i < this.numPoints; i++) {
const radian = i / (this.numPoints - 1) * Math.PI;
this.delayPointsArray[i] = (Math.sin(-radian) + Math.sin(-radian * range) + 2) / 4 * this.delayPointsMax;
}
if (this.isOpened === false) {
this.open();
} else {
this.close();
}
}
open() {
this.isOpened = true;
this.elm.classList.add('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
close() {
this.isOpened = false;
this.elm.classList.remove('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
updatePath(time) {
const points = [];
for (var i = 0; i < this.numPoints + 1; i++) {
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
}
let str = '';
str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `;
for (var i = 0; i < this.numPoints - 1; i++) {
const p = (i + 1) / (this.numPoints - 1) * 100;
const cp = p - (1 / (this.numPoints - 1) * 100) / 2;
str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `;
}
str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`;
return str;
}
render() {
if (this.isOpened) {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)));
}
} else {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1))));
}
}
}
renderLoop() {
this.render();
if (Date.now() - this.timeStart < this.duration + this.delayPerPath * (this.path.length - 1) + this.delayPointsMax) {
requestAnimationFrame(() => {
this.renderLoop();
});
}
else {
this.isAnimating = false;
}
}
}
(function() {
const elmHamburger = document.querySelector('.hamburger');
const gNavItems = document.querySelectorAll('.global-menu__item');
const elmOverlay = document.querySelector('.shape-overlays');
const overlay = new ShapeOverlays(elmOverlay);
elmHamburger.addEventListener('click', () => {
if (overlay.isAnimating) {
return false;
}
overlay.toggle();
if (overlay.isOpened === true) {
elmHamburger.classList.add('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.add('is-opened');
}
} else {
elmHamburger.classList.remove('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.remove('is-opened');
}
}
});
}());
Can some one please explain this code? I don't really get how the paths are created using time,how the points are placed and how could I modify it.What is range used for? Why are trigonometral functions used for the delayPointsArray?
Basically it's this part that I don't get:
updatePath(time) {
const points = [];
for (var i = 0; i < this.numPoints + 1; i++) {
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
}
let str = '';
str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `;
for (var i = 0; i < this.numPoints - 1; i++) {
const p = (i + 1) / (this.numPoints - 1) * 100;
const cp = p - (1 / (this.numPoints - 1) * 100) / 2;
str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `;
}
str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`;
return str;
}
render() {
if (this.isOpened) {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)));
}
} else {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1))));
}
}
}
Why is time being used? What is the purpose of this:
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
If you look at how updatePath() is being called, it's like this:
this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i))
So the time value passed in is the difference between the current time, and the start time of the path we are working with.
So what then is the line of code you are interested in, doing?
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
I'm going to ignore delayPointsArray. It is modifying the start time slightly based on angle. Without seeing the full demo, I'm not sure of the reason for that.
The purpose of this line of code is to calculate how far through the current path's animation we are. The result is in the form of a coordinate value from 0 to 100.
It's doing a lot in that one line of code. So let's break down the individual steps.
Firstly, we are clamping the elapsed time to minimum of 0.
Math.max(time, 0)
In other words, anything before the animation start time becomes zero.
Then we divide by the animation's duration.
Math.max(time, 0) / duration
This will result in a value from 0, representing the start of the animation, to 1, representing the end of the animation. However, the value might also be greater than 1 if the elapsed time is after the end of the animation. Hence the next step.
Now clamp this value to a maximum of 1.
Math.min( Math.max(time, 0) / duration, 1)
We now have a value >= 0 and <= 1 whichdescribes where in the course of the animation, the path is supposed to be. 0 if we should be at the animations start position. 1 if we should be at the animations end position. And somewhere in between if the animation is in progress.
However this value is strictly linear, corresponding with the progression of time. And usually linear movement is not what you want. It is unnatural. Objects accelarate when the start moving and decelerate when the come to a stop. That will be what the easeInOut() function will be doing. If you are not familiar with easing curves, take a look at the diagram below.
Source: Google: The Basics of Easing
So we pass in a linear time value from 0..1 (horizontal axis). It will return a modified value that takes into account acceleration and deceleration.
The final step is to multiply by 100, to convert to a final coordinate value (0..100).
Hope this helps.

Calculate the nearest value on a circular variable

I have an problem where i have 3 times of the 24 hour day. To keep it simple i can use the decimal representation:
a) 23:45 (23.75)
b) 11:30 (11.50)
c) 00:15 (00.25)
I'd like to know , for each time, which other time is closest.
var closestTime = 24
var closestActualTime = 0;
for (var i = 0; i < times.length; i++) {
if (times[i].time == this.time) continue;
var temp = Math.abs(this.time - times[i].time)
if (temp < closestTime) {
closestTime = temp;
closestActualTime = times[i].time;
}
}
My issue is that 23:45 and 00:25 are actually really close but i don't know how process a variable with a modulo type
I suggest to build a list with the pairs and then calculate the difference.
The difference is the third element in the pairs array.
Basically you need to check the delta and if it greater than 12 hours, take the difference from 24 and delta.
delta = Math.abs(aa - bb);
if (delta > 12) {
delta = 24 - delta;
}
function combination(array, size) {
function c(part, start) {
var i, l, p;
for (i = start, l = array.length + part.length + 1 - size; i < l; i++) {
p = part.slice();
p.push(array[i]);
p.length < size ? c(p, i + 1) : result.push(p);
}
}
var result = [];
c([], 0);
return result;
}
function timeDelta(a, b) {
function decimalTime(s) {
var p = s.split(':');
return +p[0] + p[1] / 60;
}
function padZero(v) {
return (v < 10) ? '0' + v : String(v);
}
var aa = decimalTime(a),
bb = decimalTime(b),
delta = Math.abs(aa - bb);
if (delta > 12) {
delta = 24 - delta;
}
return padZero(Math.floor(delta)) + ':' + padZero(Math.round(60 * (delta - Math.floor(delta))));
}
var times = ['23:45', '11:30', '00:15'],
pairs = combination(times, 2);
pairs.forEach(function (a, i, aa) {
aa[i][2] = timeDelta(a[0], a[1]);
});
console.log(pairs);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop over times.
Try combinations of delta time, offset by 24 hours.
Pick smallest delta time.
var times = [23.75, 11.50, 3, 6, 7];
/**
* timeClosestTo
*
* #param {number} time
* #returns {number}
*/
function timeClosestTo(time) {
//Distance variable to compare against
var distance = 100;
//Hours in a day
var day = 24;
//Current best
var best = null;
//Test against all times
for (var i = 0; i < times.length; i++) {
//Find best score based upon day
var d = Math.min(Math.abs((times[i]) - (time)), Math.abs((times[i] + day) - time), Math.abs((times[i]) - (time + day)), Math.abs((times[i] + day) - (time + day)));
//If best found distance yet, set best to current
if (d < distance) {
best = times[i];
distance = d;
}
}
//Return best
return best;
}
console.log("times to deal with:",times.join(", "));
console.log("closest to 1:", timeClosestTo(1), "closest to 11:", timeClosestTo(11), "closest to 5:", timeClosestTo(5));
Quite functionally i would do this job as follows
var times = [23.75,11.50,0.25],
diffs = times.reduce((d,t1,i,a) => a[i+1] ? d.concat(a.slice(i+1)
.map(t2 => [t1,t2,[Math.min(Math.abs(t1-t2),24-Math.abs(t1-t2))]
.map(n => ~~n + ":" + (n%1)*60)[0]]))
: d,[]);
console.log(diffs);

Categories

Resources