FMZ 퀀트를 기반으로 하는 주문 동기화 관리 시스템의 설계 (1)

저자:리디아, 창작: 2022-11-07 10:20:01, 업데이트: 2023-09-15 20:45:23

img

FMZ 퀀트를 기반으로 하는 주문 동기화 관리 시스템의 설계 (1)

FMZ의 라이브러리의 이전 기사에서, 우리는 순서와 위치에 대한 여러 종류의 동기화 전략을 설계했습니다.

이 참조 계정 및 동기화 계정을 관리하는 하나의 전략에서 순서 및 위치 동기화를 달성합니다. 그리고 오늘 우리는 다른 디자인을 시도 할 것입니다. 우리는 FMZ 양자 거래 플랫폼의 강력한 확장 API 인터페이스를 기반으로 주문 동기화 관리 시스템을 설계 할 것입니다.

디자인 아이디어

먼저, 우리는 몇 가지 좋은 제안과 필요를 필요로 합니다. 위의 두 가지 이전 순서와 위치 동기화 전략, 우리는 함께 논의 할 몇 가지 명백한 결함이 있습니다.

    1. 동기화 전략의 사용자들은 실제 봇이 참조 계정의 교환 API 키와 동기화 계정의 교환 API 키를 가지고 있어야 합니다. 이 문제는 다른 거래소 계정이 자신의 계정을 따르는 사용 상황에 적합합니다. 그러나 참조 계정과 동기화 계정이 동일한 소유자가 아닌 상황에 문제가 될 수 있습니다. 때로는 동기화 계정의 소유자가 보안 이유로 자신의 거래소 계정의 API 키를 제공하기를 원하지 않지만 API 키를 제공하지 않고서 주문 거래를 동기화하는 방법은 무엇입니까?

    해결책: FMZ의 확장 API 인터페이스를 사용하면 동기화 된 계정 소유자 (오더 팔로워) 는 FMZ 퀀트 트레이딩 플랫폼에 계정을 등록하고 전략을 실행해야합니다.Order Synchronous Server실제 봇에서 전략). 그러면 그냥 FMZ 확장 API 키를 제공 (이 교환 계정의 API 키가 아니라는 점에 유의) 및 주문 동기 서버 실제 봇 ID 참조 계정 소유자 (명령 리더). 레퍼런스 계정 소유자 (오더 추종자) 가 실제 봇 (사용자) 이면Order Synchronization Management System Class Library (Single Server)이 문서에서 설계된 시스템에서) 신호를 보내면 동기화 계정 소유자의 실제 봇은 거래 신호를 수신하고 자동으로 다음 명령을합니다.

    1. 많은 개발자들이 좋은 전략을 가지고 있지만, 위에서 설명한 2개의 과거 순서 및 위치 동기화 전략을 사용할 수 없습니다. 왜냐하면 그들은 이러한 동기화 전략과 자신의 전략을 통합해야 하고, 전략이 급격하게 변경되어야 할 수도 있기 때문에 많은 작업과 노력이 필요할 수 있습니다. 성숙한 전략 중 일부를 순서 동기화 기능으로 직접 업그레이드하는 좋은 방법이 있습니까? 해결책: 당신은 순서 동기화 템플릿 클래스 라이브러리 (theOrder Synchronization Management System Class Library (Single Server)이 문서에서 설계된 시스템에서 전략), 그래서 참조 계정 소유자 (질서 리더) 는 순서와 위치 동기화 기능을 달성하기 위해 자신의 전략에 직접 이 템플릿 클래스 라이브러리를 삽입 할 수 있습니다.
    1. 추가로 진짜 로봇을 줄여라 마지막 단점은 당신이 2 과거 명령을 사용하는 경우, 위와 같이 설명 된 위치 동기화 전략입니다. 참조 계정의 위치를 모니터링하기 위해 추가 실제 봇을 열어야합니다. 해결책: 템플릿 클래스 라이브러리를 사용하여 참조 계정 전략에 기능을 삽입합니다.

이 시스템은 두 부분으로 구성되어 있습니다.

  1. 주문 동기화 관리 시스템 클래스 라이브러리 (Single Server)
  2. 주문 동기화 관리 시스템 (동시 서버)

일단 우리의 필요를 정의하면, 디자인을 시작합시다!

디자인 1: 주문 동기화 관리 시스템 클래스 라이브러리 (Single Server)

