Os trades históricos são as transações já executadas no mercado em períodos passados, registradas tick a tick, com preço, quantidade, agentes (corretoras) compradora e vendedora e horário exato da execução. São a base para backtests, análises de fluxo retrospectivas, cálculo de VWAP histórico, treinamento de modelos quantitativos e tape reading sobre dados consolidados.
GetHistoryTrades: função que requisita o intervalo desejado
THistoryTradeCallback: callback chamado uma vez para cada trade recebido
TProgressCallback: callback que sinaliza o progresso do download (0 a 100%)
Limites e formato da requisição
Antes do código, dois pontos definem todo o resto:
| Aspecto | Regra |
| Intervalo máximo por requisição | 10 dias |
| Recomendação prática | Requisitar dia a dia |
| Horários | Devem ser válidos para o pregão do ativo (ex: 09:00 a 18:35) |
| Formato da data | DD/MM/YYYY HH:mm:SS (em Python: '%d/%m/%Y %H:%M:%S') |
Atenção:
- Por que requisitar dia a dia: ativos voláteis (WINFUT, WDOFUT) podem gerar centenas de milhares de trades por dia. Requisições amplas demoram, consomem muita memória e, em aplicações 32 bits, podem estourar o limite de 4 GB do processo.
Quebrar em janelas diárias dá controle, permite retry isolado em caso de falha e simplifica persistência incremental.
- O formato da data é estrito. Use exatamente '%d/%m/%Y %H:%M:%S'.
Inverter a ordem (MM/DD/YYYY), omitir os zeros (5/11/2024) ou usar separadores diferentes (- em vez de /) faz a requisição falhar, o callback não dispara e nenhum trade chega. Sempre prefira datetime.strftime(...) a concatenar strings manualmente.
Como funciona o fluxo
- Você registra os dois callbacks com SetHistoryTradeCallback e SetSerieProgressCallback.
- Você requisita o histórico chamando GetHistoryTrades (ticker, bolsa, dataInicial, dataFinal).
- A DLL começa o download e chama o callback de trade uma vez para cada trade do intervalo.
- Em paralelo, a DLL notifica o progresso (0 a 100) pelo callback de progresso.
- Quando o progresso atinge 100, o download terminou.
Funções e callbacks envolvidos
| Item | Tipo | Finalidade |
| GetHistoryTrades | Função | Requisita trades históricos de um ativo em determinado período |
| SetHistoryTradeCallback | Função | Registra o callback de trades históricos |
| SetSerieProgressCallback | Função | Registra o callback de progresso do download |
| THistoryTradeCallback | Callback | Chamado para cada trade do histórico recebido |
| TProgressCallback | Callback | Chamado periodicamente com o progresso (0–100) |
Estruturas e enums
TAssetID
Estrutura que identifica o ativo nos callbacks de histórico.
from ctypes import Structure, c_wchar_p, c_int
class TAssetID(Structure):
_fields_ = [
("ticker", c_wchar_p),
("bolsa", c_wchar_p),
("feed", c_int),
] | Campo | Tipo | Significado |
| ticker | string | Código do ativo (ex: "WINZ24", "PETR4") |
| bolsa | string | Código da bolsa (ex: "F" para BM&F, "B" para Bovespa) |
| feed | int | Fonte do dado (0 = Nelogica, 255 = outros) |
THistoryTradeCallback
O callback recebe os campos do trade já destrinchados como argumentos individuais, não há ponteiro genérico nem tradução necessária.
| Posição | Parâmetro | Tipo Python | Tipo nativo | Significado |
| 1 | assetId | TAssetID | record por valor | Ativo do trade |
| 2 | date | c_wchar_p | PWideChar | Data/hora no formato DD/MM/YYYY HH:mm:SS.ZZZ |
| 3 | tradeNumber | c_uint | Cardinal | Número sequencial único do trade na sessão |
| 4 | price | c_double | Double | Preço de execução |
| 5 | vol | c_double | Double | Volume financeiro |
| 6 | qtd | c_int | Integer | Quantidade negociada |
| 7 | buyAgent | c_int | Integer | ID do agente comprador (corretora) |
| 8 | sellAgent | c_int | Integer | ID do agente vendedor (corretora) |
| 9 | tradeType | c_int | Integer | Tipo do trade (ver tabela abaixo) |
TradeType
| Valor | Significado |
| 1 | Cross trade |
| 2 | Agressão de compra |
| 3 | Agressão de venda |
| 4 | Leilão |
| 5 | Surveillance |
| 6 | Expit |
| 7 | Exercício de opções |
| 8 | Over the counter (OTC) |
| 9 | Termo de derivativos |
| 10 | Índice |
| 11 | BTC (empréstimo) |
| 12 | On Behalf |
| 13 | RLP |
| 32 | Desconhecido |
Os tipos 2 e 3 são os mais comuns no cotidiano de leitura de fluxo: indicam se a execução veio de um comprador agredindo a oferta (tipo 2) ou de um vendedor agredindo o bid (tipo 3).
TProgressCallback
| Posição | Parâmetro | Tipo | Significado |
| 1 | assetId | TAssetID | Ativo da requisição |
| 2 | progress | c_int | Progresso de 0 a 100 |
Quando progress atinge 100, o download terminou e nenhum trade adicional virá daquela requisição.
Implementação em Python
Os exemplos abaixo assumem que você já inicializou a DLL e está com a conexão completa (veja Como saber se a DLL está conectada).
- Passo 1: Definir os callbacks
from ctypes import WINFUNCTYPE, c_double, c_int, c_uint, c_wchar_p
import threading
# Buffer para acumular os trades recebidos no intervalo atual
trades_recebidos = []
historico_pronto = threading.Event()
# Assinatura do callback de trade histórico.
# Ordem dos argumentos:
# (asset, date, tradeNumber, price, vol, qtd, buyAgent, sellAgent, tradeType)
# asset -> TAssetID passada POR VALOR (não como ponteiro)
# date -> string "DD/MM/YYYY HH:mm:SS.ZZZ"
# qtd -> Integer (c_int, 32 bits)
@WINFUNCTYPE(None,
TAssetID, # asset (por valor)
c_wchar_p, # date
c_uint, # tradeNumber
c_double, # price
c_double, # vol
c_int, # qtd
c_int, # buyAgent
c_int, # sellAgent
c_int) # tradeType
def history_trade_callback(asset, date, trade_number, price, vol,
qtd, buy_agent, sell_agent, trade_type):
# Importante: callbacks rodam na ConnectorThread.
# Apenas acumule aqui — nada de processamento pesado, I/O ou chamadas à DLL.
trades_recebidos.append({
"ticker": asset.ticker,
"date": date,
"trade_number": trade_number,
"price": price,
"vol": vol,
"qtd": qtd,
"buy_agent": buy_agent,
"sell_agent": sell_agent,
"trade_type": trade_type,
})
# Callback de progresso (sinaliza fim quando chega a 100)
@WINFUNCTYPE(None, TAssetID, c_int)
def progress_callback(asset, progress):
print(f"{asset.ticker}: {progress}%")
if progress >= 100:
historico_pronto.set() Atenção à assinatura do callback: o TAssetID é passado por valor (não como ponteiro), e os campos do trade chegam destrinchados como argumentos individuais, não há tradução necessária. Note que qtd é c_int (32 bits), suficiente para quantidades típicas do mercado brasileiro.
Atenção ao garbage collector: usando @WINFUNCTYPE como decorador, o próprio nome history_trade_callback mantém a referência viva. Não redefina, não delete, e mantenha em escopo durável (atributo de classe, variável global). Se a referência for perdida, a DLL chamará um ponteiro inválido e o processo travará sem aviso.
- Passo 2: Registrar os callbacks
profit_dll.SetHistoryTradeCallback(history_trade_callback) profit_dll.SetSerieProgressCallback(progress_callback)
Esta etapa pode ser feita logo após a inicialização da DLL, não precisa ser repetida a cada requisição.
- Passo 3: Requisitar o histórico de um dia
def baixar_dia(ticker, bolsa, data, hora_inicio="09:00:00", hora_fim="18:35:00"):
"""Baixa o histórico de trades de um único dia."""
inicio = f"{data} {hora_inicio}"
fim = f"{data} {hora_fim}"
# Reseta o estado antes de cada requisição
historico_pronto.clear()
trades_recebidos.clear()
ret = profit_dll.GetHistoryTrades(
c_wchar_p(ticker),
c_wchar_p(bolsa),
c_wchar_p(inicio),
c_wchar_p(fim),
)
if ret != 0:
raise RuntimeError(f"GetHistoryTrades falhou: código {ret}")
# Aguarda até o progresso atingir 100
if not historico_pronto.wait(timeout=300):
raise TimeoutError("Histórico não terminou dentro do timeout")
return list(trades_recebidos)
# Uso
trades = baixar_dia(ticker="WINZ24", bolsa="F", data="05/11/2024")
print(f"Recebidos {len(trades)} trades")
- Passo 4: Baixar múltiplos dias
Para períodos maiores, faça em loop dia a dia:
from datetime import date, timedelta
def baixar_periodo(ticker, bolsa, data_inicial, data_final):
"""Baixa o histórico de trades dia a dia entre duas datas (inclusive)."""
todos_trades = []
d = data_inicial
while d <= data_final:
# Pula sábados e domingos
if d.weekday() < 5:
data_str = d.strftime("%d/%m/%Y")
try:
trades = baixar_dia(ticker, bolsa, data_str)
todos_trades.extend(trades)
print(f"{data_str}: {len(trades)} trades")
except (RuntimeError, TimeoutError) as e:
print(f"{data_str}: falhou — {e}")
d += timedelta(days=1)
return todos_trades
# Uso
todos = baixar_periodo(
ticker="WINZ24",
bolsa="F",
data_inicial=date(2024, 11, 4),
data_final=date(2024, 11, 8),
)
Parseando a data recebida
A date chega no formato DD/MM/YYYY HH:mm:SS.ZZZ (com milissegundos):
from datetime import datetime
def parse_date(date_str):
return datetime.strptime(date_str, "%d/%m/%Y %H:%M:%S.%f")
# Exemplo
dt = parse_date("05/11/2024 14:23:07.142")
Boas práticas
Requisite dia a dia. Mesmo que a DLL aceite até 10 dias por chamada, dia a dia dá controle, permite retry isolado em caso de falha e simplifica persistência incremental.
Use o callback de progresso para detectar o fim. Aguardar trades pararem de chegar é frágil, uma pausa breve da DLL ou da rede pode te enganar. progress == 100 é o sinal definitivo.
Pule fins de semana e feriados. Requisições para datas sem pregão simplesmente não retornam trades, mas consomem tempo da DLL desnecessariamente.
Não chame funções da DLL dentro dos callbacks. Apenas acumule os dados; deixe processamento pesado para outra thread.
Persista incrementalmente. Em projetos de longo prazo, salve cada dia logo após recebê-lo (CSV, SQLite, Parquet, etc.) em vez de manter tudo em memória.
Valide o formato da data antes de chamar. Use sempre datetime.strftime("%d/%m/%Y %H:%M:%S") em vez de concatenar strings manualmente, um caractere fora do padrão faz a requisição falhar sem retorno de trades.
Para mais informações, encaminhe um e-mail para corporativo@nelogica.com.br.
Achou útil este conteúdo?
Não esqueça de nos avaliar abaixo.
Desejamos bons trades!