diff --git a/index.js b/index.js index c3aa951..edf93b5 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const _isEmpty = require('lodash/isEmpty') const _reverse = require('lodash/reverse') const _isFunction = require('lodash/isFunction') const _isPlainObject = require('lodash/isPlainObject') +const BigNumber = require('bignumber.js') const { candleWidth } = require('bfx-hf-util') const { subscribe } = require('bfx-api-node-core') @@ -40,20 +41,27 @@ class LiveStrategyExecution extends EventEmitter { * @param {string} args.strategyOpts.tf - time frame to execute on * @param {boolean} args.strategyOpts.includeTrades - if true, trade data is subscribed to and processed * @param {number} args.strategyOpts.seedCandleCount - size of indicator candle seed window, before which trading is disabled + * @param {object} args.priceFeed + * @param {object} args.perfManager */ constructor (args) { super() - const { strategy, ws2Manager, rest, strategyOpts } = args + const { strategy = {}, ws2Manager, rest, strategyOpts, priceFeed, perfManager } = args this.strategyState = { - ...(strategy || {}), + ...strategy, emit: this.emit.bind(this) } this.ws2Manager = ws2Manager || {} this.rest = rest || {} this.strategyOpts = strategyOpts || {} + this.priceFeed = priceFeed + this.perfManager = perfManager + + const { candlePrice = 'close' } = strategy + this.candlePrice = candlePrice this.lastCandle = null this.lastTrade = null @@ -64,6 +72,10 @@ class LiveStrategyExecution extends EventEmitter { this._registerManagerEventListeners() } + async invoke (strategyHandler) { + this.strategyState = await strategyHandler(this.strategyState) + } + /** * @private */ @@ -74,6 +86,7 @@ class LiveStrategyExecution extends EventEmitter { const { includeTrades, symbol, tf } = this.strategyOpts const candleKey = `trade:${tf}:${symbol}` + let lastUpdate = 0 if (includeTrades) { this.ws2Manager.onWS('trades', { symbol }, async (trades) => { @@ -81,6 +94,11 @@ class LiveStrategyExecution extends EventEmitter { return } + if (trades.mts > lastUpdate) { + this.priceFeed.update(new BigNumber(trades.price)) + lastUpdate = trades.mts + } + this._enqueueMessage('trade', trades) }) } @@ -94,6 +112,11 @@ class LiveStrategyExecution extends EventEmitter { candle.symbol = symbol candle.tf = tf + if (candle.mts > lastUpdate) { + this.priceFeed.update(new BigNumber(candle[this.candlePrice])) + lastUpdate = candle.mts + } + this._enqueueMessage('candle', candle) }) } @@ -193,7 +216,7 @@ class LiveStrategyExecution extends EventEmitter { const price = type === 'candle' ? data[candlePrice] : data.price const openPosition = getPosition(this.strategyState, symbol) - if (openPosition) { + if (openPosition && price) { openPosition.pl = positionPl(this.strategyState, symbol, price) this.emit('opened_position_data', openPosition) } @@ -283,6 +306,8 @@ class LiveStrategyExecution extends EventEmitter { await this._seedCandles() this._subscribeCandleAndTradeEvents() + + this.perfManager.on('update', () => this._emitStrategyExecutionResults('perf', this.priceFeed)) } /** @@ -340,6 +365,14 @@ class LiveStrategyExecution extends EventEmitter { const accumulatedPLs = strategyTrades.map(x => x.pl) const stdDeviation = std(accumulatedPLs.length > 0 ? accumulatedPLs : [0]) const avgPL = _sum(accumulatedPLs) / accumulatedPLs.length + const allocation = this.perfManager.allocation + const positionSize = this.perfManager.positionSize() + const currentAllocation = this.perfManager.currentAllocation() + const availableFunds = this.perfManager.availableFunds + const equityCurve = this.perfManager.equityCurve() + const ret = this.perfManager.return() + const retPerc = this.perfManager.returnPerc() + const drawdown = this.perfManager.drawdown() return { vol, @@ -364,6 +397,15 @@ class LiveStrategyExecution extends EventEmitter { minPL: _isNil(minPL) ? 0 : minPL, maxPL: _isNil(maxPL) ? 0 : maxPL, + allocation, + positionSize, + currentAllocation, + availableFunds, + equityCurve, + return: ret, + returnPerc: retPerc, + drawdown, + strategy: { trades: strategyTrades.map(t => ({ ...t, diff --git a/package.json b/package.json index 5e2f0be..8ef8cf6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bfx-hf-strategy-exec", - "version": "1.2.3", + "version": "1.3.0", "description": "Execution logic for bfx-hf-strategy", "main": "./index.js", "directories": { @@ -37,8 +37,9 @@ "dependencies": { "bfx-api-node-core": "^1.5.8", "bfx-api-node-util": "^1.0.2", - "bfx-hf-strategy": "git+https://github.com/bitfinexcom/bfx-hf-strategy.git#v1.2.4", + "bfx-hf-strategy": "git+https://github.com/bitfinexcom/bfx-hf-strategy.git#v1.3.0", "bfx-hf-util": "git+https://github.com/bitfinexcom/bfx-hf-util.git#v1.0.12", + "bignumber.js": "^9.0.2", "debug": "^4.3.3", "lodash": "^4.17.10", "mathjs": "^10.1.0",