定量戦略を実装する際に,同時実行は多くの場合遅延を軽減し,効率を向上させることができます.ヘジングロボットを例に挙げると,2つのコインの深さを得なければなりません.順番で実行されるコードは以下のとおりです:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
rest API の要求に遅延がある.それは 100ms だと仮定すると,深さを取得する時間は実際には異なります.より多くのアクセスが必要であれば,遅延問題はより顕著になり,戦略の実装に影響します.
JavaScriptにはマルチスレッドリングがないため,この問題を解決するためにGo関数が底にカプセル化されている.しかし,設計メカニズムにより,実装は比較的面倒である.
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() // Call the wait method to wait for the return of the depth result asynchronously
var depthB = b.wait()
簡単な場合では,この方法で戦略を書くのは間違っていることではない.しかし,このプロセスは各戦略ループで繰り返されるべきであることに注意してください.中間変数 a と b は一時的な補助のみです.当時は多くの同時作業がある場合, a と depthA,および b と depthB の間の対応関係を記録する必要があります.当時の作業が不確実であるとき,状況はより複雑になります.したがって,関数を実装したいです. Go を同時書き,同時に変数を結合し,同時操作の結果が戻ると,結果は自動的に変数に割り当てられ,中間変数を排除し,したがってプログラムをより簡潔にします.具体的な実装は以下のとおりです:
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
パラメータtが実行される Go関数,ctxが記録プログラム文脈,fが特定の割り当て関数である.
この時点で,全体的なプログラムフレームワークは"生産者-消費者"モデルに類似して記述できる (いくつかの違いがある). 生産者はタスクを送信し続け,消費者は同時に実行する. 次のコードは,プログラム実行ロジックを含まないデモのみである.
var Info = [{depth:null, account:null}, {depth:null, account:null}] // If we need to obtain the depth and account of the two exchanges, more information can also be put in, such as order ID, status, etc.
var tasks = [ ] // Global list of tasks
function produce(){ // Issue various concurrent tasks
// The logic of task generation is omitted here, for demonstration purposes only.
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) // Delete executed tasks
jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
Info[task.exchange][task.ret] = v // The v here is the return value of the concurrent Go function wait(), which can be experienced carefully.
}))
}
_.each(jobs, function(t){
t.run() // Execute all tasks concurrently here
})
}
function main() {
while(true){
produce() // Send trade orders
worker() // Concurrent execution
Sleep(1000)
}
}
円を回った後,たった一つの単純な機能しか実装されていないようです. 実際,コードの複雑さは大幅に簡素化されています. プログラムが生成する必要があるタスクについてのみ気にする必要があります. ワーカー() プログラムは自動的にそれらを同時実行し,対応した結果を返します. 柔軟性は大幅に改善されました.