利用SQLite构建发明者量化数据库

摘要

数据是量化交易的源头,如何高效地管理大量数据是很是关键的环节,数据库是最佳的解决方案之一,现现在数据库的应用已是各种日内交易、高频交易等策略的量化标准配置。本篇咱们来研究一下发明者量化(FMZ.COM)内置的数据库,内容包括:如何建立数据表、存储数据、修改数据、删除数据、引用数据以及如何应用于实战。node

如何选择数据库

熟悉发明者量化平台的应该知道,在这以前要想把数据保存到本地复用,只能用_G()函数,每次中止策略时,_G()函数会自动保存须要的信息。但若是想要保存更多更复杂的格式化数据,_G()函数显然就不太适用了,因而不少人想到了自建数据库来解决这个问题。数据库

提到自建数据库,想必你们能想到Oracle、MySQL、KDB、OneTick、NoSQL...这些都是很是优秀的企业级别的应用,不论是功能仍是性能都很是强大。但也面临几个问题:上手难度大,配置繁琐维护起来麻烦,这对于量化交易散户来讲,有点用大炮打苍蝇的感受,即便上手也只是用到不多一部分功能。函数

发明者量化内置数据库

接下来让咱们认识一下发明者量化内置的轻型数据库,DBExec是发明者量化内置的一个关系型数据管理系统接口,基于SQLite开发,其自己是用C写的,不但体积小巧,占用资源低,并且处理速度快,很是适合用于金融量化分析爱好者在本地实现数据管理,由于能够将不一样的“对象”(例如交易所,数据源,价格)分红不一样的表,并在表之间定义关系。此外用户无需单独安装和配置,只要调用DBExec()函数就能够直接使用!性能

另外,SQLite语言的学习成本很低,在数据库上执行的大部分工做都由SQLite语句完成。熟悉基本语法就能知足大部分需求,如下是SQLite的基础语法。学习

基础语法

SQLite的语法是不区分大小写的,不过有一些命令对大小写敏感,如GLOB和glob表明不一样的含义。SQLite语句能够以任何关键字开始,如SELECT、INSERT、UPDATE、DELETE、ALTER、DROP等,它们分别表示:提取数据、插入数据、更新数据、删除数据、修改数据库、删除数据表。全部的语句以英文分号结束。下面是一个简单的数据库建立、增、删、改、查等操做:url

function main() {
    // 建立:若是“users”表不存在就建立一个,“id”是整数且自动增长,“name”是文本形式且不为空
    Log(DBExec('CREATE TABLE IF NOT EXISTS "users" (id INTEGER PRIMARY KEY AUTOINCREMENT, name text not NULL);'));
    
    // 增长:
    Log(DBExec("INSERT INTO users(name) values('张三')"));
    Log(DBExec("INSERT INTO users(name) values('李四')"));
    
    // 删除:
    Log(DBExec("DELETE FROM users WHERE id=1;"));
    
    // 修改
    Log(DBExec("UPDATE users SET name='王五' WHERE id=2"));
    
    // 查询
    Log(DBExec('select 2, ?, ?, ?, ?', 'ok', true,9.8,null));
    Log(DBExec('select * from kvdb'));
    Log(DBExec('select * from cfg'));
    Log(DBExec('select * from log'));
    Log(DBExec('select * from profit'));
    Log(DBExec('select * from chart'));
    Log(DBExec("selEct * from users"));
}

一个数据库一般包含一个或多个表,每一个表都有一个名字标识,须要注意的是系统保留表分别: kvdb, cfg, log, profit, chart。也就是说在建立表时,应该避开系统保留的名字。让咱们运行上面的代码,输出如下内容:
spa

策略实例

了解了SQLite的基础语法,咱们趁热打铁使用发明者量化内置的数据库,建立一个收集和使用Tick数据的实例。.net

第一步:更新托管者
首先确保您使用的是最新版本的托管者,若是以前下载使用过托管者,须要先删除,并在 https://www.fmz.com/m/add-node 页面从新下载和部署。3d

第二步:建立策略日志

