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

Always use lowest/highest price for buy/sell loss protection #1471

Merged
merged 4 commits into from
Mar 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion commands/trade.js
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ module.exports = function (program, conf) {
my_trades.find({selector: so.selector.normalized, time : {$gte : trades[0].time}}).limit(0).toArray(function (err, my_prev_trades) {
if (err) throw err
if (my_prev_trades.length) {
s.my_prev_trades = my_prev_trades.slice(0).sort(function(a,b){return a.time + a.execution_time > b.time + b.execution_time ? -1 : 1}) // simple copy, most recent executed first
s.my_prev_trades = my_prev_trades.slice(0).sort(function(a,b){return a.time + a.execution_time < b.time + b.execution_time ? -1 : 1}) // simple copy, less recent executed first
}
})
}
Expand Down
43 changes: 23 additions & 20 deletions lib/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module.exports = function (s, conf) {
if (s.my_trades.length) {
last_trade = s.my_trades[s.my_trades.length - 1]
} else {
last_trade = s.my_prev_trades[0]
last_trade = s.my_prev_trades[s.my_prev_trades.length - 1]
}
s.last_trade_worth = last_trade.type === 'buy' ? (s.period.close - last_trade.price) / last_trade.price : (last_trade.price - s.period.close) / last_trade.price
if (!s.acted_on_stop) {
Expand Down Expand Up @@ -341,7 +341,7 @@ module.exports = function (s, conf) {
// 8. if not filled after timer, repeat process
// 9. if filled, record order stats
function executeSignal (signal, _cb, size, is_reorder, is_taker) {
let price, expected_fee, buy_pct, sell_pct
let price, expected_fee, buy_pct, sell_pct, trades
delete s[(signal === 'buy' ? 'sell' : 'buy') + '_order']
s.last_signal = signal
if (!is_reorder && s[signal + '_order']) {
Expand Down Expand Up @@ -392,6 +392,11 @@ module.exports = function (s, conf) {
msg('price changed, resizing order, ' + reorder_pct + '% remain')
size = null
}
if (s.my_prev_trades.length) {
trades = _.concat(s.my_prev_trades, s.my_trades)
} else {
trades = _.cloneDeep(s.my_trades)
}
if (signal === 'buy') {
price = nextBuyForQuote(s, quote)

Expand All @@ -406,10 +411,6 @@ module.exports = function (s, conf) {
let buy_max_as_pct = n(adjusted_buy_max_amt).divide(s.balance.currency).multiply(100).value()
buy_pct = buy_max_as_pct
}
} else { // account for held assets as %
let held_pct = n(s.asset_capital).divide(s.balance.currency).multiply(100).value()
let to_buy_pct = n(buy_pct).subtract(held_pct).value()
buy_pct = to_buy_pct
}
if (so.use_fee_asset) {
fee = 0
Expand All @@ -432,13 +433,8 @@ module.exports = function (s, conf) {
size = s.product.max_size
}
msg('preparing buy order over ' + fa(size) + ' of ' + fc(tradeable_balance) + ' (' + buy_pct + '%) tradeable balance with a expected fee of ' + fc(expected_fee) + ' (' + fee + '%)')
if (!s.last_sell_price && s.my_prev_trades.length) {
var prev_sells = s.my_prev_trades.filter(trade => trade.type === 'sell')
if (prev_sells.length) {
s.last_sell_price = prev_sells[0].price
}
}
let buy_loss = s.last_sell_price ? (s.last_sell_price - Number(price)) / s.last_sell_price * -100 : null
let latest_low_sell = _.chain(trades).dropRightWhile(['type','buy']).takeRightWhile(['type','sell']).sortBy(['price']).head().value() // return lowest price
let buy_loss = latest_low_sell ? (latest_low_sell.price - Number(price)) / latest_low_sell.price * -100 : null
if (so.max_buy_loss_pct != null && buy_loss > so.max_buy_loss_pct) {
let err = new Error('\nloss protection')
err.desc = 'refusing to buy at ' + fc(price) + ', buy loss of ' + pct(buy_loss / 100)
Expand Down Expand Up @@ -485,13 +481,8 @@ module.exports = function (s, conf) {
if (s.product.max_size && Number(size) > Number(s.product.max_size)) {
size = s.product.max_size
}
if (!s.last_buy_price && s.my_prev_trades.length) {
var prev_buys = s.my_prev_trades.filter(trade => trade.type === 'buy')
if (prev_buys.length) {
s.last_buy_price = prev_buys[0].price
}
}
let sell_loss = s.last_buy_price ? (Number(price) - s.last_buy_price) / s.last_buy_price * -100 : null
let latest_high_buy = _.chain(trades).dropRightWhile(['type','sell']).takeRightWhile(['type','buy']).sortBy(['price']).reverse().head().value() // return highest price
let sell_loss = latest_high_buy ? (Number(price) - latest_high_buy.price) / latest_high_buy.price * -100 : null
if (so.max_sell_loss_pct != null && sell_loss > so.max_sell_loss_pct) {
let err = new Error('\nloss protection')
err.desc = 'refusing to sell at ' + fc(price) + ', sell loss of ' + pct(sell_loss / 100)
Expand Down Expand Up @@ -588,6 +579,12 @@ module.exports = function (s, conf) {
}
}
s.action = 'bought'
if (!s.last_sell_price && s.my_prev_trades.length) {
let prev_sells = s.my_prev_trades.filter(trade => trade.type === 'sell')
if (prev_sells.length) {
s.last_sell_price = prev_sells[prev_sells.length - 1].price
}
}
let my_trade = {
order_id: trade.order_id,
time: trade.time,
Expand Down Expand Up @@ -631,6 +628,12 @@ module.exports = function (s, conf) {
}
}
s.action = 'sold'
if (!s.last_buy_price && s.my_prev_trades.length) {
let prev_buys = s.my_prev_trades.filter(trade => trade.type === 'buy')
if (prev_buys.length) {
s.last_buy_price = prev_buys[prev_buys.length - 1].price
}
}
let my_trade = {
order_id: trade.order_id,
time: trade.time,
Expand Down
2 changes: 1 addition & 1 deletion templates/dashboard.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@
<% }); %>
<% } %>
<% if (my_prev_trades) { %>
<% my_prev_trades.sort(function(a,b){return a.time > b.time ? -1 : 1;}).forEach(function(trade){ %>
<% my_prev_trades.reverse().forEach(function(trade){ %>
<tr class="text-muted">
<td><%= trade.type.toUpperCase() %></span></td>
<td><%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(trade.size) %> <%= asset.toUpperCase() %></td>
Expand Down