
Al implementar estrategias cuantitativas, en muchos casos, la ejecución simultánea puede reducir la latencia y mejorar la eficiencia. Tomando como ejemplo el robot de cobertura, es necesario obtener la profundidad de dos monedas. El código que se debe ejecutar en secuencia es el siguiente:
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Hay un retraso en la solicitud de una API de descanso. Supongamos que es de 100 ms. En ese caso, el tiempo para obtener la profundidad dos veces es realmente diferente. Si se requiere más acceso, el problema del retraso será más evidente y afectará la ejecución de la estrategia.
Como JavaScript no tiene subprocesos múltiples, la función Go subyacente está encapsulada para resolver este problema, pero debido a su mecanismo de diseño, la implementación es bastante engorrosa.
var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() //调用wait方法等待返回异步获取depth结果
var depthB = b.wait()
En la mayoría de los casos simples, no hay nada de malo en redactar la política de esta manera. Pero tenga en cuenta que este proceso debe repetirse cada vez que se repite la estrategia, y las variables intermedias a y b son en realidad sólo ayudas temporales. Si tenemos muchas tareas simultáneas, necesitamos registrar la correspondencia entre a y profundidad A, y b y profundidad B. Cuando nuestras tareas simultáneas son inciertas, la situación se vuelve más complicada. Por lo tanto, queremos implementar una función: al escribir concurrencia en Go, vincular una variable al mismo tiempo, y cuando se devuelve el resultado de la ejecución concurrente, el resultado se asigna automáticamente a la variable, eliminando así las variables intermedias y haciendo que el programa sea más conciso. La implementación específica es la siguiente:
function G(t, ctx, f) {
return {run:function(){
f(t.wait(1000), ctx)
}}
}
Definimos una función G, donde el parámetro t es la función Go a ejecutar, ctx es el contexto del programa y f es la función para la asignación específica. Veremos esta función en acción en breve.
En este punto, el marco general del programa se puede escribir como un modelo de “productor-consumidor” (con algunas diferencias), donde los productores emiten tareas continuamente y los consumidores las ejecutan simultáneamente. El código siguiente es solo para demostración y no involucra al programa. Ejecutar lógica.
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)
}
}
Parece que solo hemos implementado una función simple después de realizar muchos pasos, pero, de hecho, la complejidad del código se ha simplificado enormemente. Solo debemos preocuparnos por las tareas que el programa necesita generar y el trabajador( ) el programa los ejecutará automáticamente de forma simultánea y devolverá los resultados correspondientes. La flexibilidad se ha mejorado mucho.