Gestaltung eines FMZ-basierten Quantitativ-Synchronisierungsmanagementsystems (1)

Schriftsteller:Kleine Träume, Erstellt: 2022-02-14 19:46:30, Aktualisiert: 2023-09-15 20:44:11

img

Gestaltung eines FMZ-basierten Quantitativ-Synchronisierungsmanagementsystems (1)

In früheren Artikeln der FMZ-Dokumentation haben wir verschiedene Bestell- und Lagerhalts-Synchronisierungsstrategien entwickelt.

Das ist eine Strategie zur Verwaltung der Auftragserfüllung, der Synchronisierung der Bestände und der Verknüpfung von Referenz- und Synchronisierungskonten. Heute versuchen wir, ein anderes Design zu entwickeln, basierend auf der leistungsstarken erweiterten API-Schnittstelle der FMZ Quantitative Trading Plattform. Wir entwerfen ein Synchronisierungsmanagementsystem für Bestellungen.

Entwurfsideen

Zuerst brauchen wir einige gute Vorschläge, Bedürfnisse.

  • 1. Die Implementierer der Synchronisierungsstrategie müssen über die API KEY des Referenzkontos verfügen. Das Problem bei einem Nutzungsszenario ist: Es ist in Ordnung, wenn ein eigenes anderes Austauschkonto einem eigenen Konto folgt. Es ist jedoch problematisch, wenn ein Referenzkonto und ein Synchronisationskonto nicht ein Eigentümer sind.

    Die Lösung: Mit der erweiterten API-Oberfläche von FMZ müssen sich die Besitzer von Sync-Accounts ("Abonnenten") lediglich auf der FMZ Quantum-Trading-Plattform anmelden und dann eine Strategie (in einem System, das in diesem Artikel entworfen wurde) ausführen:订单同步管理系统(Synchronous Server)Die Funktion "Synchronous Server" (Synchronous Server) kann dann mit der Erweiterung des FMZ-API-Key (beachten Sie, dass es sich nicht um den API-Key eines Austauschkontos handelt) und der Synchronous Server-ID des Auftragsmanagementsystems (Synchronous Server) an den Eigentümer des Referenzkontos (Bandholder) weitergegeben werden. Wenn der Referenz-Account-Inhaber (der Benutzer) in einem System verwendet wird, das für dieses Buch entwickelt wurde, wird der Benutzer in der Regel von einem Benutzer abgelehnt.订单同步管理系统类库(Single Server)Wenn ein Signal gesendet wird, erhält das Festplattensystem des Synchronisierungs-Kontoinhabers ein Transaktionssignal, das automatisch ausgebucht wird.

  • 2. Viele Entwickler haben eine bessere Strategie, die nicht mit den beiden oben beschriebenen Forward-Orders, also mit den Synchronisierungsstrategien, funktioniert. Die Lösung: Es ist möglich, eine Synchronisierungsvorlage zu erstellen, die in einem System, das in diesem Artikel entworfen wurde, verwendet wird.订单同步管理系统类库(Single Server)Die Benutzer können diese Modelle direkt in ihre eigenen Strategien einbinden, um die Synchronisierung von Bestellungen und Lagerbestände zu ermöglichen.

  • 3. Verringern Sie eine zusätzliche Platte. Ein letzter Schmerzpunkt ist, dass Sie zusätzlich ein Holding-Bandkonto für ein echtes Monitoring-Referenzkonto eröffnen müssen, wenn Sie die beiden oben beschriebenen Term-Orders, die Synchronisierungsstrategie für die Haltigkeit, verwenden. Die Lösung: Verwenden Sie die Template-Klasse-Bibliothek, um Funktionen in die Referenz-Konto-Richtlinie zu integrieren.

Das System besteht also aus zwei Teilen: 1, Klassensammlung für das System zur Verwaltung von Auftragssynchronisierungen (Single Server) 2. Synchronous Server (Synchronous Server), ein System zum Synchronisieren von Bestellungen

Wenn Sie Ihre Bedürfnisse kennen, dann beginnen Sie mit dem Design.

Entwurf 1: Klassensammlung für das Synchronisierungsmanagement von Bestellungen (Single Server)

Bitte beachten Sie, dass dies keine Strategie ist. Es handelt sich um eine FMZ-Template-Datei, deren Konzepte in der FMZ API-Dokumentation gesucht werden können.

Code für die Template-Klasse:

// 全局变量
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) {
        // 开仓
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // 平仓
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("未检测到持仓")
            return 
        }
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "错误"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("调用CommandRobot接口,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // 判断ex类型
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "仅支持期货跟单"
    }

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

        // 切换到对应的交易对、合约代码
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // 监控持仓
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // 没有初始化数据,初始化          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // 监控
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // 计算仓位变动
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // 检测变动
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // 执行多头动作
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行多头跟单,变动量:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // 执行空头动作
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行空头跟单,变动量:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // 执行跟单操作后,更新
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // 恢复 symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // 现货
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "同步数据", 
        "cols" : [], 
        "rows" : []
    }
    // 构造表头
    tbl.cols.push("监控账户:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`监控持仓:{"时间戳":xxx,"多头持仓量":xxx,"空头持仓量":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // 写入数据
    _.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
}

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Die Design-Klasse ist sehr einfach und verfügt über zwei Funktionen.订单同步管理系统类库(Single Server)Nach der Template-Klasse-Bibliothek. kann man die folgende Funktion verwenden.

  • $$. PosMonitor Die Funktion überwacht die Haltungsänderungen von Börsenobjekten in der Strategie und sendet dann Handelssignale auf der Festplatte, die in den Parametern von Template:Order Synchronous Management System (Single Server) festgelegt sind.

  • Sie haben es nicht geschafft. Die Synchronisierungsdaten werden von der Überwachung zurückgegeben.

