makebit-简易对冲策略(高级下单功能模板函数)


创建日期: 2025-08-08 18:45:49 最后修改: 2025-08-13 16:21:52
复制: 0 点击次数: 487
avatar of makebit makebit
5
关注
313
关注者

免费公开一个简易版的对冲策略,其中包含了实现高级功能的下单接口,为新手提供一些开发思路。 makebit-简易对冲策略(高级下单功能模板函数) 有开发OKX交易接口能力的看这里: OKX没有节点返佣时下单tag参数填写 4944196c4337SUDE 可获得40%经纪商返佣到你自己账户(策略默认行为)不使用我提供的交易模板也一样自动返佣到你自己账户。 OKX已有节点返佣时经纪商额外返佣比例为12%,也是全自动返到你自己的账户。 没有FMZ平台账号的看这里; 注册返红包链接 https://www.fmz.com/sign-up/6203996 高级下单功能模板函数 支持功能: 1市价下单:币安 okx gate 现货与合约 2高级选项下单: okx gate 币安 bitget Bybit mexc CoinEx kucoin 3修改订单: okx,币安,CoinEx,Bybit,gate 1:创建订单 $.creatOrder( e , instId , side , type , price , amount , timeInForce , reduceOnly , isModif , sleepMode ) 参数说明: e 交易所对象 instId 交易对名称 side 下单方向 ‘buy’ 或 ‘sell’ type 下单类型 limit 限价单 market 市价单 price 下单价格 amount 下单数量 timeInForce 高级选项 GTC - Good Till Cancel 成交为止 IOC - Immediate or Cancel 无法立即成交(吃单)的部分就撤销 FOK - Fill or Kill 无法全部立即成交就撤销 GTX - Good Till Crossing 无法成为挂单方就撤销 reduceOnly bool 是否是只减仓合约可用 isModif bool 是否为修改订单 sleepMode bool 当超过下单频率是否等待

调用成功后生成交易订单信息然后执行下单函数

2:执行下单 \(.batchOrders( e , orderBox , rMode , ws , tdMode ) 参数说明: e 交易所对象, orderBox 数组 就是 \).creatOrder 生成的订单信息列表,支持批量下单 rMode 可填 ‘go’ 就是异步下单之后获取结果 否则是阻塞下单获取结果 ws 当用websocket链接下单时传入ws对象 tdMode okx账户专用参数,根据账户类型 现货一般使用 ‘cash’ 合约使用 ‘cross’

3:查看执行结果 function handleWaitList() 具体使用方法可以查看本策略里的代码

策略使用说明: 创建机器人: 1:添加交易所时注意选择交易对,策略下单交易为配置的交易对。 目前支持 币安 OKX gate 现货与合约交易所之间的对冲。 2:点击按钮 做多匹配 或 做空匹配 开始确定做多与做空的交易所账户在匹配信息里可以看到匹配状态 3:点击对冲开仓或平仓,将对进行匹配成功的交易对同时执行买入与卖出操作实现对冲。

有问题的可以在电报群找我 https://t.me/FMZ_makebit

策略源码

var exKeyList = []
var exInfo = []
// index : index,
// key : key,
// exname : exname,
// quote : quote,
// label : label,
// currency : currency,
// balance : {},
// positon : {},
// ticker : {},
// contractType : ".swap",
// waitResultsList : [],
// roomId : null,
var configInfo = {}
var tradeRoom = []
var roomId = 0
const MarginLevel = 20
const red = "#FF0000"
const green = "#238E23"
const orange = "#FF7F00"
const blue = "#0000ff"
var okxAcctLv = ''
var tdMode = "cash"
    
