I don't see any other bundle messages, ends with the last object
What's the output below that I see in your screenshot?
SORRY !
{"bundle":"Object","obj":{"id":21620119,"version":2,"account":{"id":32144558,"type":"paper_trading","name":"Paper Account 1006740","market":"Paper trading account","link":"/accounts/32144558"},"pair":"USDT_DASH","instant":false,"status":{"type":"finished","basic_type":"finished","title":"Finished"},"leverage":{"enabled":false},"position":{"type":"buy","editable":false,"units":{"value":"220.994","editable":false},"price":{"value":"45.28","value_without_commission":"45.24","editable":false},"total":{"value":"10007.76632856"},"order_type":"market","status":{"type":"finished","basic_type":"finished","title":"Finished"}},"take_profit":{"enabled":true,"steps":[{"id":90614457,"order_type":"market","editable":false,"units":{"value":"220.994"},"price":{"value":"45.9785","type":"last","percent":null},"volume":"100.0","total":"10160.972629","trailing":{"enabled":true,"percent":"-1.0"},"status":{"type":"finished","basic_type":"finished","title":"Finished"},"data":{"cancelable":false,"panic_sell_available":false},"position":1}]},"stop_loss":{"enabled":false},"reduce_funds":{"steps":[]},"market_close":{},"note":"--30m_0.67_0.5_1_S.BUY_2_1_2.5_🡇_3","note_raw":"--30m_0.67_0.5_1_S.BUY_2_1_2.5_🡇_3","skip_enter_step":false,"data":{"editable":false,"current_price":{"day_change_percent":"7.388","bid":"45.64","ask":"45.65","last":"45.64","quote_volume":"8639544.58807"},"target_price_type":"price","base_order_finished":true,"missing_funds_to_close":0,"liquidation_price":null,"average_enter_price":"45.28","average_close_price":"45.92","average_enter_price_without_commission":"45.24","average_close_price_without_commission":"45.97","panic_sell_available":false,"add_funds_available":false,"reduce_funds_available":false,"force_start_available":false,"force_process_available":false,"cancel_available":false,"finished":true,"base_position_step_finished":true,"entered_amount":"220.994","entered_total":"10007.76632856","closed_amount":"220.994","closed_total":"10148.93508582","created_at":"2022-12-01T14:24:04.844Z","updated_at":"2022-12-01T14:24:04.844Z","closed_at":"2022-12-01T17:07:30.337Z","type":"smart_trade"},"profit":{"volume":"141.16875726","usd":"141.16875726","percent":"1.41","roe":null},"margin":{"amount":null,"total":null},"is_position_not_filled":false},"_msgid":"6dffd6ebd6a0483a"}
Ok. That's part of what I was looking for. Is there more of these below that? Or is that the only one? I guess I should say, what's the last item listed in your debug output?
There are actually 3:
First, Bundle "Original Message" with 64 records
Second, Bundle "Filtered Message" with 57 records (filtered down?)
Third, Bundle "Object"
Hmm, I may have found our syntax error. Try this block below. There was a closing brace } that was commented out. It should have broken the for loop, but it didn't. See if this works and spits out everything we're expecting. You should have a final object in your debug window with the bundle label "Final Message".
var check = context.get('recordKeeper');
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
for(let obj of input){
node.send({bundle:"Object", obj});
/*if(!(check.hasOwnProperty(obj.id))){
*/ check[obj.id] = obj;
obj.pair = (String(obj.pair)).replace("USDT_", "")
obj.trade_id = obj.id
obj.profit_usd = Number(obj.profit.usd).toFixed(2)
obj.profit_percent = obj.profit.percent
obj.position = Number(obj.position.total.value).toFixed(0)
obj.volume = obj.data.current_price.quote_volume
obj.close_price = obj.data.average_close_price
obj.closed = obj.data.closed_at
if (obj.status.type === "stop_loss_finished") {obj.status = "SL"} else if (obj.status.type === "finished") {obj.status = "TP"} else if (obj.status.type === "panic_sold") {obj.status = "➦"} else {
obj.status= obj.status.type
}
if (obj.stop_loss.enabled) {
obj.to_sl = ((1 - obj.stop_loss.conditional.price.value / obj.data.average_enter_price) * 100).toFixed(2)
}
if (obj.status.type == "stop_loss_finished") {
obj.S_L = (((obj.data.average_enter_price - obj.stop_loss.conditional.price.value) / obj.data.average_enter_price) * 100).toFixed(2)
}
if (obj.status.type == "finished") {
obj.T_P = (((obj.take_profit.steps[0].price.value - obj.data.average_enter_price) / obj.data.average_enter_price) * 100).toFixed(2)
}
obj.in = obj.note.split("_")
obj.frames = obj.in[0]
obj.gain = obj.in[1]
obj.gain_st = obj.in[2]
obj.freq = obj.in[3]
obj.analysis = obj.in[4]
obj.tp_a = obj.in[5]
obj.tp_trl_a = obj.in[6]
obj.sl_a = obj.in[7]
obj.sl_trl_a = obj.in[8]
obj.tm_a = obj.in[9]
}
}
context.set('recordKeeper', check);
msg = {};
msg.payload = check;
return({bundle:"Final Message", msg});
No data, and there is "unrecoverable syntax" warning in the function itself. Plus "SyntaxError: Unexpected identifier (body:line 55)"
Had to put it in my Visual Studio Code to find the other mistake. I needed to comment out the if statement to make all the opening and closing brackets to work correctly. Trying to track stuff down in the posting window probably isn't the best idea...
var check = context.get('recordKeeper');
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
for(let obj of input){
node.send({bundle:"Object", obj});
if(!(check.hasOwnProperty(obj.id))){
check[obj.id] = obj;
obj.pair = (String(obj.pair)).replace("USDT_", "")
obj.trade_id = obj.id
obj.profit_usd = Number(obj.profit.usd).toFixed(2)
obj.profit_percent = obj.profit.percent
obj.position = Number(obj.position.total.value).toFixed(0)
obj.volume = obj.data.current_price.quote_volume
obj.close_price = obj.data.average_close_price
obj.closed = obj.data.closed_at
if (obj.status.type === "stop_loss_finished") {obj.status = "SL"} else if (obj.status.type === "finished") {obj.status = "TP"} else if (obj.status.type === "panic_sold") {obj.status = "➦"} else {
obj.status= obj.status.type
}
if (obj.stop_loss.enabled) {
obj.to_sl = ((1 - obj.stop_loss.conditional.price.value / obj.data.average_enter_price) * 100).toFixed(2)
}
if (obj.status.type == "stop_loss_finished") {
obj.S_L = (((obj.data.average_enter_price - obj.stop_loss.conditional.price.value) / obj.data.average_enter_price) * 100).toFixed(2)
}
if (obj.status.type == "finished") {
obj.T_P = (((obj.take_profit.steps[0].price.value - obj.data.average_enter_price) / obj.data.average_enter_price) * 100).toFixed(2)
}
obj.in = obj.note.split("_")
obj.frames = obj.in[0]
obj.gain = obj.in[1]
obj.gain_st = obj.in[2]
obj.freq = obj.in[3]
obj.analysis = obj.in[4]
obj.tp_a = obj.in[5]
obj.tp_trl_a = obj.in[6]
obj.sl_a = obj.in[7]
obj.sl_trl_a = obj.in[8]
obj.tm_a = obj.in[9]
}
}
context.set('recordKeeper', check);
msg = {};
msg.payload = check;
return({bundle:"Final Message", msg});
Still only one "Object"?
Seems we're back we were at this step
Ok. Simplest for loop:
var check = {};
//check = context.get('recordKeeper');
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
for(let obj of input){
node.send({bundle:"Object", obj});
if(!(check.hasOwnProperty(obj.id))){
check[obj.id] = obj;
}
}
//context.set('recordKeeper', check);
msg = {};
msg.payload = check;
msg.bundle = "Final Message";
return msg;
Good. Now that part is working. Try this for adding in the stuff you had before while not working with recordKeeper.
//var check = context.get('recordKeeper');
var check = {};
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
for(let obj of input){
node.send({bundle:"Object", obj});
if(!(check.hasOwnProperty(obj.id))){
obj.pair = (String(obj.pair)).replace("USDT_", "");
obj.trade_id = obj.id;
obj.profit_usd = Number(obj.profit.usd).toFixed(2);
obj.profit_percent = obj.profit.percent;
obj.position = Number(obj.position.total.value).toFixed(0);
obj.volume = obj.data.current_price.quote_volume;
obj.close_price = obj.data.average_close_price;
obj.closed = obj.data.closed_at;
if (obj.status.type === "stop_loss_finished"){obj.status = "SL";}
else if (obj.status.type === "finished"){obj.status = "TP";}
else if (obj.status.type === "panic_sold"){obj.status = "➦";}
else {obj.status = obj.status.type}
if (obj.stop_loss.enabled) {
obj.to_sl = ((1 - obj.stop_loss.conditional.price.value / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "stop_loss_finished") {
obj.S_L = (((obj.data.average_enter_price - obj.stop_loss.conditional.price.value) / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "finished") {
obj.T_P = (((obj.take_profit.steps[0].price.value - obj.data.average_enter_price) / obj.data.average_enter_price) * 100).toFixed(2);
}
obj.in = obj.note.split("_");
obj.frames = obj.in[0];
obj.gain = obj.in[1];
obj.gain_st = obj.in[2];
obj.freq = obj.in[3];
obj.analysis = obj.in[4];
obj.tp_a = obj.in[5];
obj.tp_trl_a = obj.in[6];
obj.sl_a = obj.in[7];
obj.sl_trl_a = obj.in[8];
obj.tm_a = obj.in[9];
check[obj.id] = obj;
}
}
//context.set('recordKeeper', check);
msg = {};
msg.payload = check;
msg.bundle = "Final Message";
return msg;
Made a couple of edits after the original post. Should be good now if you're seeing this message as well.
So lots of data: "original message" with a full set or records, "filtered", then all of the records coming individually, and the "final message". Shouldn't the unused fields been discarded at this point?
Yes! That means that the flow is working finally. Still just the beginning, but working.
Not yet. There's nothing in there to clear them. Running under the assumption that you only want everything that was in the function, try this:
//var check = context.get('recordKeeper');
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
var tempObj;
for(let obj of input){
node.send({bundle:"Object", obj});
if(!(check.hasOwnProperty(obj.id))){
tempObj = {};
tempObj.pair = (String(obj.pair)).replace("USDT_", "");
tempObj.trade_id = obj.id;
tempObj.profit_usd = Number(obj.profit.usd).toFixed(2);
tempObj.profit_percent = obj.profit.percent;
tempObj.position = Number(obj.position.total.value).toFixed(0);
tempObj.volume = obj.data.current_price.quote_volume;
tempObj.close_price = obj.data.average_close_price;
tempObj.closed = obj.data.closed_at;
if (obj.status.type === "stop_loss_finished"){tempObj.status = "SL";}
else if (obj.status.type === "finished"){tempObj.status = "TP";}
else if (obj.status.type === "panic_sold"){tempObj.status = "➦";}
else {tempObj.status = obj.status.type}
if (obj.stop_loss.enabled) {
tempObj.to_sl = ((1 - obj.stop_loss.conditional.price.value / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "stop_loss_finished") {
tempObj.S_L = (((obj.data.average_enter_price - obj.stop_loss.conditional.price.value) / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "finished") {
tempObj.T_P = (((obj.take_profit.steps[0].price.value - obj.data.average_enter_price) / obj.data.average_enter_price) * 100).toFixed(2);
}
tempObj.in = obj.note.split("_");
tempObj.frames = obj.in[0];
tempObj.gain = obj.in[1];
tempObj.gain_st = obj.in[2];
tempObj.freq = obj.in[3];
tempObj.analysis = obj.in[4];
tempObj.tp_a = obj.in[5];
tempObj.tp_trl_a = obj.in[6];
tempObj.sl_a = obj.in[7];
tempObj.sl_trl_a = obj.in[8];
tempObj.tm_a = obj.in[9];
check[obj.id] = tempObj;
}
}
//context.set('recordKeeper', check);
msg = {};
msg.payload = check;
msg.bundle = "Final Message";
return msg;
This will work in a way that it "clears out" the stuff you don't want. Here's the steps of how the data is assigned.
- The message arrives
- The message is filtered and assigned to "input"
- The for loop goes through each "input" object and assigns the individual object to "obj" for processing
- Part of processing "obj" is assigning the desired properties to "tempObj", which will only hold desired properties.
- When the processing of "obj" is complete, "tempObj" is assigned to "check", which holds an array of the desired fields from the filtered output.
- "check" is assigned to the message to be sent out and the message is sent.
Give this a try and see if it does what you want. If so, we'll tackle the last part and get the storage working.
Something is off - no data
Oops... Yep. Missed the original declaration of "check"... Here, try it now.
//var check = context.get('recordKeeper');
check = {};
node.send({bundle:"Original Message", msg});
const input = msg.payload.filter(s => s.status.type == "stop_loss_finished" || s.status.type == "finished");
node.send({bundle:"Filtered Message", input});
var tempObj;
for(let obj of input){
node.send({bundle:"Object", obj});
if(!(check.hasOwnProperty(obj.id))){
tempObj = {};
tempObj.pair = (String(obj.pair)).replace("USDT_", "");
tempObj.trade_id = obj.id;
tempObj.profit_usd = Number(obj.profit.usd).toFixed(2);
tempObj.profit_percent = obj.profit.percent;
tempObj.position = Number(obj.position.total.value).toFixed(0);
tempObj.volume = obj.data.current_price.quote_volume;
tempObj.close_price = obj.data.average_close_price;
tempObj.closed = obj.data.closed_at;
if (obj.status.type === "stop_loss_finished"){tempObj.status = "SL";}
else if (obj.status.type === "finished"){tempObj.status = "TP";}
else if (obj.status.type === "panic_sold"){tempObj.status = "➦";}
else {tempObj.status = obj.status.type}
if (obj.stop_loss.enabled) {
tempObj.to_sl = ((1 - obj.stop_loss.conditional.price.value / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "stop_loss_finished") {
tempObj.S_L = (((obj.data.average_enter_price - obj.stop_loss.conditional.price.value) / obj.data.average_enter_price) * 100).toFixed(2);
}
if (obj.status.type == "finished") {
tempObj.T_P = (((obj.take_profit.steps[0].price.value - obj.data.average_enter_price) / obj.data.average_enter_price) * 100).toFixed(2);
}
tempObj.in = obj.note.split("_");
tempObj.frames = obj.in[0];
tempObj.gain = obj.in[1];
tempObj.gain_st = obj.in[2];
tempObj.freq = obj.in[3];
tempObj.analysis = obj.in[4];
tempObj.tp_a = obj.in[5];
tempObj.tp_trl_a = obj.in[6];
tempObj.sl_a = obj.in[7];
tempObj.sl_trl_a = obj.in[8];
tempObj.tm_a = obj.in[9];
check[obj.id] = tempObj;
}
}
//context.set('recordKeeper', check);
msg = {};
msg.payload = check;
msg.bundle = "Final Message";
return msg;