JavaScript版本行情收集器

最近,FMZ量化交易平臺支持了數據庫接口,因此使用JavaScript語言也能夠很方便的實現一個K線行情數據收集器了。
有了需求,立刻行動~數據庫

構建JavaScript版本行情收集器以前,咱們先來熟悉FMZ的數據庫接口DBExec函數

DBExec 函數

先熟悉如下幾種操做:測試

  • 建立表
  • 向表中寫入數據
  • 查詢表中數據
function main() {
    /* 建立表
 var strSql = [
 "CREATE TABLE RECORDS_MIN1(", 
 "TS INT PRIMARY KEY NOT NULL,",
 "HIGH REAL NOT NULL,", 
 "OPEN REAL NOT NULL,", 
 "LOW REAL NOT NULL,", 
 "CLOSE REAL NOT NULL,", 
 "VOLUME REAL NOT NULL)"
 ].join("")
 // DBExec函數返回:{"rowsAffected":1,"lastInsertId":18}
 */    
    
    /* 表寫入數據
 // INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
 // VALUES (1, 'Paul', 32, 'California', 20000.00 );
 var strSql = [
 "INSERT INTO RECORDS_MIN1 (TS, HIGH, OPEN, LOW, CLOSE, VOLUME)", 
 "VALUES (111111, 111.11, 111.12, 111.13, 111.14, 111.16);"
 ].join("")
 // DBExec函數返回:{"rowsAffected":1,"lastInsertId":1}
 */
    
    /* 查詢表中數據
 // SELECT * FROM RECORDS_MIN1;
 var strSql = ["SELECT * FROM RECORDS_MIN1;"].join("")
 // DBExec函數返回:{"columns":["TS","HIGH","OPEN","LOW","CLOSE","VOLUME"],"values":[[111111,111.11,111.12,111.13,111.14,111.16]]}
 */
    
    var ret = DBExec(strSql)    // 執行SQL語句
    Log(ret)    
}

設計行情收集器

利用FMZ的數據庫接口DBExec能夠實現收集交易所的K線數據。
例若有些策略基於很長的K線數據計算指標,很不容易收集數據讓K線數據長度足夠計算指標,可是遇到策略程序設計不完善實盤異常中止、臨時調整代碼、臨時調整策略參數等須要重啓實盤的場景。此時實盤一旦重啓收集的數據就沒有了(程序變量中保存)。因此使用數據庫接口,保存收集的行情數據是一個很是好的解決辦法。this

咱們的需求也十分簡單:url

  • 程序輪詢獲取行情
  • 判斷BAR更新,將完成的BAR數據寫入數據庫表保存。
  • 查詢數據庫中表的數據
  • 本例子爲了展現數據,增長了畫圖(使用畫線類庫),經過策略交互按鈕,更新K線圖表。
  • 刪除數據庫表
  • 初始化,從新建立數據庫表,寫入最新的數據。

簡單的數據收集器源碼:spa

var collecter = {}
collecter.init = function(tableName) {
	this.preBarTS = 0
	this.tableName = tableName
    this.tableAvaliable = false 
    // 檢測tableName表
    if (typeof(tableName) == "undefined" || typeof(tableName) != "string") {
    	Log(tableName)
        throw "tableName error!"
    }

    // SELECT * FROM RECORDS_MIN1 LIMIT 1
    var strSql = "SELECT * FROM " + tableName + " LIMIT 1"
    var ret = DBExec(strSql)    
    if (!ret) {
    	// 表不存在,建立表
        Log("嘗試讀取表", this.tableName, "的數據,讀取失敗,開始建立表", this.tableName)
    	var strSql = [
            "CREATE TABLE " + tableName + "(", 
            "TS INT PRIMARY KEY NOT NULL,",
            "HIGH REAL NOT NULL,", 
            "OPEN REAL NOT NULL,", 
            "LOW REAL NOT NULL,", 
            "CLOSE REAL NOT NULL,", 
            "VOLUME REAL NOT NULL)"
        ].join("")
        ret = DBExec(strSql)
        if (!ret) {
        	throw "建立" + tableName + "表失敗!"
        }
        Log("建立", tableName, "表", ret)
    }
    Log(this.tableName, ret)
    this.tableAvaliable = true 
}