function initExInfo(){
    //将每个交易所
    var index = 0
    exchanges.forEach( function( e ){
        var exname = e.GetName()
        if( exname == 'OKEX' || exname == 'Futures_OKCoin' ){
            var ret = e.IO("api", "GET", "/api/v5/account/config")
            //1:简单交易模式,2:单币种保证金模式 ,3:跨币种保证金模式 ,4:组合保证金模式
            if( ret ){
            okxAcctLv = ret.data[0].acctLv
                if( okxAcctLv == 3 || exname == 'Futures_OKCoin'){
                    tdMode = "cross"
                }
            if( okxAcctLv == 4 ){throw exname+"不支持组合保证金模式"}
            }else{throw "Okx获取账户配置信息失败"}
        }
        if(typeof(configInfo[exname]) == 'undefined' ){
            configInfo[exname] = {}
        }
        configInfo[exname] = e.GetMarkets()
        var quote = e.GetQuoteCurrency()
        var label = e.GetLabel()
        var isFutures = exname.indexOf("Futures_") == 0
        var key = exname+'@'+quote+'@'+label
        if( exKeyList.indexOf(key) == -1 ){
            exKeyList.push(key)
        }else{
            Log("重复的交易所对象请删除",key)
            return
        }
        if( isFutures ){
            e.SetContractType("swap")
            //e.SetMarginLevel(MarginLevel)
        }
        configInfo[exname]
        var currency = e.GetCurrency()
        var info = {
            index : index,
            key : key,
            exname : exname,
            quote : quote,
            label : label,
            currency : currency,
            balance : {},
            positon : {},
            ticker : {},
            contractType : "",
            waitResultsList : [],
            roomId : null,
        }
        if( isFutures ){
            info.contractType = ".swap",
            info.positon[currency] = {
                Amount : 0,
                FrozenAmount : 0,
                Price : 0,
                Type : 0,
                Profit : 0,
            }
        }
        exInfo.push(info)
        index++
    })
}

function getConfig( info ){
    var key = info.currency+ info.contractType
    if( !configInfo[info.exname][key].MinNotional ){
        configInfo[info.exname][key].MinNotional = 5
    }
    if( !configInfo[info.exname][key].CtVal ){
        configInfo[info.exname][key].CtVal = 1
    }
    if( info.exname == 'GateIO' && !configInfo[info.exname][key].MinQty){
        configInfo[info.exname][key].MinQty = Number(configInfo[info.exname][key].Info.min_base_amount)
    }
    return configInfo[info.exname][key]
}

function updateBalance(){
    exInfo.forEach( function( item ){
        var e = exchanges[item.index]
        var Assets = e.GetAssets()
        Assets.forEach( function( coin ){
            if( typeof(item.balance[coin.Currency]) == 'undefined' ){
                item.balance[coin.Currency] = {
                    free : 0,
                    locked : 0,
                }
            }
            item.balance[coin.Currency].free = coin.Amount
            item.balance[coin.Currency].locked = coin.FrozenAmount
        })
    })
}

function updatePos(){
    exInfo.forEach( function( item ){
        var e = exchanges[item.index]
        var isFutures = item.exname.indexOf("Futures_") == 0
        if( isFutures ){
            var positon = e.GetPositions("USDT.swap")
            if( positon ){
                for( cur in item.positon ){
                    item.positon[cur] = {
                        Amount : 0,
                        FrozenAmount : 0,
                        Price : 0,
                        Type : 0,
                        Profit : 0,
                    }
                }
            }
            positon.forEach( function( pos ){
                if( typeof(item.positon[item.currency]) == 'undefined' ){
                    item.positon[item.currency] = {
                        Amount : 0,
                        FrozenAmount : 0,
                        Price : 0,
                        Type : 0,
                        Profit : 0,
                    }
                }
                item.positon[item.currency].Amount = pos.Type == PD_SHORT ? -1*pos.Amount : pos.Amount
                item.positon[item.currency].FrozenAmount = pos.FrozenAmount
                item.positon[item.currency].Price = pos.Price
                item.positon[item.currency].Type = pos.Type
                item.positon[item.currency].Profit = pos.Profit
            })
        }
    })
}

function updateTicker(){
    exInfo.forEach( function( item ){
        var e = exchanges[item.index]
        var ticker = e.GetTicker()
        item.ticker = ticker
    })
}

