The resource loading... loading...

Transplanting OKCoin to the cabbage harvester

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

Transplantation from:https://github.com/richox/okcoin-leeks-reaper

The original author said that it would not work after the fee, so I just did the transplant, no physical testing, interested in learning. Inventors of Quantitative Tick-level retrieval support playback of Depth and Trades, allowing direct retrieval of learning strategy logic

The following is the original description

OKCoin is a cabbage harvester

This is a high-frequency trading robot program on the OKCoin Bitcoin trading platform, which was successfully brushed from its initial investment of 6,000 to 250,000 by mid-January 2017. The strategy has effectively failed due to the recent high-pressure policy of the Central Bank against Bitcoin, which has led to the cessation of all major platforms and the start of charging transaction fees.

image

This robotic program is based on two main strategies:

  1. Trend strategy: order in a timely manner and follow up when price fluctuates in a trendy way, as the saying goesChasing and killing
  2. Balancing strategy: When a position deviates 50%, the slips are released to gradually bring the position back down to 50%, preventing a reversal at the end of the trend from causing a retracement, i.e.Revenues dropped in bags, fish tails not eaten

This procedure requires balancing the position, i.e. (capital + financing = money), so that the position is at 50% when the net assets do not fluctuate with the price, but also guarantees when trend fluctuations occur.It's all right.

Thank you to the following two projects:

Thanks to 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

The King of Hip HopThe strategy has failed, and profits come from high-frequency low-differential income with zero handling fees.

kongbai979 self.vol到底是个啥?是一个ticker期间内所有交易量的总和吗?

dayTrader2018for (var i = 0; i < 15; i++) { self.prices[i] = trades[trades.length - 1].Price }; is there a bit of a problem here, so isn't every element in the price array the most recent transaction price?

kouyou7035I have several exchanges with no fees and good trading depths. Can you try this strategy?

bijiasuoIt's great, I'm sorry it won't work, is it working now?

skyfffireThe price of the commentary is: 2000 copies, unofficial, with intentional link.

rajajackIf anyone has tried it, come out and discuss the benefits.

valennnWhen will the annotations come?

wuqianmingHow do you run a botvs unsupported, free-to-trade exchange, how do you write an exchange API?

JThank you for sharing such a great strategy! exchange.CancelOrder ((orders[i].Id) The code for cancellation has a bit of a problem with the constant cancellation of orders. If you look at the original code below, you should have waited 10 seconds to withdraw it. The rest is basically fine, and I've changed it to run on a fee-free exchange, which feels good.

kmstudio 66行prices需加.length

snowpeaWhat language is that?

Zero 平衡那里下单忘加上Price属性了。。已更正,有发现bug请及时提交.

The AquariusIt seems that there is a strategy to make money, or not to sell and keep your money.

1213761768It's too early.

Chang is unyielding.No, the bid price has to be less than the ask price, one is the bid price, one is the sell price.

bwxiaokPlease, when calculating bid price and ask price, the order is placed as if the bid price is not greater than the ask price, so if the buy and sell is very close, the calculation is very likely to be high buy low sell, will there be this problem?

I love the fluff.I wrote a commentary that everyone needs to be able to add my Weibo post Hoo_tongxue, and most importantly, it's free.

I love the fluff.The real face is thick enough.

Small coal ballsWhat exchanges?

ZeroThis should initialize to the latest price, followed by a shift operation.

Miracle at the Re-StorageIt's been a long time since we've had a robot war.

suskiYes, this is a better cut of cabbage ^_^

skyfffireLet the seller sell, and let the buyer buy; and let them not contend with thee.

The bride too.The source code has been made public by everyone, can you comment on it, sell 2000?

akkk 请问zaif.jp现在还是免手续费吗?怎么通过认证呢

xiahaohuan001See the ID.

J 在Zaif.jp上测试,买一卖一间经常就没有空间,用这个策略有什么问题吗?

JIs it true? Come out and give a lecture.

xiahaohuan001Surprised by Author

JGood, I have a few more questions, please, and another post: https://www.botvs.com/bbs-topic/677

ZeroIf you have any questions or lessons to share about this strategy, please post them in the forum, thanks for your support!

ZeroThanks for the suggestion, I added a parameter, balance order waiting time, if you want to process simultaneously, you can record the ID of each order with the time of ordering, and then selectively cancel, so as to reduce the delay, but logically, should be first balance re-opening, because not all exchanges support the Time attribute to get the order, so the platform does not add this attribute in the Order, needing its own statistics.

xiahaohuan001I feel like it's a weird strategy, I like it.

ZeroI haven't tried this, so I need you to do your own research.

Orion1708Hard Z major port. Please, does changing the policy parameter default have a big impact on the policy?

ZeroHa ha, thank you, it's been added.

Zero Javascript

ZeroHigh frequency of transactions

Inventors quantify - small dreamsThe original author was also released on the same day as the fee was collected.

xiahaohuan001Why are trend strategists afraid of shock costs?