
Bei der Implementierung quantitativer Strategien kann die gleichzeitige Ausführung in vielen Fällen die Latenz reduzieren und die Effizienz verbessern. Am Beispiel des Hedging-Roboters ist es notwendig, die Tiefe von zwei Münzen zu ermitteln. Der nacheinander ausgeführte Code lautet wie folgt:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Es gibt eine Verzögerung bei der Anforderung einer Rest-API. Angenommen, sie beträgt 100 ms. Dann ist die Zeit, um die Tiefe zweimal zu erhalten, tatsächlich unterschiedlich. Wenn mehr Zugriffe erforderlich sind, wird das Verzögerungsproblem deutlicher und beeinträchtigt die Ausführung der Strategie.
Da JavaScript nicht über Multithreading verfügt, wird die zugrunde liegende Go-Funktion gekapselt, um dieses Problem zu lösen. Aufgrund des Entwurfsmechanismus ist die Implementierung jedoch ziemlich umständlich.
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 falsch, die Police auf diese Weise zu verfassen. Beachten Sie jedoch, dass dieser Vorgang bei jeder Strategieschleife wiederholt werden muss und die Zwischenvariablen a und b eigentlich nur temporäre Hilfsmittel sind. Wenn wir viele gleichzeitige Aufgaben haben, müssen wir die Entsprechung zwischen a und TiefeA sowie b und TiefeB aufzeichnen. Wenn unsere gleichzeitigen Aufgaben unsicher sind, wird die Situation komplizierter. Daher möchten wir eine Funktion implementieren: Beim Schreiben von Go-Parallelität wird eine Variable gleichzeitig gebunden, und wenn das gleichzeitig ausgeführte Ergebnis zurückgegeben wird, wird das Ergebnis automatisch der Variablen zugewiesen, wodurch die Zwischenvariablen eliminiert und das Programm mehr prägnant. Die konkrete Implementierung sieht wie folgt aus:
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
Wir definieren eine G-Funktion, wobei der Parameter t die auszuführende Go-Funktion, ctx der Programmkontext und f die Funktion für die spezifische Zuweisung ist. Wir werden diese Funktion in Kürze in Aktion sehen.
An diesem Punkt kann das gesamte Programmgerüst als „Produzent-Konsument“-Modell (mit einigen Unterschieden) geschrieben werden, bei dem Produzenten kontinuierlich Aufgaben erteilen und Konsumenten diese gleichzeitig ausführen. Der folgende Code dient nur zur Demonstration und betrifft nicht das Programm. Logik ausführen.
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]
tasks.splice(i,1) //删掉已执行的任务
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() //在这里并发执行所有任务
})
}
function main() {
while(true){
produce() // 发出交易指令
worker() // 并发执行
Sleep(1000)
}
}
Es scheint, dass wir nach vielen Schritten nur eine einfache Funktion implementiert haben, aber tatsächlich wurde die Komplexität des Codes erheblich vereinfacht. Wir müssen uns nur darum kümmern, welche Aufgaben das Programm generieren muss, und den Worker ( ) Programm führt sie automatisch gleichzeitig aus und gibt die entsprechenden Ergebnisse zurück. Die Flexibilität wurde erheblich verbessert.