diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc31c01..7f172092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,10 @@ All notable changes to this project will be documented in this file. - Fixed the issue that cannot export huge logs - [#561](https://github.com/chrisleekr/binance-trading-bot/pull/561), [#567](https://github.com/chrisleekr/binance-trading-bot/pull/567) - Fixed the balance calculation to include dust balances by [@uhliksk](https://github.com/uhliksk) - [#571](https://github.com/chrisleekr/binance-trading-bot/pull/571) - Fixed the open orders to be cancelled when the current price is higher/lower than the order price by [@uhliksk](https://github.com/uhliksk) - [#569](https://github.com/chrisleekr/binance-trading-bot/pull/569) -- Improved queue processing by replacing Bull queue to customised queue system by [@uhliksk](https://github.com/uhliksk) - [#562](https://github.com/chrisleekr/binance-trading-bot/pull/562), [#581](https://github.com/chrisleekr/binance-trading-bot/pull/581) +- Improved queue processing by replacing Bull queue to customised queue system by [@uhliksk](https://github.com/uhliksk) - [#562](https://github.com/chrisleekr/binance-trading-bot/pull/562), [#581](https://github.com/chrisleekr/binance-trading-bot/pull/581) +- Added conservative sell strategy, which can reduce the sell trigger price as the grid gets deeper by [@rando128](https://github.com/rando128) - [#585](https://github.com/chrisleekr/binance-trading-bot/pull/585) -Thanks [@uhliksk](https://github.com/uhliksk) for your great contributions. 💯 :heart: +Thanks [@uhliksk](https://github.com/uhliksk) and [@rando128](https://github.com/rando128) for your great contributions. 💯 :heart: ## [0.0.96] - 2022-12-28 diff --git a/app/cronjob/trailingTrade/step/__tests__/get-indicators.test.js b/app/cronjob/trailingTrade/step/__tests__/get-indicators.test.js index 04e470a1..ca5d70fe 100644 --- a/app/cronjob/trailingTrade/step/__tests__/get-indicators.test.js +++ b/app/cronjob/trailingTrade/step/__tests__/get-indicators.test.js @@ -133,7 +133,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -177,6 +181,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -219,6 +227,8 @@ describe('get-indicators.js', () => { openOrders: [], stopLossDifference: null, stopLossTriggerPrice: null, + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, @@ -354,7 +364,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -398,6 +412,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -440,6 +458,8 @@ describe('get-indicators.js', () => { openOrders: [], stopLossDifference: null, stopLossTriggerPrice: null, + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, @@ -573,7 +593,11 @@ describe('get-indicators.js', () => { }, sell: { currentGridTrade: null, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -614,6 +638,10 @@ describe('get-indicators.js', () => { currentGridTrade: null, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -655,6 +683,8 @@ describe('get-indicators.js', () => { currentProfitPercentage: 72.83433333333333, stopLossDifference: 53.712900407519335, stopLossTriggerPrice: 7200, + conservativeModeApplicable: false, + triggerPercentage: null, openOrders: [], processMessage: '', updatedAt: expect.any(Object) @@ -710,7 +740,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -757,6 +791,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -799,6 +837,8 @@ describe('get-indicators.js', () => { stopLossDifference: 53.712900407519335, stopLossTriggerPrice: 7200, openOrders: [], + conservativeModeApplicable: false, + triggerPercentage: 1.06, processMessage: '', updatedAt: expect.any(Object) }, @@ -853,7 +893,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -900,6 +944,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -942,6 +990,177 @@ describe('get-indicators.js', () => { stopLossDifference: 53.712900407519335, stopLossTriggerPrice: 7200, openOrders: [], + conservativeModeApplicable: false, + triggerPercentage: 1.06, + processMessage: '', + updatedAt: expect.any(Object) + }, + tradingView: { + request: { + symbol: 'BTCUSDT', + screener: 'CRYPTO', + exchange: 'BINANCE', + interval: '15m' + }, + result: { + summary: { + RECOMMENDATION: 'SELL', + BUY: 4, + SELL: 14, + NEUTRAL: 8 + } + } + } + }); + }); + }); + + describe('when buy grid trade index is 1 and conservative mode enabled', () => { + beforeEach(async () => { + step = require('../get-indicators'); + + rawData = { + symbol: 'BTCUSDT', + symbolInfo: { + filterMinNotional: { minNotional: '10.000' } + }, + symbolConfiguration: { + candles: { limit: '100' }, + buy: { + currentGridTradeIndex: 1, + currentGridTrade: { + triggerPercentage: 1.01, + limitPercentage: 1.021 + }, + athRestriction: { + enabled: true, + restrictionPercentage: 0.9, + candles: { + interval: '1d', + limit: 30 + } + }, + gridTrade: [ + { + executed: true + }, + { + executed: true + } + ] + }, + sell: { + currentGridTrade: { + triggerPercentage: 1.06, + limitPercentage: 0.979 + }, + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: true, + factor: 0.5 + } + } + }, + baseAssetBalance: { total: 0.1 }, + openOrders: [] + }; + + result = await step.execute(loggerMock, rawData); + }); + + it('triggers getLastBuyPrice', () => { + expect(mockGetLastBuyPrice).toHaveBeenCalledWith( + loggerMock, + 'BTCUSDT' + ); + }); + + it('triggers expected value', () => { + expect(result).toStrictEqual({ + symbol: 'BTCUSDT', + symbolInfo: { + filterMinNotional: { minNotional: '10.000' } + }, + symbolConfiguration: { + candles: { limit: '100' }, + buy: { + currentGridTradeIndex: 1, + currentGridTrade: { + triggerPercentage: 1.01, + limitPercentage: 1.021 + }, + athRestriction: { + enabled: true, + restrictionPercentage: 0.9, + candles: { + interval: '1d', + limit: 30 + } + }, + gridTrade: [ + { + executed: true + }, + { + executed: true + } + ] + }, + sell: { + currentGridTrade: { + triggerPercentage: 1.06, + limitPercentage: 0.979 + }, + stopLoss: { + maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: true, + factor: 0.5 + } + } + }, + baseAssetBalance: { + total: 0.1, + estimatedValue: 1555.509, + isLessThanMinNotionalValue: false + }, + openOrders: [], + indicators: { + highestPrice: 10000, + lowestPrice: 8893.03, + athPrice: 9000 + }, + lastCandle: { + symbol: 'BTCUSDT', + close: '15555.09000000' + }, + buy: { + currentPrice: 15555.09, + limitPrice: 15881.746889999999, + highestPrice: 10000, + lowestPrice: 8893.03, + athPrice: 9000, + athRestrictionPrice: 8100, + triggerPrice: 9090, + difference: 71.12310231023102, + openOrders: [], + processMessage: '', + updatedAt: expect.any(Object) + }, + sell: { + currentPrice: 15555.09, + limitPrice: 15228.43311, + lastBuyPrice: 9000, + triggerPrice: 9270, + difference: 40.40535927468115, + currentProfit: 655.509, + currentProfitPercentage: 72.83433333333333, + stopLossDifference: 53.712900407519335, + stopLossTriggerPrice: 7200, + openOrders: [], + conservativeModeApplicable: true, + triggerPercentage: 1.03, processMessage: '', updatedAt: expect.any(Object) }, @@ -1077,7 +1296,11 @@ describe('get-indicators.js', () => { }, sell: { currentGridTrade: null, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -1148,6 +1371,10 @@ describe('get-indicators.js', () => { currentGridTrade: null, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -1275,6 +1502,8 @@ describe('get-indicators.js', () => { updatedAt: expect.any(Object) } ], + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, @@ -1329,7 +1558,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -1406,6 +1639,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -1533,6 +1770,8 @@ describe('get-indicators.js', () => { updatedAt: expect.any(Object) } ], + conservativeModeApplicable: false, + triggerPercentage: 1.06, processMessage: '', updatedAt: expect.any(Object) }, @@ -1587,7 +1826,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -1664,6 +1907,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -1791,6 +2038,292 @@ describe('get-indicators.js', () => { updatedAt: expect.any(Object) } ], + conservativeModeApplicable: false, + triggerPercentage: 1.06, + processMessage: '', + updatedAt: expect.any(Object) + }, + tradingView: { + request: { + symbol: 'BTCUSDT', + screener: 'CRYPTO', + exchange: 'BINANCE', + interval: '15m' + }, + result: { + summary: { + RECOMMENDATION: 'SELL', + BUY: 4, + SELL: 14, + NEUTRAL: 8 + } + } + } + }); + }); + }); + + describe('when buy grid trade index is 1 with conservative mode enabled', () => { + beforeEach(async () => { + step = require('../get-indicators'); + + rawData = { + symbol: 'BTCUSDT', + symbolInfo: { + filterMinNotional: { minNotional: '10.000' } + }, + symbolConfiguration: { + candles: { limit: '100' }, + buy: { + currentGridTradeIndex: 1, + currentGridTrade: { + triggerPercentage: 1.01, + limitPercentage: 1.021 + }, + athRestriction: { + enabled: true, + restrictionPercentage: 0.9, + candles: { + interval: '1d', + limit: 30 + } + }, + gridTrade: [ + { + executed: true + }, + { + executed: true + } + ] + }, + sell: { + currentGridTrade: { + triggerPercentage: 1.06, + limitPercentage: 0.979 + }, + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: true, + factor: 0.5 + } + } + }, + baseAssetBalance: { total: 0.1 }, + openOrders: [ + { + orderId: 1, + symbol: 'BTCUSDT', + type: 'LIMIT', + side: 'BUY', + price: '13000.000', + origQty: '0.005', + time: 1615465601162 + }, + { + orderId: 2, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'BUY', + price: '16000.000', + origQty: '0.005', + stopPrice: '16100.000', + time: 1615465601162 + }, + { + orderId: 3, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'SELL', + price: '16000.000', + origQty: '0.005', + stopPrice: '15900.000', + time: 1615465601162 + } + ] + }; + + result = await step.execute(loggerMock, rawData); + }); + + it('triggers getLastBuyPrice', () => { + expect(mockGetLastBuyPrice).toHaveBeenCalledWith( + loggerMock, + 'BTCUSDT' + ); + }); + + it('triggers expected value', () => { + expect(result).toStrictEqual({ + symbol: 'BTCUSDT', + symbolInfo: { + filterMinNotional: { minNotional: '10.000' } + }, + symbolConfiguration: { + candles: { limit: '100' }, + buy: { + currentGridTradeIndex: 1, + currentGridTrade: { + triggerPercentage: 1.01, + limitPercentage: 1.021 + }, + athRestriction: { + enabled: true, + restrictionPercentage: 0.9, + candles: { + interval: '1d', + limit: 30 + } + }, + gridTrade: [ + { + executed: true + }, + { + executed: true + } + ] + }, + sell: { + currentGridTrade: { + triggerPercentage: 1.06, + limitPercentage: 0.979 + }, + stopLoss: { + maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: true, + factor: 0.5 + } + } + }, + baseAssetBalance: { + total: 0.1, + estimatedValue: 1555.509, + isLessThanMinNotionalValue: false + }, + openOrders: [ + { + orderId: 1, + symbol: 'BTCUSDT', + type: 'LIMIT', + side: 'BUY', + price: '13000.000', + origQty: '0.005', + time: 1615465601162, + currentPrice: 15555.09, + updatedAt: expect.any(Object) + }, + { + orderId: 2, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'BUY', + price: '16000.000', + origQty: '0.005', + stopPrice: '16100.000', + time: 1615465601162, + currentPrice: 15555.09, + differenceToCancel: -1.37423868741684, + differenceToExecute: -3.5030976998525976, + updatedAt: expect.any(Object) + }, + { + orderId: 3, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'SELL', + price: '16000.000', + origQty: '0.005', + stopPrice: '15900.000', + time: 1615465601162, + currentPrice: 15555.09, + differenceToCancel: -4.40995396669539, + differenceToExecute: -2.2173449333947826, + minimumProfit: 35, + minimumProfitPercentage: 77.77777777777777, + updatedAt: expect.any(Object) + } + ], + indicators: { + highestPrice: 10000, + lowestPrice: 8893.03, + athPrice: 9000 + }, + lastCandle: { + symbol: 'BTCUSDT', + close: '15555.09000000' + }, + buy: { + currentPrice: 15555.09, + limitPrice: 15881.746889999999, + highestPrice: 10000, + lowestPrice: 8893.03, + athPrice: 9000, + athRestrictionPrice: 8100, + triggerPrice: 9090, + difference: 71.12310231023102, + openOrders: [ + { + orderId: 1, + symbol: 'BTCUSDT', + type: 'LIMIT', + side: 'BUY', + price: '13000.000', + origQty: '0.005', + time: 1615465601162, + currentPrice: 15555.09, + updatedAt: expect.any(Object) + }, + { + orderId: 2, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'BUY', + price: '16000.000', + origQty: '0.005', + stopPrice: '16100.000', + time: 1615465601162, + currentPrice: 15555.09, + differenceToCancel: -1.37423868741684, + differenceToExecute: -3.5030976998525976, + updatedAt: expect.any(Object) + } + ], + processMessage: '', + updatedAt: expect.any(Object) + }, + sell: { + currentPrice: 15555.09, + limitPrice: 15228.43311, + lastBuyPrice: 9000, + triggerPrice: 9270, + difference: 40.40535927468115, + currentProfit: 655.509, + currentProfitPercentage: 72.83433333333333, + stopLossDifference: 53.712900407519335, + stopLossTriggerPrice: 7200, + openOrders: [ + { + orderId: 3, + symbol: 'BTCUSDT', + type: 'STOP_LOSS_LIMIT', + side: 'SELL', + price: '16000.000', + origQty: '0.005', + stopPrice: '15900.000', + time: 1615465601162, + currentPrice: 15555.09, + differenceToCancel: -4.40995396669539, + differenceToExecute: -2.2173449333947826, + minimumProfit: 35, + minimumProfitPercentage: 77.77777777777777, + updatedAt: expect.any(Object) + } + ], + conservativeModeApplicable: true, + triggerPercentage: 1.03, processMessage: '', updatedAt: expect.any(Object) }, @@ -1926,7 +2459,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { @@ -1998,6 +2535,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -2125,6 +2666,8 @@ describe('get-indicators.js', () => { updatedAt: expect.any(Object) } ], + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, @@ -2260,7 +2803,11 @@ describe('get-indicators.js', () => { triggerPercentage: 0.99, limitPercentage: 0.98 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { @@ -2308,6 +2855,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -2350,6 +2901,8 @@ describe('get-indicators.js', () => { stopLossDifference: null, stopLossTriggerPrice: null, openOrders: [], + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: 'World', updatedAt: expect.any(Object) }, @@ -2425,7 +2978,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -2463,7 +3020,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -2558,7 +3119,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { total: 0.1 }, @@ -2598,6 +3163,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -2642,6 +3211,8 @@ describe('get-indicators.js', () => { stopLossDifference: null, stopLossTriggerPrice: null, openOrders: [], + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, @@ -2742,7 +3313,11 @@ describe('get-indicators.js', () => { triggerPercentage: 1.06, limitPercentage: 0.979 }, - stopLoss: { maxLossPercentage: 0.8 } + stopLoss: { maxLossPercentage: 0.8 }, + conservativeMode: { + enabled: false, + factor: 0.5 + } } }, baseAssetBalance: { @@ -2784,6 +3359,10 @@ describe('get-indicators.js', () => { }, stopLoss: { maxLossPercentage: 0.8 + }, + conservativeMode: { + enabled: false, + factor: 0.5 } } }, @@ -2826,6 +3405,8 @@ describe('get-indicators.js', () => { stopLossDifference: null, stopLossTriggerPrice: null, openOrders: [], + conservativeModeApplicable: false, + triggerPercentage: null, processMessage: '', updatedAt: expect.any(Object) }, diff --git a/app/cronjob/trailingTrade/step/get-indicators.js b/app/cronjob/trailingTrade/step/get-indicators.js index 54c7d013..b90604e1 100644 --- a/app/cronjob/trailingTrade/step/get-indicators.js +++ b/app/cronjob/trailingTrade/step/get-indicators.js @@ -49,6 +49,7 @@ const execute = async (logger, rawData) => { buy: { currentGridTradeIndex: currentBuyGridTradeIndex, currentGridTrade: currentBuyGridTrade, + gridTrade: buyGridTrade, athRestriction: { enabled: buyATHRestrictionEnabled, candles: { @@ -60,7 +61,11 @@ const execute = async (logger, rawData) => { }, sell: { currentGridTrade: currentSellGridTrade, - stopLoss: { maxLossPercentage: sellMaxLossPercentage } + stopLoss: { maxLossPercentage: sellMaxLossPercentage }, + conservativeMode: { + enabled: conservativeModeEnabled, + factor: conservativeFactor + } } }, baseAssetBalance: { total: baseAssetTotalBalance }, @@ -224,6 +229,8 @@ const execute = async (logger, rawData) => { let sellTriggerPrice = null; let sellDifference = null; let sellLimitPrice = null; + let conservativeModeApplicable = false; + let triggerPercentage = null; if (lastBuyPrice > 0 && currentSellGridTrade !== null) { const { @@ -231,7 +238,21 @@ const execute = async (logger, rawData) => { limitPercentage: sellLimitPercentage } = currentSellGridTrade; - sellTriggerPrice = lastBuyPrice * sellTriggerPercentage; + const lastExecutedBuyTradeIndex = _.findLastIndex( + buyGridTrade, + trade => trade.executed === true + ); + + conservativeModeApplicable = + conservativeModeEnabled && lastExecutedBuyTradeIndex >= 1; + + triggerPercentage = conservativeModeApplicable + ? 1 + + (sellTriggerPercentage - 1) * + conservativeFactor ** lastExecutedBuyTradeIndex + : sellTriggerPercentage; + + sellTriggerPrice = lastBuyPrice * triggerPercentage; sellDifference = (1 - sellTriggerPrice / currentPrice) * 100; sellLimitPrice = currentPrice * sellLimitPercentage; } @@ -326,6 +347,8 @@ const execute = async (logger, rawData) => { stopLossDifference: sellStopLossDifference, currentProfit: sellCurrentProfit, currentProfitPercentage: sellCurrentProfitPercentage, + conservativeModeApplicable, + triggerPercentage, openOrders: newOpenOrders?.filter(o => o.side.toLowerCase() === 'sell'), processMessage: _.get(data, 'sell.processMessage', ''), updatedAt: moment().utc().toDate() diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json index b890d921..26f8e755 100644 --- a/config/custom-environment-variables.json +++ b/config/custom-environment-variables.json @@ -311,6 +311,18 @@ "__format": "boolean" } } + }, + "conservativeMode": { + "enabled": { + "__name": "BINANCE_JOBS_TRAILING_TRADE_SELL_CONSERVATIVE_MODE_ENABLED", + "__description": "Set a boolean for selling at a trigger price reduced by the conservative ratio for each executed buy grid. You can use this feature in bear market conditions to secure smaller benefits over unreached higher gains. At least 2 buy trades must have been executed for the ratio to be applied.", + "__format": "boolean" + }, + "factor": { + "__name": "BINANCE_JOBS_TRAILING_TRADE_SELL_CONSERVATIVE_MODE_FACTOR", + "__description": "Set the conservative factor to be applied on sell trades with at least 2 executed buy grids.", + "__format": "number" + } } }, "system": { diff --git a/config/default.json b/config/default.json index 1fc19e30..fffa98f6 100644 --- a/config/default.json +++ b/config/default.json @@ -144,6 +144,10 @@ "whenSell": false, "whenStrongSell": false } + }, + "conservativeMode": { + "enabled": false, + "factor": 0.5 } }, "system": { diff --git a/migrations/1672576246043-flush-configuration-cache.js b/migrations/1672576246043-flush-configuration-cache.js new file mode 100644 index 00000000..2688f610 --- /dev/null +++ b/migrations/1672576246043-flush-configuration-cache.js @@ -0,0 +1,19 @@ +const path = require('path'); +const { logger: rootLogger, cache } = require('../app/helpers'); + +module.exports.up = async () => { + const logger = rootLogger.child({ + gitHash: process.env.GIT_HASH || 'unspecified', + migration: path.basename(__filename) + }); + + logger.info('Start migration'); + + cache.hdelall('trailing-trade-configurations:*'); + + logger.info('Finish migration'); +}; + +module.exports.down = next => { + next(); +}; diff --git a/public/js/CoinWrapperSellSignal.js b/public/js/CoinWrapperSellSignal.js index 4e2f1368..686a99f6 100644 --- a/public/js/CoinWrapperSellSignal.js +++ b/public/js/CoinWrapperSellSignal.js @@ -160,9 +160,13 @@ class CoinWrapperSellSignal extends React.Component {
0.90
, your
+ current grid sell percentage
+ will be reduced by{' '}
+ 10%
for each
+ executed buy grid (except the
+ first one). For example, if
+ your sell trigger percentage
+ is 1.10
, and you
+ have 3 executed buy grids, the
+ sell order trigger will be{' '}
+ 1.081
. Remember
+ the sell trigger is not
+ modified if you have only 1
+ executed buy grid.
+ 0.90
, your
+ current grid sell percentage
+ will be reduced by{' '}
+ 10%
for each
+ executed buy grid (except the
+ first one). For example, if
+ your sell trigger percentage
+ is 1.10
, and you
+ have 3 executed buy grids, the
+ sell order trigger will be{' '}
+ 1.081
. Remember
+ the sell trigger is not
+ modified if you have only 1
+ executed buy grid.
+