Construção de um banco de dados quantitativo de FMZ com SQLite

Autora:Lydia., Criado: 2022-11-09 11:40:34, Atualizado: 2023-09-20 10:55:14

img

Resumo

Os dados são a fonte de negociação quantitativa, como gerenciar uma grande quantidade de dados de forma eficiente é um elo muito crítico, banco de dados é uma das melhores soluções, hoje em dia a aplicação de banco de dados é o padrão quantitativo para todos os tipos de negociação diária, negociação de alta frequência e outras estratégias.https://www.fmz.com), incluindo: como criar tabelas de dados, armazenar dados, modificar dados, excluir dados, dados de referência e como aplicá-los na prática.

Como escolher a base de dados

Aqueles que estão familiarizados com a plataforma FMZ Quant devem saber que antes de salvar dados para reutilização local, você só pode usar a função _G(), que salva automaticamente as informações necessárias toda vez que você parar a estratégia.

Quando se trata de bancos de dados auto-construídos, você deve pensar em Oracle, MySQL, KDB, OneTick, NoSQL... Estes são aplicativos de nível empresarial muito excelentes em função e desempenho. No entanto, também há vários problemas: é difícil começar, e a configuração é engorrosa e a manutenção é difícil. Para os comerciantes quantitativos de varejo, é um pouco como atirar moscas com canhão. Mesmo que eles comecem, eles usam apenas uma pequena parte das funções.

Base de dados integrada da FMZ Quant

Em seguida, vamos dar uma olhada no banco de dados de luz embutido pela FMZ Quant. DBExec é uma interface de sistema de gerenciamento de dados relacional embutido da FMZ Quant. Ele é desenvolvido com base no SQLite e é escrito em C. Ele não é apenas de tamanho pequeno, pouco consumo de recursos, mas também rápido no processamento. É muito adequado para os entusiastas da análise quantitativa financeira implementarem o gerenciamento de dados localmente, porque diferentes objectos (como exchanges, fontes de dados e preços) podem ser divididos em diferentes tabelas e as relações entre tabelas podem ser definidas. Além disso, os usuários não precisam instalá-los e configurá-los separadamente. Eles podem usá-los diretamente ligando a função DBExec!

Além disso, é muito fácil aprender a linguagem SQLite, e a maioria do trabalho realizado no banco de dados é concluído por instruções SQLite.

Gramática básica

A gramática do SQLite é insensible a minúsculas e pequenas, embora existam alguns comandos que são sensíveis a minúsculas e pequenas, como GLOB e glob, que representam significados diferentes. As instruções do SQLite podem começar com qualquer palavra-chave, como SELECT, INSERT, UPDATE, DELETE, ALTER, DROP, etc., que significam: extrair dados, inserir dados, atualizar dados, excluir dados, modificar banco de dados e excluir tabela de dados. Todas as instruções são terminadas por pontos e vírgulas em inglês. A seguir está uma simples criação de banco de dados, adicionar, excluir, alterar e verificar operações:

