From 6d8cbbd98c014137b69d1f45315d0f273bdb34e3 Mon Sep 17 00:00:00 2001 From: develoQ Date: Sat, 9 Jan 2021 00:19:08 +0900 Subject: [PATCH 1/8] Add exchange GMO Coin --- .github/workflows/node.yml | 1 + README.md | 1 + __tests__/exchanges/gmocoin-client.spec.js | 81 ++++++++++ src/exchanges/gmocoin-client.js | 180 +++++++++++++++++++++ src/index.js | 3 + 5 files changed, 266 insertions(+) create mode 100644 __tests__/exchanges/gmocoin-client.spec.js create mode 100644 src/exchanges/gmocoin-client.js diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index a0e1bd1e..447010b2 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -62,6 +62,7 @@ jobs: - ftx-us - gateio - gemini + - gmocoin - hitbtc - huobi - huobi-futures diff --git a/README.md b/README.md index 64658268..d6987609 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ binance.subscribeLevel2Snapshots(market); | FTX US | 1 | FtxUs | ✓ | ✓ | - | - | ✓\* | - | - | | Gate.io | 3 | Gateio | ✓ | ✓ | - | - | ✓\* | - | - | | Gemini | 1 | Gemini | - | ✓ | - | - | ✓\* | - | - | +| GMOCoin | 1 | GMOCoin | ✓ | ✓ | - | ✓ | - | - | - | | HitBTC | 2 | HitBTC | ✓ | ✓ | ✓ | - | ✓\* | - | - | | Huobi Global | 1 | Huobi | ✓ | ✓ | ✓ | ✓ | - | - | - | | Huobi Global Futures | 1 | HuobiFutures | ✓ | ✓ | ✓ | ✓ | ✓\* | - | - | diff --git a/__tests__/exchanges/gmocoin-client.spec.js b/__tests__/exchanges/gmocoin-client.spec.js new file mode 100644 index 00000000..e7909118 --- /dev/null +++ b/__tests__/exchanges/gmocoin-client.spec.js @@ -0,0 +1,81 @@ +const { testClient } = require("../test-runner"); +const GMOCoinClient = require("../../src/exchanges/gmocoin-client"); + +testClient({ + clientFactory: () => new GMOCoinClient(), + clientName: "GMOCoinClient", + exchangeName: "GMOCoin", + markets: [ + { + id: "BTC", + base: "BTC", + quote: "JPY", + }, + { + id: "ETH", + base: "XRP", + quote: "JPY", + }, + { + id: "BCH", + base: "XRP", + quote: "JPY", + }, + { + id: "LTC", + base: "XRP", + quote: "JPY", + }, + { + id: "XRP", + base: "XRP", + quote: "JPY", + }, + ], + + testConnectEvents: false, + testDisconnectEvents: false, + testReconnectionEvents: false, + testCloseEvents: false, + + hasTickers: true, + hasTrades: true, + hasCandles: false, + hasLevel2Snapshots: true, + hasLevel2Updates: false, + hasLevel3Snapshots: false, + hasLevel3Updates: false, + + ticker: { + hasTimestamp: true, + hasLast: true, + hasOpen: false, + hasHigh: true, + hasLow: true, + hasVolume: true, + hasQuoteVolume: false, + hasChange: false, + hasChangePercent: false, + hasBid: true, + hasBidVolume: false, + hasAsk: true, + hasAskVolume: false, + }, + + trade: { + hasTradeId: false, + }, + + l2snapshot: { + hasTimestampMs: true, + hasSequenceId: false, + hasCount: false, + }, + + l2update: { + hasSnapshot: true, + hasTimestampMs: false, + hasSequenceId: false, + hasCount: false, + }, +}); diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js new file mode 100644 index 00000000..e862f5ec --- /dev/null +++ b/src/exchanges/gmocoin-client.js @@ -0,0 +1,180 @@ +const BasicClient = require("../basic-client"); +const BasicMultiClient = require("../basic-multiclient"); +const Ticker = require("../ticker"); +const Trade = require("../trade"); +const Level2Point = require("../level2-point"); +const Level2Snapshot = require("../level2-snapshot"); +const moment = require("moment"); + +class GMOCoinClient extends BasicMultiClient { + constructor(options = {}) { + super(); + this.options = options; + this.hasTickers = true; + this.hasTrades = true; + this.hasLevel2Snapshots = true; + } + + _createBasicClient() { + return new GMOCoinSingleClient({ ...this.options, parent: this }); + } +} +class GMOCoinSingleClient extends BasicClient { + constructor({ wssPath = "wss://api.coin.z.com/ws/public/v1", watcherMs, parent } = {}) { + super(wssPath, "GMOCoin", undefined, watcherMs); + + this.hasTickers = true; + this.hasTrades = true; + this.hasLevel2Snapshots = true; + this.parent = parent; + } + + _sendPong(id) { + this._wss.send(JSON.stringify({ pong: id })); + } + + _sendSubTicker(remote_id) { + this._wss.send( + JSON.stringify({ + command: "subscribe", + channel: "ticker", + symbol: remote_id, + }) + ); + } + + _sendUnsubTicker(remote_id) { + this._wss.send( + JSON.stringify({ + command: "unsubscribe", + channel: "ticker", + symbol: remote_id, + }) + ); + } + + _sendSubTrades(remote_id) { + this._wss.send( + JSON.stringify({ + command: "subscribe", + channel: "trades", + symbol: remote_id, + // option:'TAKER_ONLY' + }) + ); + } + + _sendUnsubTrades(remote_id) { + this._wss.send( + JSON.stringify({ + command: "unsubscribe", + channel: "trades", + symbol: remote_id, + // option:'TAKER_ONLY' + }) + ); + } + + _sendSubLevel2Snapshots(remote_id) { + this._wss.send( + JSON.stringify({ + command: "subscribe", + channel: "orderbooks", + symbol: remote_id, + }) + ); + } + + _sendUnsubLevel2Snapshots(remote_id) { + this._wss.send( + JSON.stringify({ + command: "unsubscribe", + channel: "orderbooks", + symbol: remote_id, + }) + ); + } + + _onMessage(raw) { + let msg = JSON.parse(raw); + + if (msg.ping) { + this._sendPong(msg.ping); + return; + } + + // tickers + if (msg.channel === "ticker") { + let market = this._tickerSubs.get(msg.symbol); + if (!market) return; + + let ticker = this._constructTicker(msg, market); + this.emit("ticker", ticker, market); + return; + } + + // trade + if (msg.channel === "trades") { + let market = this._tradeSubs.get(msg.symbol); + if (!market) return; + + let trade = this._constructTrade(msg, market); + this.emit("trade", trade, market); + return; + } + + // l2 snapshot + if (msg.channel === "orderbooks") { + let market = this._level2SnapshotSubs.get(msg.symbol); + if (!market) return; + + let snapshot = this._constructLevel2Snapshot(msg, market); + this.emit("l2snapshot", snapshot, market); + return; + } + } + + _constructTicker(msg, market) { + let { ask, bid, high, last, low, timestamp, volume } = msg; + return new Ticker({ + exchange: this._name, + base: market.base, + quote: market.quote, + timestamp: moment.utc(timestamp).valueOf(), + last: last, + high: high, + low: low, + volume: volume, + bid, + ask, + }); + } + + _constructTrade(datum, market) { + let { price, side, size, timestamp } = datum; + let unix = moment(timestamp).valueOf(); + return new Trade({ + exchange: this._name, + base: market.base, + quote: market.quote, + side: side.toLowerCase(), + unix, + price: price, + amount: size, + }); + } + + _constructLevel2Snapshot(msg, market) { + let asks = msg.asks.map(p => new Level2Point(p.price, p.size)); + let bids = msg.bids.map(p => new Level2Point(p.price, p.size)); + return new Level2Snapshot({ + exchange: this._name, + base: market.base, + quote: market.quote, + timestampMs: moment.utc(msg.timestamp).valueOf(), + asks, + bids, + }); + } +} +module.exports = GMOCoinClient; diff --git a/src/index.js b/src/index.js index 0f31505a..48fbebd7 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,7 @@ const ethfinex = require("./exchanges/ethfinex-client"); const ftx = require("./exchanges/ftx-client"); const gateio = require("./exchanges/gateio-client"); const gemini = require("./exchanges/gemini-client"); +const gmocoin = require("./exchanges/gmocoin-client"); const hitbtc = require("./exchanges/hitbtc-client"); const huobi = require("./exchanges/huobi-client"); const kucoin = require("./exchanges/kucoin-client"); @@ -42,6 +43,7 @@ module.exports = { ftx, gateio, gemini, + gmocoin, hitbtc, hitbtc2: hitbtc, huobi, @@ -79,6 +81,7 @@ module.exports = { FtxUs: require("./exchanges/ftx-us-client"), Gateio: gateio, Gemini: gemini, + GMOCoin: gmocoin, HitBTC: hitbtc, Huobi: huobi, HuobiFutures: require("./exchanges/huobi-futures-client"), From 56c53e381f794a699aaf41a012ea1406999b9087 Mon Sep 17 00:00:00 2001 From: develoQ Date: Sat, 9 Jan 2021 15:33:56 +0900 Subject: [PATCH 2/8] fix market base currency at test --- __tests__/exchanges/gmocoin-client.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/exchanges/gmocoin-client.spec.js b/__tests__/exchanges/gmocoin-client.spec.js index e7909118..ba625a04 100644 --- a/__tests__/exchanges/gmocoin-client.spec.js +++ b/__tests__/exchanges/gmocoin-client.spec.js @@ -13,17 +13,17 @@ testClient({ }, { id: "ETH", - base: "XRP", + base: "ETH", quote: "JPY", }, { id: "BCH", - base: "XRP", + base: "BCH", quote: "JPY", }, { id: "LTC", - base: "XRP", + base: "LTC", quote: "JPY", }, { From 10a47ddb3cdbae5fa4f4d76294f882dde4077e4b Mon Sep 17 00:00:00 2001 From: develoQ Date: Sat, 9 Jan 2021 22:42:15 +0900 Subject: [PATCH 3/8] fix multiClient name --- src/exchanges/gmocoin-client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index e862f5ec..f09f4b62 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -9,6 +9,7 @@ const moment = require("moment"); class GMOCoinClient extends BasicMultiClient { constructor(options = {}) { super(); + this._name = "GMOCoin"; this.options = options; this.hasTickers = true; this.hasTrades = true; From dfb2dc533fb89e6225cd7c88cdde324aca9b1f2d Mon Sep 17 00:00:00 2001 From: develoQ Date: Sun, 10 Jan 2021 02:24:16 +0900 Subject: [PATCH 4/8] fix one channnel to one websocket --- src/exchanges/gmocoin-client.js | 125 ++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index f09f4b62..6fbb07ee 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -1,10 +1,12 @@ const BasicClient = require("../basic-client"); const BasicMultiClient = require("../basic-multiclient"); +const { MarketObjectTypes } = require("../enums"); const Ticker = require("../ticker"); const Trade = require("../trade"); const Level2Point = require("../level2-point"); const Level2Snapshot = require("../level2-snapshot"); const moment = require("moment"); +const { wait } = require("../util"); class GMOCoinClient extends BasicMultiClient { constructor(options = {}) { @@ -19,6 +21,129 @@ class GMOCoinClient extends BasicMultiClient { _createBasicClient() { return new GMOCoinSingleClient({ ...this.options, parent: this }); } + + async unsubscribeTicker(market) { + if (!this.hasTickers) return; + let key; + this._clients.keys(k => { + if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.ticker) { + key = k; + return; + } + }); + + if (this._clients.has(key)) { + (await this._clients.get(key)).unsubscribeTicker(market); + } + } + + async unsubscribeTrades(market) { + if (!this.hasTrades) return; + let key; + this._clients.keys(k => { + if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.trade) { + key = k; + return; + } + }); + + if (this._clients.has(key)) { + (await this._clients.get(key)).unsubscribeTrades(market); + } + } + + async unsubscribeLevel2Snapshots(market) { + if (!this.hasLevel2Snapshots) return; + let key; + this._clients.keys(k => { + if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.level2snapshot) { + key = k; + return; + } + }); + + if (this._clients.has(key)) { + (await this._clients.get(key)).unsubscribeLevel2Snapshots(market); + } + } + + async _subscribe(market, map, marketObjectType) { + try { + let remote_id = market.id; + let client = null; + let key; + map.keys(k => { + if ( + key.remote_id === remote_id && + key.marketObjectType == MarketObjectTypes.level2snapshot + ) { + key = k; + return; + } + }); + // construct a client + if (!map.has(key)) { + let clientArgs = { auth: this.auth, market: market }; + client = this._createBasicClientThrottled(clientArgs); + // we MUST store the promise in here otherwise we will stack up duplicates + map.set(key, client); + } + + // wait for client to be made! + client = await map.get(key); + await wait(1000); + + if (marketObjectType === MarketObjectTypes.ticker) { + let subscribed = client.subscribeTicker(market); + if (subscribed) { + client.on("ticker", (ticker, market) => { + this.emit("ticker", ticker, market); + }); + } + } + + if (marketObjectType === MarketObjectTypes.candle) { + let subscribed = client.subscribeCandles(market); + if (subscribed) { + client.on("candle", (candle, market) => { + this.emit("candle", candle, market); + }); + } + } + + if (marketObjectType === MarketObjectTypes.trade) { + let subscribed = client.subscribeTrades(market); + if (subscribed) { + client.on("trade", (trade, market) => { + this.emit("trade", trade, market); + }); + } + } + + if (marketObjectType === MarketObjectTypes.level2update) { + let subscribed = client.subscribeLevel2Updates(market); + if (subscribed) { + client.on("l2update", (l2update, market) => { + this.emit("l2update", l2update, market); + }); + client.on("l2snapshot", (l2snapshot, market) => { + this.emit("l2snapshot", l2snapshot, market); + }); + } + } + + if (marketObjectType === MarketObjectTypes.level2snapshot) { + let subscribed = client.subscribeLevel2Snapshots(market); + if (subscribed) { + client.on("l2snapshot", (l2snapshot, market) => { + this.emit("l2snapshot", l2snapshot, market); + }); + } + } + } catch (ex) { + this.emit("error", ex, market); + } + } } class GMOCoinSingleClient extends BasicClient { constructor({ wssPath = "wss://api.coin.z.com/ws/public/v1", watcherMs, parent } = {}) { From 39be68c4709c01744a8d36b74d2bbdb80654e518 Mon Sep 17 00:00:00 2001 From: develoQ Date: Sun, 10 Jan 2021 02:52:52 +0900 Subject: [PATCH 5/8] fix --- src/exchanges/gmocoin-client.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index 6fbb07ee..fda89e66 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -73,10 +73,7 @@ class GMOCoinClient extends BasicMultiClient { let client = null; let key; map.keys(k => { - if ( - key.remote_id === remote_id && - key.marketObjectType == MarketObjectTypes.level2snapshot - ) { + if (key.remote_id === remote_id && key.marketObjectType == marketObjectType) { key = k; return; } From 88a18067f5a20426e0a76b1504959d65785c0c29 Mon Sep 17 00:00:00 2001 From: develoQ Date: Sun, 10 Jan 2021 10:57:53 +0900 Subject: [PATCH 6/8] fix --- src/exchanges/gmocoin-client.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index fda89e66..5658d02f 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -71,13 +71,16 @@ class GMOCoinClient extends BasicMultiClient { try { let remote_id = market.id; let client = null; - let key; + let key = null; map.keys(k => { if (key.remote_id === remote_id && key.marketObjectType == marketObjectType) { key = k; return; } }); + if (key === null) { + key = { remote_id: remote_id, marketObjectType: marketObjectType }; + } // construct a client if (!map.has(key)) { let clientArgs = { auth: this.auth, market: market }; From 0a254de4b972414ade7ae309aaff216a2ce27605 Mon Sep 17 00:00:00 2001 From: develoQ Date: Mon, 11 Jan 2021 17:47:05 +0900 Subject: [PATCH 7/8] fix PR Advice --- __tests__/exchanges/gmocoin-client.spec.js | 15 +- src/exchanges/gmocoin-client.js | 155 ++------------------- 2 files changed, 16 insertions(+), 154 deletions(-) diff --git a/__tests__/exchanges/gmocoin-client.spec.js b/__tests__/exchanges/gmocoin-client.spec.js index ba625a04..a2e97b43 100644 --- a/__tests__/exchanges/gmocoin-client.spec.js +++ b/__tests__/exchanges/gmocoin-client.spec.js @@ -33,10 +33,10 @@ testClient({ }, ], - testConnectEvents: false, - testDisconnectEvents: false, - testReconnectionEvents: false, - testCloseEvents: false, + testConnectEvents: true, + testDisconnectEvents: true, + testReconnectionEvents: true, + testCloseEvents: true, hasTickers: true, hasTrades: true, @@ -71,11 +71,4 @@ testClient({ hasSequenceId: false, hasCount: false, }, - - l2update: { - hasSnapshot: true, - hasTimestampMs: false, - hasSequenceId: false, - hasCount: false, - }, }); diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index 5658d02f..85e037fd 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -1,160 +1,29 @@ const BasicClient = require("../basic-client"); -const BasicMultiClient = require("../basic-multiclient"); -const { MarketObjectTypes } = require("../enums"); +const { throttle } = require("../flowcontrol/throttle"); const Ticker = require("../ticker"); const Trade = require("../trade"); const Level2Point = require("../level2-point"); const Level2Snapshot = require("../level2-snapshot"); const moment = require("moment"); -const { wait } = require("../util"); -class GMOCoinClient extends BasicMultiClient { - constructor(options = {}) { - super(); - this._name = "GMOCoin"; - this.options = options; - this.hasTickers = true; - this.hasTrades = true; - this.hasLevel2Snapshots = true; - } - - _createBasicClient() { - return new GMOCoinSingleClient({ ...this.options, parent: this }); - } - - async unsubscribeTicker(market) { - if (!this.hasTickers) return; - let key; - this._clients.keys(k => { - if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.ticker) { - key = k; - return; - } - }); - - if (this._clients.has(key)) { - (await this._clients.get(key)).unsubscribeTicker(market); - } - } - - async unsubscribeTrades(market) { - if (!this.hasTrades) return; - let key; - this._clients.keys(k => { - if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.trade) { - key = k; - return; - } - }); - - if (this._clients.has(key)) { - (await this._clients.get(key)).unsubscribeTrades(market); - } - } - - async unsubscribeLevel2Snapshots(market) { - if (!this.hasLevel2Snapshots) return; - let key; - this._clients.keys(k => { - if (key.remote_id === market.id && key.marketObjectType == MarketObjectTypes.level2snapshot) { - key = k; - return; - } - }); - - if (this._clients.has(key)) { - (await this._clients.get(key)).unsubscribeLevel2Snapshots(market); - } - } - - async _subscribe(market, map, marketObjectType) { - try { - let remote_id = market.id; - let client = null; - let key = null; - map.keys(k => { - if (key.remote_id === remote_id && key.marketObjectType == marketObjectType) { - key = k; - return; - } - }); - if (key === null) { - key = { remote_id: remote_id, marketObjectType: marketObjectType }; - } - // construct a client - if (!map.has(key)) { - let clientArgs = { auth: this.auth, market: market }; - client = this._createBasicClientThrottled(clientArgs); - // we MUST store the promise in here otherwise we will stack up duplicates - map.set(key, client); - } - - // wait for client to be made! - client = await map.get(key); - await wait(1000); - - if (marketObjectType === MarketObjectTypes.ticker) { - let subscribed = client.subscribeTicker(market); - if (subscribed) { - client.on("ticker", (ticker, market) => { - this.emit("ticker", ticker, market); - }); - } - } - - if (marketObjectType === MarketObjectTypes.candle) { - let subscribed = client.subscribeCandles(market); - if (subscribed) { - client.on("candle", (candle, market) => { - this.emit("candle", candle, market); - }); - } - } - - if (marketObjectType === MarketObjectTypes.trade) { - let subscribed = client.subscribeTrades(market); - if (subscribed) { - client.on("trade", (trade, market) => { - this.emit("trade", trade, market); - }); - } - } - - if (marketObjectType === MarketObjectTypes.level2update) { - let subscribed = client.subscribeLevel2Updates(market); - if (subscribed) { - client.on("l2update", (l2update, market) => { - this.emit("l2update", l2update, market); - }); - client.on("l2snapshot", (l2snapshot, market) => { - this.emit("l2snapshot", l2snapshot, market); - }); - } - } - - if (marketObjectType === MarketObjectTypes.level2snapshot) { - let subscribed = client.subscribeLevel2Snapshots(market); - if (subscribed) { - client.on("l2snapshot", (l2snapshot, market) => { - this.emit("l2snapshot", l2snapshot, market); - }); - } - } - } catch (ex) { - this.emit("error", ex, market); - } - } -} -class GMOCoinSingleClient extends BasicClient { - constructor({ wssPath = "wss://api.coin.z.com/ws/public/v1", watcherMs, parent } = {}) { +class GMOCoinClient extends BasicClient { + constructor({ + wssPath = "wss://api.coin.z.com/ws/public/v1", + throttleMs = 1000, + watcherMs, + } = {}) { super(wssPath, "GMOCoin", undefined, watcherMs); this.hasTickers = true; this.hasTrades = true; this.hasLevel2Snapshots = true; - this.parent = parent; + this._send = throttle(this._send.bind(this), throttleMs); } + _send(message) { + this._wss.send(message); + } + _sendPong(id) { this._wss.send(JSON.stringify({ pong: id })); } From d7cf0cc64a00d50fac2375f3ef3c730451d86725 Mon Sep 17 00:00:00 2001 From: develoQ Date: Sat, 16 Jan 2021 10:20:26 +0900 Subject: [PATCH 8/8] fix --- src/exchanges/gmocoin-client.js | 61 ++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/src/exchanges/gmocoin-client.js b/src/exchanges/gmocoin-client.js index 85e037fd..1355db03 100644 --- a/src/exchanges/gmocoin-client.js +++ b/src/exchanges/gmocoin-client.js @@ -23,13 +23,12 @@ class GMOCoinClient extends BasicClient { _send(message) { this._wss.send(message); } - _sendPong(id) { - this._wss.send(JSON.stringify({ pong: id })); + this._send(JSON.stringify({ pong: id })); } _sendSubTicker(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "subscribe", channel: "ticker", @@ -39,7 +38,7 @@ class GMOCoinClient extends BasicClient { } _sendUnsubTicker(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "unsubscribe", channel: "ticker", @@ -49,7 +48,7 @@ class GMOCoinClient extends BasicClient { } _sendSubTrades(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "subscribe", channel: "trades", @@ -60,7 +59,7 @@ class GMOCoinClient extends BasicClient { } _sendUnsubTrades(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "unsubscribe", channel: "trades", @@ -71,7 +70,7 @@ class GMOCoinClient extends BasicClient { } _sendSubLevel2Snapshots(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "subscribe", channel: "orderbooks", @@ -81,7 +80,7 @@ class GMOCoinClient extends BasicClient { } _sendUnsubLevel2Snapshots(remote_id) { - this._wss.send( + this._send( JSON.stringify({ command: "unsubscribe", channel: "orderbooks", @@ -129,6 +128,25 @@ class GMOCoinClient extends BasicClient { } } + _onClosing() { + this._sendMessage.cancel(); + super._onClosing(); + } + + /** + * Response example: + * { + * "channel":"ticker", + * "ask": "750760", + * "bid": "750600", + * "high": "762302", + * "last": "756662", + * "low": "704874", + * "symbol": "BTC", + * "timestamp": "2018-03-30T12:34:56.789Z", + * "volume": "194785.8484" + * } + */ _constructTicker(msg, market) { let { ask, bid, high, last, low, timestamp, volume } = msg; return new Ticker({ @@ -145,6 +163,17 @@ class GMOCoinClient extends BasicClient { }); } + /** + * Response example: + * { + * "channel":"trades", + * "price": "750760", + * "side": "BUY", + * "size": "0.1", + * "timestamp": "2018-03-30T12:34:56.789Z", + * "symbol": "BTC" + * } + */ _constructTrade(datum, market) { let { price, side, size, timestamp } = datum; let unix = moment(timestamp).valueOf(); @@ -159,6 +188,22 @@ class GMOCoinClient extends BasicClient { }); } + /** + * Response example: + * { + * "channel":"orderbooks", + * "asks": [ + * {"price": "455659","size": "0.1"}, + * {"price": "455658","size": "0.2"} + * ], + * "bids": [ + * {"price": "455665","size": "0.1"}, + * {"price": "455655","size": "0.3"} + * ], + * "symbol": "BTC", + * "timestamp": "2018-03-30T12:34:56.789Z" + * } + */ _constructLevel2Snapshot(msg, market) { let asks = msg.asks.map(p => new Level2Point(p.price, p.size)); let bids = msg.bids.map(p => new Level2Point(p.price, p.size));