移植 OKCoin 韭菜收割机

Author: Zero, Date: 2017-01-30 19:38:25
Tags: High-frequency

移植自: https://github.com/richox/okcoin-leeks-reaper

原作者说收手续费以后就失效了, 我只做了移植, 没有实盘测试, 有兴趣可以学习 发明者量化Tick级回测支持Depth与Trades的回放, 可以直接进行回测学习策略逻辑

以下为原说明

OKCoin韭菜收割机

这是一个在OKCoin比特币交易平台上的高频交易机器人程序,从2016年6月策略基本定型,到2017年1月中旬,这个策略成功的把最初投入的6000块钱刷到了250000。由于近日央行对比特币实行高压政策,各大平台都停止了配资,并且开始征收交易费,该策略实际上已经失效了。

image

本机器人程序基于两个主要策略:

  1. 趋势策略:在价格发生趋势性的波动时,及时下单跟进,即俗话说的追涨杀跌
  2. 平衡策略:仓位偏离50%时,放出小单使仓位逐渐回归50%,防止趋势末期的反转造成回撤,即收益落袋,不吃鱼尾

本程序要求平衡仓位,即(本金+融资=融币),使得仓位在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)
    }
}

Related

More

梭哈大魔王 策略已失效,利润来源于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 趋势策略为什么会怕冲击成本呢。。。。。