Skip to content

Commit

Permalink
Merge pull request #1 from f3rno/master
Browse files Browse the repository at this point in the history
v1.0.0: (initial import from bfx-hf-strategy)
  • Loading branch information
prdn authored Sep 9, 2019
2 parents 2ab4e6e + 4e9ff51 commit 4b12709
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.idea
dist/*
node_modules
npm-debug.log
.vscode
*.swo
*.swp
.DS_Store
db/*.sql
.env
scripts/*
!db/.keep
db/*
package-lock.json
163 changes: 163 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
'use strict'

const debug = require('debug')('hf:strategy:exec')
const { subscribe } = require('bfx-api-node-core')
const { padCandles } = require('bfx-api-node-util')
const { candleWidth } = require('bfx-hf-util')
const _isEmpty = require('lodash/isEmpty')
const _reverse = require('lodash/reverse')
const PromiseThrottle = require('promise-throttle')

const {
onSeedCandle, onCandle, onCandleUpdate, onTrade, indicatorValues
} = require('bfx-hf-strategy')

const CANDLE_FETCH_LIMIT = 1000
const pt = new PromiseThrottle({
requestsPerSecond: 10.0 / 60.0, // taken from docs
promiseImplementation: Promise
})

module.exports = async (strategy = {}, wsManager = {}, args = {}) => {
const { symbol, tf, includeTrades, seedCandleCount = 5000 } = args
const candleKey = `trade:${tf}:${symbol}`
const messages = []
let strategyState = strategy
let lastCandle = null
let processing = false

debug('seeding with last ~%d candles...', seedCandleCount)

const cWidth = candleWidth(tf)
const now = Date.now()
const seedStart = now - (seedCandleCount * cWidth)

for (let i = 0; i < Math.ceil(seedCandleCount / CANDLE_FETCH_LIMIT); i += 1) {
let seededCandles = 0
let candle

const start = seedStart + (i * 1000 * cWidth)
const end = Math.min(seedStart + ((i + 1) * 1000 * cWidth), now)

const candleResponse = await pt.add(
wsManager.rest.candles.bind(wsManager.rest, ({
symbol,
timeframe: tf,
query: {
limit: CANDLE_FETCH_LIMIT,
start,
end,
}
}))
)

const candles = _reverse(padCandles(candleResponse, cWidth))

for (let i = 0; i < candles.length; i += 1) {
candle = candles[i]

if (lastCandle && lastCandle.mts >= candle.mts) {
continue
}

candle.tf = tf
candle.symbol = symbol

strategyState = await onSeedCandle(strategyState, candle)
lastCandle = candle
seededCandles += 1
}

debug(
'seeded with %d candles from %s - %s',
seededCandles, new Date(start).toLocaleString(), new Date(end).toLocaleString()
)
}

const enqueMessage = (type, data) => {
debug('enqueue %s', type)

messages.push({ type, data })

if (!processing) {
processMessages().catch((err) => {
debug('error processing: %s', err.stack)
})
}
}

const processMessage = async (msg) => {
const { type, data } = msg

switch (type) {
case 'trade': {
debug('recv trade: %j', data)
strategyState = await onTrade(strategyState, data)
break
}

case 'candle': {
if (lastCandle === null || lastCandle.mts < data.mts) {
debug('recv candle %j', data)
strategyState = await onCandle(strategyState, data)
lastCandle = data
} else if (lastCandle.mts === data.mts) {
debug('updated candle %j', data)
strategyState = await onCandleUpdate(strategyState, data)
}

break
}

default: {
debug('unknown message type: %s', type)
}
}
}

const processMessages = async () => {
processing = true

while (!_isEmpty(messages)) {
const [ msg ] = messages.splice(0, 1)

await processMessage(msg)
}

processing = false
}


if (includeTrades) {
wsManager.onWS('trades', { symbol }, async (trades) => {
if (trades.length > 1) { // we don't pass snapshots through
return
}

const [trade] = trades
enqueMessage('trade', trade)
})
}

wsManager.onWS('candles', { key: candleKey }, async (candles) => {
if (candles.length > 1) { // seeding happens at start via RESTv2
return
}

const [candle] = candles
candle.symbol = symbol
candle.tf = tf

enqueMessage('candle', candle)
})

wsManager.withSocket((socket) => {
let nextSocket = subscribe(socket, 'candles', { key: candleKey })

if (includeTrades) {
nextSocket = subscribe(nextSocket, 'trades', { symbol })
}

return nextSocket
})
}
74 changes: 74 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "bfx-hf-strategy-exec",
"version": "1.0.0",
"description": "Execution logic for bfx-hf-strategy",
"main": "./index.js",
"directories": {
"lib": "lib"
},
"author": "Cris Mihalache <[email protected]> (https://www.bitfinex.com)",
"license": "Apache-2.0",
"scripts": {
"build": "babel -q ./index.js -d ./dist && copy package.json dist",
"test": "NODE_ENV=test BABEL_ENV=test node_modules/tape-watch/bin/tape-watch -r babel-register ./test/*.spec.js | faucet",
"postinstall": "npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/f3rno/bfx-hf-strategy-exec.git"
},
"bugs": {
"url": "https://github.com/f3rno/bfx-hf-strategy-exec/issues"
},
"keywords": [
"honey framework",
"bitfinex",
"bitcoin",
"BTC"
],
"dependencies": {
"babel-core": "^6.26.3",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-plugin-transform-regenerator": "^6.24.1",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"bfx-api-node-core": "^1.0.0",
"bfx-api-node-util": "^1.0.0",
"bfx-hf-indicators": "^1.0.0",
"bfx-hf-strategy": "^1.0.0-alpha.2",
"bfx-hf-util": "^1.0.0",
"copy": "^0.3.1",
"lodash": "^4.17.10",
"p-iteration": "^1.1.8",
"promise-throttle": "^1.0.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-eslint": "^7.2.2",
"babel-loader": "^6.4.1",
"babel-plugin-import-directory": "^1.0.3",
"babel-plugin-lodash": "^3.2.11",
"babel-preset-env": "^1.4.0",
"babel-preset-stage-0": "^6.24.1",
"bitfinex-api-node": "^2.0.0",
"cli-table": "^0.3.1",
"colors": "^1.3.1",
"compression-webpack-plugin": "^0.4.0",
"create-index": "^2.3.0",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-config-standard": "^7.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^2.0.1",
"faucet": "^0.0.1",
"moment": "^2.22.2",
"sprintf-js": "^1.1.1",
"tape": "^4.6.3",
"tape-watch": "^2.3.0",
"webpack": "^2.4.1",
"yargs": "6.6.0"
}
}

0 comments on commit 4b12709

Please sign in to comment.