I'm building a trading bot and I have this code which takes an array of arrays of 5 (API allows 5 price requests at a time). For each of these currencies, this api does an API call and retrieves results with a promise. In the promise I forEach through each currency returned, calculate the average of the prices and then save it to MongoDB.
Market.prototype.fetchPrices = function(currencyPairs){
var self = this
let currencyPairGroups = chunkBy5(currencyPairs)
_.forEach(currencyPairGroups, function(currencyPairGroup){
wc.price(currencyPairGroup).then(function(res){
let pairs = Object.keys(res);
_.forEach(pairs, function(pair) {
let currentObj = res[pair]
currentObj.pair = pair
currentObj.mid = _.mean([currentObj.bid, currentObj.ask])
console.log('Before saving ' + '\n' +
'this is the pair ' + currentObj.pair + '\n' +
'and this is the bid ' + currentObj.bid + '\n' +
'and this is the ask ' + currentObj.ask + '\n' +
'and this is the mid ' + currentObj.mid + '\n' +
'is the mid a NaN? ' + isNaN(currentObj.mid) + '\n')
savePrice(currentObj)
self.emit('emitPrice', currentObj)
})
})
})
}
Almost always, this works perfectly. Sometimes, however, the currentObj.mid gets passed as NaN and the save validation to Mongoose fails. The console.log looks like this.
this is the pair USD-MXN
and this is the bid 17.90732
and this is the ask 17.91332
and this is the mid NaN
is the mid a NaN? true
I feel like it's an async issue, but I don't think anything in my promise is async. Also, don't know why it works almost every other time. Don't even know what question to ask to figure this out.
Related
I am not entirely sure what to even search to find a solution here, but essentially I have a random text generator that creates a writing prompt from a series of arrays. The behaviour I want to add to it is the ability to "reroll" any of the individual random elements by clicking on them. Here's what the current function looks like that gets returned when the button is clicked.
function art_prompt() {
return (
'<p>' + 'The main character is a ' + get_three_random_words(personality) + ' ' + get_random_word(gender) +
' who ' + get_random_word(frequency) + ' ' + get_random_word(flaws) + ' and ' + get_random_word(frequency) +
' ' + get_random_word(flaws) + '. The character is paired with ' + get_random_word(atmospheres) +
' atmosphere, set ' + get_random_word(places) + ' during ' + get_random_word(time) + '.<br><br>' +
'The scene portrays ' + get_random_word(portrayals) + '.<br><br>' + '<strong>Bonus restriction:</strong> ' +
get_random_word(bonus_restrictions) + '.' + '</p>'
);
}
So essentially, each of the get_random_word(array) functions I want to be a clickable element that generates a new random string from the same array. I have tried something where each one has a button concatenated around it and create a separate function for each array that is being brought in, but I want a more elegant solution if one exists.
Also I realize it's a bit janky of an implementation, but it's all I knew how to do when I started on it.
So I seem to have figured out a working solution. Just wrapped each object in a button, like this:
'<p>' + 'The main character is a ' + '<button onclick="rollPersonality1()" class="reroll personality1">' + personality[rand1] + '</button>, '
Using the buttons is a bit janky but it seemed to do the trick in this instance. I ran into another issue where I was trying to run the onclick function the same way I did for a static button, but it didn't work because the selector outside the function was no good. So the function for the above looks something like this.
var rollPersonality1 = () => {
var PersonalityElement = document.querySelector('.personality1');
PersonalityElement.textContent = randomPersonality();
}
I doubt this will help anybody else, but if it does that's awesome! If anyone has a more elegant way of doing this, I am not super happy with the messiness of what I came up with. So lay it on me!
I am creating a script that would show the keys of my array, in the first attempt worked perfectly, but when I added but a while block, he did not execute and returned this error:
classificacao-v2.js:128 Uncaught TypeError: Cannot read property 'Period' of undefined
at classificacao-v2.js:128
Realizing that my problem was in the variable 'n' that appeared as undefined, so I created other variables with different names for each structure.
I wonder if it is possible to rewrite it more efficiently without having to repeat each block.
let GoldemStates = [{Period: ' 1°',Points:'300'},
{Period: ' 2°',Points:'250'},
{Period: ' 3°', Points:'155'}]
let Chicago = [{Period: ' 1°',Points:'100'},
{Period: ' 2°',Points:'420'},
{Period: ' 3°', Points:'350'}]
let Broklyn = [{Period: ' 1°',Points:'300'},
{Period: ' 2°',Points:'250'},
{Period: ' 3°', Points:'155'}]
// Show the Teams
icons('','Match Results ','div_titulo')
let n = 0
icons('golden','Golden States', 'destaque_golden') //Team Title (Symbol, Team Name, CSS)
//Goldem States Statistics
do {
icons('clock',GoldemStates[n].Period + ' Period | ' + 'Points ' + GoldemStates[n].Points ,'texto') // // Show period and points
n ++
} while (n < GoldemStates.length);
let d = 0 // <-------- CHANGE WHICH WOULD NEED
//Chicago Bulls Statistics
icones('bulls','Chicago Bulls', 'destaque_bulls')//Team Title (Symbol, Team Name, CSS)
do {
icons('clock',Chicago[d].Period + ' Period | ' + 'Points ' + Chicago[d].Points ,'texto')// Show period and points
d ++
} while (d < Chicago.length);
Console Output
I think your code could be simpler, shorter and easier to read if you leave the iteration to array built in methods. That way you will remove the need to use an iteration variable and access each item:
GoldemStates.forEach(
item => icons('clock',item.Period + ' Period | ' + 'Points ' + item.Points ,'texto')
)
But we can do it eve better. Since all the teams render exactly the same, we can build a function that renders one single item and then let the methods specialized on iteration do their work. That way your code only takes care of rendering and the built-in methods takes care of iterating, separation of conerns:
const renderTeam = team => icons('clock',team.Period + ' Period | ' + 'Points ' + team.Points ,'texto')
// Render part
icons('golden','Golden States', 'destaque_golden') //Team Title (Symbol, Team Name, CSS)
GoldemStates.forEach(renderTeam)
icons('bulls','Chicago Bulls', 'destaque_bulls')//Team Title (Symbol, Team Name, CSS)
Chicago.forEach(renderTeam)
I have this code:
compareList[productName] = productID + ',' + productHref;
console.log(productName + ' ' + productID + ' ' + productHref + ' ' + compareList.length);
Which logs into this (I have removed the link):
Acer Iconia B1-790 [NT.LDFEE.002] 112576 link removed for confidentiality 0
As you can see, all three variables are valid strings, but the json object still fails to assign (compareList.length logs as 0). I've been thinking and thinking but I simply can't figure it out. Any help is appreciated.
Maybe this version of adding and checking array length can be useful to you?
var compareList=[]
var productName = {productID:'saban',productHref:'http://saulic.com'};
compareList.push(productName);
console.log(compareList.length);
I am playing with some basic js I am just beginning to learn, so far I have the code below. I am trying to ask the user what their name is and then tell them if they share the same name as a racing driver (from my array driversNames).
If they have the same name as a racing driver it would tell them they do, if not it would tell them they don't. However I have a feeling I have something wrong here: if (yourName === driversNames) but I cannot figure it out.
It doesn't matter what I enter into the prompt, it always says sorry you don't have the same name.
var driversNames = ["Lewis", "Fernando", "Sebastian", "Jenson", "Daniel"]
for (var i = 0; i < driversNames.length; i++) {
console.log(driversNames[i] + " " + "is a drivers name");
}
var yourName = prompt("What is your name?")
console.log("Your name is" + " " + yourName)
if (yourName === driversNames) {
console.log("Awesome" + " " + yourName + " " + "you share the same name as a Formula 1 driver!")
} else {
console.log("Sorry" + " " + yourName + " " + "you don't have the same name as any Formula 1 drivers")
}
You made one mistake in this line if (yourName === driversNames).
It doesnt compare your name with names from driversNames. The most easiest way: its use indexOf method. So this line should be like below
if (driversNames.indexOf(yourName) > -1) //Get Name otherwise no
And jsfiddle example for you, also indefOf link
Thanks
You are comparing a string to an array, so the comparison will return false. You have a few options to fix this though - I'll explain using a loop to check each string, and using indexOf.
Loop: You need to loop through each element in the driversNames array and compare each one. This is the manual way.
var sameName = false; //flag to keep track of if name matches or not
driversNames.forEach(function(name) { //loop through each name in driversNames
if(yourName === name) { //compare your name to driver name
sameName = true; //if match, set flag to true
}
}); //loop ends here
if(sameName) { //if flag is true, a name matched
console.log("Awesome" + " " + yourName + " " + "you share the same name as a Formula 1 driver!"); //Console log success statement
} else { // else, no name matched
console.log("Sorry" + " " + yourName + " " + "you don't have the same name as any Formula 1 drivers"); //console log fail statement
}
IndexOf: This method uses less lines of code, but isn't compatible on all browsers - I believe anything under IE8 will break when using this for example. But if compatibility isn't an issue, it looks like this:
if (driversNames.indexOf(yourName) > -1) { //indexof returns -1 for no match, and a number for match
console.log("Awesome" + " " + yourName + " " + "you share the same name as a Formula 1 driver!"); //console log success statement
} else {
console.log("Sorry" + " " + yourName + " " + "you don't have the same name as any Formula 1 drivers"); //console log fail statement
}
indexof is a little more elegant, although easy to forget the compatibility issue. Code is commented but just to explain it: Arrays have a method you can call, called indexOf() which takes a parameter. This method will then check if that parameter is in the array and if it is, return a value which is it's position in the array. If it isn't in the array, it will return -1.
router.get("/roll", function (req, res) {
//Re-enable the session.
//req.session.isrolling = 1;
if(typeof req.session.isrolling === "undefined") {
console.log(classname + "** setting the variable **");
req.session.isrolling = 1;
}
console.log(classname + "[0]" + req.session.isrolling);
if(req.session.isrolling == 1 || req.session.isrolling == 3) {
console.log(classname + "[1] " + req.session.isrolling);
req.session.isrolling = 0;
console.log(classname + "[2] " + req.session.isrolling);
As you can see, little obvious, I uncomment the 3rd line to re-enable incase I stucked myself with 'debugging'.
Anyways the outputs are normally;
[index.js] [0]3
[index.js] [1] 3
[index.js] [2] 0
I use an boolean to try and check where it goes wrong.
Anyways after some callbacks and functions within functions I end on this part -
rollController.UpdateDeposit(true, winAmmount, req.session.userSecret, function(callbackresult) {
if(callbackresult) {
console.log(classname + "[3]" + req.session.isrolling);
req.session.isrolling = 3;
console.log(classname + "[4]" + req.session.isrolling);
}
Despite all of this, and the expected 'outputs', I can keep spamming while an roll is pending while the console hasn't even outputted;
[index.js] [3]0
[index.js] [4]3
If I try to create an local variable within index.js (ofcourse not the optimal way) it fixes it, but its 1 query per, and not per user (dumb yes).
I added the undefined thing, it happends when I mess around with mySQL and reset some data. I am wondering myself if I should switch to mongoDB due performance but that might something for later.
So the main question is, where do I go wrong and what would be an better approach to make a queue per user(session?) and, obvious, not per server ?
I finally found the solution.
This kept me busy for a large week, while reading a lot, and learning more, about node.
req.session.save(function(error) {
console.log(classname + " Error in saving session " + error)
});
Thank you achmad.