diff --git a/app/binance/user.js b/app/binance/user.js index ddbe7df0..10909a38 100644 --- a/app/binance/user.js +++ b/app/binance/user.js @@ -1,3 +1,4 @@ +const { v4: uuidv4 } = require('uuid'); const _ = require('lodash'); const { binance } = require('../helpers'); const queue = require('../cronjob/trailingTradeHelper/queue'); @@ -52,8 +53,15 @@ const setupUserWebsocket = async logger => { totalTradeQuantity, orderTime: transactTime // Transaction time } = evt; - logger.info( - { symbol, evt, saveLog: true }, + + const symbolLogger = logger.child({ + jobName: 'trailingTrade', + correlationId: uuidv4(), + symbol + }); + + symbolLogger.info( + { evt, saveLog: true }, `There is a new update in order. ${orderId} - ${side} - ${orderStatus}` ); @@ -72,10 +80,14 @@ const setupUserWebsocket = async logger => { orderId !== lastOrder.orderId || transactTime < lastOrder.transactTime ) { + symbolLogger.info( + { lastOrder, evt, saveLog: true }, + 'This order update is an old order. Do not update last grid trade order.' + ); return; } - await updateGridTradeLastOrder(logger, symbol, side.toLowerCase(), { + const updatedOrder = { ...lastOrder, status: orderStatus, type: orderType, @@ -88,13 +100,20 @@ const setupUserWebsocket = async logger => { isWorking: isOrderWorking, updateTime: eventTime, transactTime - }); - logger.info( - { symbol, lastOrder, saveLog: true }, - 'The last order has been updated.' + }; + + await updateGridTradeLastOrder( + logger, + symbol, + side.toLowerCase(), + updatedOrder + ); + symbolLogger.info( + { lastOrder, updatedOrder, saveLog: true }, + `The last order has been updated. ${orderId} - ${side} - ${orderStatus}` ); - queue.executeFor(logger, symbol); + queue.executeFor(symbolLogger, symbol); } }; diff --git a/app/cronjob/trailingTrade/step/__tests__/ensure-grid-trade-order-executed.test.js b/app/cronjob/trailingTrade/step/__tests__/ensure-grid-trade-order-executed.test.js index c210f0ca..90cadab1 100644 --- a/app/cronjob/trailingTrade/step/__tests__/ensure-grid-trade-order-executed.test.js +++ b/app/cronjob/trailingTrade/step/__tests__/ensure-grid-trade-order-executed.test.js @@ -14,6 +14,7 @@ describe('ensure-grid-trade-order-executed.js', () => { let mockIsExceedAPILimit; let mockDisableAction; let mockSaveOrderStats; + let mockRefreshOpenOrdersAndAccountInfo; let mockSaveSymbolGridTrade; @@ -46,6 +47,14 @@ describe('ensure-grid-trade-order-executed.js', () => { mockIsExceedAPILimit = jest.fn().mockReturnValue(false); mockDisableAction = jest.fn().mockResolvedValue(true); mockSaveOrderStats = jest.fn().mockResolvedValue(true); + mockRefreshOpenOrdersAndAccountInfo = jest.fn().mockResolvedValue({ + accountInfo: { + accountInfo: 'updated' + }, + openOrders: [{ openOrders: 'retrieved' }], + buyOpenOrders: [{ buyOpenOrders: 'retrived' }], + sellOpenOrders: [{ sellOpenOrders: 'retrived' }] + }); mockSaveSymbolGridTrade = jest.fn().mockResolvedValue(true); @@ -62,7 +71,8 @@ describe('ensure-grid-trade-order-executed.js', () => { getAPILimit: mockGetAPILimit, isExceedAPILimit: mockIsExceedAPILimit, disableAction: mockDisableAction, - saveOrderStats: mockSaveOrderStats + saveOrderStats: mockSaveOrderStats, + refreshOpenOrdersAndAccountInfo: mockRefreshOpenOrdersAndAccountInfo })); jest.mock('../../../trailingTradeHelper/configuration', () => ({ @@ -148,6 +158,10 @@ describe('ensure-grid-trade-order-executed.js', () => { expect(mockSaveOrderStats).not.toHaveBeenCalled(); }); + it('does not trigger refreshOpenOrdersAndAccountInfo', () => { + expect(mockRefreshOpenOrdersAndAccountInfo).not.toHaveBeenCalled(); + }); + it('does not trigger slack.sendMessage', () => { expect(slackMock.sendMessage).not.toHaveBeenCalled(); }); @@ -337,7 +351,9 @@ describe('ensure-grid-trade-order-executed.js', () => { getAPILimit: mockGetAPILimit, isExceedAPILimit: mockIsExceedAPILimit, disableAction: mockDisableAction, - saveOrderStats: mockSaveOrderStats + saveOrderStats: mockSaveOrderStats, + refreshOpenOrdersAndAccountInfo: + mockRefreshOpenOrdersAndAccountInfo })); jest.mock('../../../trailingTradeHelper/configuration', () => ({ @@ -417,6 +433,13 @@ describe('ensure-grid-trade-order-executed.js', () => { checkOrderExecutePeriod: 10, temporaryDisableActionAfterConfirmingOrder: 20 } + }, + openOrders: [], + buy: { + openOrders: [] + }, + sell: { + openOrders: [] } }; @@ -448,6 +471,12 @@ describe('ensure-grid-trade-order-executed.js', () => { it('does not trigger saveOrderStats', () => { expect(mockSaveOrderStats).not.toHaveBeenCalled(); }); + + it('does not trigger refreshOpenOrdersAndAccountInfo', () => { + expect( + mockRefreshOpenOrdersAndAccountInfo + ).not.toHaveBeenCalled(); + }); } else if (t.lastBuyOrder.status.includes('FILLED')) { // do filled thing it('triggers calculated last buy price as order filled', () => { @@ -488,6 +517,13 @@ describe('ensure-grid-trade-order-executed.js', () => { ); }); + it('triggers refreshOpenOrdersAndAccountInfo as order filled', () => { + expect(mockRefreshOpenOrdersAndAccountInfo).toHaveBeenCalledWith( + loggerMock, + t.symbol + ); + }); + it('triggers PubSub.publish for check-open-orders channel', () => { expect(PubSubMock.publish).toHaveBeenCalledWith( 'check-open-orders', @@ -551,6 +587,13 @@ describe('ensure-grid-trade-order-executed.js', () => { ]); }); + it('triggers refreshOpenOrdersAndAccountInfo due to cancelled order', () => { + expect(mockRefreshOpenOrdersAndAccountInfo).toHaveBeenCalledWith( + loggerMock, + t.symbol + ); + }); + if (t.notifyOrderExecute === true) { it('triggers slack.sendMessage due to cancelled order', () => { expect(slackMock.sendMessage).toHaveBeenCalledWith( @@ -760,7 +803,9 @@ describe('ensure-grid-trade-order-executed.js', () => { getAPILimit: mockGetAPILimit, isExceedAPILimit: mockIsExceedAPILimit, disableAction: mockDisableAction, - saveOrderStats: mockSaveOrderStats + saveOrderStats: mockSaveOrderStats, + refreshOpenOrdersAndAccountInfo: + mockRefreshOpenOrdersAndAccountInfo })); jest.mock('../../../trailingTradeHelper/configuration', () => ({ @@ -840,6 +885,13 @@ describe('ensure-grid-trade-order-executed.js', () => { checkOrderExecutePeriod: 10, temporaryDisableActionAfterConfirmingOrder: 20 } + }, + openOrders: [], + buy: { + openOrders: [] + }, + sell: { + openOrders: [] } }; @@ -885,6 +937,13 @@ describe('ensure-grid-trade-order-executed.js', () => { ); }); + it('triggers refreshOpenOrdersAndAccountInfo as order filled', () => { + expect(mockRefreshOpenOrdersAndAccountInfo).toHaveBeenCalledWith( + loggerMock, + t.symbol + ); + }); + it('triggers disableAction as order filled', () => { expect(mockDisableAction).toHaveBeenCalledWith( loggerMock, @@ -944,6 +1003,13 @@ describe('ensure-grid-trade-order-executed.js', () => { ]); }); + it('triggers refreshOpenOrdersAndAccountInfo due to cancelled order', () => { + expect(mockRefreshOpenOrdersAndAccountInfo).toHaveBeenCalledWith( + loggerMock, + t.symbol + ); + }); + it('triggers slack.sendMessage due to cancelled order', () => { expect(slackMock.sendMessage).toHaveBeenCalledWith( expect.stringContaining('Order Removed'), diff --git a/app/cronjob/trailingTrade/step/ensure-grid-trade-order-executed.js b/app/cronjob/trailingTrade/step/ensure-grid-trade-order-executed.js index 55f82a47..2cde64b6 100644 --- a/app/cronjob/trailingTrade/step/ensure-grid-trade-order-executed.js +++ b/app/cronjob/trailingTrade/step/ensure-grid-trade-order-executed.js @@ -7,7 +7,8 @@ const { getAPILimit, isExceedAPILimit, disableAction, - saveOrderStats + saveOrderStats, + refreshOpenOrdersAndAccountInfo } = require('../../trailingTradeHelper/common'); const { @@ -228,6 +229,16 @@ const execute = async (logger, rawData) => { // Remove grid trade last order await removeGridTradeLastOrder(logger, symbols, symbol, 'buy'); + const { + accountInfo, + openOrders: updatedOpenOrders, + buyOpenOrders + } = await refreshOpenOrdersAndAccountInfo(logger, symbol); + + data.accountInfo = accountInfo; + data.openOrders = updatedOpenOrders; + data.buy.openOrders = buyOpenOrders; + slackMessageOrderFilled( logger, symbol, @@ -261,6 +272,16 @@ const execute = async (logger, rawData) => { // If order is no longer available, then delete from cache await removeGridTradeLastOrder(logger, symbols, symbol, 'buy'); + const { + accountInfo, + openOrders: updatedOpenOrders, + buyOpenOrders + } = await refreshOpenOrdersAndAccountInfo(logger, symbol); + + data.accountInfo = accountInfo; + data.openOrders = updatedOpenOrders; + data.buy.openOrders = buyOpenOrders; + slackMessageOrderDeleted( logger, symbol, @@ -291,6 +312,16 @@ const execute = async (logger, rawData) => { // Remove grid trade last order await removeGridTradeLastOrder(logger, symbols, symbol, 'sell'); + const { + accountInfo, + openOrders: updatedOpenOrders, + sellOpenOrders + } = await refreshOpenOrdersAndAccountInfo(logger, symbol); + + data.accountInfo = accountInfo; + data.openOrders = updatedOpenOrders; + data.sell.openOrders = sellOpenOrders; + slackMessageOrderFilled( logger, symbol, @@ -315,6 +346,16 @@ const execute = async (logger, rawData) => { // If order is no longer available, then delete from cache await removeGridTradeLastOrder(logger, symbols, symbol, 'sell'); + const { + accountInfo, + openOrders: updatedOpenOrders, + sellOpenOrders + } = await refreshOpenOrdersAndAccountInfo(logger, symbol); + + data.accountInfo = accountInfo; + data.openOrders = updatedOpenOrders; + data.sell.openOrders = sellOpenOrders; + slackMessageOrderDeleted( logger, symbol,