Die Ressourcen sind geladen. Beförderung...

FMZ-Quantifizierungsplattform-Strategie Schreib-zu-Schritt-Tutorial

Schriftsteller:Das Gras, Erstellt: 2019-08-19 15:54:35, aktualisiert: 2021-06-08 16:14:57

[TOC] Das ist eine sehr schwierige Aufgabe, aber wir müssen sie lernen.FMZ-Erfinder nutzen die Quantitative PlattformundFMZ-Quantifizierungsplattform-Strategie für die ErstausbildungSie sind in der Lage, sich mit Programmiersprachen vertraut zu machen.Die ersten Tutorials behandeln die am häufigsten verwendeten Funktionen, aber es gibt noch viele Funktionen und Funktionen, die nicht in diesem Tutorial behandelt werden. Sie müssen sich die Plattform-API-Dokumentation ansehen.Wenn Sie dieses Tutorial gelernt haben, werden Sie in der Lage sein, eine freiere, kundenspezifischere Strategie zu schreiben, und die FMZ-Plattform ist nur ein Tool.

Zugriff auf die ursprünglichen Daten der Börse

Die FMZ-Plattform ist für alle unterstützten Börsen verpackt. Um die Einheitlichkeit zu gewährleisten, ist die API-Unterstützung für eine einzelne Börse nicht vollständig. Zum Beispiel, wenn man eine K-Leitung erhält, kann man in der Regel die Anzahl der K-Leitung oder die Startzeit übertragen, während die FMZ-Plattform feststeht.Für öffentliche Schnittstellen (z. B. Branchen)HttpQuery, für den Zugriff auf die Kontoinformationen.IODie spezifischen Eingabeparameter sind in der entsprechenden API-Dokumentation zu lesen.InfoDas Feld hat die ursprüngliche Information zurückgegeben, aber das Problem, dass die Schnittstelle nicht unterstützt wird, kann immer noch nicht behoben werden.

