PáginasDados OHLCV e de barras · 10 / 29
Dados OHLCV e de barras
Os backtests do QuantCraft precisam de velas OHLCV (abertura, máxima, mínima, fechamento, volume) para cada símbolo que você negocia. O mecanismo carrega esses dados antes de a sua estratégia rodar e, então, aciona os callbacks do ciclo de vida da sua estratégia com uma visão da barra atual (bar) em cada passo. No fim da execução você pode, opcionalmente, trabalhar com a série completa passada a on_finish(bars, …). Configure os carregamentos pelo Test (Executando código).
Esta página cobre de onde vêm os dados (carregadores), como funcionam os intervalos de datas e o aquecimento e como usar o argumento bars de série completa em on_finish. Combine com Dados fundamentalistas ao misturar preços e relatórios arquivados; veja Modelo de conta para saber como as operações se relacionam com os preços.
Carregadores (fontes de dados)
Na aba Symbol & data do Run backtest você escolhe um feed de preços. O mecanismo usa, nos bastidores, um de dois carregadores:
Feed da corretora conectada
- Carrega velas da sua conta de corretora conectada usando sua chave de API e seu segredo, ou uma conexão vinculada por OAuth com um id de vínculo válido.
- Suporta ações dos EUA e criptomoedas (você escolhe o tipo de ativo na caixa).
- Suporta muitos intervalos de tempo — diário, semanal, horário, 4 horas e várias barras de minutos intradiárias (alinhados aos rótulos de intervalo do gráfico do aplicativo).
- O histórico é buscado em partes até que o intervalo solicitado seja satisfeito (ou até atingir um número mínimo de barras ao usar o modo legado "sem datas explícitas").
Use o feed da corretora conectada quando quiser dados da corretora conectada ou o conjunto completo de intervalos intradiários (de 1 minuto a 4 horas, mais diário e semanal).
Armazenamento do QuantCraft (hospedado)
- Carrega velas do armazenamento hospedado do QuantCraft quando você está conectado (o aplicativo envia o seu token de sessão).
- Os arquivos são organizados por símbolo e intervalo de tempo. Em um plano gratuito, a caixa de backtest oferece diário, semanal e mensal; o Premium libera o intradiário e intervalos estendidos.
- O arquivo completo é buscado e, opcionalmente, filtrado para o intervalo de datas corridas escolhido.
- As barras diárias trazem um
tsó com data, como"2024-01-02", lido como UTC.
Códigos de intervalo do QuantCraft B2: 1s, 1m, 2m, m5, 15m, 30m, h1, 2h, 4h, d, w, m, q, y. Atenção: m significa mensal, não minutos — 1 minuto é 1m, 5 minutos é m5.
Se um intervalo de datas não tiver barras, o carregamento falha com uma mensagem como No AAPL bars (d) between 2010-01-01 and 2010-02-01. Available range is … to … — adjust the backtest dates.
Use o armazenamento do QuantCraft quando estiver conectado sem credenciais de corretora, ou quando quiser pacotes OHLCV hospedados do catálogo de símbolos do QuantCraft (5 minutos, horário, diário, semanal ou mensal).
Escolhendo entre os dois
| Necessidade | Escolha típica |
|---|---|
| Conjunto intradiário completo da corretora conectada (1m, 5m, 15m, 30m, 1H, 4H, …) | Feed da corretora conectada |
| 5 minutos ou horário do catálogo do QuantCraft | Armazenamento do QuantCraft |
| Diário / semanal / mensal de arquivos hospedados | Armazenamento do QuantCraft |
| Conta de corretora conectada + chaves | Feed da corretora conectada |
| Acesso conectado sem credenciais de corretora | Armazenamento do QuantCraft |
Nos callbacks da estratégia, leia os preços do objeto
barque o mecanismo passa para você — não de um singleton OHLCV global. No IDE, oqc_ohlcvde nível de módulo costuma estar indefinido quando o seu arquivo é carregado; depender dele pode quebrar o código. Ele também éNoneem uma execução com alvo de screener e, onde está definido, abrange o intervalo completo carregado, incluindo o aquecimento — não a janela executada que o gráfico desenha — sendo, portanto, a fonte errada para séries de gráfico. A visãobarestá sempre correta para o passo atual da simulação.
Intervalos de tempo
Você controla quais barras participam do backtest com a data de início, a data de fim e, opcionalmente, o aquecimento.
Intervalo de calendário (start_date + end_date)
Quando você define as duas datas na aba Simulation (formato YYYY-MM-DD, interpretadas como dias corridos UTC):
- O mecanismo mantém apenas as barras que caem nessa janela.
- O intervalo é tratado como semiaberto: do início do dia de partida até o fim do dia final, segundo a convenção usual do produto (as barras do dia corrido final são incluídas conforme configurado pelo mecanismo).
Feed da corretora conectada: as velas são solicitadas para esse período do calendário.
Armazenamento do QuantCraft: a série completa do arquivo é baixada e então filtrada para a mesma janela de dias corridos.
Se você omitir as duas datas:
- O feed da corretora conectada usa uma varredura legada para trás: o mecanismo recua no tempo até carregar histórico suficiente (sujeito aos limites do intervalo), em vez de uma janela de calendário digitada por você.
- O armazenamento do QuantCraft usa todas as barras do arquivo (sem filtro extra).
Barras de aquecimento (warmup_bars)
Inteiro não negativo opcional: barras extras carregadas antes da sua data de início para que os indicadores possam olhar para trás sem ficar sem histórico.
- As barras de aquecimento ficam visíveis por
bar.close[1],bar.close[2], … ebar.bars_backna primeira barra de execução. on_bar/on_tick/on_timerainda rodam apenas dentro da janela de execução selecionada — o aquecimento serve só ao histórico, não acrescenta "dias de negociação" simulados ao resultado.
bar_index vs calendário
bar_indexconta apenas barras de execução (a primeira barra dentro do intervalo selecionado é0, depois1, …). Ele não conta barras só de aquecimento.- As barras são simuladas da mais antiga para a mais recente dentro da janela de execução.
Dados da barra dentro dos callbacks (bar)
Em todo on_bar e on_tick (e on_timer nas execuções forward, quando configurado), o mecanismo passa bar: uma visão de barra OHLC (OhlcvBarView) do símbolo ao qual o callback se refere. Ela se comporta como um mapeamento somente leitura, mas isinstance(bar, dict) é falso — use bar["close"] ou acesso por atributo, não APIs exclusivas de dict.
No backtest, o on_tick recebe preços sintéticos derivados do OHLC de cada barra (quatro chamadas por barra, sem histórico real de ticks). Nas execuções forward, o on_tick dispara a cada cotação ao vivo da corretora conectada enquanto o argumento price acompanha a última marca — veja Ciclo de vida da estratégia.
Você pode usá-la como um mapeamento somente leitura:
o = float(bar["open"])
h = float(bar["high"])
l = float(bar["low"])
c = float(bar["close"])
v = float(bar["volume"])
t = bar["t"] # ISO timestamp string (QuantCraft B2 daily bars: a date like "2024-01-02", UTC)Você também pode ler o histórico relativo à barra atual com indexação por deslocamento (a mesma barra, fechamentos anteriores etc.):
current_close = bar.close[0]
prev_close = bar.close[1]bar.close[0]é o fechamento do contexto da barra atual (a mesma ideia defloat(bar["close"])noon_bardo backtest) — veja Índices de barras emon_barvson_tickpara saber qual barra é essa em cada callback.- Índices maiores andam para trás no tempo;
bar.bars_backdiz até onde você pode olhar.
Índices de barras em on_bar vs on_tick
Deslocamentos como bar.close[0], bar.close[1], … sempre contam para trás a partir da barra mais nova que o callback consegue ver — mas qual é a "mais nova" depende do callback:

