移植自: https://github.com/richox/okcoin-leeks-reaper
原作者说收手续费以后就失效了, 我只做了移植, 没有实盘测试, 有兴趣可以学习 发明者量化Tick级回测支持Depth与Trades的回放, 可以直接进行回测学习策略逻辑
以下为原说明
这是一个在OKCoin比特币交易平台上的高频交易机器人程序,从2016年6月策略基本定型,到2017年1月中旬,这个策略成功的把最初投入的6000块钱刷到了250000。由于近日央行对比特币实行高压政策,各大平台都停止了配资,并且开始征收交易费,该策略实际上已经失效了。
本机器人程序基于两个主要策略:
本程序要求平衡仓位,即(本金+融资=融币),使得仓位在50%时净资产不随着价格波动,也保证了发生趋势性波动时涨跌都赚。
感谢以下两个项目:
感谢OKCoin:
BTC: 3QFn1qfZMhMQ4FhgENR7fha3T8ZVw1bEeU
/*backtest start: 2019-09-05 00:00:00 end: 2019-09-05 22:00:00 period: 1h exchanges: [{"eid":"Binance","currency":"BTC_USDT","fee":[0,0]}] mode: 1 */ function LeeksReaper() { var self = {} self.numTick = 0 self.lastTradeId = 0 self.vol = 0 self.askPrice = 0 self.bidPrice = 0 self.orderBook = {Asks:[], Bids:[]} self.prices = [] self.tradeOrderId = 0 self.p = 0.5 self.account = null self.preCalc = 0 self.preNet = 0 self.updateTrades = function() { var trades = _C(exchange.GetTrades) if (self.prices.length == 0) { while (trades.length == 0) { trades = trades.concat(_C(exchange.GetTrades)) } for (var i = 0; i < 15; i++) { self.prices[i] = trades[trades.length - 1].Price } } self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) { // Huobi not support trade.Id if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) { self.lastTradeId = Math.max(trade.Id == 0 ? trade.Time : trade.Id, self.lastTradeId) mem += trade.Amount } return mem }, 0) } self.updateOrderBook = function() { var orderBook = _C(exchange.GetDepth) self.orderBook = orderBook if (orderBook.Bids.length < 3 || orderBook.Asks.length < 3) { return } self.bidPrice = orderBook.Bids[0].Price * 0.618 + orderBook.Asks[0].Price * 0.382 + 0.01 self.askPrice = orderBook.Bids[0].Price * 0.382 + orderBook.Asks[0].Price * 0.618 - 0.01 self.prices.shift() self.prices.push(_N((orderBook.Bids[0].Price + orderBook.Asks[0].Price) * 0.35 + (orderBook.Bids[1].Price + orderBook.Asks[1].Price) * 0.1 + (orderBook.Bids[2].Price + orderBook.Asks[2].Price) * 0.05)) } self.balanceAccount = function() { var account = exchange.GetAccount() if (!account) { return } self.account = account var now = new Date().getTime() if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) { self.preCalc = now var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)) if (net != self.preNet) { self.preNet = net LogProfit(net) } } self.btc = account.Stocks self.cny = account.Balance self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny) var balanced = false if (self.p < 0.48) { Log("开始平衡", self.p) self.cny -= 300 if (self.orderBook.Bids.length >0) { exchange.Buy(self.orderBook.Bids[0].Price + 0.00, 0.01) exchange.Buy(self.orderBook.Bids[0].Price + 0.01, 0.01) exchange.Buy(self.orderBook.Bids[0].Price + 0.02, 0.01) } } else if (self.p > 0.52) { Log("开始平衡", self.p) self.btc -= 0.03 if (self.orderBook.Asks.length >0) { exchange.Sell(self.orderBook.Asks[0].Price - 0.00, 0.01) exchange.Sell(self.orderBook.Asks[0].Price - 0.01, 0.01) exchange.Sell(self.orderBook.Asks[0].Price - 0.02, 0.01) } } Sleep(BalanceTimeout) var orders = exchange.GetOrders() if (orders) { for (var i = 0; i < orders.length; i++) { if (orders[i].Id != self.tradeOrderId) { exchange.CancelOrder(orders[i].Id) } } } } self.poll = function() { self.numTick++ self.updateTrades() self.updateOrderBook() self.balanceAccount() var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct var bull = false var bear = false var tradeAmount = 0 if (self.account) { LogStatus(self.account, 'Tick:', self.numTick, ', lastPrice:', self.prices[self.prices.length-1], ', burstPrice: ', burstPrice) } if (self.numTick > 2 && ( self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -1)) > burstPrice || self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -2)) > burstPrice && self.prices[self.prices.length-1] > self.prices[self.prices.length-2] )) { bull = true tradeAmount = self.cny / self.bidPrice * 0.99 } else if (self.numTick > 2 && ( self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -1)) < -burstPrice || self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -2)) < -burstPrice && self.prices[self.prices.length-1] < self.prices[self.prices.length-2] )) { bear = true tradeAmount = self.btc } if (self.vol < BurstThresholdVol) { tradeAmount *= self.vol / BurstThresholdVol } if (self.numTick < 5) { tradeAmount *= 0.8 } if (self.numTick < 10) { tradeAmount *= 0.8 } if ((!bull && !bear) || tradeAmount < MinStock) { return } var tradePrice = bull ? self.bidPrice : self.askPrice while (tradeAmount >= MinStock) { var orderId = bull ? exchange.Buy(self.bidPrice, tradeAmount) : exchange.Sell(self.askPrice, tradeAmount) Sleep(200) if (orderId) { self.tradeOrderId = orderId var order = null while (true) { order = exchange.GetOrder(orderId) if (order) { if (order.Status == ORDER_STATE_PENDING) { exchange.CancelOrder(orderId) Sleep(200) } else { break } } } self.tradeOrderId = 0 tradeAmount -= order.DealAmount tradeAmount *= 0.9 if (order.Status == ORDER_STATE_CANCELED) { self.updateOrderBook() while (bull && self.bidPrice - tradePrice > 0.1) { tradeAmount *= 0.99 tradePrice += 0.1 } while (bear && self.askPrice - tradePrice < -0.1) { tradeAmount *= 0.99 tradePrice -= 0.1 } } } } self.numTick = 0 } return self } function main() { var reaper = LeeksReaper() while (true) { reaper.poll() Sleep(TickInterval) } }
梭哈大魔王 策略已失效,利润来源于0手续费的高频小差价收入。
kongbai979 self.vol到底是个啥?是一个ticker期间内所有交易量的总和吗?
dayTrader2018 for (var i = 0; i < 15; i++) { self.prices[i] = trades[trades.length - 1].Price };这儿是不是有点问题,这样岂不是prices数组中的每个元素都是最新的成交价格?
kouyou7035 我有几个没有手续费,交易深度不错的交易所。可以试这个策略么?有没有大神指导一下,我能帮助申请交易所账号。
bijiasuo 厉害,可惜不会用,现在能用么
skyfffire 注释版售价:2000一份,非官方,有意联系
rajajack 有谁测试过了,都出来讨论一下收益情况呗??
valennn 什么时候来个注释版
wuqianming 怎么在botvs不支持的,免交易费的交易所跑,需要怎么写交易所api?
J 感谢分享这么好的策略! exchange.CancelOrder(orders[i].Id) 这里撤单的代码有点问题,实测时不断的下单、撤单。 看了下原版的代码,应该是等10秒后才撤单。 其它基本都没问题了,我修改后放在免手续费的交易所跑,感觉很不错。
kmstudio 66行prices需加.length
snowpea 这是什么语言?
Zero 平衡那里下单忘加上Price属性了。。已更正,有发现bug请及时提交.
水生 看来还是有赚钱的策略,有就是不卖,留着自己赚。
1213761768 早不放出来
张无忌 不会, bidprice一定小于askprice, 一个是买单价格, 一个是卖单价格
bwxiaok 请问在计算bidprice和askprice时,下单是好像没有判断bidprice大于askprice时才下单,这样如果买一卖一很近的话,计算出来很可能就是高买低卖,会有这个问题吗
我爱毛爷爷 我写了个注释版,大家需要可以加我微信Hoo_tongxue,最重要的是免费。。
我爱毛爷爷 真的脸皮够厚。。服
小煤球 哪些交易所?
Zero 这个应该间初始化成最新价格的, 后面有shift操作
重仓出奇迹 早就失效了..现在都是机器人大战..
suski 可以可以,这波韭菜割得更好^_^
skyfffire 卖者愿卖,买者愿买,不与你争论。
诺女也 人家都公开了源码,你注释一下,卖2000?真好意思。
akkk 请问zaif.jp现在还是免手续费吗?怎么通过认证呢
xiahaohuan001 看ID是的
J 在Zaif.jp上测试,买一卖一间经常就没有空间,用这个策略有什么问题吗?
J 是不是真的!出来给大家讲课吧
xiahaohuan001 惊现原作者
J 好的,还有些问题请教,另外开了个帖子: https://www.botvs.com/bbs-topic/677
Zero 如果有对这个策略的学习分享或者疑问, 请在论坛里发布, 感谢支持 !
Zero 多谢建议,我加了个参数,平衡单等待时间, 如果想要并发处理, 可以记录每个订单的ID与下单时间, 再选择性取消, 这样可以减少延迟, 不过道理上,应该是先平衡再开仓的, 因为不是所有交易所都支持获取订单的Time属性 , 所以平台没有在Order里加这个属性, 需要自己统计.
xiahaohuan001 感觉这个策略很怪,我喜欢(*^__^*)
Zero 这个我也没试过 需要你们自己研究了
Orion1708 辛苦Z大移植~。请教,策略参数默认值的变化对策略有很大影响吗
Zero 哈哈, 多谢, 已经加上.
Zero Javascript
Zero 交易频率高
发明者量化-小小梦 原作者 也是 在收手续费 那几天 才公开的。
xiahaohuan001 趋势策略为什么会怕冲击成本呢。。。。。