gdax-sim
Version:
Simulator used to help unit test and back test various Coinbase-Pro (gdax) interactions.
186 lines (172 loc) • 4.9 kB
JavaScript
const crypto = require("crypto");
const Parse24Time = require("../Lib/Parse24Time");
const Heartbeat = require("./Heartbeat");
function createTempCandle() {
return {
time: null,
open: null,
high: -Infinity,
low: Infinity,
close: null,
volume: 0,
};
}
function getBucket(_time) {
let bucket = Math.floor(_time.getMinutes() / 15);
return bucket;
}
function createMatch(templateObj) {
let ret = {
type: "match",
side: templateObj.side,
size:
templateObj.size === undefined
? templateObj.filled_size
: templateObj.size,
price: templateObj.price.toString(),
time: templateObj.time,
product_id: templateObj.product_id,
trade_id: Math.round(100000000 * Math.random()),
sequence: Math.round(100000000 * Math.random()),
taker_order_id:
templateObj.taker_order_id !== undefined
? templateObj.taker_order_id
: crypto
.createHash("sha1")
.update(JSON.stringify(Math.random().toString()))
.digest("hex"),
maker_order_id:
templateObj.maker_order_id !== undefined
? templateObj.maker_order_id
: crypto
.createHash("sha1")
.update(JSON.stringify(Math.random().toString()))
.digest("hex"),
};
if (templateObj.isUser) ret.isUser = 1;
return ret;
}
function createMatchesFromCandle(
candlesArrayOrObj,
start_time = "0000",
end_time = "2460",
pair = "BTC-USD",
reduce_signals = false,
) {
let messages = [];
let candles =
candlesArrayOrObj.length === undefined
? [candlesArrayOrObj]
: candlesArrayOrObj;
let candleCount = candles.length;
let lastTime = null;
let start = Parse24Time(start_time);
let end = Parse24Time(end_time);
let afterStart = false;
let afterEnd = false;
let tmp = createTempCandle();
let lastBucket = -1;
for (let c = 0; c < candleCount; c++) {
let candle = candles[c];
let candleTime = new Date(candle.time);
if (
!afterStart &&
candleTime.getUTCHours() >= start.hours &&
candleTime.getMinutes() >= start.minutes
) {
afterStart = true;
}
if (
!afterEnd &&
candleTime.getUTCHours() >= end.hours &&
candleTime.getMinutes() >= end.minutes
) {
afterEnd = true;
}
if (afterStart && !afterEnd) {
if (lastTime !== null) {
while (lastTime + 60000 < candleTime.getTime() && !reduce_signals) {
lastTime += 60000;
messages.push(Heartbeat.create(pair, lastTime));
}
}
if (lastTime !== candleTime.getTime()) {
lastTime = candleTime.getTime();
let bucket = getBucket(candleTime);
if (lastBucket < 0) lastBucket = bucket;
if (reduce_signals && bucket !== lastBucket) {
tmp.time.setTime(
tmp.time.setTime(
tmp.time.getTime() -
60000 * (tmp.time.getMinutes() - lastBucket * 15),
),
);
messages = messages.concat(breakCandleIntoMatches(tmp, pair));
lastBucket = bucket;
tmp = createTempCandle();
}
//handle tmp candle
tmp.time = candleTime;
tmp.open = tmp.open || candle.open;
tmp.high = candle.high > tmp.high ? candle.high : tmp.high;
tmp.low = candle.low < tmp.low ? candle.low : tmp.low;
tmp.close = candle.close;
tmp.volume += parseFloat(candle.volume);
if (!reduce_signals || (reduce_signals && c === candleCount - 1)) {
messages = messages.concat(breakCandleIntoMatches(tmp, pair));
tmp = createTempCandle();
}
}
}
}
return messages;
}
function breakCandleIntoMatches(tmp, pair) {
let lastPrice = 0;
let messages = [];
for (let i = 0; i < 4; i++) {
let key;
switch (i) {
case 0:
key = "open";
break;
case 1:
if (tmp.close < tmp.open) {
key = "high";
} else {
key = "low";
}
break;
case 2:
if (tmp.close < tmp.open) {
key = "low";
} else {
key = "high";
}
break;
case 3:
key = "close";
break;
}
let side = "buy";
if (tmp[key] < lastPrice) {
side = "sell";
}
lastPrice = tmp[key];
messages.push(
createMatch({
side: side,
size: tmp.volume * 0.25,
time: tmp.time.toISOString(),
product_id: pair,
price: tmp[key],
}),
);
tmp.time.setTime(tmp.time.getTime() + 14000);
}
return messages;
}
module.exports = {
createMatch: createMatch,
createMatchesFromCandle: createMatchesFromCandle,
};