
定量的な戦略を実装する場合、多くの場合、同時実行によってレイテンシが短縮され、効率が向上します。ヘッジロボットを例にとると、2 つのコインの深さを取得する必要があります。順番に実行されるコードは次のとおりです。
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
REST API のリクエストには遅延があります。100 ミリ秒と仮定します。すると、深度を 2 回取得する時間は実際には異なります。より多くのアクセスが必要な場合、遅延の問題がより顕著になり、戦略の実行に影響します。
JavaScript にはマルチスレッドがないため、この問題を解決するために基礎となる Go 関数がカプセル化されていますが、その設計メカニズムにより、実装はかなり面倒です。
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果
var depthB = b.wait()
最も単純なケースでは、このようにポリシーを記述しても問題はありません。ただし、このプロセスは戦略がループするたびに繰り返す必要があり、中間変数 a と b は実際には一時的な補助にすぎないことに注意してください。同時実行タスクが多数ある場合は、a と depthA、b と depthB の対応を記録する必要があります。同時実行タスクが不確実な場合、状況はさらに複雑になります。そこで、Goの並行処理を書くときに、同時に変数をバインドし、並行実行の結果が返されたときに、その結果が自動的に変数に割り当てられるようにする関数を実装したい。これにより、中間変数がなくなり、プログラムがよりシンプルになる。簡潔。具体的な実装は以下のとおりです。
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
G 関数を定義します。ここで、パラメーター t は実行される Go 関数、ctx はプログラム コンテキスト、f は特定の割り当てのための関数です。この機能が実際にどのように動作するかは、後ほど説明します。
この時点で、全体的なプログラム フレームワークは、プロデューサーが継続的にタスクを発行し、コンシューマーがそれらを同時に実行する「プロデューサー - コンシューマー」モデルとして記述できます (いくつかの違いがあります)。次のコードはデモンストレーションのみを目的としており、プログラムには関係ありません。ロジックを実行します。
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)
}
}
多くのステップを経て単純な関数を実装しただけのように見えますが、実際にはコードの複雑さが大幅に簡素化されています。プログラムが生成する必要のあるタスクとワーカー( ) プログラムはそれらを自動的に同時に実行し、対応する結果を返します。柔軟性が大幅に向上しました。