[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.
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.IO
。Die spezifischen Eingabeparameter sind in der entsprechenden API-Dokumentation zu lesen.Info
Das Feld hat die ursprüngliche Information zurückgegeben, aber das Problem, dass die Schnittstelle nicht unterstützt wird, kann immer noch nicht behoben werden.
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)
}
Zugriff auf die öffentliche Schnittstelle, die Js nutzen könnenHttpQuery
In Python kann man die entsprechenden Pakete selbst verwenden, wie z.B.urllib
oderrequests
。
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()
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.
https://www.bitmex.com/api/explorer/
。https://www.bitmex.com/api/v1/order
Die Methode istPOST
◦ Da FMZ bereits die Root-Adresse intern festgelegt hat, muss nur "/api/v1/order" eingegeben werden.symbol=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
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.
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"]}')
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)
}
}
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.
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
}
}
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.
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)
}
}
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.
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
,GetAccount
So weiter.IO
Sie 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.
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.__isStock
Um 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
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()
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.
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.
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
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.
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.
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
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.
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.
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.
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.