FMZ에 기반한 순서 동기 관리 시스템 설계 (1)

저자:니나바다스, 창작: 2022-04-06 15:08:26, 업데이트: 2022-04-24 18:00:51

FMZ에 기반한 순서 동기 관리 시스템 설계 (1)

FMZ 다이제스트의 이전 기사에서 우리는 여러 순서와 위치 동기 전략을 설계했습니다.

이 설계는 참조 계정과 동기 계정을 동일한 전략으로 받아서 주문과 포지션의 동기화를 실현하기 위해 관리 할 수 있습니다. 오늘날, 우리는 다른 디자인을 시도 할 수 있습니다. FMZ의 강력한 확장 API 인터페이스를 기반으로, 여기 우리는 주문 동기 관리 시스템을 설계합니다.

디자인 사고

우선, 우리는 몇 가지 좋은 제안과 요구 사항이 필요합니다. 위의 두 개의 이전 명령과 위치 동기화 전략에는 몇 가지 명백한 단점이 있습니다. 함께 논의하자:

  • 1.전략 봇 동기화를 구현하는 사용자는 참조 계정 플랫폼의 API 키와 동기화 계정의 API 키를 가지고 있어야합니다. 사용 시나리오의 경우, 문제는: 다른 플랫폼 계정이 자신의 계정 중 하나를 따르는 것이 좋습니다. 그러나 참조 계정과 동기화 계정이 동일한 소유자가없는 시나리오에 문제가 될 수 있습니다. 동기화 계정 소유자는 보안상의 이유로 때때로 플랫폼 계정의 API 키를 제공하기를 원하지 않습니다. 그러나 API 키를 제공하지 않고 동시 거래에 대한 주문을 어떻게 할 수 있습니까?

    해결책: FMZ 확장 API를 사용하면 동기화 계정 소유자 (오더 감독자) 는 FMZ 퀀트 거래 플랫폼을 등록하고 전략을 실행해야합니다.Order Synchronous Management System (Synchronous Server)그 다음, FMZ의 확장 된 API 키 (플랫폼 계정의 API 키가 아니라는 점에 유의하십시오) 와 주문 동기화 관리 시스템 (동시 서버) 의 bot ID는 참조 계정 소유자 (오더 소유자) 에 제공됩니다. 참조 계정 소유자의 (계정 소유자)Order Synchronous Management System Library (Single Server)이 기사에서 설계된 시스템에서) 신호를 보내면 동기화 계정 소유자의 봇이 거래 신호를 수신합니다. 주문은 나중에 자동으로 배치됩니다.

  • 2.많은 개발자는 더 나은 전략을 가지고 있으며 위에서 설명한 이전 두 가지 순서 및 위치 동기화 전략을 사용할 수 없습니다. 왜냐하면 자신의 전략을 이러한 동기화 전략과 결합해야하고 전략이 크게 수정되어야 할 수 있기 때문에 시간이 많이 걸리고 노동이 많이 필요합니다. 성숙한 전략 중 일부를 순서 동기화 기능으로 직접 업그레이드 할 수있는 좋은 방법이 있습니까?

    해결책: 당신은 순서 동기 템플릿 라이브러리를 설계할 수 있습니다 (Order Synchronous Management System Library (Single Server)기사에 설계된 시스템에서 전략), 그래서 참조 계정 소유자 (명령 소유자) 는 순서와 위치 동기화를 달성하기 위해 자신의 전략에 직접 이 템플릿 라이브러리를 삽입 할 수 있습니다.

  • 3.더 많은 로봇을 줄이세요. 마지막 단점은 위에서 설명한 두 가지 이전 명령과 위치 동기화 전략을 사용하는 경우 보트 모니터링을 위해 참조 계정의 추가 위치 (명령과 계정) 를 여는 것이 필요하다는 것입니다. 해결책: 템플릿 라이브러리를 사용하여 참조 계정 전략에 함수를 삽입합니다.

