3
집중하다
1444
수행원

JavaScript를 사용하여 양적 전략의 동시 실행 구현 - Go 함수 캡슐화

만든 날짜: 2019-06-29 11:24:57, 업데이트 날짜: 2023-10-26 20:06:10
comments   3
hits   2797

JavaScript를 사용하여 양적 전략의 동시 실행 구현 - Go 함수 캡슐화

정량적 전략을 구현할 때 많은 경우 동시 실행을 통해 지연 시간을 줄이고 효율성을 향상시킬 수 있습니다. 헤지 로봇을 예로 들면, 두 개의 동전의 깊이를 얻는 것이 필요합니다. 순서대로 실행되는 코드는 다음과 같습니다.

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() //调用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)
    }
}

많은 단계를 거쳐서 간단한 함수만 구현한 것 같지만, 사실 코드의 복잡성이 크게 단순화되었습니다. 우리는 프로그램이 어떤 작업을 생성해야 하는지에만 신경을 쓰면 되고, 워커( ) 프로그램은 자동으로 이 두 가지를 동시에 실행하고 해당 결과를 반환합니다. 유연성이 크게 향상되었습니다.