O livro de profundidade (price depth) consolida, para um ativo, todas as ofertas de compra e venda agrupadas por nível de preço. Em cada nível você encontra três informações: o preço, a quantidade total ofertada e quantas ofertas individuais compõem aquele grupo. É a base para leitura de fluxo, identificação de paredes de liquidez, cálculo de spread e detecção de leilão.
A ProfitDLL expõe o livro de profundidade através das funções SubscribePriceDepth, GetPriceGroup e GetPriceDepthSideCount, complementadas pelo callback TConnectorPriceDepthCallback.
Como funciona o acesso ao livro
O acesso ao livro segue um modelo de três etapas. A DLL mantém internamente o estado completo do livro, e a sua aplicação consulta os dados sob demanda:
- Você assina o livro do ativo desejado com SubscribePriceDepth.
- A DLL notifica sua aplicação via callback (TConnectorPriceDepthCallback) sempre que houver uma alteração no livro.
- Você consulta o estado atual do livro chamando GetPriceGroup e GetPriceDepthSideCount.
Essa separação entre notificação e consulta traz duas vantagens práticas: você não precisa manter sua própria cópia sincronizada do livro, e os cálculos de preço teórico durante leilão já são feitos pela DLL.
Funções e callbacks envolvidos
| Item | Tipo | Finalidade |
| SubscribePriceDepth | Função | Assina o recebimento de atualizações do livro de um ativo |
| UnsubscribePriceDepth | Função | Cancela a assinatura |
| GetPriceDepthSideCount | Função | Retorna a quantidade de níveis em um lado do livro |
| GetPriceGroup | Função | Retorna os dados de um nível específico do livro |
| GetTheoreticalValues | Função | Retorna o preço teórico atual durante leilão |
| SetPriceDepthCallback | Função | Registra o callback de atualizações do livro |
| TConnectorPriceDepthCallback | Callback | Notifica que houve uma alteração no livro |
| SetTheoreticalPriceCallback | Callback | Notifica mudanças no preço teórico durante leilão |
Estruturas e enums
TConnectorPriceGroup
Estrutura retornada por GetPriceGroup. Cada instância representa um nível de preço do livro.
from ctypes import Structure, c_ubyte, c_double, c_uint, c_longlong
class TConnectorPriceGroup(Structure):
_fields_ = [
("Version", c_ubyte),
("Price", c_double),
("Count", c_uint),
("Quantity", c_longlong), # Int64 (8 bytes) — NUNCA use c_long em Windows x64
("PriceGroupFlags", c_uint),
] | Campo | Tipo nativo | Significado |
| Version | Byte | Versão da estrutura. Preencha com 0 antes de chamar GetPriceGroup |
| Price | Double | Preço do nível |
| Count | Cardinal (uint32) | Número de ofertas individuais agrupadas naquele preço |
| Quantity | Int64* | Quantidade total ofertada no nível |
| PriceGroupFlags | Cardinal (uint32) | Flags do grupo. Atualmente apenas PG_IS_THEORIC = 1 (indica preço teórico em leilão) |
*Atenção ao tipo de Quantity: é Int64 (64 bits). Em Python, use c_longlong (ou c_int64), não c_long, que em Windows x64 é apenas 32 bits. Os sintomas dessa troca são silenciosos e enganosos: Quantity retorna 0 em todos os níveis e a flag PG_IS_THEORIC pode ficar falsamente ligada, porque os bytes altos da quantidade vazam para o campo seguinte da struct. Em C/C++, use __int64 ou long long.
Lados do livro (TConnectorBookSideType)
| Valor | Constante | Significado |
| 0 | bsBuy | Lado da compra (bid) |
| 1 | bsSell | Lado da venda (ask) |
| 254 | bsBoth | Ambos os lados |
| 255 | bsNone | Nenhum lado |
Para GetPriceGroup e GetPriceDepthSideCount, utilize 0 para compra e 1 para venda.
Tipos de atualização (TConnectorUpdateType)
O callback TConnectorPriceDepthCallback informa qual o tipo de alteração ocorrida:
| Valor | Constante | Significado |
| 0 | utAdd | Um novo nível foi adicionado |
| 1 | utEdit | Um nível existente foi modificado |
| 2 | utDelete | Um nível foi removido |
| 3 | utInsert | Um nível foi inserido em uma posição específica |
| 4 | utFullBook | O livro completo foi (re)entregue |
| 5 | utPrepare | Início de uma sequência de atualizações em lote |
| 6 | utFlush | Fim de uma sequência de atualizações em lote |
| 7 | utTheoricPrice | O preço teórico mudou (apenas em leilão) |
| 8 | utDeleteFrom | Remoção em lote a partir de uma posição |
Em momentos de alta volatilidade, várias atualizações chegam em rajada encapsuladas entre um utPrepare e um utFlush. Esse é o melhor ponto para adiar processamentos pesados, como redesenhar a UI, até receber o utFlush.
Implementação em Python
Os exemplos abaixo assumem que você já inicializou a DLL com DLLInitializeLogin ou DLLInitializeMarketLogin e que está com a conexão completa (veja o artigo Como saber se a DLL está conectada).
- Passo 1: Registrar o callback de atualizações
from ctypes import WINFUNCTYPE, byref, c_double, c_int, c_int64, c_ubyte
from profitTypes import TConnectorAssetIdentifier
# Assinatura do callback de price depth.
# Ordem dos argumentos: (asset, side, position, updateType).
# asset -> TConnectorAssetIdentifier passada POR VALOR (não como ponteiro)
# side -> byte (0 = buy, 1 = sell)
# position -> int32 (índice do nível afetado; 0 = topo do livro)
# updateType -> byte (TConnectorUpdateType)
TConnectorPriceDepthCallback = WINFUNCTYPE(
None,
TConnectorAssetIdentifier, # asset (por valor)
c_ubyte, # side
c_int, # position
c_ubyte, # updateType
)
def price_depth_callback(asset, side, position, update_type):
# Importante: callbacks rodam na ConnectorThread.
# Não faça processamento pesado aqui — enfileire e processe em outra thread.
print(f"Update | ticker={asset.Ticker} | side={side} | pos={position} | type={update_type}")
# Mantenha esta referência viva (atributo de classe ou variável global)
callback_ref = TConnectorPriceDepthCallback(price_depth_callback)
profit_dll.SetPriceDepthCallback(callback_ref) Atenção à assinatura do callback: o TConnectorAssetIdentifier é passado por valor, não como ponteiro, e a ordem dos parâmetros é (asset, side, position, updateType). O updateType é um byte (c_ubyte), não um inteiro. Usar POINTER, inverter a ordem de position e updateType, ou trocar c_ubyte por c_int faz o processo travar silenciosamente ou receber lixo nos parâmetros, sem mensagem de erro.
Atenção ao garbage collector: guarde a callback_ref em uma variável de escopo durável (atributo de classe, variável global). Se o GC do Python liberar a função, a DLL chamará um ponteiro inválido e o processo travará sem aviso.
- Passo 2: Assinar o livro de um ativo
asset = TConnectorAssetIdentifier()
asset.Version = 0
asset.Ticker = "WDOFUT"
asset.Exchange = "F"
asset.FeedType = 0
result = profit_dll.SubscribePriceDepth(byref(asset))
if result != 0: # NL_OK == 0
raise RuntimeError(f"Falha ao assinar livro: código {result}")
- Passo 3: Consultar o livro a qualquer momento
def ler_topo_do_livro(asset_id, n_niveis=5):
"""Retorna os N primeiros níveis de cada lado do livro."""
resultado = {"bid": [], "ask": []}
for nome, side in [("bid", 0), ("ask", 1)]:
total = profit_dll.GetPriceDepthSideCount(byref(asset_id), side)
for pos in range(min(n_niveis, total)):
grupo = TConnectorPriceGroup()
grupo.Version = 0
ret = profit_dll.GetPriceGroup(byref(asset_id), side, pos, byref(grupo))
if ret == 0:
resultado[nome].append({
"preco": grupo.Price,
"quantidade": grupo.Quantity,
"ofertas": grupo.Count,
"is_theoric": bool(grupo.PriceGroupFlags & 1),
})
return resultado A posição 0 é sempre o topo do livro: o melhor bid no lado de compra, o melhor ask no lado de venda.
- Passo 4: Cancelar a assinatura
Quando você não precisar mais receber atualizações daquele ativo, cancele a assinatura para reduzir o volume de callbacks processados:
profit_dll.UnsubscribePriceDepth(byref(asset))
Caso especial: leilão e preço teórico
Durante o leilão (abertura, fechamento, retomada após circuit breaker, etc.), a posição 0 do livro pode conter um preço teórico em vez de uma oferta real. Quando isso acontece:
- A flag PG_IS_THEORIC (PriceGroupFlags & 1) virá ligada;
- O campo Price retornado por GetPriceGroup será -INF (menos infinito) como sinalização — não use esse valor diretamente em cálculos;
- Para obter o preço teórico real, chame GetTheoreticalValues:
preco_teorico = c_double()
qtd_teorica = c_int64()
ret = profit_dll.GetTheoreticalValues(byref(asset), byref(preco_teorico), byref(qtd_teorica))
if ret == 0:
print(f"Teórico: {preco_teorico.value} @ {qtd_teorica.value}") Mudanças no preço teórico durante o leilão também podem ser monitoradas via SetTheoreticalPriceCallback, ou pelo próprio callback de price depth com update_type = 7 (utTheoricPrice).
Boas práticas
-
Não chame funções da DLL dentro do callback. O callback roda na ConnectorThread, que também processa as próprias atualizações internas. Bloqueá-la causa atrasos cumulativos no recebimento de dados. O padrão recomendado é enfileirar o evento em uma queue.Queue e processá-lo em outra thread.
-
Aguarde o utFlush antes de redesenhar interface gráfica. Atualizar a UI a cada utAdd ou utEdit durante uma rajada de updates gera flicker e consumo desnecessário de CPU.
-
Cancele assinaturas que não estão em uso. Especialmente em aplicações que monitoram muitos ativos simultaneamente.
-
Trate o preço teórico como caso especial. Sempre verifique a flag PG_IS_THEORIC antes de usar o campo Price em cálculos.
-
Verifique sempre o retorno de GetPriceGroup. Em momentos de transição, uma posição pode ter sido removida entre a notificação e a consulta. Trate retornos diferentes de NL_OK (0).
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!