따라서 시스템은 두 부분으로 구성됩니다. 1.order 동기 관리 시스템 라이브러리 (Single Server) 주문 동기 관리 시스템 (동시 서버)

일단 우리의 요구사항을 확인하면, 디자인을 시작합시다!

설계 1: 주문 동기 관리 시스템 라이브러리 (단독 서버)

여기 전략이 아니라 FMZ 템플릿 라이브러리가 있다는 점에 유의하십시오. FMZ API 문서에서 검색할 수 있습니다.

템플릿 코드:

// Global variable
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}

function parseConfigs(configs) {
    var arr = []
    _.each(configs, function(config) {
        if (config == "") {
            return 
        }
        var strArr = config.split(",")
        if (strArr.length != 4) {
            throw "configs error!"
        }
        var obj = {}
        obj[keyName_label] = strArr[0]
        obj[keyName_robotId] = strArr[1]
        obj[keyName_extendAccessKey] = strArr[2]
        obj[keyName_extendSecretKey] = strArr[3]
        arr.push(obj)
    })
    return arr 
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    var timestamp = new Date().getTime()
    return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}

function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
    var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
    Log(url)
    var ret = HttpQuery(url)
    return ret 
}

function follow(nowPosAmount, symbol, ct, type, delta) {
    var msg = ""
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // Open position
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // Send signal
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // Open position 
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("No position detected")
            return 
        }
        // Send signal 
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "error"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("Call CommandRobot interface,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // Judge the type of ex
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "Only support futures order supervising"
    }

    if (exType == "futures") {
        // Cache symbol ct
        var buffSymbol = ex.GetCurrency()
        var buffCt = ex.GetContractType()

        // Switch to the corresponding trading pair and contract code 
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // Monitor position 
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // The data is not initialized; initialize it          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // Monitor
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // Calculate position changes 
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // Detect changes 
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // Execute long position action 
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute long position order supervision, change volume:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // Execute short position action 
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute short position order supervision, change volume:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // After executing the order supervision operation, update  
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // Recover symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // Spot 
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "Synchrodata", 
        "cols" : [], 
        "rows" : []
    }
    // Construct the table title 
    tbl.cols.push("Monitoring account:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`Mintoring position:{"timestamp":xxx,"long position volume":xxx,"short position volume":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // Write in the data 
    _.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
        var arr = [key, JSON.stringify(initRefPosAmount)]
        _.each(fmzExtendApis, function(extendApiData) {
            arr.push(extendApiData[keyName_robotId])
        })
        tbl.rows.push(arr)
    })

    return tbl
}

