I have a problem. In my NodeJS API. I use the Node-Binance-API
package to use the API from Binance. In this API I can subscribe to account changes using a websocket. The function to subscribe to my account looks like the following:
exports.subscribeAccount = async (agentId) => {
binance.websockets.userData((response) => {
if (eventType === "outboundAccountPosition") {
console.log("outboundAccountPosition")
}
else if (eventType === "executionReport") {
const order = Order.executionReportToOrder(response, agentId);
order.save();
}
})
}
The order.save()
method looks like this:
save() {
let sql = `
INSERT INTO \`Order\` (
orderId, agentId, symbol, clientOrderId, side, orderType, timeInForce, orderQuantity, orderPrice, stopPrice, icebergQuantity, originalClientOrderId, currentExecutionType, currentOrderStatus, orderRejectReason, lastExecutedQuantity, cumulativeFilledQuantity, lastExecutedPrice, commissionAmount, commissionAsset, transactionTime, tradeId, isOrderOnBook, isTradeMakerSide, creationTime, cumulativeQuoteAssetTransactedQuantity, lastQuoteAssetTransactedQuantity, quoteOrderQuantity
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE currentExecutionType=VALUES(currentExecutionType), currentOrderStatus=VALUES(currentOrderStatus), orderRejectReason=VALUES(orderRejectReason), lastExecutedQuantity=VALUES(lastExecutedQuantity), cumulativeFilledQuantity=VALUES(cumulativeFilledQuantity), lastExecutedPrice=VALUES(lastExecutedPrice), commissionAmount=VALUES(commissionAmount), commissionAsset=VALUES(commissionAsset), transactionTime=VALUES(transactionTime), tradeId=VALUES(tradeId), isOrderOnBook=VALUES(isOrderOnBook), isTradeMakerSide=VALUES(isTradeMakerSide), creationTime=VALUES(creationTime), cumulativeQuoteAssetTransactedQuantity=VALUES(cumulativeQuoteAssetTransactedQuantity), lastQuoteAssetTransactedQuantity=VALUES(lastQuoteAssetTransactedQuantity), quoteOrderQuantity=VALUES(quoteOrderQuantity);`;
return db.execute(sql, [
this.orderId,
this.agentId,
this.symbol,
this.clientOrderId,
this.side,
this.orderType,
this.timeInForce,
this.orderQuantity,
this.orderPrice,
this.stopPrice,
this.icebergQuantity,
this.originalClientOrderId,
this.currentExecutionType,
this.currentOrderStatus,
this.orderRejectReason,
this.lastExecutedQuantity,
this.cumulativeFilledQuantity,
this.lastExecutedPrice,
this.commissionAmount,
this.commissionAsset,
this.transactionTime,
this.tradeId,
this.isOrderOnBook,
this.isTradeMakerSide,
this.creationTime,
this. cumulativeQuoteAssetTransactedQuantity,
this.lastQuoteAssetTransactedQuantity,
this.quoteOrderQuantity
]);
}
But now I have the following problem. The websocket works great and it pushes updates about orders. When I enter an order that gets executed instantly, this method gets called twice, right after each other. The first call is the NEW
order and the second one is the FILLED
order. the order.save()
function writes the object to the database using the db.execute()
function of the mysql2
package, but I can see that sometimes the second query gets executed faster than the first, so the final state of the order in my database is NEW
. How can I prevent this from happening? Can I cancel the first query when I see the second one coming in or let them execute after each other?
TABLE
The SHOW CREATE TABLE Order
results in:
CREATE TABLE `Order` (
`orderId` bigint(20) NOT NULL,
`agentId` int(11) NOT NULL,
`symbol` varchar(25) NOT NULL,
`clientOrderId` varchar(255) NOT NULL,
`side` enum('BUY','SELL') NOT NULL,
`orderType` enum('MARKET','LIMIT','STOP_LOSS','STOP_LOSS_LIMIT','TAKE_PROFIT','TAKE_PROFIT_LIMIT') NOT NULL,
`timeInForce` enum('GTC','IOC','FOK') NOT NULL,
`orderQuantity` decimal(16,8) NOT NULL,
`orderPrice` decimal(16,8) NOT NULL,
`stopPrice` decimal(16,8) NOT NULL,
`icebergQuantity` decimal(16,8) NOT NULL,
`originalClientOrderId` varchar(255) NOT NULL,
`currentExecutionType` enum('NEW','CANCELED','REPLACED','REJECTED','TRADE','EXPIRED') NOT NULL,
`currentOrderStatus` enum('NEW','FILLED','CANCELED','EXPIRED','PENDING_CANCEL','PARTIALLY_FILLED') NOT NULL,
`orderRejectReason` varchar(255) NOT NULL,
`lastExecutedQuantity` decimal(16,8) NOT NULL,
`cumulativeFilledQuantity` decimal(16,8) NOT NULL,
`lastExecutedPrice` decimal(16,8) NOT NULL,
`commissionAmount` decimal(16,8) NOT NULL,
`commissionAsset` varchar(15) DEFAULT NULL,
`transactionTime` bigint(20) NOT NULL,
`tradeId` bigint(20) NOT NULL,
`isOrderOnBook` tinyint(1) NOT NULL,
`isTradeMakerSide` tinyint(1) NOT NULL,
`creationTime` bigint(20) NOT NULL,
`cumulativeQuoteAssetTransactedQuantity` decimal(16,8) NOT NULL,
`lastQuoteAssetTransactedQuantity` decimal(16,8) NOT NULL,
`quoteOrderQuantity` decimal(16,8) NOT NULL,
PRIMARY KEY (`orderId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4