function getTableInfo(){
    var logstatus = ''
    var table1 = {
        type: "table",
        title:"账号信息汇总",
        scroll : "auto",
        cols: ["index","key","当前交易对","可用资金(U)","可用币","买一价","卖一价","持仓价格","持仓数量","浮动盈亏","持仓方向","最小开仓金额","匹配状态","买入","卖出","做多匹配","做空匹配","取消匹配"],
        rows: []
    }
    exInfo.forEach( function( info ){
        var buy1 = 0
        var sell1 = 0
        var price = 0
        var amount = 0
        var profit = 0
        var free = 0
        var stock = 0
        var type = '/'
        var 匹配状态 = info.roomId > 0 ? "已匹配"+ info.roomId + green : "未匹配" + orange
        var config = getConfig(info)
        var 最小开仓金额 = 0
        if( info.ticker ){
            最小开仓金额 = _N(Math.max(config.MinNotional,config.MinQty*config.CtVal*info.ticker.Last),2) 
            buy1 = info.ticker.Sell
            sell1 = info.ticker.Buy
        }
        if( info.positon[info.currency] ){
            price = _N(info.positon[info.currency].Price,config.PricePrecision)
            amount = info.positon[info.currency].Amount
            profit = info.positon[info.currency].Profit
            if( amount != 0 ){
                type = info.positon[info.currency].Type == PD_LONG ? "多":"空"
            }
        }
        if( info.balance[info.quote] ){
            free = _N(info.balance[info.quote].free,2)
        }
        if( info.balance[config.BaseAsset]){
            stock = _N(info.balance[config.BaseAsset].free,config.AmountPrecision)
        }
        var button1 = {
            'type': 'button',
            'cmd':  info.key + "|buyMatch",                              
            'name': '做多匹配' ,
            "class": "btn btn-xs btn-primary"
        }
        var button2 = {
            'type': 'button',
            'cmd': info.key + "|sellMatch",                              
            'name': '做空匹配' ,
            "class": "btn btn-xs btn-warning"
        }
        var button3 = {
            'type': 'button',
            'cmd': info.key + "|cancelMatch",                              
            'name': '取消匹配' ,
            "class": "btn btn-xs btn-danger"
        }
        var button7 = {
            'type': 'button',
            'cmd':  info.key + "|buyPos",                              
            'name': '买入' ,
            "class": "btn btn-xs btn-primary"
        }
        var button8 = {
            'type': 'button',
            'cmd': info.key + "|sellPos",                              
            'name': '卖出' ,
            "class": "btn btn-xs btn-warning"
        }
        table1.rows.push([
            info.index,
            info.key,
            info.currency,
            free,
            stock,
            buy1,
            sell1,
            price,
            amount,
            profit,
            type,
            最小开仓金额,
            匹配状态,
            button7,
            button8,
            button1,
            button2,
            button3,
        ])
    })
    var table2 = {
        type: "table",
        title:"匹配信息",
        scroll : "auto",
        cols: ["roomId","做多方","做空方","匹配状态","开仓价差率","对冲开仓","对冲平仓","删除匹配"],
        rows: []
    }
    tradeRoom.forEach( function( room ){
        var buyExInfo = null
        var sellExInfo = null
        if( room.buyKey ){
            buyExInfo = getInfoByKey(room.buyKey)
        }
        if( room.sellKey ){
            sellExInfo = getInfoByKey(room.sellKey)
        }
        var button4 = {
            'type': 'button',
            'cmd': room.roomId + "|open",                              
            'name': '对冲开仓' ,
            "class": "btn btn-xs btn-primary"
        }
        var button5 = {
            'type': 'button',
            'cmd': room.roomId + "|close",                              
            'name': '对冲平仓' ,
            "class": "btn btn-xs btn-warning"
        }
        var button6 = {
            'type': 'button',
            'cmd': room.roomId + "|delRoom",                              
            'name': '删除匹配' ,
            "class": "btn btn-xs btn-danger"
        }
        var 价差比 = '/'
        if( room.state == 1 && buyExInfo && buyExInfo.ticker && sellExInfo && sellExInfo.ticker ){
            // var buyConfig = getConfig(buyExInfo)
            // var sellConfig = getConfig(sellExInfo)
            价差比 = (sellExInfo.ticker.Buy - buyExInfo.ticker.Sell)/buyExInfo.ticker.Sell
            价差比 = _N( 价差比 * 100 , 3 ) + '%' 
        }
        table2.rows.push( [
            room.roomId,
            buyExInfo ? buyExInfo.key : '待匹配',
            sellExInfo ? sellExInfo.key : '待匹配',
            room.state == 1 ? "匹配成功" + green : "匹配中" + orange,
            价差比,
            button4,
            button5,
            button6,
        ] )
    })
    logstatus = ( 
        '`' + JSON.stringify([table1]) + '`' + '\n'+
        '`' + JSON.stringify([table2]) + '`' + '\n')
    return logstatus
}

