使用JavaScript實現量化策略併發執行

本文代碼和文章發在FMZ發明者比特幣量化交易平臺上:javascript

使用JavaScript實現量化策略併發執行--封裝Go函數 - 發明者量化 https://www.fmz.com/digest-topic/3981java

在實現量化策略時,不少狀況下,併發執行能夠下降延時提高效率。以對衝機器人爲例,須要獲取兩個幣的深度,順序執行的代碼以下:多線程

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

  

請求一次rest API存在延時,假設是100ms,那麼兩次獲取深度的時間實際上不同,若是須要更多的訪問,延時問題將會更突出,影響策略的執行。併發

JavaScript因爲沒有多線程,所以底層封裝了Go函數解決這個問題,但因爲設計機制,實現起來較爲繁瑣。app

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)
    }
}

  

看上去兜了一圈只實現了一個簡單功能,實際上大大簡化了代碼複雜程度,咱們只需關心程序須要產生什麼任務,由worker()程序自動將他們併發執行,並返回相應的結果。靈活性提高了不少。this

相關文章
相關標籤/搜索