function main() {
    // Create: If the "users" table does not exist, create one, "id" is an integer and is incremented automatically, "name" is in text form and is not empty
    Log(DBExec('CREATE TABLE IF NOT EXISTS "users" (id INTEGER PRIMARY KEY AUTOINCREMENT, name text not NULL);'));
    
    // Add:
    Log(DBExec("INSERT INTO users(name) values('Zhang San')"));
    Log(DBExec("INSERT INTO users(name) values('Li Si')"));
    
    // Delete:
    Log(DBExec("DELETE FROM users WHERE id=1;"));
    
    // Modify:
    Log(DBExec("UPDATE users SET name='Wang Wu' WHERE id=2"));
    
    // Search:
    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 tabela é identificada por um nome, note que as tabelas reservadas ao sistema são: kvdb, cfg, log, lucro, gráfico. ou seja, ao criar tabelas, você deve evitar os nomes reservados ao sistema.

img

Exemplos de estratégia

Tendo aprendido a gramática básica do SQLite, nós atacamos enquanto o ferro está quente para criar uma instância de coleta e uso de dados do Tick usando o banco de dados integrado do FMZ Quant.

Passo 1: Atualizar o docker

Primeiro, certifique-se de que você está usando a versão mais recente do docker. Se você já baixou e usou o docker antes, você precisa excluí-lo primeiro, e depois redistribuí-lo e redistribuí-lo emhttps://www.fmz.com/m/add-node page.

Passo 2: Criar a estratégia

function main() {
    // Subscribe contracts
    _C(exchange.SetContractType, 'swap');
    
    // Create data table
    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);'
    ));
    
    // Get 10 pieces of tick data
    while (true) {
        let tick = exchange.GetTicker();
        // Add data to the tick table
        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})`);
        // Search all data
        let allDate = DBExec('select * from tick');
        if (allDate.values.length > 10) {
            break;
        }
        Sleep(1000);
    }
    
    // Search all data
    Log(DBExec('select * from tick'));
    
    // Search the first data
    Log(DBExec('select * from tick limit 1'));
    
    // Search first two pieces of data
    Log(DBExec('select * from tick limit 0,2'));
    
    // Delete the first data
    Log(DBExec('DELETE FROM tick WHERE id=1;'));
    
    // Modify the second data
    Log(DBExec('UPDATE tick SET High=10000 WHERE id=2'));
    
    // Search all data
    let allDate = DBExec('select * from tick')
    Log(allDate);
}

Passo 3: Execute a estratégia

Tomemos o Windows como exemplo, depois de executar a estratégia, uma pasta com o nome do número do robô será criada no diretório \logs\storage do diretório do docker. Abra a pasta e há um arquivo com o sufixo . db3, que é o arquivo do banco de dados integrado do FMZ Quant. Como mostrado na figura a seguir:

img

O código acima cria uma tabela de dados chamada tick primeiro, então adiciona o campo de dados de tick à tabela, então obtém os dados de tick da troca no loop e insere os dados na tabela de dados tick. Ao mesmo tempo, julgamos que a quantidade de dados na tabela de dados excede 10, então saímos do loop. Finalmente, usamos 5 comandos SQLite para pesquisar, excluir e modificar os dados na tabela de dados, respectivamente. E imprimimos nos registros, como mostrado na imagem a seguir:

img

Passo 4: Crie a barra de estado

Finalmente, adicionamos algum código para criar uma barra de status para a estratégia, obtendo os dados no banco de dados FMZ Quant para exibir os dados de forma mais visual, o código adicionado mostra como segue:

    // Create status bar
    let table = {
        type: 'table',
        title: 'Binance Tick data',
        cols: allDate.columns,
        rows: allDate.values
    }
    LogStatus('`' + JSON.stringify(table) + '`');

O código acima cria uma tabela de Binance Tick data através dos dados no banco de dados. O campo colunas no banco de dados representa as colunas na barra de status, e o campo valores representa as colunas na barra de status.

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;'));
    // Subscribe contracts
    _C(exchange.SetContractType, 'swap');

    // Create data table
    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);'
    ));

    // Obtain 10 pieces of tick data
    while (true) {
        let tick = exchange.GetTicker();
        // Add data to the tick table
        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})`);
        // Search all data
        let allDate = DBExec('select * from tick');
        if (allDate.values.length > 10) {
            break;
        }
        Sleep(1000);
    }

    // Search all data
    Log(DBExec('select * from tick'));

    // Search the first data
    Log(DBExec('select * from tick limit 1'));

    // Search first two pieces of data
    Log(DBExec('select * from tick limit 0,2'));

    // Delete the first data
    Log(DBExec('DELETE FROM tick WHERE id=1;'));

    // Modify the second data
    Log(DBExec('UPDATE tick SET High=10000 WHERE id=2'));

    // Search all data
    let allDate = DBExec('select * from tick')
    Log(allDate);

    // Create status bar
    let table = {
        type: 'table',
        title: 'Binance Tick data',
        cols: allDate.columns,
        rows: allDate.values
    }
    LogStatus('`' + JSON.stringify(table) + '`');
}

Clique neste linkhttps://www.fmz.com/strategy/388963para copiar o código completo da estratégia.

Base de dados de memória

Se você não quiser salvar os dados no disco permanentemente, você pode adicionar o símbolo : antes da instrução SQL para operar no banco de dados de memória, e os dados serão reiniciados após o reinicio do robô.

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

Resumo

O banco de dados não só pode transportar dados maciços, mas também carrega o sonho de muitos entusiastas de negociação quantitativa. O uso de bancos de dados não se limita de forma alguma aos exemplos neste artigo. Para mais métodos de uso, consulte o tutorial do SQLite e os artigos de acompanhamento do FMZ Quant.


Relacionados

Mais.