// Invocation example of the strategy in the template
function main() {
    // Clear all logs
    LogReset(1)

    //Switch to OKEX simulated bot test
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Call the interface function in the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors, to minitor different exchange objects in the strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar 
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

설계는 매우 간단합니다, 라이브러리는 2 기능이 있습니다.Order Synchronous Management System Library (Single Server)템플릿 클래스 라이브러리. 이 전략은 다음 함수를 사용할 수 있습니다.

  • $. 포스 모니터 이 함수의 효과는 전략에서 교환 객체의 위치 변화를 모니터링하고 다음 템플릿의 매개 변수에서 설정된 봇에 거래 신호를 전송하는 것입니다: 주문 동기 관리 시스템 라이브러리 (Single Server).
  • $.getTbl 이 함수는 모니터링 된 동기 데이터를 반환합니다.

사용 예는main순서 동기 관리 시스템 라이브러리 (Single Server):

// Invocation example of the strategy in the template 
function main() {
    // Clear all logs 
    LogReset(1)

    // Switch to OKEX simulated bot test 
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strateg...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Use the interface function of the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors to monitor different exchange objects on an strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

템플릿 라이브러리 자체는 또한 일반적으로 템플릿 라이브러리를 테스트하는 데 사용되는 전략 봇을 만들 수 있습니다. 예를 들어 이 템플릿에 대한 테스트입니다.main템플릿의 함수는main자신의 전략 중 하나에 대한 기능입니다.

테스트 코드는 테스트를 위해 OKEX 시뮬레이션 봇을 사용하도록 작성되었으며, OKEX 시뮬레이션 봇의 API KEY는 FMZ에서 참조 계정 (오더와 함께) 으로 구성되어야하며, 주요 기능은 시뮬레이션 봇으로 전환되기 시작합니다. 그 다음 거래 쌍을 ETH_USDT로 설정하고 계약을 교환하도록 설정합니다. 그 다음 while 루프를 입력합니다. 루프에서 전략 거래의 트리거를 시뮬레이션하기 위해 3 분마다 주문이 배치됩니다.$.PosMonitor(0, "ETH_USDT", "swap")while 루프에서 호출되고 호출 함수의 첫 번째 매개 변수는 0이며, 이는 교환 객체 교환[0], 거래 쌍 ETH_USDT 및 교환 계약을 모니터링하는 것을 의미합니다.$.getTbl()차트 정보를 얻고,LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")상태 표시줄에 표시되는 차트 데이터를 만들기 위해서입니다.

그래서, 당신이 볼 수 있는 한,$.PosMonitor(0, "ETH_USDT", "swap")템플릿을 호출하는 전략에서 사용되면, 전략은 특정 기호 위치를 모니터링하고 위치 변경 메시지를 푸싱하는 기능을 가질 수 있습니다.

시험 전에, 테스트의 매개 변수 설계 설명Order Synchronous Management System Library (Single Server)전략: 방금 템플릿의 인터페이스 기능을 사용하여 주문을 수행하는 기능으로 전략을 업그레이드하는 방법에 대해 이야기했습니다. 누가 보내야 하는지에 대한 질문은order synchronous management system library (Single Server).

img

당신은 최대 5 개의 푸시를 지원 할 수있는 다섯 개의 매개 변수를 볼 수 있습니다 (두려움 번호를 증가시킬 필요가 있다면, 당신은 그것을 스스로 확장 할 수 있습니다); 매개 변수의 기본 설정은 처리되지 않은 빈 문자열입니다. 구성된 문자열 형식에서: 레이블, robotId, accessKey, secretKey

  • 라벨 동기 계정의 라벨, 계정을 라벨하는 데 사용된다. 라벨 이름은 무작위로 설정될 수 있다.

  • 로봇 봇 아이디order synchronous management system (Synchronous Server)동시 계정 소유자가 만든 것입니다.

  • accessKey FMZ 확장 API의 AccessKey.

  • 비밀 키 FMZ의 비밀 키는 확장된 API입니다.

그러면 간단한 테스트를 할 수 있습니다.

명령 동기 관리 시스템 라이브러리 (단독 서버) 봇 동작:

img

오더 동기 관리 시스템 (동시 서버) 봇은 신호를 받았습니다: 주문 동기 관리 시스템 (동시 서버) 지금은 우리가 완전히 설계되지 않았으며, 우리는 간단한 코드를 사용하여 그것을 실현 할 수 있습니다, 거래 없이, 단지 신호 인쇄:

주문 동기 관리 시스템 (동시 서버) 임시 코드:

function main() {
    LogReset(1)
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            // cmd: ETH_USDT,swap,buy,1
            Log("cmd: ", cmd)
        }
        Sleep(1000)
    }
}

img

보시다시피 동시 계정 소유자의 봇은 이 메시지를 받았습니다.ETH_USDT,swap,buy,1- 네 따라서 다음 단계에서는 거래 쌍, 계약 코드, 거래 방향 및 부피에 따라 주문을 자동으로 감독할 수 있습니다.

현재,order synchronous management system (Synchronous Server)단지 임시적인 코드입니다. 다음 기사에서 그 설계에 대해 더 자세히 설명할 수 있습니다.


더 많은