function getMaxOrderAmout( info , side , reduceOnly ){
    var config = getConfig(info)
    //子线程
    var maxAmount = 0
    var isFutures = info.exname.indexOf("Futures_") == 0
    var freeBalance = info.balance[info.quote].free
    var freeStock = 0
    if( typeof(info.balance[config.BaseAsset]) != 'undefined'){
        freeStock = info.balance[config.BaseAsset].free
    }
    //计算最大可下单量
    if( isFutures ){ //有深度信息应该就是支持交易的
        var amount = info.positon[info.currency].Amount
        var 原仓位可平数 = 0
        var 保证金可开仓数 =  0
        if( (side == 'buy' && amount < 0) || (side == 'sell' && amount > 0)){
            原仓位可平数 = Math.abs( amount )
        }
        if( !reduceOnly ){
            保证金可开仓数 = (freeBalance)*MarginLevel*0.99/info.ticker.Last
            保证金可开仓数 = 保证金可开仓数/config.CtVal
        }
        //maxBuyAmount 是合约下单量,1000SATS这种
        maxAmount =  Math.min( 原仓位可平数 + 保证金可开仓数 , tradeQuoteLimit/info.ticker.Last/config.CtVal )
    }else{
        if( side == 'buy' ){
            maxAmount =  Math.min( freeBalance*0.99 , tradeQuoteLimit)/info.ticker.Last/config.CtVal
        }else{
            maxAmount =  Math.min( freeStock , tradeQuoteLimit/info.ticker.Last/config.CtVal)
        }
    }
    maxAmount = _N(maxAmount,config.AmountPrecision) 
    return maxAmount
}

function tradeSingle( key , side ){
    var reduceOnly = false
    var info = getInfoByKey(key)
    if( !info ){
        Log("未找到info",key)
        return
    }
    var isFutures = info.exname.indexOf("Futures_") == 0
    if( isFutures ){ //有深度信息应该就是支持交易的
        var amount = info.positon[info.currency].Amount
        if( (side == 'buy' && amount < 0) || (side == 'sell' && amount > 0)){
            reduceOnly = true
        }
    }
    var maxAmount = getMaxOrderAmout( info , side , reduceOnly )
    Log( info.key,"side",side,"maxAmount",maxAmount)
    creatOrder( info , side , info.ticker.Last , maxAmount , reduceOnly )
}