참고로 이것은 전략이 아닙니다. 그것은 FMZ의 템플릿 클래스 라이브러리입니다. 템플릿 클래스 라이브러리의 개념은 FMZ API 문서에서 검색 할 수 있으며 다시 반복하지 않을 것입니다.

템플릿 클래스 라이브러리 코드:

// Global variables
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 the position
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // send signals
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // close the position
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("no positions found")
            return 
        }
        // send signals
        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 the 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 future-following is supported"
    }

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

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

        // monitor positions
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // no initialization data, initialize it
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

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

        // detect changes
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // Perform long positions
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform long position-following, changes in volume:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // Perform short positions
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform short position-following, changes in volume:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // Update after performing the order-following operation
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

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

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "synchronization of data", 
        "cols" : [], 
        "rows" : []
    }
    // construct the table headers
    tbl.cols.push("monitor the account: refPos-exIndex-symbol-contractType")
    tbl.cols.push(`monitor the position: {"timestamp":xxx,"long positions":xxx,"short positions":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // Write data in
    _.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
}

// Example of the strategy call that references the template class library
function main() {
    // Clear all logs
    LogReset(1)

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

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

    // Timed trading interval
    var tradeInterval = 1000 * 60 * 3        // Trade for every three minutes to observe the order-following signals
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Simulated trading triggers for testing
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Interface functions that use templates
        $.PosMonitor(0, "ETH_USDT", "swap")    // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy  
        var tbl = $.getTbl()
        
        // Display status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

디자인은 매우 간단합니다, 클래스 라이브러리는 2 가지 기능이 있습니다. FMZ 플랫폼의 프로그래밍 거래 전략이 템플릿 클래스 라이브러리를 참조하면Order Synchronization Management System Class Library (Single Server)그러면 전략은 다음 함수를 사용할 수 있습니다.

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

  • $.getTbl 감시된 동기화 데이터로 돌아가

사용 예는main주문 동기화 관리 시스템 클래스 라이브러리 (단독 서버) 템플릿의 함수:

// Example of the strategy call that references the template class library
function main() {
    // Clear all logs
    LogReset(1)

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

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

    // Timed trading interval
    var tradeInterval = 1000 * 60 * 3        // Trade for every three minutes to observe the order-following signals
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Simulated trading triggers for testing
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Interface functions by using templates
        $.PosMonitor(0, "ETH_USDT", "swap")    // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy  
        var tbl = $.getTbl()
        
        // Display status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

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

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

그래서 우리는 전략이 특정 종의 위치를 모니터링 할 수 있는 능력을 가지고 있다는 것을 볼 수 있습니다. 그리고 위치를 변경하여 메시지를 전송하는 방법을 사용할 수 있습니다.$.PosMonitor(0, "ETH_USDT", "swap")이 계열에 해당하는 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 모든 계열에 해당하는 계열에 해당하는 모든 계열에 해당하는 계열에 해당하는 모든 계열에 해당하는 계열에 해당하는 계열에 해당하는 모든 계열에 해당하는 계열에 해당하는 계열에

테스트 전에, 우리는 전략 매개 변수 디자인을 설명합니다Order Synchronization Management System Class Library (Single Server)- 그래요 우리는 방금 어떻게 템플릿의 인터페이스 함수를 사용하여 전략을 업그레이드 하 고 순서 선도 함수를 가지고 이야기 했습니다. 위치 변경 때 전송 된 신호에 대해 어떻게, 누가 전송 될 것입니다? 누가 보내야 하는지에 대한 질문은Order Synchronization Management System Class Library (Single Server).

img

우리는 5 매개 변수가 있다고 볼 수 있습니다, 최대 5 푸시를 지원 (이 증가해야하는 경우 자체로 확장 될 수 있습니다), 기본 매개 변수는 빈 문자열, 즉, 처리되지 않습니다. 구성 문자열 형식: 라벨,로봇Id,accessKey,secretKey

  • 라벨 동기화 계정에 대한 라벨, 원하는 이름으로 계정에 대한 라벨을 설정하는 데 사용됩니다.

  • 로봇 로봇 ID,Order Synchronous Server동시 계정 소유자가 만든 실제 봇입니다.

  • accessKey 확장된 API 액세스 FMZ 키

  • 비밀 키 FMZ의 확장된 API 비밀 키

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

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 Synchronization Management System (Synchronous Server)임시 코드입니다. 우리는 다음 주에서 그 디자인을 계속 탐구할 것입니다.


관련

더 많은