Skip to content

Latest commit

 

History

History
255 lines (224 loc) · 9.18 KB

不同计价币的现货对冲策略教学.md

File metadata and controls

255 lines (224 loc) · 9.18 KB

Name

不同计价币的现货对冲策略教学

Author

小小梦

Strategy Description

不同计价币的现货对冲策略(教学)

相关文章:https://www.fmz.com/digest-topic/7593

Strategy Arguments

Argument Default Description
keepBalanceCyc 300 平衡周期
diffAsPercentage true 使用差价百分比
hedgeDiffPrice 20 对冲差价
hedgeDiffPercentage 0.04 对冲差价百分比
minHedgeAmount 0.005 对冲最小下单量
maxHedgeAmount 0.2 对冲最大下单量
rateA true A交易所汇率
rateB true B交易所汇率
isReset false 重置所有信息
pricePrecisionA 2 A价格精度
amountPrecisionA 3 A下单量精度
pricePrecisionB 2 B价格精度
amountPrecisionB 3 B下单量精度

Source (javascript)

// 全局变量
var lastKeepBalanceTS = 0

function hedge(buyEx, sellEx, price, amount) {
    var buyRoutine = buyEx.Go("Buy", price, amount)
    var sellRoutine = sellEx.Go("Sell", price, amount)
    Sleep(500)
    buyRoutine.wait()
    sellRoutine.wait()
}

function getDepthPrice(depth, side, amount) {
    var arr = depth[side]
    var sum = 0
    var price = null
    for (var i = 0 ; i < arr.length ; i++) {
        var ele = arr[i]
        sum += ele.Amount
        if (sum >= amount) {
            price = ele.Price
            break
        }
    }
    return price
}

function keepBalance(initAccs, nowAccs, depths) {
    var initSumStocks = 0
    var nowSumStocks = 0 
    _.each(initAccs, function(acc) {
        initSumStocks += acc.Stocks + acc.FrozenStocks
    })
    _.each(nowAccs, function(acc) {
        nowSumStocks += acc.Stocks + acc.FrozenStocks
    })
    
    var diff = nowSumStocks - initSumStocks
    // 计算币差
    if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
        Log("触发平衡操作,平衡量:", Math.abs(diff))
        var index = -1
        var available = []
        var side = diff > 0 ? "Bids" : "Asks"
        for (var i = 0 ; i < nowAccs.length ; i++) {
            var price = getDepthPrice(depths[i], side, Math.abs(diff))
            if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
                available.push(i)
            } else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
                available.push(i)
            }
        }
        for (var i = 0 ; i < available.length ; i++) {
            if (index == -1) {
                index = available[i]
            } else {
                var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
                var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
                if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
                    index = available[i]
                } else if (priceIndex && priceI && priceI < priceIndex) {
                    index = available[i]
                }
            }
        }
        if (index == -1) {
            Log("无法平衡")            
        } else {
            // 平衡下单
            var price = getDepthPrice(depths[index], side, Math.abs(diff))
            if (price) {
                var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
                tradeFunc(price, Math.abs(diff))
            } else {
                Log("价格无效", price)
            }
        }        
        return false
    } else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
        Log("错误:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
        return true 
    } else {
        return true 
    }
}

function cancelAll() {
    _.each(exchanges, function(ex) {
        while (true) {
            var orders = _C(ex.GetOrders)
            if (orders.length == 0) {
                break
            }
            for (var i = 0 ; i < orders.length ; i++) {
                ex.CancelOrder(orders[i].Id, orders[i])
                Sleep(500)
            }
        }
    })
}

function updateAccs(arrEx) {
    var ret = []
    for (var i = 0 ; i < arrEx.length ; i++) {
        var acc = arrEx[i].GetAccount()
        if (!acc) {
            return null
        }
        ret.push(acc)
    }
    return ret 
}

function main() {
    var exA = exchanges[0]
    var exB = exchanges[1]
    // 精度,汇率设置
    if (rateA != 1) {
        // 设置汇率A
        exA.SetRate(rateA)
        Log("交易所A设置汇率:", rateA, "#FF0000")
    }
    if (rateB != 1) {
        // 设置汇率B
        exB.SetRate(rateB)
        Log("交易所B设置汇率:", rateB, "#FF0000")
    }
    exA.SetPrecision(pricePrecisionA, amountPrecisionA)
    exB.SetPrecision(pricePrecisionB, amountPrecisionB)

    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log("重置所有数据", "#FF0000")
    }

    var nowAccs = _C(updateAccs, exchanges)
    var initAccs = _G("initAccs")
    if (!initAccs) {
        initAccs = nowAccs
        _G("initAccs", initAccs)
    }

    var isTrade = false 
    while (true) {
        var ts = new Date().getTime()
        var depthARoutine = exA.Go("GetDepth")
        var depthBRoutine = exB.Go("GetDepth")
        var depthA = depthARoutine.wait()
        var depthB = depthBRoutine.wait()
        if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
            Sleep(500)
            continue 
        }

        var targetDiffPrice = hedgeDiffPrice
        if (diffAsPercentage) {
            targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
        }

        if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B 盘口条件满足            
            var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
            var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
            if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
                Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // 提示信息
                hedge(exB, exA, price, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        } else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) {   // B -> A 盘口条件满足
            var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
            var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
            if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
                Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // 提示信息
                hedge(exA, exB, price, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        }
        
        if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
            nowAccs = _C(updateAccs, exchanges)
            var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
            cancelAll()
            if (isBalance) {
                lastKeepBalanceTS = ts
                if (isTrade) {
                    var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                    var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                    LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
                    isTrade = false 
                }                
            }            
        }
        LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n", 
            "当前A,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
            "当前B,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
            "初始A,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
            "初始B,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
        Sleep(1000)
    }
}

Detail

https://www.fmz.com/strategy/298752

Last Modified

2021-07-30 16:54:39