function tradePoll( roomId , reduceOnly ){
    Log( "roomId:" , roomId , "reduceOnly:" , reduceOnly )
    var roomInfo = getRoomInfoById( roomId ) 
    if( !roomInfo ){
        Log("未找到room信息",roomInfo)
        return
    }else if( roomInfo.state != 1 ){
        Log( roomInfo.roomId,"匹配未完成")
        return
    }
    //分别找到多空两边的信息
    var longExInfo = getInfoByKey(roomInfo.buyKey)
    var shortExInfo = getInfoByKey(roomInfo.sellKey)
    if( !longExInfo || !shortExInfo ){
        Log(longExInfo,"多空双方信息不齐全",shortExInfo)
        return
    }
    var buyIsFutures = false
    var sellIsFutures = false
    var buyConfig = null
    var sellConfig = null
    var maxBuyAmount = 0
    var maxSellAmount = 0
    var realBuyAmount = 0
    var realSellAmount = 0
    if( reduceOnly ){
        buyIsFutures = shortExInfo.exname.indexOf( 'Futures_' ) == 0
        sellIsFutures = longExInfo.exname.indexOf( 'Futures_' ) == 0
        buyConfig = getConfig(shortExInfo)
        sellConfig = getConfig(longExInfo)
        maxBuyAmount = getMaxOrderAmout( shortExInfo , 'buy' , reduceOnly )
        maxSellAmount = getMaxOrderAmout( longExInfo , 'sell' , reduceOnly )
        realBuyAmount =   maxBuyAmount*buyConfig.CtVal
        realSellAmount =  maxSellAmount*sellConfig.CtVal
    }else{
        buyIsFutures = longExInfo.exname.indexOf( 'Futures_' ) == 0
        sellIsFutures = shortExInfo.exname.indexOf( 'Futures_' ) == 0
        buyConfig = getConfig(longExInfo)
        sellConfig = getConfig(shortExInfo)
        maxBuyAmount = getMaxOrderAmout( longExInfo , 'buy' , reduceOnly )
        maxSellAmount = getMaxOrderAmout( shortExInfo , 'sell' , reduceOnly )
        realBuyAmount =   maxBuyAmount*buyConfig.CtVal
        realSellAmount =  maxSellAmount*sellConfig.CtVal
    }
    //精度处理
    var fixAmout = Math.min( realBuyAmount , realSellAmount )
    if( (buyIsFutures && sellIsFutures) || (!buyIsFutures && !sellIsFutures)){
        fixAmout = Math.min(_N( fixAmout/buyConfig.CtVal , buyConfig.AmountPrecision )*buyConfig.CtVal , _N( fixAmout/sellConfig.CtVal , sellConfig.AmountPrecision )*sellConfig.CtVal )
        realBuyAmount = _N( fixAmout/buyConfig.CtVal , buyConfig.AmountPrecision ) 
        realSellAmount = _N( fixAmout/sellConfig.CtVal , sellConfig.AmountPrecision ) 
    }else if(buyIsFutures){
        realBuyAmount = _N( fixAmout/buyConfig.CtVal , buyConfig.AmountPrecision )
        //现货精度以修正后的合约的精度为准
        realSellAmount = realBuyAmount*buyConfig.CtVal
        realSellAmount = _N( realSellAmount/sellConfig.CtVal , sellConfig.AmountPrecision ) 
    }else if( sellIsFutures ){
        realSellAmount = _N( fixAmout/sellConfig.CtVal , sellConfig.AmountPrecision ) 
        realBuyAmount = realSellAmount*sellConfig.CtVal
        realBuyAmount = _N( realBuyAmount/buyConfig.CtVal  , buyConfig.AmountPrecision )
    }
    if( realBuyAmount > 0 && realSellAmount > 0 ){
        if( realBuyAmount < buyConfig.MinQty || 
            realSellAmount < sellConfig.MinQty ){
            Log(realBuyAmount,'<',buyConfig.MinQty,"不满足最小下单量要求")
            Log(realSellAmount,'<',sellConfig.MinQty,"不满足最小下单量要求")
            return
        }
        if( (!buyIsFutures || !reduceOnly) && 
            realBuyAmount * buyConfig.CtVal * longExInfo.ticker.Last < buyConfig.MinNotional ){
            Log( realBuyAmount * buyConfig.CtVal * longExInfo.ticker.Last,"不满足最小下单金额要求",buyConfig.MinNotional)
            return
        }
        if( (!sellIsFutures || !reduceOnly) && 
            realSellAmount * sellConfig.CtVal * shortExInfo.ticker.Last < sellConfig.MinNotional ){
            Log( realSellAmount * sellConfig.CtVal * shortExInfo.ticker.Last,"不满足最小下单金额要求",sellConfig.MinNotional)
            return
        }
        if( reduceOnly ){
            creatOrder( shortExInfo , 'buy' ,  shortExInfo.ticker.Last , realBuyAmount , reduceOnly )
            creatOrder( longExInfo , 'sell' ,  longExInfo.ticker.Last , realSellAmount , reduceOnly )
        }else{
            creatOrder( longExInfo , 'buy' , longExInfo.ticker.Last , realBuyAmount , reduceOnly )
            creatOrder( shortExInfo , 'sell' , shortExInfo.ticker.Last , realSellAmount , reduceOnly )
        }
    }
}

//创建订单
function creatOrder( info , side , price , amount , reduceOnly ){
    var orderList = []
    var e = exchanges[info.index] 
    var config = getConfig(info)
    let order = $.creatOrder( e  , config.Symbol , side , 'MARKET' , price , amount , 'ioc' , reduceOnly  , false )
    if( order ){
        orderList.push( order )
    }else{
        Log(info.key,"生成订单失败")
        return
    }
    batchOrders( info , orderList , 'go' )
}
//下单
function batchOrders( info , orderList , rmode ){
    var ret = []
    if( orderList.length <= 0 ){
        return ret
    }
    var e = exchanges[info.index] 
    ret = $.batchOrders( e , orderList , rmode , null , tdMode )
    if( ret ){
        ret.forEach( function(event){
            info.waitResultsList.push( event )
        })
    }
    return ret
}
//处理订单结果
function handleWaitList(){
    exInfo.forEach( function(info){
        var newResultList = []
        info.waitResultsList.forEach( function(event){
            if( event.obj == null ){
                Log( info.key , "wait对象创建失败" )
            }else if (typeof (event.obj.wait) != "undefined") {
                let result = event.obj.wait(1);  
                if (typeof (result) != "undefined") {
                    if( event.name == 'batchOrders' ){
                        if( result ){
                            try {result = JSON.parse(result)} catch (error) {}
                            Log( event.exname,"下单结果result",result)
                        }else{
                            Log( result,event.exname,event,"下单失败",red)
                        }
                    }
                }else{
                    newResultList.push( event )
                }
            }
        })
        info.waitResultsList = newResultList
    })
}