Ein Beispiel dafür ist: Ein Template für die Klassensammlung für das Synchronisierungsmanagement von Bestellungen (Single Server).mainDie Funktion:

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Eine Template-Klasse-Buchmaschine selbst kann auch eine Strategie-Realdisk erstellen, die normalerweise verwendet wird, um die Template-Klasse-Buchmaschine zu testen.mainDie Funktion ist eine eigene Strategie.mainDie Funktion.

Der Testcode wurde geschrieben, um mit der OKEX-Analogdiskette zu testen, wobei der API KEY der OKEX-Analogdiskette als Referenzkonto (Band) auf der FMZ konfiguriert werden muss, die in der Main-Funktion als Analogdiskette gestartet wird. Dann wird das Transaktionspaar auf ETH_USDT gesetzt und der Vertrag auf dauerhaft gesetzt (Swap).$.PosMonitor(0, "ETH_USDT", "swap")Der erste Parameter der Funktion, der aufgerufen wird, wird 0 eingegeben, was bedeutet, dass die Exchange-Objekte, die ETH_USDT-Transaktionen überwachen, von den Exchange-Objekten überwacht werden.$.getTbl()Grafikinformationen zu erhalten und zu verwendenLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")Die Daten des Diagramms werden in der Status-Tabelle angezeigt.

Also sehen Sie, wenn Sie es in einer Strategie verwenden, die auf diese Vorlage verweist,$.PosMonitor(0, "ETH_USDT", "swap")Die Strategie kann eine Funktion haben, die die Haltbarkeit einer Sorte überwacht und die Haltbarkeitsveränderungen zur Nachrichtensendung ermöglicht.

Erklären Sie es mir, bevor Sie es testen.订单同步管理系统类库(Single Server)Die Parameter des Strategiedesigns: Ich habe gerade darüber gesprochen, wie man die Schablonen-Interface-Funktionen nutzt, um eine Strategie mit Bandwidth-Funktionen zu aktualisieren. Die Frage, wem sie geschickt werden soll, wird von订单同步管理系统类库(Single Server)Die Parameter werden so konfiguriert.

img

Sie können sehen, dass die Parameter 5 sind und bis zu 5 Pushes unterstützen. Die Parameter sind standardmäßig leere Strings, d.h. sie werden nicht behandelt.

  • Etikett Synchronisierte Accounts sind Tags, die verwendet werden, um ein Konto zu kennzeichnen, und die Namen können beliebig eingestellt werden.

  • RobotId Festplatten-ID, erstellt vom Besitzer des Synchronisationskontos订单同步管理系统(Synchronous Server)Die ID der Festplatte.

  • Zugriffskey AccessKey für die FMZ-Erweiterung API

  • Geheimer Schlüssel SecretKey für die FMZ-Erweiterung

Wir können dann einen einfachen Test durchführen.

Die klassische Bibliothek für das Synchronisierungsmanagement von Bestellungen (Single Server) läuft:

img

Die Festplatte des Synchronous Servers erhält ein Signal: Derzeit sind wir noch nicht fertig mit dem Design eines Synchronous Server, das wir mit einem einfachen Code implementieren, der keine Transaktionen durchführt, sondern nur Signale druckt:

Der temporäre Code für den Synchronous Server:

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

img

Sie können sehen, dass die Festplatte des Besitzers des Sync-Accounts eine Nachricht erhält:ETH_USDT,swap,buy,1Das ist nicht wahr. Das bedeutet, dass man sich automatisch nach den in der Information enthaltenen Paaren, den Vertragscodes, der Handelsrichtung und der Anzahl der Transaktionen erkundigen kann.

Gegenwärtig订单同步管理系统(Synchronous Server)Es ist nur ein vorläufiger Code, dessen Design wir in der nächsten Ausgabe weiter untersuchen werden.


Verwandt

Mehr

Mingxi1005Um eine Liste zu realisieren, benötigen Sie zwei Festplatten, eine für die Klassen- und eine für die Order-Management-Systeme.

Mingxi1005Das tutorial zeigt konfigurierungsfehler

Ich weiß.Welche Parameter müssen geändert werden?

Ich weiß.Wenn man sich selbst bezahlt, muss man auch zwei Festplatten anlegen, eine, die Signale sendet und eine, die Signale empfängt, und die beiden können kombiniert werden.

Kleine TräumeWie Sie vielleicht nicht verstanden haben, ist die Bibliothek ein Werkzeug, das direkt in die Politikzeile des Benutzers eingebunden werden kann, und wenn die Politik eine Benutzerfunktion hat, sendet sie eine Nachricht an ein gut eingerichtetes Benutzerkonto, und der Benutzerbot erhält die Nachricht. Einfach ausgedrückt, das ist die Szene.

Kleine TräumeSie können sich die Artikel und die Konfigurationsinformationen ansehen: Tags, Festplatten-ID, Accesskey, Secretkey.

Mingxi1005Fehler configs error!, in der Bestellsynchronisierungssystem-Klassebuch (Single Server), füllen Sie die Bandträger und die 2 KEYs ein, und dann verweisen Sie auf die Bestellsynchronisierungssystem-Klassebuch (Single Server) auf der Festplatte, um einen Fehler zu melden, Fehler configs error!

Mingxi1005Fehler bei der Konfiguration!

Kleine TräumeSie müssen sich mit den Informationen vertraut machen, die Sie erhalten.

Kleine TräumeIch bin der Meinung, dass wir unsere Strategie ändern müssen.

Kleine TräumeDer Code ist öffentlich zugänglich und Sie können ihn anpassen, wie Sie es wünschen.