collecter.run = function(records) {
    if (!this.tableAvaliable) {
        return 
    }
	var len = records.length
	var lastBar = records[len - 1]
	var beginBar = records[0]
	var ret = null 
    if (this.preBarTS == 0) {
        // 初始
        /*
 DELETE FROM table_name WHERE [condition];
 */
        var strSql = "DELETE FROM " + this.tableName + " WHERE TS >= " + beginBar.Time + ";"
        ret = DBExec(strSql)
        Log("刪除與當前記錄重複部分", ret)

        // 寫入
        ret = DBExec("BEGIN")
        Log("BEGIN:", ret)
        for (var i = 0 ; i < len - 1 ; i++) {
        	var strSql = [
                "INSERT INTO " + this.tableName + " (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) ", 
                `VALUES (${records[i].Time}, ${records[i].High}, ${records[i].Open}, ${records[i].Low}, ${records[i].Close}, ${records[i].Volume});`
            ].join("")
            DBExec(strSql)
        }
        ret = DBExec("COMMIT")
        Log("COMMIT:", ret)
        this.preBarTS = lastBar.Time
    } else if(this.preBarTS != lastBar.Time) {
        // 更新
        var strSql = [
            "INSERT INTO " + this.tableName + " (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) ", 
            `VALUES (${records[len-2].Time}, ${records[len-2].High}, ${records[len-2].Open}, ${records[len-2].Low}, ${records[len-2].Close}, ${records[len-2].Volume});`
        ].join("")
        ret = DBExec(strSql)
        Log("INSERT:", ret)
        this.preBarTS = lastBar.Time
    }
}

collecter.getRecords = function() {
	// 讀取數據庫
    var strSql = "SELECT * FROM " + this.tableName + ";"
    var ret = DBExec(strSql)
    // Log("SELECT * FROM .. :", ret)
    // SELECT * FROM .. : {"columns":["TS","HIGH","OPEN","LOW","CLOSE","VOLUME"],"values":[[1616110200000,58085.9,57716.2,57664.3,57757.6,24.216], ...]}
    var arr = ret.values 
    var r = []
    for (var i = 0 ; i < arr.length ; i++) {
        r.push({
        	Time : arr[i][0],
        	High : arr[i][1],
        	Open : arr[i][2],
        	Low : arr[i][3],
        	Close : arr[i][4],
        	Volume : arr[i][5]
        })
    }
    return r
}

collecter.deleteTable = function() {
    // DROP TABLE database_name.table_name;
    var strSql = "DROP TABLE " + this.tableName
    var ret = DBExec(strSql)
    if (!ret) {
        Log("刪除表", this.tableName, "失敗:", ret)
    } else {
        Log("刪除表", this.tableName, " DROP TABLE:", ret)
        this.tableAvaliable = false 
    }
}

function main() {
	collecter.init(tableName)
    while(true) {    
    	var r = _C(exchange.GetRecords)
        // records tbl
        var rTbl = {
            type : "table", 
            title : "數據",
            cols : ["strTime", "Time", "High", "Open", "Low", "Close", "Volume"], 
            rows : [] 
        }
        var arrR = []
        if (collecter.tableAvaliable) {
            arrR = collecter.getRecords()
        }
        for (var i = arrR.length - 1; (i > arrR.length - 1 - 9) && (i >= 0); i--) {
            var bar = arrR[i]
            rTbl.rows.push([_D(bar.Time), bar.Time, bar.High, bar.Open, bar.Low, bar.Close, bar.Volume])
        }
    	LogStatus(_D(), "獲取的K線數據長度:", arrR.length, ", collecter.tableAvaliable:", collecter.tableAvaliable, "\n", 
            "`" + JSON.stringify(rTbl) + "`")
    	collecter.run(r)

    	// 交互測試
    	var cmd = GetCommand()
        if(cmd) {
            // 處理交互
            Log("交互命令:", cmd)
            var arr = cmd.split(":")
            // 從數據庫中讀取K線數據,刷新圖表
            if(arr[0] == "refreshRecords") {
                if (collecter.tableAvaliable) {
                    var records = collecter.getRecords()
                    $.PlotRecords(records, collecter.tableName)   // 使用畫線類庫畫圖
                } else {
                    Log("對應的數據庫表不存在 collecter.tableAvaliable:", collecter.tableAvaliable)
                }
            } else if (arr[0] == "deleteBDTable") {     // 刪除數據庫表
                collecter.deleteTable()
            } else if (arr[0] == "initCollecter") {     // 初始化收集器
                Log("初始化收集器")
                collecter.init(tableName)
            }
        }
    	Sleep(5000)
    }
}

測試

對比數據.net

策略地址:https://www.fmz.com/strategy/267223設計

相關文章
相關標籤/搜索