function getInfoByKey( key ){
    var info = null
    for( var i = 0 ; i < exInfo.length ; i++ ){
        if( key == exInfo[i].key ){
            info = exInfo[i]
            return info
        }
    }
}

function getRoomInfoById( roomId ){
    var room = null
    for( var i = 0 ; i < tradeRoom.length ; i++ ){
        if( roomId == tradeRoom[i].roomId ){
            room = tradeRoom[i]
            return room
        }
    }
}

function roomMatch( key , side ){
    //首先扫描是否有匹配
    var info = getInfoByKey( key )
    if(!info){
        Log("未找到指定账户信息key",key)
        return
    }
    //扫描tradeRoom
    var roomInfo = null
    for(var i = 0 ; i < tradeRoom.length ; i++ ){
        if(tradeRoom[i].buyKey == key || tradeRoom[i].sellKey == key ){
            roomInfo = tradeRoom[i]
            break
        }
    }
    if( side == 'buyMatch'){
        if( roomInfo && (roomInfo.buyKey == key || roomInfo.sellKey == key)){
            Log(key,"已经匹配过了")
        }else{
            for(var i = 0 ; i < tradeRoom.length ; i++ ){
                if(tradeRoom[i].buyKey == null ){
                    tradeRoom[i].buyKey = key
                    info.roomId = tradeRoom[i].roomId
                    if( tradeRoom[i].sellKey ){
                        tradeRoom[i].state = 1
                    }
                    return
                }
            }
            creatRoom( key , null )
        }
    }else if( side == 'sellMatch' ){
        if( roomInfo && (roomInfo.sellKey == key || roomInfo.buyKey == key)){
            Log(key,"已经匹配过了")
        }else{
            for(var i = 0 ; i < tradeRoom.length ; i++ ){
                if(tradeRoom[i].sellKey == null ){
                    tradeRoom[i].sellKey = key
                    info.roomId = tradeRoom[i].roomId
                    if( tradeRoom[i].buyKey ){
                        tradeRoom[i].state = 1
                    }
                    return
                }
            }
            creatRoom( null , key )
        }
    }else if( side == 'cancelMatch' ){
        Log("取消匹配",key)
        var exInfo = getInfoByKey(key)
        exInfo.roomId = null
        var newRoomInfo = []
        tradeRoom.forEach( function(room){
            if( room.buyKey == key ){
                room.buyKey  = null
                room.state = 0
            }else if( room.sellKey == key ){
                room.sellKey  = null
                room.state = 0
            }
            if( room.buyKey || room.sellKey ){
                newRoomInfo.push(room)
            }
        })
        tradeRoom  = newRoomInfo
    }
}

function creatRoom( buyKey , sellKey ){
    roomId++
    var roomInfo = {
        roomId : roomId,
        buyKey : buyKey,
        sellKey : sellKey,
        state : 0   // 0 等待匹配 1 匹配完成
    }
    if( buyKey ){
        var exInfo = getInfoByKey(buyKey)
        exInfo.roomId = roomId
    }
    if( sellKey ){
        var exInfo = getInfoByKey(sellKey)
        exInfo.roomId = roomId
    }
    if( buyKey && sellKey ){
        roomInfo.state = 1
    }
    tradeRoom.push( roomInfo )
}

function delRoom( roomId ){
    var index = null
    for( var i = 0 ; i < tradeRoom.length ; i++ ){
        if( tradeRoom[i].roomId == roomId ){
            if( tradeRoom[i].buyKey ){
                var info = getInfoByKey(tradeRoom[i].buyKey)
                info.roomId = null
                tradeRoom[i].buyKey = null
                tradeRoom[i].state = 0
            }
            if( tradeRoom[i].sellKey ){
                var info = getInfoByKey(tradeRoom[i].sellKey)
                info.roomId = null
                tradeRoom[i].sellKey = null
                tradeRoom[i].state = 0
            }
            index = i
            break
        }
    }
    if( index != null ){
        tradeRoom.splice(index, 1)
    }
}

