From 05a0c9c62133db2b7396e83e851ec2f668c444ed Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 22 Jan 2020 13:56:46 +0700 Subject: [PATCH 1/7] (feature) add OCOCO order type --- index.js | 1 + lib/ococo/events/life_start.js | 8 + lib/ococo/events/life_stop.js | 3 + lib/ococo/events/orders_order_cancel.js | 17 ++ lib/ococo/events/orders_order_fill.js | 14 ++ lib/ococo/events/self_submit_initial_order.js | 19 +++ lib/ococo/events/self_submit_oco_order.js | 19 +++ lib/ococo/index.js | 55 +++++++ lib/ococo/meta/declare_events.js | 9 ++ lib/ococo/meta/gen_order_label.js | 14 ++ lib/ococo/meta/gen_preview.js | 5 + lib/ococo/meta/get_ui_def.js | 146 ++++++++++++++++++ lib/ococo/meta/init_state.js | 8 + lib/ococo/meta/process_params.js | 40 +++++ lib/ococo/meta/serialize.js | 11 ++ lib/ococo/meta/unserialize.js | 11 ++ lib/ococo/meta/validate_params.js | 32 ++++ lib/ococo/util/generate_initial_order.js | 41 +++++ lib/ococo/util/generate_oco_order.js | 39 +++++ 19 files changed, 492 insertions(+) create mode 100644 lib/ococo/events/life_start.js create mode 100644 lib/ococo/events/life_stop.js create mode 100644 lib/ococo/events/orders_order_cancel.js create mode 100644 lib/ococo/events/orders_order_fill.js create mode 100644 lib/ococo/events/self_submit_initial_order.js create mode 100644 lib/ococo/events/self_submit_oco_order.js create mode 100644 lib/ococo/index.js create mode 100644 lib/ococo/meta/declare_events.js create mode 100644 lib/ococo/meta/gen_order_label.js create mode 100644 lib/ococo/meta/gen_preview.js create mode 100644 lib/ococo/meta/get_ui_def.js create mode 100644 lib/ococo/meta/init_state.js create mode 100644 lib/ococo/meta/process_params.js create mode 100644 lib/ococo/meta/serialize.js create mode 100644 lib/ococo/meta/unserialize.js create mode 100644 lib/ococo/meta/validate_params.js create mode 100644 lib/ococo/util/generate_initial_order.js create mode 100644 lib/ococo/util/generate_oco_order.js diff --git a/index.js b/index.js index 47592dbe..f889aa6e 100644 --- a/index.js +++ b/index.js @@ -7,5 +7,6 @@ module.exports = { AccumulateDistribute: require('./lib/accumulate_distribute'), PingPong: require('./lib/ping_pong'), MACrossover: require('./lib/ma_crossover'), + OCOCO: require('./lib/ococo'), NoDataError: require('./lib/errors/no_data') } diff --git a/lib/ococo/events/life_start.js b/lib/ococo/events/life_start.js new file mode 100644 index 00000000..26a0fdf3 --- /dev/null +++ b/lib/ococo/events/life_start.js @@ -0,0 +1,8 @@ +'use strict' + +module.exports = async (instance = {}) => { + const { h = {} } = instance + const { emitSelf } = h + + await emitSelf('submit_initial_order') +} diff --git a/lib/ococo/events/life_stop.js b/lib/ococo/events/life_stop.js new file mode 100644 index 00000000..ceec7efe --- /dev/null +++ b/lib/ococo/events/life_stop.js @@ -0,0 +1,3 @@ +'use strict' + +module.exports = async (instance = {}) => {} diff --git a/lib/ococo/events/orders_order_cancel.js b/lib/ococo/events/orders_order_cancel.js new file mode 100644 index 00000000..a1e16623 --- /dev/null +++ b/lib/ococo/events/orders_order_cancel.js @@ -0,0 +1,17 @@ +'use strict' + +module.exports = async (instance = {}, order) => { + const { state = {}, h = {} } = instance + const { args = {}, orders = {}, gid, timeout } = state + const { emit, debug } = h + const { cancelDelay } = args + + debug('detected atomic cancelation, stopping...') + + if (timeout) { + clearTimeout(timeout) + } + + await emit('exec:order:cancel:all', gid, orders, cancelDelay) + await emit('exec:stop') +} diff --git a/lib/ococo/events/orders_order_fill.js b/lib/ococo/events/orders_order_fill.js new file mode 100644 index 00000000..e01273aa --- /dev/null +++ b/lib/ococo/events/orders_order_fill.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = async (instance = {}) => { + const { state = {}, h = {} } = instance + const { updateState, emitSelf } = h + const { initialOrderFilled } = state + + if (initialOrderFilled) { + await emitSelf('exec:stop') + } else { + await updateState(instance, { initialOrderFilled: true }) + await emitSelf('submit_oco_order') + } +} diff --git a/lib/ococo/events/self_submit_initial_order.js b/lib/ococo/events/self_submit_initial_order.js new file mode 100644 index 00000000..cabb4387 --- /dev/null +++ b/lib/ococo/events/self_submit_initial_order.js @@ -0,0 +1,19 @@ +'use strict' + +const generateInitialOrder = require('../util/generate_initial_order') + +module.exports = async (instance = {}) => { + const { state = {}, h = {} } = instance + const { emit, debug } = h + const { args = {}, gid } = state + const { submitDelay } = args + + const order = generateInitialOrder(instance) + + debug( + 'generated order %s for %f @ %f', + order.type, order.amount, order.price || 'MARKET' + ) + + await emit('exec:order:submit:all', gid, [order], submitDelay) +} diff --git a/lib/ococo/events/self_submit_oco_order.js b/lib/ococo/events/self_submit_oco_order.js new file mode 100644 index 00000000..01301818 --- /dev/null +++ b/lib/ococo/events/self_submit_oco_order.js @@ -0,0 +1,19 @@ +'use strict' + +const generateOCOOrder = require('../util/generate_oco_order') + +module.exports = async (instance = {}) => { + const { state = {}, h = {} } = instance + const { emit, debug } = h + const { args = {}, gid } = state + const { submitDelay } = args + + const order = generateOCOOrder(instance) + + debug( + 'generated order %s for %f @ %f', + order.type, order.amount, order.price || 'MARKET' + ) + + await emit('exec:order:submit:all', gid, [order], submitDelay) +} diff --git a/lib/ococo/index.js b/lib/ococo/index.js new file mode 100644 index 00000000..7fa0659c --- /dev/null +++ b/lib/ococo/index.js @@ -0,0 +1,55 @@ +'use strict' + +const defineAlgoOrder = require('../define_algo_order') + +const validateParams = require('./meta/validate_params') +const processParams = require('./meta/process_params') +const initState = require('./meta/init_state') +const onSelfSubmitInitialOrder = require('./events/self_submit_initial_order') +const onSelfSubmitOCOOrder = require('./events/self_submit_oco_order') +const onLifeStart = require('./events/life_start') +const onLifeStop = require('./events/life_stop') +const onOrdersOrderCancel = require('./events/orders_order_cancel') +const onOrdersOrderFill = require('./events/orders_order_fill') +const genOrderLabel = require('./meta/gen_order_label') +const genPreview = require('./meta/gen_preview') +const declareEvents = require('./meta/declare_events') +const getUIDef = require('./meta/get_ui_def') +const serialize = require('./meta/serialize') +const unserialize = require('./meta/unserialize') + +const OCOCO = defineAlgoOrder({ + id: 'bfx-ococo', + name: 'OCOCO', + + meta: { + validateParams, + processParams, + declareEvents, + getUIDef, + genOrderLabel, + genPreview, + initState, + serialize, + unserialize + }, + + events: { + self: { + submit_initial_order: onSelfSubmitInitialOrder, + submit_oco_order: onSelfSubmitOCOOrder + }, + + life: { + start: onLifeStart, + stop: onLifeStop + }, + + orders: { + order_cancel: onOrdersOrderCancel, + order_fill: onOrdersOrderFill + } + } +}) + +module.exports = OCOCO diff --git a/lib/ococo/meta/declare_events.js b/lib/ococo/meta/declare_events.js new file mode 100644 index 00000000..f840739e --- /dev/null +++ b/lib/ococo/meta/declare_events.js @@ -0,0 +1,9 @@ +'use strict' + +module.exports = (instance = {}, host) => { + const { h = {} } = instance + const { declareEvent } = h + + declareEvent(instance, host, 'self:submit_initial_order', 'submit_initial_order') + declareEvent(instance, host, 'self:submit_oco_order', 'submit_oco_order') +} diff --git a/lib/ococo/meta/gen_order_label.js b/lib/ococo/meta/gen_order_label.js new file mode 100644 index 00000000..a264394c --- /dev/null +++ b/lib/ococo/meta/gen_order_label.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = (state = {}) => { + const { args = {} } = state + const { + orderType, orderPrice, amount, ocoAmount, limitPrice, stopPrice + } = args + + return [ + 'OCOCO', + ` | ${amount} @ ${orderPrice || orderType} `, + ` | triggers ${ocoAmount} @ ${limitPrice} (stop ${stopPrice})` + ].join('') +} diff --git a/lib/ococo/meta/gen_preview.js b/lib/ococo/meta/gen_preview.js new file mode 100644 index 00000000..754902b6 --- /dev/null +++ b/lib/ococo/meta/gen_preview.js @@ -0,0 +1,5 @@ +'use strict' + +module.exports = (args = {}) => { + return [] +} diff --git a/lib/ococo/meta/get_ui_def.js b/lib/ococo/meta/get_ui_def.js new file mode 100644 index 00000000..7208933d --- /dev/null +++ b/lib/ococo/meta/get_ui_def.js @@ -0,0 +1,146 @@ +module.exports = () => ({ + label: 'Order Creates OcO', + id: 'bfx-ococo', + + uiIcon: 'ma-crossover-active', + connectionTimeout: 10000, + actionTimeout: 10000, + + header: { + component: 'ui.checkbox_group', + fields: ['hidden', 'postonly'] + }, + + sections: [{ + title: '', + name: 'general', + rows: [ + ['orderType', 'orderPrice'], + ['amount', 'action'] + ] + }, { + title: 'OcO Settings', + name: 'shortEMASettings', + fixed: true, + + rows: [ + ['limitPrice', 'stopPrice'], + ['ocoAmount', 'ocoAction'] + ] + }, { + title: '', + name: 'submitSettings', + fixed: true, + + rows: [ + ['submitDelaySec', 'cancelDelaySec'] + ] + }, { + title: '', + name: 'lev', + fullWidth: true, + rows: [ + ['lev'] + ], + + visible: { + _context: { eq: 'f' } + } + }], + + fields: { + submitDelaySec: { + component: 'input.number', + label: 'Submit Delay (sec)', + customHelp: 'Seconds to wait before submitting orders', + default: 1 + }, + + cancelDelaySec: { + component: 'input.number', + label: 'Cancel Delay (sec)', + customHelp: 'Seconds to wait before cancelling orders', + default: 0 + }, + + orderType: { + component: 'input.dropdown', + label: 'Order Type', + default: 'LIMIT', + options: { + LIMIT: 'Limit', + MARKET: 'Market' + } + }, + + amount: { + component: 'input.amount', + label: 'Amount $BASE', + customHelp: 'Initial Order amount', + priceField: 'orderPrice' + }, + + ocoAmount: { + component: 'input.amount', + label: 'Amount $BASE', + customHelp: 'OcO Order amount' + }, + + orderPrice: { + component: 'input.price', + label: 'Initial Order Price $QUOTE', + + disabled: { + orderType: { eq: 'MARKET' } + } + }, + + limitPrice: { + component: 'input.price', + label: 'OcO Limit Price $QUOTE' + }, + + stopPrice: { + component: 'input.price', + label: 'OcO Stop Price $QUOTE' + }, + + lev: { + component: 'input.range', + label: 'Leverage', + min: 1, + max: 100, + default: 10 + }, + + hidden: { + component: 'input.checkbox', + label: 'HIDDEN', + default: false + }, + + postonly: { + component: 'input.checkbox', + label: 'POST-ONLY', + default: false + }, + + action: { + component: 'input.radio', + label: 'Action', + options: ['Buy', 'Sell'], + inline: true, + default: 'Buy' + }, + + ocoAction: { + component: 'input.radio', + label: 'Action', + options: ['Buy', 'Sell'], + inline: true, + default: 'Buy' + } + }, + + actions: ['preview', 'submit'] +}) diff --git a/lib/ococo/meta/init_state.js b/lib/ococo/meta/init_state.js new file mode 100644 index 00000000..d65e38b4 --- /dev/null +++ b/lib/ococo/meta/init_state.js @@ -0,0 +1,8 @@ +'use strict' + +module.exports = (args = {}) => { + return { + args, + initialOrderFilled: false + } +} diff --git a/lib/ococo/meta/process_params.js b/lib/ococo/meta/process_params.js new file mode 100644 index 00000000..c150aaa0 --- /dev/null +++ b/lib/ococo/meta/process_params.js @@ -0,0 +1,40 @@ +'use strict' + +module.exports = (data) => { + const params = { ...data } + + if (params._symbol) { + params.symbol = params._symbol + delete params._symbol + } + + if (!params._futures) { + delete params.lev + } + + if (!params.cancelDelay) { + params.cancelDelay = 1500 + } + + if (!params.submitDelay) { + params.submitDelay = 5000 + } + + if (params.action) { + if (params.action === 'Sell') { + params.amount = (+params.amount) * -1 + } + + delete params.action + } + + if (params.ocoAction) { + if (params.ocoAction === 'Sell') { + params.ocoAmount = (+params.ocoAmount) * -1 + } + + delete params.ocoAction + } + + return params +} diff --git a/lib/ococo/meta/serialize.js b/lib/ococo/meta/serialize.js new file mode 100644 index 00000000..84d4633b --- /dev/null +++ b/lib/ococo/meta/serialize.js @@ -0,0 +1,11 @@ +'use strict' + +module.exports = (state = {}) => { + const { args = {}, label, name } = state + + return { + label, + name, + args + } +} diff --git a/lib/ococo/meta/unserialize.js b/lib/ococo/meta/unserialize.js new file mode 100644 index 00000000..ab666845 --- /dev/null +++ b/lib/ococo/meta/unserialize.js @@ -0,0 +1,11 @@ +'use strict' + +module.exports = (loadedState = {}) => { + const { args = {}, name, label } = loadedState + + return { + label, + name, + args + } +} diff --git a/lib/ococo/meta/validate_params.js b/lib/ococo/meta/validate_params.js new file mode 100644 index 00000000..1172a008 --- /dev/null +++ b/lib/ococo/meta/validate_params.js @@ -0,0 +1,32 @@ +'use strict' + +const _isFinite = require('lodash/isFinite') + +const ORDER_TYPES = ['MARKET', 'LIMIT'] + +module.exports = (args = {}) => { + const { + orderPrice, amount, orderType, submitDelay, cancelDelay, limitPrice, + stopPrice, ocoAmount, lev, _futures + } = args + + if (ORDER_TYPES.indexOf(orderType) === -1) return `Invalid order type: ${orderType}` + if (!_isFinite(amount)) return 'Invalid amount' + if (!_isFinite(submitDelay) || submitDelay < 0) return 'Invalid submit delay' + if (!_isFinite(cancelDelay) || cancelDelay < 0) return 'Invalid cancel delay' + if (orderType === 'LIMIT' && !_isFinite(orderPrice)) { + return 'Limit price required for LIMIT order type' + } + + if (!_isFinite(limitPrice)) return 'Invalid OCO limit price' + if (!_isFinite(stopPrice)) return 'Invalid OCO stop price' + if (!_isFinite(ocoAmount)) return 'Invalid OCO amount' + + if (_futures) { + if (!_isFinite(lev)) return 'Invalid leverage' + if (lev < 1) return 'Leverage less than 1' + if (lev > 100) return 'Leverage greater than 100' + } + + return null +} diff --git a/lib/ococo/util/generate_initial_order.js b/lib/ococo/util/generate_initial_order.js new file mode 100644 index 00000000..d9662476 --- /dev/null +++ b/lib/ococo/util/generate_initial_order.js @@ -0,0 +1,41 @@ +'use strict' + +const { Order } = require('bfx-api-node-models') +const { nonce } = require('bfx-api-node-util') + +module.exports = (instance = {}) => { + const { state = {} } = instance + const { args = {} } = state + const { + amount, symbol, orderType, orderPrice, hidden, postonly, lev, _margin, + _futures + } = args + + const sharedOrderParams = { + symbol, + amount, + hidden, + postonly + } + + if (_futures) { + sharedOrderParams.lev = lev + } + + if (orderType === 'MARKET') { + return new Order({ + ...sharedOrderParams, + cid: nonce(), + type: _margin || _futures ? 'MARKET' : 'EXCHANGE MARKET' + }) + } else if (orderType === 'LIMIT') { + return new Order({ + ...sharedOrderParams, + price: +orderPrice, + cid: nonce(), + type: _margin || _futures ? 'LIMIT' : 'EXCHANGE LIMIT' + }) + } else { + throw new Error(`unknown order type: ${orderType}`) + } +} diff --git a/lib/ococo/util/generate_oco_order.js b/lib/ococo/util/generate_oco_order.js new file mode 100644 index 00000000..3a208481 --- /dev/null +++ b/lib/ococo/util/generate_oco_order.js @@ -0,0 +1,39 @@ +'use strict' + +const { Order } = require('bfx-api-node-models') +const { nonce } = require('bfx-api-node-util') + +module.exports = (instance = {}) => { + const { state = {} } = instance + const { args = {} } = state + const { + ocoAmount, symbol, limitPrice, stopPrice, hidden, postonly, lev, + _margin, _futures + } = args + + const cid = nonce() + const sharedOrderParams = { + symbol, + amount: ocoAmount + } + + if (_futures) { + sharedOrderParams.lev = lev + } + + const o = new Order({ + ...sharedOrderParams, + price: +limitPrice, + priceAuxLimit: +stopPrice, + oco: true, + cid: cid, + cidOCO: cid, + type: _margin || _futures ? 'LIMIT' : 'EXCHANGE LIMIT', + hidden, + postonly + }) + + console.log(JSON.stringify(o.toNewOrderPacket(), null, 2)) + + return o +} From 960b9a9b03fba303b2e12510b4fb7266c455ea2c Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 22 Jan 2020 14:00:13 +0700 Subject: [PATCH 2/7] (fix) rm vestigial console.log --- lib/ococo/util/generate_oco_order.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ococo/util/generate_oco_order.js b/lib/ococo/util/generate_oco_order.js index 3a208481..2d70c9a1 100644 --- a/lib/ococo/util/generate_oco_order.js +++ b/lib/ococo/util/generate_oco_order.js @@ -33,7 +33,5 @@ module.exports = (instance = {}) => { postonly }) - console.log(JSON.stringify(o.toNewOrderPacket(), null, 2)) - return o } From 720251a1eb593e3c65e1891a20ffc8cea1a90082 Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 29 Jan 2020 19:15:56 +0700 Subject: [PATCH 3/7] (feature) add basic OCOCO docs --- docs/ococo.md | 25 +++++++++++++++++++++++++ lib/ococo/index.js | 20 ++++++++++++++++++++ package.json | 3 ++- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 docs/ococo.md diff --git a/docs/ococo.md b/docs/ococo.md new file mode 100644 index 00000000..8f06e154 --- /dev/null +++ b/docs/ococo.md @@ -0,0 +1,25 @@ + + +## OCOCO +Order Creates OCO (or OCOCO) triggers an OCO order after an initial MARKET +or LIMIT order fills. + +**Kind**: global variable + +| Param | Type | Description | +| --- | --- | --- | +| symbol | string | symbol to trade on | +| orderType | string | initial order type, LIMIT or MARKET | +| orderPrice | number | price for initial order if `orderType` is LIMIT | +| amount | number | initial order amount | +| _margin | boolean | if false, order type is prefixed with EXCHANGE | +| _futures | boolean | if false, order type is prefixed with EXCHANGE | +| action | string | initial order direction, Buy or Sell | +| limitPrice | number | oco order limit price | +| stopPrice | number | oco order stop price | +| ocoAmount | number | oco order amount | +| ocoAction | string | oco order direction, Buy or Sell | +| submitDelaySec | number | submit delay in seconds | +| cancelDelaySec | number | cancel delay in seconds | +| lev | number | leverage for relevant markets | + diff --git a/lib/ococo/index.js b/lib/ococo/index.js index 7fa0659c..f4c20e1a 100644 --- a/lib/ococo/index.js +++ b/lib/ococo/index.js @@ -18,6 +18,26 @@ const getUIDef = require('./meta/get_ui_def') const serialize = require('./meta/serialize') const unserialize = require('./meta/unserialize') +/** + * Order Creates OCO (or OCOCO) triggers an OCO order after an initial MARKET + * or LIMIT order fills. + * + * @name OCOCO + * @param {string} symbol - symbol to trade on + * @param {string} orderType - initial order type, LIMIT or MARKET + * @param {number} orderPrice - price for initial order if `orderType` is LIMIT + * @param {number} amount - initial order amount + * @param {boolean} _margin - if false, order type is prefixed with EXCHANGE + * @param {boolean} _futures - if false, order type is prefixed with EXCHANGE + * @param {string} action - initial order direction, Buy or Sell + * @param {number} limitPrice - oco order limit price + * @param {number} stopPrice - oco order stop price + * @param {number} ocoAmount - oco order amount + * @param {string} ocoAction - oco order direction, Buy or Sell + * @param {number} submitDelaySec - submit delay in seconds + * @param {number} cancelDelaySec - cancel delay in seconds + * @param {number} lev - leverage for relevant markets + */ const OCOCO = defineAlgoOrder({ id: 'bfx-ococo', name: 'OCOCO', diff --git a/package.json b/package.json index 912ac697..54f546e4 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "twap_docs": "node_modules/jsdoc-to-markdown/bin/cli.js lib/twap/index.js > docs/twap.md", "pingpong_docs": "node_modules/jsdoc-to-markdown/bin/cli.js lib/ping_pong/index.js > docs/ping_pong.md", "ad_docs": "node_modules/jsdoc-to-markdown/bin/cli.js lib/accumulate_distribute/index.js > docs/accumulate_distribute.md", - "docs": "npm run aohost_docs && npm run helpers_docs && npm run iceberg_docs && npm run twap_docs && npm run ad_docs && npm run macrossover_docs && npm run pingpong_docs" + "ococo_docs": "node_modules/jsdoc-to-markdown/bin/cli.js lib/ococo/index.js > docs/ococo.md", + "docs": "npm run aohost_docs && npm run helpers_docs && npm run iceberg_docs && npm run twap_docs && npm run ad_docs && npm run macrossover_docs && npm run pingpong_docs && npm run ococo_docs" }, "repository": { "type": "git", From eea463cddc0a65833d87331109bff7a0df1ceabd Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 29 Jan 2020 19:17:04 +0700 Subject: [PATCH 4/7] (manifest) bump to 2.0.6 --- CHANGELOG | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 133d70fd..84e475ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +# 2.0.6 +- feature: OCOCO type + # 2.0.5 - feature: futures support diff --git a/package.json b/package.json index 54f546e4..0ea75bcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bfx-hf-algo", - "version": "2.0.5", + "version": "2.0.6", "description": "HF Algorithmic Order Module", "main": "index.js", "directories": { From a34e76a3fe27f041cd21fca003969301ea55dbb4 Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 29 Jan 2020 19:23:40 +0700 Subject: [PATCH 5/7] (fix) submitDelay and cancelDelay parsing --- lib/ococo/meta/process_params.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/ococo/meta/process_params.js b/lib/ococo/meta/process_params.js index c150aaa0..ac2867e3 100644 --- a/lib/ococo/meta/process_params.js +++ b/lib/ococo/meta/process_params.js @@ -1,5 +1,7 @@ 'use strict' +const _isFinite = require('lodash/isFinite') + module.exports = (data) => { const params = { ...data } @@ -12,12 +14,22 @@ module.exports = (data) => { delete params.lev } - if (!params.cancelDelay) { - params.cancelDelay = 1500 + if (params.cancelDelaySec) { + params.cancelDelay = params.cancelDelaySec * 1000 + delete params.cancelDelaySec + } + + if (params.submitDelaySec) { + params.submitDelay = params.submitDelaySec * 1000 + delete params.submitDelaySec + } + + if (!_isFinite(params.cancelDelay)) { + params.cancelDelay = 1000 } - if (!params.submitDelay) { - params.submitDelay = 5000 + if (!_isFinite(params.submitDelay)) { + params.submitDelay = 2000 } if (params.action) { From ad97ff47e7f9949482db41887540ddfbd13184fb Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 29 Jan 2020 19:45:13 +0700 Subject: [PATCH 6/7] (fix) OCOCO: only handle order fill if fully filled --- lib/ococo/events/orders_order_fill.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ococo/events/orders_order_fill.js b/lib/ococo/events/orders_order_fill.js index e01273aa..a4af7284 100644 --- a/lib/ococo/events/orders_order_fill.js +++ b/lib/ococo/events/orders_order_fill.js @@ -1,10 +1,17 @@ 'use strict' -module.exports = async (instance = {}) => { +const { Config } = require('bfx-api-node-core') +const { DUST } = Config + +module.exports = async (instance = {}, order) => { const { state = {}, h = {} } = instance const { updateState, emitSelf } = h const { initialOrderFilled } = state + if (order.amount > DUST) { // partial fill + return + } + if (initialOrderFilled) { await emitSelf('exec:stop') } else { From 9c1f9febfb44452485b1f77394979a6c7f18a29a Mon Sep 17 00:00:00 2001 From: Cris Mihalache Date: Wed, 29 Jan 2020 19:45:27 +0700 Subject: [PATCH 7/7] (refactor) OCOCO: check action and ocoAction validity --- lib/ococo/meta/validate_params.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ococo/meta/validate_params.js b/lib/ococo/meta/validate_params.js index 1172a008..9df34d95 100644 --- a/lib/ococo/meta/validate_params.js +++ b/lib/ococo/meta/validate_params.js @@ -7,7 +7,7 @@ const ORDER_TYPES = ['MARKET', 'LIMIT'] module.exports = (args = {}) => { const { orderPrice, amount, orderType, submitDelay, cancelDelay, limitPrice, - stopPrice, ocoAmount, lev, _futures + stopPrice, ocoAmount, lev, _futures, action, ocoAction } = args if (ORDER_TYPES.indexOf(orderType) === -1) return `Invalid order type: ${orderType}` @@ -22,6 +22,9 @@ module.exports = (args = {}) => { if (!_isFinite(stopPrice)) return 'Invalid OCO stop price' if (!_isFinite(ocoAmount)) return 'Invalid OCO amount' + if (action !== 'Buy' && action !== 'Sell') return `Invalid action: ${action}` + if (ocoAction !== 'Buy' && ocoAction !== 'Sell') return `Invalid OCO action: ${ocoAction}` + if (_futures) { if (!_isFinite(lev)) return 'Invalid leverage' if (lev < 1) return 'Leverage less than 1'