GetRawJSON ((()

Die ursprüngliche Inhalte (String) der letzten REST-API-Anfrage zurückgegeben, kann für die eigene Analyse der Erweiterung Informationen verwendet werden.

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery (() Zugriff auf die öffentliche Schnittstelle

Zugriff auf die öffentliche Schnittstelle, die Js nutzen könnenHttpQueryIn Python kann man die entsprechenden Pakete selbst verwenden, wie z.B.urlliboderrequests

HttpQuery ist standardmäßig die GET-Methode und unterstützt weitere Funktionen. Siehe API-Dokumentation.

var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo)
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
var kline = JSON.parse(HttpQuery("https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596"))

Beispiel für Python-Anfragen

import requests
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596')
data = resp.json()

IO-Funktion für den Zugriff auf die Verknüpfung

Für Schnittstellen, die eine API-KEY-Signatur benötigen, kann die IO-Funktion verwendet werden. Der Benutzer muss sich nur um die Eingabe von Parametern kümmern. Der spezifische Signaturprozess wird von der Unterseite durchgeführt.

Die FMZ-Plattform unterstützt derzeit keine BitMEX-Stopp-Loss-Inserate.

  • Die API-Anleitung für BitMEX finden Sie hier:https://www.bitmex.com/api/explorer/
  • BitMEX findet sich unter:https://www.bitmex.com/api/v1/orderDie Methode istPOST◦ Da FMZ bereits die Root-Adresse intern festgelegt hat, muss nur "/api/v1/order" eingegeben werden.
  • Entsprechende Parametersymbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop

Der spezifische Code:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
//也可以直接传入对象
var id = exchange.IO("api", "POST", "/api/v1/order", "", JSON.stringify({symbol:"XBTUSD",side:"Buy",orderQty:1,stopPx:4000,ordType:"Stop"}))

Weitere Beispiele für IO:https://www.fmz.com/bbs-topic/3683

Mit dem Websocket

Grundsätzlich unterstützen alle digitalen Währungsbörsen Websocket-Send-Markt, einige unterstützen Websocket-Aktualisierungsinformationen. Im Vergleich zu Rest-API hat Websocket im Allgemeinen eine geringe Verzögerung, eine hohe Frequenz, keine Frequenzbeschränkung der Rest-API.

Dieser Artikel behandelt vor allem die Quantitative Plattform von FMZ-Erfinder, die Verwendung von JavaScript, die Verbindung der Dial-Funktion, die mit der Plattform verpackt ist, die Spezifikationen und Parameter in Dokumentationen, die Suche nach Dial, die Dial-Funktion wurde mehrmals aktualisiert, um verschiedene Funktionen zu realisieren. Dieser Artikel behandelt auch die WSS-basierte Ereignis-Treibstrategie und die Probleme mit der Verbindung mehrerer Börsen.

1.websocket连接

Die Anschlüsse sind in der Regel direkt verfügbar, so dass Sie die Sicherheitsticker erhalten:

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")

Für die zurückgegebenen Daten ist das komprimierte Format, das bei der Verbindung angegeben werden muss, und die komprimierte Formate wird durch den Modus repräsentiert, der die zurückgesandten Daten repräsentiert, die komprimiert werden müssen, wie bei der Verbindung OKEX:

var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")

Die Dial-Funktion unterstützt die Wiederverknüpfung, die von der unteren Go-Sprache durchgeführt wird, und die Verbindung, die detektiert wird, wird wiederverknüpft. Für den Inhalt der angeforderten Daten, die bereits in der URL sind, wie zum Beispiel bei Binance, ist dies sehr praktisch.

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")

Einige Anfragen von Börsen sind in den URLs, und es gibt auch einige Kanäle, die selbst ein Abonnement senden müssen, wie Coinbase:

client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')

2.加密接口连接

Der Websocket wird normalerweise zum Lesen von Transaktionen verwendet, kann aber auch für den Erhalt von Bestellungen und Konto-Push verwendet werden, wobei die Verstärkung dieser Art von verschlüsselten Daten manchmal sehr langwierig ist und mit Vorsicht verwendet werden muss. Da die Verschlüsselungsmethode komplex ist, finden Sie hier einige Beispiele.

    //火币期货推送例子
    var ACCESSKEYID = '你的火币账户的accesskey'
    var apiClient = Dial('wss://api.hbdm.com/notification|compress=gzip&mode=recv')
    var date = new Date(); 
    var now_utc =  Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    var utc_date = new Date(now_utc)
    var Timestamp = utc_date.toISOString().substring(0,19)
    var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent(Timestamp)
    var signature = exchange.HMAC("sha256", "base64", quest, "{{secretkey} }") //去掉}}之间的多余空格
    auth = {op: "auth",type: "api",AccessKeyId: ACCESSKEYID, SignatureMethod: "HmacSHA256",SignatureVersion: "2", Timestamp: Timestamp, Signature:encodeURI(signature)}
    apiClient.write(JSON.stringify(auth))
    apiClient.write('{"op": "sub","cid": "orders","topic": "orders.btc'}')
    while (true){
        var data = datastream.read()
        if('op' in data && data.op == 'ping'){
            apiClient.write(JSON.stringify({op:'pong', ts:data.ts}))
        }
    }
    
    //币安推送例子,注意需要定时更新listenKey
    var APIKEY = '你的币安accesskey'
    var req = HttpQuery('https://api.binance.com/api/v3/userDataStream',{method: 'POST',data: ''},null,'X-MBX-APIKEY:'+APIKEY);
    var listenKey = JSON.parse(req).listenKey;
    HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'DELETE',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
    listenKey = JSON.parse(HttpQuery('https://api.binance.com/api/v3/userDataStream','',null,'X-MBX-APIKEY:'+APIKEY)).listenKey;
    var datastream = Dial("wss://stream.binance.com:9443/ws/"+listenKey+'|reconnect=true',60);
    var update_listenKey_time =  Date.now()/1000;
    while (true){
        if (Date.now()/1000 - update_listenKey_time > 1800){
            update_listenKey_time = Date.now()/1000;
            HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'PUT',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
        }
        var data = datastream.read()
    }

    //BitMEX推送例子
    var APIKEY = "你的Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")//secretkey在执行时自动替换,不用填写
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }

