-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.js
125 lines (95 loc) · 2.81 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
'use strict'
const debug = require('debug')('bfx:hf:strategy-dazaar')
const {
onSeedCandle, onCandle, onTrade
} = require('bfx-hf-strategy')
const { Candle, Trade } = require('bfx-api-node-models')
const { candleWidth } = require('bfx-hf-util')
const FilterCandles = require('./lib/filter_stream.js')
const _isTrade = (k, v) => {
return k.candle === null
}
/**
* Executes a backtest on a dazaar market data stream, logs results to the
* console.
*
* @param {Object[]} strategy
* @param {Object} market
* @param {Object} args
* @param {Function?} args.isTrade - optional, function to detect a trade vs. a candle
*/
const execStream = async (strategy = {}, market, db, args = {}) => {
const isTrade = args.isTrade || _isTrade
const {
submitOrder,
seedCandleCount,
backtesting,
simulateFill
} = args
let state = {
backtesting: backtesting || false,
simulateFill,
submitOrder,
trades: [],
...strategy
}
if (!market.tf) throw new Error('ERR_MISSING_TF')
const exec = getExec(market, state, isTrade, args)
if (typeof seedCandleCount === 'number' && seedCandleCount !== 0) {
state = await seedState(state, db, exec, market, args)
}
const { stream } = getStream(db, market, args)
return { exec, state, stream }
}
function getStream (db, market, args) {
const { tf } = market
const since = db.feed.length
const hs = db.createHistoryStream({
gt: since,
live: true
})
const ts = new FilterCandles({ key: tf })
const stream = hs.pipe(ts)
return { stream }
}
async function seedState (strategyState, db, exec, market, args) {
const { seedCandleCount } = args
const { tf } = market
const cWidth = candleWidth(tf)
const now = Date.now()
const since = new Date(now - (Math.abs(seedCandleCount) * cWidth))
debug('seeding with last ~%d candles...', seedCandleCount)
debug('seeding starting from', since)
const hs = db.createReadStream({
gt: { candle: tf, timestamp: since },
lt: { candle: tf, timestamp: now },
limit: seedCandleCount
})
for await (const data of hs) {
strategyState = await exec(data.key, data.value, { isSeed: true })
}
debug('seeding complete')
return strategyState
}
function getExec (market, strategyState, isTrade, args) {
const { symbol, tf } = market
const { includeTrades } = args
return async function (k, el, opts = {}) {
const isSeed = opts.isSeed || false
if (includeTrades && isTrade(k, el)) {
const t = new Trade(el)
strategyState = await onTrade(strategyState, t)
return strategyState
}
const c = new Candle(el)
c.tf = tf
c.symbol = symbol
if (isSeed) {
strategyState = await onSeedCandle(strategyState, c)
} else {
strategyState = await onCandle(strategyState, c)
}
return strategyState
}
}
module.exports = execStream