on_bardispara quando uma barra fecha. O índice[0]é essa barra recém-fechada,[1]é a barra anterior,[2]a anterior a essa, e assim por diante. Todo índice aponta para uma barra concluída.on_tickdispara enquanto uma barra ainda está se formando. O índice[0]é a barra em formação (seus valores mudam a cada tick),[1]é a última barra fechada,[2]a anterior, e assim por diante.
Assim, a mesma vela fica um índice acima no on_tick do que no on_bar:
| Vela | No on_bar | No on_tick |
|---|---|---|
| Em formação (ainda não fechada) | não visível | [0] |
| Recém-fechada | [0] | [1] |
| Uma antes | [1] | [2] |
| Duas antes | [2] | [3] |
def on_bar(bar_index, bar, fundamentals=None, symbol=None):
last_closed = bar.close[0] # the bar that just closed
one_before = bar.close[1]
def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, symbol=None):
forming = bar.close[0] # still forming — latest price so far
last_closed = bar.close[1] # same candle on_bar saw as [0]O mesmo deslocamento vale para toda série da visão (open, high, low, close, volume). Se você mover lógica do on_bar para o on_tick, some 1 a cada deslocamento para continuar lendo as mesmas velas.
Backtest: o
on_tickreproduz a barra atual como quatro ticks sintéticos, então[0]ali é a barra que está sendo simulada, lida a partir da sua linha completa (veja Volume em[0]abaixo) — não é uma vela parcialmente construída como em uma execução forward.
Precisão dos dados ao vivo (execuções forward)
O fluxo de preços ao vivo da sua corretora é uma aproximação, não um registro completo do mercado:
- Os planos gratuitos de dados ao vivo costumam ver negócios de uma única bolsa — uma pequena fração de toda a negociação dos EUA — então as velas construídas ao vivo mostram volume bem menor e podem perder as máximas e mínimas reais.
- Os planos pagos com feed consolidado veem todas as bolsas, mas os negócios ainda podem chegar atrasados em rajadas, sobretudo perto da abertura em ações muito ativas.
O aplicativo substitui cada vela construída ao vivo pela barra histórica finalizada da corretora logo após o fechamento. Em intervalos pequenos como 1 minuto, isso significa:
| Índice | O que é | Para que usar |
|---|---|---|
bar.close[0] | A vela em formação, construída a partir de ticks ao vivo | A estimativa do preço atual |
bar.close[1] | A barra recém-fechada — pode ainda ser construída por ticks nos primeiros ~10–30 segundos | Use com cuidado logo depois que uma nova barra abre |
bar.close[2] | Uma barra totalmente finalizada | Sinais que precisam de um fechamento confirmado |
Para sinais que dependem de um fechamento confirmado em barras de 1 minuto, prefira bar.close[2].
Volume em [0]:
on_tickforward:volume[0]na vela em formação é provisório (muitas vezes o tamanho de um único tick). Usevolume[1]para o volume da última barra concluída.- Backtest: os quatro ticks sintéticos usam a linha completa da barra —
volume[0]é o volume completo da barra, não um tamanho provisório de tick.
Este é o lugar certo para a lógica de negociação por passo: entradas, saídas no fechamento da barra, médias móveis simples e tudo que só precise da barra atual mais o histórico.
Intervalos principal e adicionais (get_bar)
O intervalo principal da execução está sempre disponível por rt.get_bar (não é preciso listá-lo em Additional timeframes). Quando a sua estratégia também precisa de barras em uma resolução diferente (por exemplo, filtros de tendência diários em um backtest de 5 minutos), selecione esses extras no menu Additional timeframes da caixa Run backtest, em Symbol & data, e leia-os de qualquer callback:
from quantcraft import Timeframe
import quantcraft.runtime as rt
def on_bar(bar_index, bar, fundamentals=None, symbol=None):
# Primary TF works without listing it under Additional timeframes
# (use the Timeframe member that matches the modal primary, e.g. M5):
prev_primary = rt.get_bar(Timeframe.M5, shift=1)
daily = rt.get_bar(Timeframe.DAILY, shift=1)
if daily and bar.close[0] > daily.close:
... # primary bar closed above yesterday's daily closeConfigure Additional timeframes em Backtests; salve as seleções em predefinições de execução (.qcs) em secondaryTimeframes.
Campos de BarSnapshot
get_bar retorna um BarSnapshot (ou None) com: open, high, low, close, volume, t.
Semântica de shift
shift | .close | .high / .low / .open |
|---|---|---|
0 | Preço de execução atual — idêntico em todos os intervalos no mesmo callback (backtest; veja a nota forward abaixo) | Da barra armazenada daquele intervalo — não unificado com o intervalo principal |
>= 1 | Fechamento da barra concluída naquele intervalo | OHLC completo da barra concluída — preferível para os pavios da vela anterior |
Backtest: get_bar só enxerga barras até o passo atual da simulação — nunca as posteriores — no intervalo principal e em cada adicional. Em shift=0, os high/low secundários são alinhados no tempo ao relógio da simulação para cada intervalo. get_bar lê as barras do símbolo de relógio; em uma execução com vários símbolos, use os bar.close[i] de cada ticker para o seu histórico.
Execução forward: a bar principal segue o intervalo da barra de ferramentas do gráfico. Os buffers secundários são atualizados quando uma barra se completa no fluxo daquele intervalo — high/low em shift=0 podem atrasar até esse balde se completar; prefira shift=1 para um OHLC confiável da barra anterior. Em forward, o .close de shift=0 é o último fechamento próprio de cada buffer, não unificado entre intervalos. No on_tick, volume[0] na barra principal pode ser provisório (ainda em formação).
Retorna None quando aquele intervalo não tem buffer para a execução (não é o principal nem foi selecionado em Additional timeframes), em um backtest Screener (sem símbolo de relógio — use os deslocamentos bar.close[i] de cada ticker para o histórico) ou quando os dados não estão disponíveis. Uma exceção no backtest: shift=0 em um intervalo que você não selecionou retorna o snapshot atual do intervalo principal em vez de None.
tf pode ser um membro de Timeframe ou uma string como "1D" / "5Min".
Enumeração Timeframe
Importe com from quantcraft import Timeframe:
| Membro | Valor em string | Descrição |
|---|---|---|
M1 | "1Min" | Barras de 1 minuto |
M5 | "5Min" | Barras de 5 minutos |
M15 | "15Min" | Barras de 15 minutos |
M30 | "30Min" | Barras de 30 minutos |
H1 | "1Hour" | Barras horárias |
H4 | "4Hour" | Barras de 4 horas |
DAILY | "1D" | Barras diárias |
WEEKLY | "1Week" | Barras semanais |
Alguns intervalos do QuantCraft B2 (2 minutos, 2 horas, 1 segundo, mensal m, trimestral q, anual y) não têm membro em Timeframe — passe-os a get_bar como strings.
Série completa opcional: on_finish(bars, …)
Quando a simulação termina, o mecanismo chama on_finish uma vez. Se a sua estratégia define a assinatura estendida, você recebe linhas OHLC de série completa para o pós-processamento — indicadores sobre toda a execução, exportação de séries, marcas finais para refresh_metrics etc.
def on_finish(bars, symbol=None, bars_by_symbol=None):
...bars — símbolo de relógio, a mais antiga primeiro
barsé umalistde dicionários do símbolo de relógio (oSYMBOLdo script se esse ticker estiver carregado, senão o primeiro símbolo carregado — a caixa não tem controle de símbolo principal). Em uma execução Screener não há símbolo de relógio:barsé[]esymbolé"", então usebars_by_symbol.- A ordem é cronológica: barra mais antiga primeiro, a mais nova por último — a convenção oposta à do índice
[0] = mais novadoQcOhlcvem APIs no estilo notebook. - Cada linha inclui ao menos
open,high,low,close,volumeetquando há carimbos de tempo. Quando os dados fundamentalistas estão ativados, as linhas também podem incluir um snapshotfundamentalsdaquela barra.
Usos típicos:
def on_finish(bars, symbol=None, bars_by_symbol=None):
if not bars:
return
closes = [float(b["close"]) for b in bars]
last = float(bars[-1]["close"])
sym = (symbol or "AAPL").strip().upper()
metrics = account.refresh_metrics({sym: last})
chart_indicators.add(...)Use bars[-1]["close"] (ou os campos da última linha) como marca final ao chamar account.refresh_metrics({symbol: last_price}), para que as posições abertas sejam avaliadas no fim da execução.
Para chart_indicators, prefira os valores que você acumulou por símbolo enquanto a execução percorria as barras e use on_finish apenas para entregá-los; recalcule a partir de bars somente os indicadores que você não acompanhou barra a barra — veja Séries de indicadores.
bars_by_symbol — execuções com vários símbolos
Quando você faz backtest de mais de um ticker, bars ainda se refere apenas ao símbolo de relógio. Para a série completa e alinhada de cada símbolo, use bars_by_symbol:
- Um mapeamento de ticker em maiúsculas → lista com o mesmo formato de
bars(dicts cronológicos por símbolo). - Use-o quando precisar de históricos completos transversais ou por símbolo ao final (correlação, força relativa, indicadores por símbolo).
Quando você não precisa de on_finish
Se a sua estratégia só precisa da barra atual e dos deslocamentos de histórico, você pode implementar só on_bar / on_tick e dispensar o trabalho pesado de série completa. on_finish é opcional para a lógica — mas ainda é onde as séries de chart_indicators são entregues e onde refresh_metrics recebe o último preço. Note que todo return em on_finish é silencioso: a execução continua com sucesso, apenas pula o que vinha depois.
Como isso se liga ao Test Results
O resultado estruturado do backtest inclui uma lista ohlcv.bars (ou equivalente): uma linha por passo de execução simulado, com campos OHLC e snapshots fundamentals opcionais — alinhada ao que você viu nos callbacks. on_finish(bars, …) é a mesma série cronológica que o mecanismo usa nas contas de "execução inteira" do símbolo de relógio, então o seu código de fim de execução corresponde ao que aparece nos resultados e nos gráficos.
Referência rápida
| Tópico | Resumo para o usuário |
|---|---|
| Carregadores | Feed da corretora conectada (chaves + amplo intradiário) vs armazenamento do QuantCraft (conectado; diário / semanal / mensal, mais com o Premium). |
| Datas | Início + fim YYYY-MM-DD → janela filtrada pelo calendário; omitir ambos → retrospectiva legada do feed da corretora ou arquivo completo do armazenamento do QuantCraft. |
| Aquecimento | Histórico extra antes do início para os deslocamentos de bar; callbacks apenas na janela de execução. |
| Por passo | Use bar / bar["close"] / bar.close[k] em on_bar / on_tick. [0] = última barra fechada no on_bar, barra em formação no on_tick. |
| Intervalos principal / adicionais | O principal sempre por rt.get_bar; os extras por Additional timeframes + rt.get_bar(Timeframe.X, shift). |
| Série completa | Use on_finish(bars, symbol=..., bars_by_symbol=...) — bars da mais antiga para a mais nova do símbolo de relógio; bars_by_symbol para todos os símbolos nas execuções com vários símbolos. |
| Retornos de fatores globais | Não estão em QcOhlcv nem em bar — use os fatores Fama-French (fama_french.qc). As rows mensais são um dict YYYYMM; use latest_row, não rows[0]. |

