Skip to content
This repository has been archived by the owner on Feb 15, 2022. It is now read-only.

Commit

Permalink
Order type: allow consumer to specify type of order to use (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
DeviaVir authored Jun 9, 2017
1 parent e7b5703 commit 6534aad
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 14 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ zenbot trade --help
-h, --help output usage information
--conf <path> path to optional conf overrides file
--strategy <name> strategy to use
--order_type <type> order type to use (maker/taker)
--paper use paper trading mode (no real trades will take place)
--currency_capital <amount> for paper trading, amount of start capital in currency
--asset_capital <amount> for paper trading, amount of start capital in asset
Expand Down Expand Up @@ -325,6 +326,7 @@ The moving average convergence divergence calculation is a lagging indicator, us
- `--oversold_rsi=<rsi>` will try to buy when the price dives. This is one of the ways to get profit above buy/hold, but setting it too high might result in a loss of the price continues to fall.
- In a market with predictable price surges and corrections, `--profit_stop_enable_pct=10` will try to sell when the last buy hits 10% profit and then drops to 9% (the drop % is set with `--profit_stop_pct`). However in strong, long uptrends this option may end up causing a sell too early.
- As of v4.0.5, the `--neutral_rate=auto` filter is disabled, which is currently producing better results with the new default 10m period. Some coins may benefit from `--neutral_rate=auto` though, try simulating with and without it.
- For Kraken and GDAX you may wish to use `--order_type="taker"`, this uses market orders instead of limit orders. You usually pay a higher fee, but you can be sure that your order is filled instantly. This means that the sim will more closely match your live trading. Please note that GDAX does not charge maker fees (limit orders), so you will need to choose between not paying fees and running the risk orders do not get filled on time, or paying somewhat high % of fees and making sure your orders are always filled on time.

## Manual trade tools

Expand Down
1 change: 1 addition & 0 deletions commands/sim.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = function container (get, set, clear) {
.description('run a simulation on backfilled data')
.option('--conf <path>', 'path to optional conf overrides file')
.option('--strategy <name>', 'strategy to use', String, c.strategy)
.option('--order_type <type>', 'order type to use (maker/taker)', /^(maker|taker)$/i, c.order_type)
.option('--filename <filename>', 'filename for the result output (ex: result.html)', String, c.filename)
.option('--start <timestamp>', 'start at timestamp')
.option('--end <timestamp>', 'end at timestamp')
Expand Down
6 changes: 6 additions & 0 deletions commands/trade.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = function container (get, set, clear) {
.description('run trading bot against live market data')
.option('--conf <path>', 'path to optional conf overrides file')
.option('--strategy <name>', 'strategy to use', String, c.strategy)
.option('--order_type <type>', 'order type to use (maker/taker)', /^(maker|taker)$/i, c.order_type)
.option('--paper', 'use paper trading mode (no real trades will take place)', Boolean, false)
.option('--currency_capital <amount>', 'for paper trading, amount of start capital in currency', Number, c.currency_capital)
.option('--asset_capital <amount>', 'for paper trading, amount of start capital in asset', Number, c.asset_capital)
Expand Down Expand Up @@ -63,6 +64,11 @@ module.exports = function container (get, set, clear) {
}
var engine = get('lib.engine')(s)

var order_types = ['maker', 'taker']
if (!so.order_type in order_types) {
so.order_type = 'maker'
}

var db_cursor, trade_cursor
var query_start = tb().resize(so.period).subtract(so.min_periods * 2).toMilliseconds()
var days = Math.ceil((new Date().getTime() - query_start) / 86400000)
Expand Down
3 changes: 3 additions & 0 deletions conf-sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ c.gdax.passphrase = 'YOUR-PASSPHRASE'
c.poloniex = {}
c.poloniex.key = 'YOUR-API-KEY'
c.poloniex.secret = 'YOUR-SECRET'
// please note: poloniex does not support market orders via the API

// to enable Kraken trading, enter your API credentials:
c.kraken = {}
Expand Down Expand Up @@ -79,6 +80,8 @@ c.order_poll_time = 5000
c.wait_for_settlement = 5000
// % to mark up or down price for orders
c.markup_pct = 0
// become a market taker (high fees) or a market maker (low fees)
c.order_type = 'maker'

// Misc options:

Expand Down
8 changes: 4 additions & 4 deletions extensions/exchanges/bittrex/exchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,18 +217,18 @@ module.exports = function container(get, set, clear) {
}

if (type === 'buy') {
if (opts.order_type === 'limit') {
if (opts.order_type === 'maker') {
bittrex_authed.buylimit(params, fn)
}
if (opts.order_type === 'market') {
if (opts.order_type === 'taker') {
bittrex_authed.buymarket(params, fn)
}
}
if (type === 'sell') {
if (opts.order_type === 'limit') {
if (opts.order_type === 'maker') {
bittrex_authed.selllimit(params, fn)
}
if (opts.order_type === 'market') {
if (opts.order_type === 'taker') {
bittrex_authed.sellmarket(params, fn)
}
}
Expand Down
11 changes: 11 additions & 0 deletions extensions/exchanges/gdax/exchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ module.exports = function container (get, set, clear) {
name: 'gdax',
historyScan: 'backward',
makerFee: 0,
takerFee: 0.3,

getProducts: function () {
return require('./products.json')
Expand Down Expand Up @@ -130,6 +131,11 @@ module.exports = function container (get, set, clear) {
if (typeof opts.post_only === 'undefined') {
opts.post_only = true
}
if (opts.order_type === 'taker') {
delete opts.price
opts.type = 'market'
}
delete opts.order_type
client.buy(opts, function (err, resp, body) {
if (body && body.message === 'Insufficient funds') {
var order = {
Expand All @@ -151,6 +157,11 @@ module.exports = function container (get, set, clear) {
if (typeof opts.post_only === 'undefined') {
opts.post_only = true
}
if (opts.order_type === 'taker') {
delete opts.price
opts.type = 'market'
}
delete opts.order_type
client.sell(opts, function (err, resp, body) {
if (body && body.message === 'Insufficient funds') {
var order = {
Expand Down
7 changes: 5 additions & 2 deletions extensions/exchanges/kraken/exchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module.exports = function container(get, set, clear) {
name: 'kraken',
historyScan: 'forward',
makerFee: 0.16,
takerFee: 0.26,
// The limit for the public API is not documented, 1750 ms between getTrades in backfilling seems to do the trick to omit warning messages.
backfillRateLimit: 1750,

Expand Down Expand Up @@ -184,12 +185,14 @@ module.exports = function container(get, set, clear) {
var params = {
pair: joinProduct(opts.product_id),
type: type,
ordertype: 'limit',
price: opts.price,
ordertype: (opts.order_type === 'maker' ? 'limit' : 'market'),
volume: opts.size,
trading_agreement: c.kraken.tosagree,
oflags: opts.post_only === true ? 'post' : undefined
}
if ('price' in opts) {
params.price = opts.price
}
client.api('AddOrder', params, function (error, data) {
if (error && error.message.match(recoverableErrors)) {
return retry('trade', args, error)
Expand Down
1 change: 1 addition & 0 deletions extensions/exchanges/poloniex/exchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module.exports = function container (get, set, clear) {
name: 'poloniex',
historyScan: 'backward',
makerFee: 0.15,
takerFee: 0.25,

getProducts: function () {
return require('./products.json')
Expand Down
35 changes: 27 additions & 8 deletions lib/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,17 @@ module.exports = function container (get, set, clear) {
s.balance.asset = n(s.balance.asset).add(s.buy_order.size).format('0.00000000')
var total = n(price).multiply(s.buy_order.size)
s.balance.currency = n(s.balance.currency).subtract(total).format('0.00000000')
if (s.exchange.makerFee) {
fee = n(s.buy_order.size).multiply(s.exchange.makerFee / 100).value()
s.balance.asset = n(s.balance.asset).subtract(fee).format('0.00000000')
if (so.order_type === 'maker') {
if (s.exchange.makerFee) {
fee = n(s.buy_order.size).multiply(s.exchange.makerFee / 100).value()
s.balance.asset = n(s.balance.asset).subtract(fee).format('0.00000000')
}
}
if (so.order_type === 'taker') {
if (s.exchange.takerFee) {
fee = n(s.buy_order.size).multiply(s.exchange.takerFee / 100).value()
s.balance.asset = n(s.balance.asset).subtract(fee).format('0.00000000')
}
}
}
s.action = 'bought'
Expand All @@ -528,8 +536,9 @@ module.exports = function container (get, set, clear) {
slippage: n(price).subtract(s.buy_order.orig_price).divide(s.buy_order.orig_price).value(),
type: 'buy',
size: s.buy_order.orig_size,
fee: fee,
price: price,
fee: fee
order_type: so.order_type
}
s.my_trades.push(my_trade)
if (so.stats) {
Expand All @@ -553,9 +562,18 @@ module.exports = function container (get, set, clear) {
s.balance.asset = n(s.balance.asset).subtract(s.sell_order.size).value()
var total = n(price).multiply(s.sell_order.size)
s.balance.currency = n(s.balance.currency).add(total).value()
if (s.exchange.makerFee) {
fee = n(s.sell_order.size).multiply(s.exchange.makerFee / 100).multiply(price).value()
s.balance.currency = n(s.balance.currency).subtract(fee).format('0.00000000')

if (so.order_type === 'maker') {
if (s.exchange.makerFee) {
fee = n(s.sell_order.size).multiply(s.exchange.makerFee / 100).multiply(price).value()
s.balance.currency = n(s.balance.currency).subtract(fee).format('0.00000000')
}
}
if (so.order_type === 'taker') {
if (s.exchange.takerFee) {
fee = n(s.sell_order.size).multiply(s.exchange.takerFee / 100).multiply(price).value()
s.balance.currency = n(s.balance.currency).subtract(fee).format('0.00000000')
}
}
}
s.action = 'sold'
Expand All @@ -567,8 +585,9 @@ module.exports = function container (get, set, clear) {
slippage: n(s.sell_order.orig_price).subtract(price).divide(price).value(),
type: 'sell',
size: s.sell_order.orig_size,
fee: fee,
price: price,
fee: fee
order_type: so.order_type
}
s.my_trades.push(my_trade)
if (so.stats) {
Expand Down

1 comment on commit 6534aad

@vitorego
Copy link

Choose a reason for hiding this comment

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

Hi.
I got this idea, but I don't know if it is feasible. Besides a fixed order type, how about a dynamically one. Example, if the slippage gets over a max value it will raise a maker order. In this way we can take advantage of both types.

Please sign in to comment.