function handleCommand(){
    var strCommand = GetCommand()
    if( strCommand ){
        Log("收到指令",strCommand)
        if (strCommand ==='clearlog') { 
            LogReset(1)
            LogVacuum()
            Log("已清空日志!");
        }
        else{
            if( IsVirtual() != true ){
                var arr = strCommand.split("|")
                if( arr.length == 2) {
                    var key = arr[0]
                    var side = arr[1]
                    if( side  == "buyMatch" || side == "sellMatch" || side == "cancelMatch" ){
                        roomMatch( key , side  )
                    }else if( side == 'open' ){
                        Log("对冲开仓")
                        tradePoll( key , false )
                    }else if( side == 'close'){
                        Log("对冲平仓")
                        tradePoll( key , true )
                    }else if( side == 'delRoom' ){
                        delRoom( key )
                        Log("删除匹配")
                    }else if( side == 'buyPos' ){
                        tradeSingle( key , 'buy')
                    }else if( side == 'sellPos' ){
                        tradeSingle( key , 'sell')
                    }
                }
            }
        }
    }
}

function restoreIt( info ){
    exInfo.forEach( function( item ){
        //如果保存数据里有覆盖
        for( var i = 0 ; i < info.exInfo.length ; i++ ){
            if( info.exInfo[i].key == item.key ){
                item.roomId = info.exInfo[i].roomId
                break
            }
        }
    })
    roomId = info.roomId
    tradeRoom = info.tradeRoom
    //过滤一次room信息
    var newRoomInfo = []
    tradeRoom.forEach(function(item){
        var keepFlag = true
        if( item.buyKey ){
            var buyInfo = getInfoByKey( item.buyKey )
            var sellInfo = getInfoByKey( item.sellKey )
            if( !buyInfo || buyInfo.roomId != item.roomId ){
                keepFlag = false
                if( sellInfo ){
                    sellInfo.roomId = null
                }
            }
        }
        if( item.sellKey ){
            var sellInfo = getInfoByKey( item.sellKey )
            var buyInfo = getInfoByKey( item.buyKey )
            if( !sellInfo || sellInfo.roomId != item.roomId ){
                keepFlag = false
                if( buyInfo ){
                    buyInfo.roomId = null
                }
            }
        }
        if( keepFlag ){
            newRoomInfo.push( item )
        }
    })
    tradeRoom = newRoomInfo
}

function main() {
    initExInfo()
    var reInfo = null
    if( RestoreIt ){reInfo = $.Load("restoreInfo")}
    if( reInfo ){
        Log("开始恢复数据")
        restoreIt( reInfo )
    }
    while( true ){
        handleCommand()
        var now = new Date()
        var nowTs = Date.now()
        updateBalance()
        updatePos()
        updateTicker()
        handleWaitList()
        var allstatus = ''
        allstatus += getTableInfo()
        var 轮询耗时 = Date.now() - nowTs
        allstatus+=('`'+JSON.stringify({'type':'button', 'cmd': 'clearlog', 'name': '清空日志'})+'`'+'\n');
        allstatus+=('轮询耗时: ' + 轮询耗时 + ' 毫秒, 当前时间:' + _D() + ', 星期' + ['日', '一', '二', '三', '四', '五', '六'][now.getDay()] + '\n');
        LogStatus(allstatus)
        Sleep(5000)
    }
}

function onexit(){
    Log("Exit");
    handle_exit()
}
function onerror(msg){
    Log("errorExit",msg);
    handle_exit()
}

var restoreInfo = {
    exInfo : exInfo,
    roomId : roomId,
    tradeRoom : tradeRoom,
}

function handle_exit(){
    if( RestoreIt ){
        Log("数据持久化")
        restoreInfo.exInfo = exInfo
        restoreInfo.roomId = roomId
        restoreInfo.tradeRoom = tradeRoom
        var ret = $.Save("restoreInfo", restoreInfo)
        if( !ret ){
            Log("保存历史数据是失败")
            for( key in restoreInfo ){
                Log( key , restoreInfo[key] )
            }
        }
    }else{
        $.Save("restoreInfo", null)
    }
}
全部留言
avatar of makebit
makebit
/upload/asset/1860dfc77c2b30bfea4d5.png
2025-08-27 22:32:52