Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Order creates OcO 2.0.6 #23

Merged
merged 7 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 2.0.6
- feature: OCOCO type

# 2.0.5
- feature: futures support

Expand Down
25 changes: 25 additions & 0 deletions docs/ococo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<a name="OCOCO"></a>

## 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 | <code>string</code> | symbol to trade on |
| orderType | <code>string</code> | initial order type, LIMIT or MARKET |
| orderPrice | <code>number</code> | price for initial order if `orderType` is LIMIT |
| amount | <code>number</code> | initial order amount |
| _margin | <code>boolean</code> | if false, order type is prefixed with EXCHANGE |
| _futures | <code>boolean</code> | if false, order type is prefixed with EXCHANGE |
| action | <code>string</code> | initial order direction, Buy or Sell |
| limitPrice | <code>number</code> | oco order limit price |
| stopPrice | <code>number</code> | oco order stop price |
| ocoAmount | <code>number</code> | oco order amount |
| ocoAction | <code>string</code> | oco order direction, Buy or Sell |
| submitDelaySec | <code>number</code> | submit delay in seconds |
| cancelDelaySec | <code>number</code> | cancel delay in seconds |
| lev | <code>number</code> | leverage for relevant markets |

1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}
8 changes: 8 additions & 0 deletions lib/ococo/events/life_start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict'

module.exports = async (instance = {}) => {
const { h = {} } = instance
const { emitSelf } = h

await emitSelf('submit_initial_order')
}
3 changes: 3 additions & 0 deletions lib/ococo/events/life_stop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict'

module.exports = async (instance = {}) => {}
17 changes: 17 additions & 0 deletions lib/ococo/events/orders_order_cancel.js
Original file line number Diff line number Diff line change
@@ -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')
}
14 changes: 14 additions & 0 deletions lib/ococo/events/orders_order_fill.js
Original file line number Diff line number Diff line change
@@ -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 })
f3rno marked this conversation as resolved.
Show resolved Hide resolved
await emitSelf('submit_oco_order')
}
}
19 changes: 19 additions & 0 deletions lib/ococo/events/self_submit_initial_order.js
Original file line number Diff line number Diff line change
@@ -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)
}
19 changes: 19 additions & 0 deletions lib/ococo/events/self_submit_oco_order.js
Original file line number Diff line number Diff line change
@@ -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)
}
75 changes: 75 additions & 0 deletions lib/ococo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'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')

/**
* 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',

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
9 changes: 9 additions & 0 deletions lib/ococo/meta/declare_events.js
Original file line number Diff line number Diff line change
@@ -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')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, didnt realize you could create custom events

declareEvent(instance, host, 'self:submit_oco_order', 'submit_oco_order')
}
14 changes: 14 additions & 0 deletions lib/ococo/meta/gen_order_label.js
Original file line number Diff line number Diff line change
@@ -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('')
}
5 changes: 5 additions & 0 deletions lib/ococo/meta/gen_preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict'

module.exports = (args = {}) => {
return []
}
146 changes: 146 additions & 0 deletions lib/ococo/meta/get_ui_def.js
Original file line number Diff line number Diff line change
@@ -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']
})
8 changes: 8 additions & 0 deletions lib/ococo/meta/init_state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict'

module.exports = (args = {}) => {
return {
args,
initialOrderFilled: false
}
}