O recurso está a ser carregado... Carregamento...

Construir um banco de dados de inventores quantificados com o SQLite

Autora: , Criado: 2021-03-26 17:09:32, Atualizado: 2024-12-05 21:56:39

[TOC]

img

Resumo

Os dados são a fonte de transações de quantificação, como gerenciar eficientemente grandes quantidades de dados é um elo muito crítico, os bancos de dados são uma das melhores soluções, e hoje os aplicativos de bancos de dados já são a configuração padrão de quantificação para todos os tipos de estratégias de negociação diurna, negociação de alta frequência e outros.FMZ.COM) com um banco de dados embutido, que inclui: como criar tabelas de dados, armazenar dados, modificar dados, excluir dados, referenciar dados e como aplicá-los em combate.

Como escolher um banco de dados

Os inventores que estão familiarizados com plataformas de quantificação devem saber que, até agora, para salvar dados para repetição local, só era possível usar a função _G(), que automaticamente salvava as informações necessárias quando a política era interrompida. Mas se você quisesse guardar dados com formatos mais complexos, a função _G() não era muito útil, então muitas pessoas pensaram em construir seus próprios bancos de dados para resolver o problema.

Quando falamos de construir um banco de dados, é provável que todos pensem em Oracle, MySQL, KDB, OneTick, NoSQL... são aplicativos de nível empresarial muito bons, com funcionalidades e desempenho muito poderosos. Mas também enfrentam alguns problemas: dificuldade de utilização, configuração pesada e problemas de manutenção, o que é um pouco de artilharia para os varejistas de transações quantitativas, mesmo que os operadores usem apenas uma pequena parte das funcionalidades.

Inventor quantificou o banco de dados embutido

O DBExec é uma interface para um sistema de gerenciamento de dados relacional, baseado no SQLite, desenvolvido em C, que é pequeno e de baixo uso de recursos, e rápido, ideal para os amantes da análise quantitativa financeira, pois pode dividir diferentes blocos de objetos (por exemplo, exchanges, fontes de dados, preços) em diferentes tabelas e definir relações entre as tabelas. Além disso, os usuários não precisam instalar e configurar separadamente, basta chamar a função DBExec ().

Além disso, o custo de aprendizagem da linguagem SQLite é baixo, e a maior parte do trabalho realizado no banco de dados é feito por instruções SQLite. A familiaridade com a gramática básica pode atender a maioria das necessidades.

Gramática básica

A sintaxe do SQLite é sem distinção de tamanho, mas há alguns comandos sensíveis ao tamanho, como o GLOB e o glob, que representam diferentes significados. As instruções do SQLite podem começar com qualquer palavra-chave, como SELECT, INSERT, UPDATE, DELETE, ALTER, DROP, etc., que indicam: extrair dados, inserir dados, atualizar dados, excluir dados, modificar banco de dados, excluir tabela de dados. Todas as instruções terminam em ponto em inglês.

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

Um banco de dados geralmente contém uma ou mais tabelas, cada uma com um nome identificador. É importante notar que o sistema reserva tabelas: kvdb, cfg, log, profit, chart. Ou seja, quando você cria uma tabela, você deve evitar o nome reservado pelo sistema.img

Exemplos de estratégias

Compreendendo a sintaxe básica do SQLite, aproveitamos o calor do ferro para quantificar o banco de dados embutido do inventor e criar um exemplo de coleta e uso de dados do Tick.

Primeiro passo: atualizar o administradorPrimeiro, certifique-se de que você está usando a versão mais recente do host.https://www.fmz.com/m/add-nodeA página foi recarregada e implementada.

Segundo passo: criar uma estratégia

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

Passo 3: A estratégia de execuçãoNo exemplo do Windows, depois de executar a política, uma pasta chamada de folha robótica é gerada e aberta no catálogo dos administradores, no catálogo dos servidores, com um arquivo com o suffix.db3 que é o arquivo do inventor para quantificar o banco de dados embutido.imgO código acima primeiro cria uma tabela de dados chamada tick-bar e, em seguida, adiciona um campo de dados de tick à tabela, obtém dados de tick da bolsa em um ciclo e insere esses dados na tabela de dados de tick-bar, saltando o ciclo se houver mais de 10 dados na tabela. Finalmente, os dados da tabela são consultados, excluídos ou modificados com 5 comandos SQLite, respectivamente. E é impresso no log, como mostrado na figura abaixo:img Passo 4: Crie um status barFinalmente, adicionamos um pouco de código para criar uma barra de status para a política, obtendo dados do inventor e quantificando os dados do banco de dados, mostrando os dados de forma mais intuitiva.

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

O código acima usa os dados do banco de dados para criar uma barra de dados do Tick. A barra de campos do banco de dados é representada pela barra de barras do barro de estado, e a barra de campos do barro de valores é representada pela barra de colunas do barro de estado.img

Código de estratégia completo

/*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) + '`');
}

Clique neste linkhttps://www.fmz.com/strategy/388963O código da política completa pode ser copiado.

Base de dados em memória

Se os dados da operação não quiserem ser guardados permanentemente no disco, podem ser adicionados antes da instrução SQL:O símbolo pode ser operado em um banco de dados em memória, e os dados podem ser reiniciados quando o robô reinicia.

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

Resumo

Os bancos de dados não só podem conter grandes quantidades de dados, mas também os sonhos de muitos amantes da quantificação. Para o uso de bancos de dados, não se limitam aos exemplos deste artigo, mais métodos de uso podem ser consultados no tutorial do SQLite e na série de artigos lançados posteriormente pelos inventores da quantificação.


Relacionados

Mais.

Dianwan99Ótimo. A única desvantagem é que os dados não podem ser gravados localmente, no disco.

WilliamfuO banco de dados não suporta reexame, certo?

Graças a Deus.Muito bom.

Suporte, você pode experimentar o banco de dados local

Obrigado.