FMZ Quant をベースにした注文同期管理システムの設計 (1)

作者: リン・ハーンリディア, 作成日:2022-11-07 10:20:01, 更新日:2023-09-15 20:45:23

img

FMZ Quant をベースにした注文同期管理システムの設計 (1)

FMZのライブラリに載った前の記事では,順序と位置のための複数の種類の同期戦略を設計しました.

順序と位置の同期を達成するための1つの戦略で参照アカウントと同期アカウントを管理します. そして今日,私たちは別のデザインを試みます. FMZ Quant Trading Platformの強力な拡張 API インターフェースに基づいた注文同期管理システムを設計します.

デザイン アイデア

先ほどの2つの順序と位置同期戦略には,いくつかの明らかな欠点があります.

    1. リアルボットの同期戦略のユーザは,参照アカウントの交換 API キーと同期アカウントの交換 API キーを持っている必要があります. この問題は,他の交換アカウントが自分のアカウントをフォローする使用状況では問題ありません. ただし,参照アカウントと同期アカウントが同じ所有者でない状況では問題になります. 時には同期アカウントの所有者がセキュリティ上の理由で自分の交換アカウントのAPI KEYを提供したくない場合もありますが,API KEYを提供せずに注文トランザクションを同期するにはどうすればよいですか?

    解決策: FMZの拡張APIインターフェースを使用すると,同期アカウント (オーダーフォロワー) の所有者は,FMZ Quant Trading Platformでアカウントを登録し,戦略を実行する必要があります (この記事で設計したシステムでは:Order Synchronous Server参照アカウントの所有者 (オーダーリーダー) に FMZ 拡張 API KEY (交換アカウントの API KEY ではないことに注意してください) と Order Synchronous Server real bot ID を提供してください. 参照アカウント所有者 (注文フォロワー) が本物ボット (Order Synchronization Management System Class Library (Single Server)この記事で設計されたシステムで) 信号を送信すると,同期アカウント所有者の実際のボットが取引信号を受け取り,次の注文を自動的にします.

    1. 多くの開発者は良い戦略を持っているが,上記2つの過去順序と位置同期戦略を使用することはできません.彼らはこれらの同期戦略と独自の戦略を統合する必要があるため,戦略は大幅に変更する必要があり,多くの作業と労力を要します.あなたの成熟した戦略の一部を直接順序同期機能にアップグレードする良い方法がありますか? 解決策: 順序同期テンプレートクラスライブラリ (theOrder Synchronization Management System Class Library (Single Server)この記事で設計されたシステムにおける戦略) で,参照アカウントの所有者 (オーダーリーダー) は,このテンプレートクラスライブラリを直接自分の戦略に組み込み,順序と位置の同期機能を達成することができます.
    1. もう"人の本物のボットを 削減します 最後の欠点は,上記に記述された2つの過去の注文を使用した場合,ポジションの同期戦略です. 参照アカウントのポジションを監視するために追加の実際のボットを開く必要があります (注文リーダーのためのアカウント). 解決策: テンプレートクラスライブラリを使用して参照アカウント戦略に機能を埋め込む.

システムには2つの部分があります.

  1. 注文同期管理システムクラスライブラリ (シングルサーバー)
  2. 注文同期管理システム (同期サーバー)

デザインを始めましょう!

設計1:オーダー同期管理システムクラスライブラリ (シングルサーバー)

これは戦略ではないことに注意してください. これは 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)
    }
}

FMZ プラットフォームのプログラミング取引戦略が FMZ のテンプレートクラスライブラリを参照するときに,Order Synchronization Management System Class Library (Single Server)戦略は次の関数を使うことができます.

  • $ PosMonitor について この機能の目的は,戦略内の交換オブジェクトの位置変化を監視し,その後,テンプレートのパラメータに設定された実際のボット市場に取引信号を送信することです: Order Synchronization Management Systemクラスライブラリ (シングルサーバー).

  • $$$$$$$ 監視した同期データに戻る

この例は,mainOrder Synchronization Management System Class Library (Single Server) テンプレートの関数について

// 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 KEY を参照アカウント (オーダーリード) として設定し,メイン機能でデモに切り替えるようになります. その後,取引ペアを ETH_USDT に設定し,契約をスワップに設定します. その後,一時ループに入ります.ループでは,戦略取引のトリガーシミュレーションのために 3 分ごとに注文が表示されます.$.PosMonitor(0, "ETH_USDT", "swap")この関数の最初のパラメータは0に転送され,これはThES交換オブジェクト交換を監視することを意味します[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

設定文字列フォーマット: label,robotId,accessKey,secretKey. 設定文字列形式: label,robotId,accessKey,secretKey. 設定文字列形式: label,robotId,accessKey,secretKey.

  • ラベル 同期アカウントのラベル,任意に設定できる名前を持つアカウントのラベルを設定するために使用されます.

  • ロボット ロボットのIDはOrder Synchronous Server本物のボットで 同期アカウントの所有者が作成しました

  • アクセスKey FMZ の拡張 API アクセスキー

  • 秘密キー 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)そのデザインを次の号で 探求していきます.


関連性

もっと