3.websocket读取

Der Code lautet folgendermaßen:

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) //把json字符串解析为可引用的object
// 处理data数据
    }
}

wss-Daten werden sehr schnell geschickt. Die Unterseite von Go läßt alle Daten in der Warteschlange liegen und kehrt dann wieder zurück, wenn der Programm den Read-Aufruf einlädt. Eine Verzögerung wie das Auflisten der Festplatte kann zu einer Datenaufstockung führen. Bei Transaktions-Push, Konto-Push, Tiefenwert-Push usw. benötigen wir historische Daten.

read()Wenn keine Parameter hinzugefügt werden, wird die älteste Datenquelle zurückgegeben.client.read(-2)Die Daten werden sofort neu zurückgegeben, aber wenn keine Daten mehr vorhanden sind, wird null zurückgegeben, sodass eine weitere Referenz erforderlich ist.

Je nachdem, wie man mit den alten Daten umgeht, die im Cache gespeichert sind, und ob sie bei fehlender Datenfläche verstopft sind, gibt es verschiedene Parameter für das Lesen, wie in der folgenden Abbildung dargestellt, was kompliziert aussieht, aber das Programm flexibler macht.img

4.连接多个交易所websocket

Für diese Situation kann man offensichtlich nicht einfach "read" verwenden, da eine Börse die Warte-Nachricht blockiert, und die andere keine Nachricht empfängt, selbst wenn sie eine neue Nachricht hat.

    function main() {
        var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        var coinbase = Dial("wss://ws-feed.pro.coinbase.com", 60)
        coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
        while (true) {
            var msgBinance = binance.read(-1) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // 此时币安有数据返回
            }
            if(msgCoinbase){
                // 此时coinbase有数据返回
            }
            Sleep(1) // 可以休眠1ms
        }
    }

5.断线重连问题

Dieser Teil ist problematisch, da die Push-Daten unterbrochen werden können, oder die Push-Verzögerung extrem hoch ist. Auch wenn der Empfang von Heartbeat nicht bedeutet, dass die Daten weitergeschickt werden, kann ein Ereignisintervall festgelegt werden, wenn keine Aktualisierungen empfangen werden.

6.使用websocket的一般程序框架

Da die Push-Daten bereits verwendet wurden, kann ein Programm natürlich auch als Event-Driver geschrieben werden. Achten Sie darauf, dass die Push-Daten häufig ausgeführt werden, um nicht zu viele Anfragen zu verursachen, die zum Verschluss führen.

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//这里即限制了2s内只交易一次
            tradeTime = Date.now()
            //交易逻辑
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//这里即限制了5s内只获取账户一次
            accountTime = Date.now()
            return exchange.GetAccount()
        }
    }
    function main() {
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true");
        while (true) {
            var msg = client.read()
            var data = JSON.parse(msg)
            var account = GetAccount()
            trade(data)
        }
    }

7.总结

Die Art und Weise, wie die Websockets der verschiedenen Börsen verbunden sind, wie Daten gesendet werden, was abonniert werden kann, und das Datenformat sind oft unterschiedlich, so dass die Plattform nicht verpackt ist und eine automatische Verbindung mit der Dial-Funktion erforderlich ist. Dieser Artikel umfasst im Wesentlichen einige grundlegende Vorsichtsmaßnahmen.

PS. Einige Börsen bieten zwar keine Websocket-Markt, aber tatsächlich die Ankunft auf der Website mit der Funktion der Schalldaten, und finden, dass die Websocket-Push verwendet wird. Eine Untersuchung zeigt, dass das Abonnement-Format und das Rückkehrformat gefunden werden.

Multi-Thread-Zusammenführung

JavaScript kann mit der Go-Funktion parallel realisiert werden, Python kann eine entsprechende Multi-Threaded Library verwenden.

Bei der Implementierung von Quantitative Strategien kann die gleichzeitige Ausführung in vielen Fällen die Effizienz der Verzögerungsförderung reduzieren.

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