function main() {
    // 订阅合约
    _C(exchange.SetContractType, 'swap');
    
    // 建立数据表
    DBExec('CREATE TABLE IF NOT EXISTS "tick" (id INTEGER PRIMARY KEY AUTOINCREMENT,'.concat(
        'High FLOAT not NULL,', 
        'Low FLOAT not NULL,', 
        'Sell FLOAT not NULL,', 
        'Buy FLOAT not NULL,', 
        'Last FLOAT not NULL,', 
        'Volume INTEGER not NULL,', 
        'Time INTEGER not NULL);'
    ));
    
    // 获取10个tick数据
    while (true) {
        let tick = exchange.GetTicker();
        // 在tick表中增长数据
        DBExec(`INSERT INTO tick(High, Low, Sell, Buy, Last, Volume, Time) values(${tick.High}, ${tick.Low}, ${tick.Sell}, ${tick.Buy}, ${tick.Last}, ${tick.Volume}, ${tick.Time})`);
        // 查询全部数据
        let allDate = DBExec('select * from tick');
        if (allDate.values.length > 10) {
            break;
        }
        Sleep(1000);
    }
    
    // 查询全部数据
    Log(DBExec('select * from tick'));
    
    // 查询第一个数据
    Log(DBExec('select * from tick limit 1'));
    
    // 查询前两个数据
    Log(DBExec('select * from tick limit 0,2'));
    
    // 删除第一个数据
    Log(DBExec('DELETE FROM tick WHERE id=1;'));
    
    // 修改第二个数据
    Log(DBExec('UPDATE tick SET High=10000 WHERE id=2'));
    
    // 查询全部数据
    let allDate = DBExec('select * from tick')
    Log(allDate);
}

第三步:运行策略
以Windows为例,运行策略以后,会在托管者目录的“\logs\storage”目录中生成一个以机器人编号命名的文件夹,打开该文件夹,里面有一个以“.db3”做为后缀的文件,这个文件就是发明者量化内置数据库的文件。如下图所示:

上面的代码首先建立了一个以“tick”命名的数据表,而后给该表添加tick数据字段,接着在循环中从交易所获取tick数据,并把这些数据插入到“tick”数据表中,同时判断该数据表中的数据量超过10个就跳出循环。最后分别用5个SQLite命令查询、删除、修改数据表中的数据。并在日志中打印出来,如下图所示:

第四步:建立状态栏
最后咱们增长一些代码,经过获取发明者量化数据库中的数据,给策略建立一个状态栏,把数据更直观的展现出来,新增代码以下:

// 建立状态栏
    let table = {
        type: 'table',
        title: '币安Tick数据',
        cols: allDate.columns,
        rows: allDate.values
    }
    LogStatus('`' + JSON.stringify(table) + '`');

上面的代码经过数据库中的数据,建立了一个“币安Tick数据”表。其中数据库中的“columns”字段表明状态栏中的“行”,“values”字段表明状态栏中的“列”。以下图所示:

完整策略代码

/*backtest
start: 2020-07-19 00:00:00
end: 2020-08-17 23:59:00
period: 15m
basePeriod: 15m
exchanges: [{"eid":"Binance","currency":"LTC_USDT"}]
*/

function main() {
    Log(DBExec('DROP TABLE tick;'));
    // 订阅合约
    _C(exchange.SetContractType, 'swap');

    // 建立数据表
    DBExec('CREATE TABLE IF NOT EXISTS "tick" (id INTEGER PRIMARY KEY AUTOINCREMENT,'.concat(
        'High FLOAT not NULL,',
        'Low FLOAT not NULL,',
        'Sell FLOAT not NULL,',
        'Buy FLOAT not NULL,',
        'Last FLOAT not NULL,',
        'Volume INTEGER not NULL,',
        'Time INTEGER not NULL);'
    ));

    // 获取10个tick数据
    while (true) {
        let tick = exchange.GetTicker();
        // 在tick表中增长数据
        DBExec(`INSERT INTO tick(High, Low, Sell, Buy, Last, Volume, Time) values(${tick.High}, ${tick.Low}, ${tick.Sell}, ${tick.Buy}, ${tick.Last}, ${tick.Volume}, ${tick.Time})`);
        // 查询全部数据
        let allDate = DBExec('select * from tick');
        if (allDate.values.length > 10) {
            break;
        }
        Sleep(1000);
    }

    // 查询全部数据
    Log(DBExec('select * from tick'));

    // 查询第一个数据
    Log(DBExec('select * from tick limit 1'));

    // 查询前两个数据
    Log(DBExec('select * from tick limit 0,2'));

    // 删除第一个数据
    Log(DBExec('DELETE FROM tick WHERE id=1;'));

    // 修改第二个数据
    Log(DBExec('UPDATE tick SET High=10000 WHERE id=2'));

    // 查询全部数据
    let allDate = DBExec('select * from tick')
    Log(allDate);

    // 建立状态栏
    let table = {
        type: 'table',
        title: '币安Tick数据',
        cols: allDate.columns,
        rows: allDate.values
    }
    LogStatus('`' + JSON.stringify(table) + '`');
}

点击该连接 https://www.fmz.com/strategy/265906 便可复制完整策略代码。

内存数据库

若是操做的数据不但愿永久保存到磁盘,能够在SQL语句前加上:符号就能够在内存数据库里操做, 机器人重启后数据重置

DBExec(":select 1,2,3");

总结

数据库不只能够承载海量数据,更能承载众多量化交易爱好者的宽客梦想。对于数据库的使用绝非仅限于本文的例子,更多使用方法能够参考SQLite教程,以及发明者量化后续推出的系列文章。

相关文章
相关标签/搜索