Search code examples
javascriptasynchronouspromisebinance

Javascript code portion not running in the right order


Im creating a trading bot on Javascript (I got no prior experience with this language). The way the trailing stoploss function runs is:

  • Websocket receives current market price
  • "active" is a boolean variable, if true, run the code
  • If price rises a %, cancel old stoploss and add a new one higher.

The problem I am getting is the code doesn't run in the right order. If you look at the picture, I don't understand why the blue box still executes if active is false. And because the program runs in the wrong order at times, the websocket stops or acts how it isn't supposed to.

Output

This is my trailing stoploss websocket code:

function binanceTrailingSLOrder(symbol, orderId, quantity, oldPrice, percentage, active) {

    const clean_trade = client.ws.trades([symbol], trade => { //run websocket
        var livePrice = parseFloat(binance_symbols[symbol]["close"]); //set new price to live price

        if (active == true) {
            binanceCheckOrderStatus(symbol, orderId).then(r => {
                switch (r.status) {
                    case "PENDING":
                        if (livePrice >= (oldPrice * ((100 + percentage) / 100)) && active == true) {
                            active = false;
                            binanceCancelOrder(symbol, orderId).then((r4) => { //Cancel previous SL
                                var newSL = livePrice * ((100 - percentage) / 100);
                                binanceStopOrder(symbol, 'SELL', r4.origQty, newSL, newSL).then((r5) => { //Set new SL
                                    orderId = r5.orderId; quantity = r5.origQty; oldPrice = r5.price;
                                    active = true;
                                }).catch((err) => {
                                    console.log(err);
                                });
                            });
                        }
                        break;
                    default:
                        break;
                }

            });
        }
    });

}

Check order status function:

//Get specific order status
function binanceCheckOrderStatus(symbol, orderId) {
    if(!orderId){
        console.log("order Id not found");
        return false;
    } else {
        var client = loadBinanceKeys2();

        return client.getOrder({
            symbol: symbol,
            orderId: orderId,
            recvWindow: 1000000
        }).then((order) => {
            return order;
        }).catch((err) => {
            console.log(err);
        });
    }
}

Solution

  • Javascript is asynchronous in nature. The function binanceCheckOrderStatus() returns a promise. The execution engine will call this function, and then move on to the next line. The code block after .then(r => only executes after the binanceCheckOrderStatus's getOrder() is completed. Now in this time period, the active may have become false in other .then() requests. It may be confusing for new developers. Since you are using lot of .then() in your code, you have to understand that the .then() part is only executed after the function before .then() completes the execution. So the function taking less time will execute it's .then() part before the others. So in short, you CANNOT control the order in this scenario unless you know how much time every function will take, which is probably impossible to confirm. For overcoming this problem, you have to use async/await. Or, you need to change your logic so it is less dependent on that deep level promises.

    I am not very sure about what you are trying to achieve here, but here is the idea about how you can solve the ordering problem. It is just a reference code, I have not tested it. Just an idea on how you can hold your threads to make sure your code runs in an order using async/await.

    async function binanceTrailingSLOrder(symbol, orderId, quantity, oldPrice, percentage, active) {
    
        const clean_trade = client.ws.trades([symbol], async trade => { //run websocket
            var livePrice = parseFloat(binance_symbols[symbol]["close"]); //set new price to live price
    
            if (active == true) {
    
                try {
    
                const order = await binanceCheckOrderStatus(symbol, orderId);
    
                if (!order) {
                    throw new Error('order not found')
                }
                    switch (order.status) {
                        case "PENDING":
                            if (livePrice >= (oldPrice * ((100 + percentage) / 100)) && active == true) {
                                active = false;
    
                                const r4 = await binanceCancelOrder(symbol, orderId);
                                if (r4) {
                                    var newSL = livePrice * ((100 - percentage) / 100);
                                    var r5 = binanceStopOrder(symbol, 'SELL', r4.origQty, newSL, newSL);
    
                                    if (r5) {
                                        orderId = r5.orderId; quantity = r5.origQty; oldPrice = r5.price;
                                        active = true;
                                    }
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
    
                catch(error) {
                    console.log('error found: ', error);
                }
    
            }
        });
    
    }
    
    
    
    async function binanceCheckOrderStatus(symbol, orderId) {
        if(!orderId){
            console.log("order Id not found");
            return false;
        } else {
            var client = loadBinanceKeys2();
    
            return new Promise((resolve, reject) => {
                client.getOrder({
                    symbol: symbol,
                    orderId: orderId,
                    recvWindow: 1000000
                }).then((order) => {
                    resolve(order);
                }).catch((err) => {
                    reject(err);
                });
            });
        }
    }