Wenn eine Request-Rest-API eine Verzögerung aufweist, die vorausgesetzt wird, dass 100 ms ist, dann ist die Zeit für die Erfassung der Tiefe bei den beiden Anfragen in der Tat unterschiedlich. Wenn mehr Zugriffe erforderlich sind, wird das Verzögerungsproblem stärker hervortreten und die Ausführung der Strategie beeinträchtigen.

Da JavaScript nicht mehrere Themen hat, löst die Go-Funktion das Problem, die unterhalb von der Go-Funktion umhüllt wird.GetDepth,GetAccountSo weiter.IOSie können sich anrufen:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders))Das Projekt wurde in der Folge von einer Reihe von Entwicklungen unterstützt, von denen die meisten von uns in der Vergangenheit gemacht wurden.

var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果 
var depthB = b.wait()

In den meisten einfachen Fällen ist es nicht problematisch, eine solche Strategie zu schreiben. Beachten Sie jedoch, dass der Prozess bei jeder Strategie-Lippe wiederholt wird, wobei die Zwischenvariablen a und b eigentlich nur temporär unterstützend sind. Wenn wir sehr viele Parallelvorgaben haben, müssen wir zusätzlich die Wechselbeziehungen zwischen a und depthA, b und depthB aufzeichnen, was die Situation komplizierter macht, wenn unsere Parallelvorgaben unsicher sind. Daher möchten wir eine Funktion realisieren:

function G(t, ctx, f) {
    return {run:function(){
        f(t.wait(1000), ctx)
    }}
}

Wir definieren eine G-Funktion, bei der der Parameter t die zu ausführende Go-Funktion ist, ctx der Kontext des Aufzeichnungsprogramms und f die Funktion, der die spezifische Zuordnung zugewiesen wird.

Das gesamte Programm-Framework kann dann ähnlich wie das Hersteller-Verbraucher-Modell geschrieben werden (mit einigen Unterschieden), bei dem der Hersteller ständig Aufgaben ausgibt, die der Verbraucher gleichzeitig ausführt, wobei der Code lediglich eine Demonstration ist und nicht die Logik der Durchführung des Programms beinhaltet.

var Info = [{depth:null, account:null}, {depth:null, account:null}] //加入我们需要获取两个交易所的深度和账户,跟多的信息也可以放入,如订单Id,状态等。
var tasks = [ ] //全局的任务列表

function produce(){ //下发各种并发任务
  //这里省略了任务产生的逻辑,仅为演示
  tasks.push({exchange:0, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:1, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:0, ret:'sellID', param:['Buy', Info[0].depth.Asks[0].Price, 10]})
  tasks.push({exchange:1, ret:'buyID', param:['Sell', Info[1].depth.Bids[0].Price, 10]})
}
function worker(){
    var jobs = []
    for(var i=0;i<tasks.length;i++){
        var task = tasks[i]
        jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
                    Info[task.exchange][task.ret] = v //这里的v就是并发Go函数wait()的返回值,可以仔细体会下
                }))
    }
    _.each(jobs, function(t){
            t.run() //在这里并发执行所有任务
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // 发出交易指令
        worker()        // 并发执行
        Sleep(1000)
    }
}

Es sieht so aus, als ob ein Kreis nur eine einfache Funktion realisiert, was die Komplexität des Codes erheblich vereinfacht hat. Wir müssen uns nur darum kümmern, welche Aufgaben ein Programm erzeugen muss.

Chart-Funktionsdiagramm

Einer der wichtigsten Anleitungen ist die Einführung von Diagrammen, die in den meisten Fällen zur Verfügung stehen.

Chart({…})Die interne Parameter sind HighStock und HighCharts Objekte, nur ein zusätzlicher Parameter hinzugefügt.__isStockUm zu unterscheiden, ob es sich um HighStock handelt. HighStock ist eher auf Zeitreihen-Charts konzentriert und wird daher häufiger verwendet. FMZ unterstützt grundsätzlich die Grundmodule von HighCharts und HighStock, aber nicht zusätzliche Module.

Ein Beispiel für Highcharts:https://www.highcharts.com/demoHighStock ist ein Beispiel:https://www.highcharts.com/stock/demoÜbersetzen Sie den Code auf FMZ, indem Sie diese Beispiele verwenden.

