Cuando se implementa la estrategia cuantitativa, la ejecución simultánea puede reducir la latencia y mejorar la eficiencia en muchos casos. Tomando el robot de cobertura como ejemplo, necesitamos obtener la profundidad de dos monedas.
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
Hay un retraso en la solicitud de una API de descanso. Suponiendo que sea de 100 ms, el tiempo para obtener la profundidad es realmente diferente. Si se requiere más acceso, el problema de retraso se volverá más prominente y afectará a la implementación de la estrategia.
JavaScript no tiene multithreading, por lo que la función Go se encapsula en la parte inferior para resolver este problema. Sin embargo, debido al mecanismo de diseño, la implementación es relativamente engorrosa.
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()
En la mayoría de los casos simples, no hay nada de malo en escribir la estrategia de esta manera. Sin embargo, se observa que este proceso debe repetirse para cada bucle de estrategia. Las variables intermedias a y b son solo ayudas temporales. Si tenemos muchas tareas concurrentes, necesitamos registrar la relación correspondiente entre a y profundidadA, y b y profundidadB. Cuando nuestras tareas concurrentes son inciertas, la situación se vuelve más compleja. Por lo tanto, queremos implementar una función: al escribir Go simultáneamente, vincular una variable al mismo tiempo, y cuando el resultado de la operación concurrente devuelve, el resultado se asignará automáticamente a la variable, eliminando la variable intermedia y, por lo tanto, 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 de grabación, y f es la función de asignación específica.
En este momento, el marco general del programa se puede escribir como similar al modelo
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)
}
}
Parece que solo se ha implementado una función simple después de ir en círculos. De hecho, la complejidad del código se ha simplificado mucho. Solo tenemos que preocuparnos por qué tareas debe generar el programa. El programa worker() las ejecutará automáticamente simultáneamente y devolverá los resultados correspondientes. La flexibilidad ha mejorado mucho.