
Lors de la mise en œuvre de stratégies quantitatives, dans de nombreux cas, l’exécution simultanée peut réduire la latence et améliorer l’efficacité. En prenant comme exemple le robot de couverture, il est nécessaire d’obtenir la profondeur de deux pièces. Le code exécuté en séquence est le suivant :
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Il y a un délai dans la demande d’une API REST. Supposons qu’il soit de 100 ms. Le temps nécessaire pour obtenir la profondeur deux fois est alors en réalité différent. Si un accès plus important est requis, le problème de délai sera plus important, affectant l’exécution de la stratégie.
Étant donné que JavaScript ne dispose pas de multithreading, la fonction Go sous-jacente est encapsulée pour résoudre ce problème, mais en raison de son mécanisme de conception, l’implémentation est plutôt lourde.
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果
var depthB = b.wait()
Dans la plupart des cas simples, il n’y a rien de mal à rédiger la politique de cette façon. Mais notez que ce processus doit être répété à chaque fois que la stratégie boucle, et les variables intermédiaires a et b ne sont en fait que des aides temporaires. Si nous avons beaucoup de tâches simultanées, nous devons enregistrer la correspondance entre a et profondeur A, et b et profondeur B. Lorsque nos tâches simultanées sont incertaines, la situation devient plus compliquée. Par conséquent, nous voulons implémenter une fonction : lors de l’écriture de la concurrence Go, lier une variable en même temps, et lorsque le résultat de l’exécution simultanée est renvoyé, le résultat est automatiquement attribué à la variable, éliminant ainsi les variables intermédiaires et rendant le programme plus concis. L’implémentation spécifique est la suivante :
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
Nous définissons une fonction G, où le paramètre t est la fonction Go à exécuter, ctx est le contexte du programme et f est la fonction d’affectation spécifique. Nous verrons cette fonction en action sous peu.
À ce stade, le cadre global du programme peut être écrit sous la forme d’un modèle « producteur-consommateur » (avec quelques différences). Le producteur émet en permanence des tâches et le consommateur les exécute simultanément. Le code suivant est uniquement destiné à la démonstration et n’implique pas le programme. Exécuter la logique.
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)
}
}
Il semble que nous n’ayons implémenté qu’une fonction simple après avoir suivi de nombreuses étapes, mais en fait, la complexité du code a été grandement simplifiée. Nous devons seulement nous soucier des tâches que le programme doit générer et du worker( ) le programme les exécutera automatiquement simultanément et renverra les résultats correspondants. La flexibilité a été grandement améliorée.