Der Aufruf add (([series index ((z.B. 0, Daten]) kann Daten zu einer bestimmten Indexreihe hinzufügen. Der Aufruf reset (() kann Daten von leeren Diagrammen entfernen. Reset kann mit einem Zahlenparameter den reservierten Eintrag angeben.

Ein konkretes Beispiel:

var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
    __isStock: true,                                    // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // 缩放工具
    title : { text : '差价分析图'},                       // 标题
    rangeSelector: {                                    // 选择范围
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
    yAxis : {                                           // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
        title: {text: '差价'},                           // 标题
        opposite: false,                                // 是否启用右边纵轴
    },
    series : [                                          // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
        {name : "line1", id : "线1,buy1Price", data : []},  // 索引为0, data 数组内存放的是该索引系列的 数据
        {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
    ]
};
function main(){
    var ObjChart = Chart(chart);  // 调用 Chart 函数,初始化 图表。
    ObjChart.reset();             // 清空
    while(true){
        var nowTime = new Date().getTime();   // 获取本次轮询的 时间戳,  即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
        var ticker = _C(exchange.GetTicker);  // 获取行情数据
        var buy1Price = ticker.Buy;           // 从行情数据的返回值取得 买一价
        var lastPrice = ticker.Last + 1;      // 取得最后成交价,为了2条线不重合在一起 ,我们加1
        ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
        ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
        Sleep(2000);
    }
}

Ein Beispiel für ein Diagrammaufbau:https://www.fmz.com/strategy/136056

Wiederholung der Stufe

Python-Lokalisierung

Die spezifische Open-Source-Adresse:https://github.com/fmzquant/backtest_python

Installation

Sie müssen die folgenden Befehle in die Befehlszeile eingeben:

pip install https://github.com/fmzquant/backtest_python/archive/master.zip

Ein einfaches Beispiel

Die Retargeting-Parameter werden zu Beginn des Policy-Codes in der Form einer Anmerkung gesetzt.

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"OKEX","currency":"LTC_BTC","balance":3,"stocks":0}]
'''
from fmz import *
task = VCtx(__doc__) # initialize backtest engine from __doc__
print exchange.GetAccount()
print exchange.GetTicker()
print task.Join() # print backtest result

Wiederholung

Da eine vollständige Strategie einen Todeszyklus erfordert, wird die EOF-Ausnahme nach Beendigung der Rückprüfung ausgestoßen, um den Prozess zu beenden.

# !/usr/local/bin/python
# -*- coding: UTF-8 -*-

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD","balance":10000,"stocks":3}]
'''

from fmz import *
import math
import talib

task = VCtx(__doc__) # initialize backtest engine from __doc__

# ------------------------------ 策略部分开始 --------------------------

print exchange.GetAccount()     # 调用一些接口,打印其返回值。
print exchange.GetTicker()

def adjustFloat(v):             # 策略中自定义的函数
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # 具体的策略代码


def main():
    InitAccount = GetAccount()
    while True:
        onTick()
        Sleep(1000)

# ------------------------------ 策略部分结束 --------------------------

try:
    main()                     # 回测结束时会 raise EOFError() 抛出异常,来停止回测的循环。所以要对这个异常处理,在检测到抛出的异常后调用 task.Join() 打印回测结果。
except:
    print task.Join()         

Benutzerdefinierte Rückmessdaten

exchange.SetData ((arr), wechseln Sie die Wiederholungsdatenquelle mit kundenspezifischen K-Liniendaten. Arr-Parameter, ein Element, das als K-Linien-Säulen-Daten-Array verwendet wird ((i.e.: K-Liniendaten-Array, die vorübergehend nur JavaScript-Rückholung unterstützt).

In der Array arr ist die Datengestalt für einzelne Elemente:

[
    1530460800,    // time     时间戳
    2841.5795,     // open     开盘价
    2845.6801,     // high     最高价
    2756.815,      // low      最低价
    2775.557,      // close    收盘价
    137035034      // volume   成交量
]

Die Datenquellen können in die Bibliothek der Architektur-Template eingegeben werden.

function init() {                                                          // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
    var arr = [                                                            // 回测的时候需要使用的K线数据
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // 时间最早的一根 K线柱 数据
        ... ,                                                              // K线数据太长,用 ... 表示,数据此处省略。
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // 时间最近的一根 K线柱 数据
    ]
    exchange.SetData(arr)                                                  // 导入上述 自定义的数据
    Log("导入数据成功")
}

Hinweis: Es ist unbedingt notwendig, dass bei der Initiierung zuerst die benutzerdefinierten Daten (d.h. die Dateneinstellungen der Exchange.SetData-Funktion) eingeführt werden. Die benutzerdefinierten K-Zeilendatenzyklen müssen mit den unteren K-Zeilendaten der Rückrufseite übereinstimmen, d.h. wenn die benutzerdefinierten K-Zeilendaten eine Zeitspanne von 1 Minute haben, dann ist auch die unteren K-Zeilendaten der Rückrufseite auf 1 Minute gesetzt.

Anhand von FMZ nicht unterstützten Börsen

Wenn die nicht unterstützte Börse und die unterstützte Börse API genau identisch sind, nur die Basisadresse unterschiedlich ist, kann sie durch den Wechsel der Basisadresse unterstützt werden.

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全

Nicht alle Börsen unterstützen FMZ, aber die Plattform bietet Zugang zu den allgemeinen Protokollen.

  • Der Code wird selbst geschrieben, um die Börse zu betreten, und der Prozess erzeugt einen Netzdienst.
  • Das ist ein einfaches System, um die Adresse und den Port des Netzdienstes anzugeben und eine Börse auf der FMZ Plattform hinzuzufügen.
  • Wenn ein Treuhänder die Plattform einer Austauschplattform mit einem allgemeinen Protokoll betreibt, werden API-Zugriffe in der Strategie an das allgemeine Protokoll gesendet.
  • Der General Protocol besucht die Börse auf Anfrage und gibt die Ergebnisse an den Treuhänder zurück.

Einfach ausgedrückt, ist das gPvP wie ein Vermittler, der die Anfragen der Gastgeber nach entsprechenden Standards vertritt und die Daten zurückgibt. Das gPvP-Code muss selbst ausgeführt werden, und das Schreiben des gPvP bedeutet, dass Sie einzeln auf die Börse zugreifen und die Richtlinien ausführen können. FMZ-Offizielle veröffentlichen manchmal eine gPvP-Exe-Version der Börse.

Ein Beispiel für ein konkretes Abkommen:https://www.fmz.com/bbs-topic/1052Ein Beispiel für ein allgemeines Python-Protokoll:https://www.fmz.com/strategy/101399

Erstellen Sie Ihre eigene Quantifizierungsplattform

Wie bei der Börse können alle Vorgänge über die API realisiert werden. Die FMZ-Website ist auch API-basiert. Sie können Ihre eigenen FMZ-Website-API-KEY-Implementierungen für verschiedene Funktionen wie Erstellen, Neustart, Löschen von Festplatten, Zugriff auf Festplattenlisten, Zugriff auf Festplattenprotokolle anfordern.

Dank der starken Skalierbarkeit der FMZ-Plattform können Sie Ihre eigene Quantitative Plattform auf Basis der Erweiterungs-API erstellen, die Benutzer auf Ihrer Plattform laufen lassen.

Wir sind Partner von FMZ

Die Nutzung von Cloud-Klassen

Der Markt für digitale Währungstransaktionen wird aufgrund seiner Besonderheiten zunehmend von quantifizierten Händlern betroffen. Programmierte Transaktionen sind in der Tat der Mainstream der digitalen Währung, und Strategien wie Hedging und Markteinführung sind ständig nicht aktiv.www.fmz.comDer Kurs kostet nur 20 US-Dollar und richtet sich an Anfänger.

VerbreitungNetEase Cloud-Klassenzimmer für digitale Währungskvantitative TransaktionenWenn du dich bei der E-Learning-Stufe anmelden und den Kurs kaufen möchtest, erhältst du eine Verteilung von 50 Prozent auf insgesamt 10 Yuan.

Werbung für die Rückkehr von Angestellten

Der Verbraucher klickt auf den Promotionslink und wird innerhalb von sechs Monaten nach der Registrierung aufgeladen. Die Provision wird in Höhe des gültigen Betrags des gültigen Auftrags zurückerstattet. Die Provision wird in Form von Punkten in das Konto des Promoteurs zurückgegeben.https://www.fmz.com/bbs-topic/3828

FMZ-Quantifizierungsplattform

Eine vollständige FMZ-Website kann auf einem exklusiven Server eines Unternehmens oder Teams bereitgestellt werden, um die vollständige Kontrolle und Funktionsanpassung zu ermöglichen. Die FMZ-Website wurde von etwa 100.000 Benutzern verwendet und getestet und erzielt eine hohe Verfügbarkeit und Sicherheit, was die Zeitkosten von Quantitative Teams und Unternehmen spart. Die Enterprise-Version richtet sich an mittlere und mittlere Quantitative Handelsteams, Kommoditäts-Futureservice-Anbieter usw.

Ein Stadtsystem

Das professionelle System zur Bereitstellung von Marktliquidität und Geldmanagement für Börsen ist möglicherweise das bestmögliche Marktsystem auf dem Markt und wird von vielen Börsen und Teams verwendet.

Börsenprogramm

Das von den Erfindern entwickelte Technologietransaktionssystem nutzt Speicherfotografie, um die Orderverarbeitung mit einer Geschwindigkeit von bis zu 2 Millionen Stück pro Sekunde zu gewährleisten. Es kann gleichzeitig den flüssigen Betrieb von Börsen mit mehr als 20 Millionen Online-Nutzern gewährleisten. Die Systemarchitektur mit mehreren Ebenen und Clustern gewährleistet die Sicherheit, Stabilität und Erweiterbarkeit des Systems.


Mehr

Bbbwwed 2009Kann man noch in die Gruppe?

- Ich weiß nicht.Der Grasgott, die Gewalt!

Das GrasIch weiß. // Token Futures Push Beispiel var ACCESSKEYID = 'Accesskey für Ihr Tokenkonto' var apiClient = Dial (('wss://api.hbdm.com/notification in zu komprimieren=gzip&mode=recv') Var date = neues Datum (); var now_utc = Date.UTC ((date.getUTCFullYear ((), date.getUTCMonth ((), date.getUTCDate ((), date.getUTCHours ((), date.getUTCMinutes ((), date.getUTCSeconds (())); VAR_UTC_DATE = neues Datum (now_utc) var Timestamp = utc_date.toISOSstring (().substring ((0,19)) Var quest = 'GET\napi.hbdm.com\n/notification\n' + 'AccessKeyId=' + ACCESSKEYID+' & SignatureMethod=HmacSHA256 & SignatureVersion=2 & Timestamp=' + encodeURIComponent (Timestamp) Die Daten werden von einem anderen Benutzer gesammelt. Var Signature = exchange.HMAC (("sha256", "base64", quest, "{{secretkey}}") Ich weiß.

Beatty TruppeBitte, wenn es sich um einen Websocket-Verbindungs-Abonnementmarkt handelt, dann wird der Markt mit der Read- () Funktion abgerufen, oder? Wenn man den Exchange.Get-Ticker () verwendet, wird nicht aus dem lokalen Cache extrahiert, sondern eine Rest-Anfrage gestartet, die die Daten zurückgibt, oder? Nur eine Token-Familie unterstützt die Änderung der Markenabnahme über den exchange.IO (WEB socket), der dann mit exchange.GetTicker (WEB und exchange.GetDepth (WEB keine Daten mehr an den exchangerest anfordert, sondern die get-Daten aus den bereits empfangenen Abonnementmärkten im lokalen Buffer enthält. Ich verstehe, oder?

Das GrasNach Hinweis überprüfen

JyzliuyuBitte beachten Sie, dass die Verifizierungsdaten der FMZ-Telegram-Gruppe lautet:

Shaltiel- Das ist ok.

Das GrasJa, es ist besser, wenn alle Websockets mit Dial bedient werden, das ist intuitiver.