如何用80行代码的高频策略剥削无脑出售的机器人

Author: 小草, Created: 2023-12-24 21:37:45, Updated: 2023-12-26 15:40:23

img

机会观察

最近这两天在看行情时无意发现币安有一个币STORJ的行情很奇怪,交易量很大,而且交易频率非常快,具体一分钟K线的如下图,可以看到每分钟的交易量都比较一致,且分钟线上能看到长长的下影线 img 用币安的1秒级K线观察下,发现了端倪,有人每隔5-7s就会市价1-2万个STORJ,不计成本,直接在K线上砸了一个小坑,而价格在短期内会恢复。这个操作显然是冰山委托的机器人造成的。这个卖出的操作持续时间非常长,总量估计达到千万美元级别,很多时候造成的滑点达到千分之1,这意味着仅交易的滑点,这个策略的执行者就亏了上万美元。但如此机械的操作和活跃的成交存在明显的做市剥头皮的机会。 img

把原来的现货高频策略简单改了下,几分钟就搞好了这个专门剥削这个无脑出售冰山委托的机器人。

策略思路

既然每隔几秒都会市价卖出,我们只需要在买单簿中找到1万的深度,把单子挂在前面。这样在这个冰山卖出时,很高的概率做市机器人正好能接到,而此时的交易非常活跃,瞬间的价格下滑也引发了一些买单,同样的道理挂卖单顺势抛出即可,如此反复操作。成交的频率非常高,即使每次的收益率不大总的收益也相当可观。当然一切的前提是有低手续费的账号,如果买卖的手续费都是千分之1,那么这个空间根本不够交手续费的。

策略表现

策略表现如下,刚开始收益都没有打印,今天下午改了下,把收益打了出来,疯狂抛售的机器人已经把每次的量改为了5000左右,所以过了最佳套利的时期了。刚开始每小时大概能赚100-200U,关键是无风险,低成本。从这里反过来看,冰山委托其实也有很多技巧,如果会写策略的话,在FMZ上花个十几分钟就能写出来观察买单订单深度决定下单大小和价格,观察主动买单的大小调整挂单大小并占据盘口等特点的冰山委托策略,轻松节约几万美元。

img

策略源码

策略代码非常简单,只有80行。适合初学者,这里的一些参数如下单精度之类的写死在程序里了,可以自己改下,需要的参数如下图,建议可以保存备下,万一那个交易所交易对又出现抽风的交易者,随时向他们收点利息。 img

function CancelPendingOrders() {
    var orders = _C(exchange.GetOrders)
    for (var j = 0; j < orders.length; j++) {
        exchange.CancelOrder(orders[j].Id, orders[j])
    }
}

function onexit(){
    CancelPendingOrders()
}

function GetPrice(Type, Depth) {
    var sumAmount = 0
    var checkAmount = Type == "Buy" ? CheckBuyAmount : CheckSellAmount
    var deep = Type == "Buy" ? Depth.Bids : Depth.Asks
    for(var i = 0; i < Math.min(20, deep.length); i++) {
        if(Type == "Buy"  && deep[i].Price == lastBuyPrice && buyId){
            sumAmount += deep[i].Amount - amountBuy //这里要减去自己的挂单
        }else if(Type == "Sell"  && deep[i].Price == lastSellPrice && sellId){
            sumAmount += deep[i].Amount - amountSell
        }else{
            sumAmount += deep[i].Amount
        }
        if(sumAmount >= checkAmount){
            return deep[i].Price
        }
    }
    return deep[19].Price
}

function OnTick() {
    var depth = _C(exchange.GetDepth)
    var buyPrice = _N(Math.min(GetPrice("Buy", depth) + 0.0001, depth.Asks[0].Price-0.0001) , 4) //保证在盘口
    var sellPrice = _N(Math.max(GetPrice("Sell", depth) - 0.0001, depth.Bids[0].Price+0.0001), 4)
    LogStatus('buy_price:'+buyPrice, '  sell price: '+sellPrice)
    if ((sellPrice - buyPrice) < DiffPrice) {
        buyPrice = 0
    }
    if(sellPrice != lastSellPrice && sellId){
        exchange.CancelOrder(sellId);
        sellId = 0
        lastSellPrice = 0
    }
    if(buyPrice != lastBuyPrice && buyId){
        exchange.CancelOrder(buyId);
        buyId = 0
        lastBuyPrice = 0
    }   
    var acc = _C(exchange.GetAccount)
    if(account.Stocks+account.FrozenStocks != acc.Stocks+acc.FrozenStocks){
        LogProfit((acc.Stocks+acc.FrozenStocks)*depth.Bids[0].Price+acc.Balance+acc.FrozenBalance - 2000)
        Log('free '+acc.Stocks, ' lock: '+ acc.FrozenStocks, ' total: ' , (acc.Stocks+acc.FrozenStocks)*depth.Bids[0].Price+acc.Balance+acc.FrozenBalance)
    }
    account = acc
    amountBuy = _N(Math.min(account.Balance / buyPrice - 0.1, Amount), 0)
    amountSell = _N(account.Stocks, 0)
    if (sellPrice > 0 && amountSell > 40 && sellId == 0) {
        sellId = exchange.Sell(_N(sellPrice,4), amountSell)
        lastSellPrice = sellPrice
    }
    if (buyPrice>0 && amountBuy > 40 && buyId == 0) {
        buyId = exchange.Buy(_N(buyPrice,4), amountBuy)
        lastBuyPrice = buyPrice
    }
    Sleep(Interval)
}
var account = {Stocks:0, FrozenStocks:0, Balance:0, FrozenBalance:0}
var buyId = 0
var sellId = 0
var lastBuyPrice = 0
var lastSellPrice = 0
var amountSell = 0
var amountBuy = 0
function main() {
    CancelPendingOrders()
    while (true) {
        OnTick()
    }
}

More

checkpoint 草神,跑的这个策略手续费是多少

yc123h 小草老师请教一下,这个策略生效的情况下,是不是每个轮训开始,经常能看到撤销之前的两个订单失败的消息(也就是说明买卖单都生效了),才说明策略是有效的

小草 这个是0手续费

yc123h 哦哦谢谢,另外就是还想向您请教下参数的问题。像这种高频策略如何优化参数。例如我看您分享的2014年的策略,默认的轮训间隔达到了3500ms,如果是高频的话,轮训间隔是不是应该短一点比较好。但是太短的话成交也挺难的,如果太长的话,收市场波动的影响就很大了,如果持仓后没有能够在利润点卖出去,就可能亏损。这块我不是太明白。。

小草 撤销失败是成交了,赚钱了才能说明有效