📝

Draft article

This draft is visible to admins and superusers only. Sign in with an authorized account.

← Voltar aos artigos
August 22, 2026
5 min read

Tempo Irregular em Modelos de Tick: Codificações de Tempo Contínuo vs. Incorporações Posicionais Simples

Tempo Irregular em Modelos de Tick: Codificações de Tempo Contínuo vs. Incorporações Posicionais Simples
#HFT
#tick-data
#deep-learning
#high-frequency
#prediction

As barras de tempo são uma compressão arbitrária que destrói o tempo do evento, e a atividade deveria definir os limites das barras — esse argumento é feito na íntegra, com 17 tipos de barras e geradores funcionais, em Tipos de barras e métodos de agregação para negociação algorítmica. Este artigo começa um passo depois, na parte que ninguém resolveu: mesmo depois de você ter mudado para barras de tick, volume ou desequilíbrio, o modelo para o qual você as alimenta ainda assume espaçamento regular. Um nn.TransformerEncoder com uma incorporação posicional aprendida trata a posição 7 como "o sétimo slot", independentemente de esse tick ter chegado 200 microssegundos ou 40 segundos após a posição 6. O tempo entre chegadas - aquilo que as barras de atividade foram construídas para preservar - é jogado fora novamente na camada de entrada.

Portanto, a questão deste artigo é restrita e testável: como um modelo de sequência deve ser informado quando um tick realmente aconteceu, e a resposta sofisticada supera a trivial?

Histórico presumido

Pulsos de eventos irregulares

A seguir estão os pré-requisitos, todos já abordados neste blog, e nenhum deles foi derivado aqui:

  • Ruído da microestrutura e salto bid-ask. O modelo de spread implícito de Roll deriva a covariância serial negativa nos retornos de ticks dos primeiros princípios, em unidades de preço, com o erro de implementação comum chamado: Modelagem de spread bid-ask com ML.
  • Recursos do livro de pedidos. Desequilíbrio do livro, preço médio ponderado, relação de profundidade acima dos níveis 1-5, pressão do livro e relação spread/tick são tabulados no mesmo artigo; as derivações OBI e médio ponderado por volume – incluindo a ressalva de que o médio ponderado não é o micropreço de Stoikov – estão em DeepLOB: Deep Learning on Limit Order Books.
  • Fluxo de pedidos e intensidade de negociação. Desequilíbrio comercial, VPIN e lambda de Kyle estão no artigo sobre modelagem de spread; intervalo entre ordens e intensidade de autoexcitação de Hawkes como recursos de tempo estão em Impressão Digital: Identificação do Trader. O bruto 1/dt intensidade que este projecto originalmente proposto é uma versão mais fraca da formulação de Hawkes.
  • Não estacionariedade intradiária. O padrão de volume em forma de U, o alargamento do spread em períodos de silêncio e a codificação sen/cos da hora do dia são abordados na modelagem de spread como características do regime de mercado.
  • Rótulos. Ambas as convenções de suavização (média futura vs. preço atual, média futura vs. média anterior), a discretização de três classes com limite α\alphae o aviso do LOBFrame sobre a sensibilidade do rótulo a α\alpha e kk estão no artigo do DeepLOB.
  • Desequilíbrio de classe. Com uma zona morta, a classe FLAT domina, e é por isso que F1, em vez de precisão, é a métrica relatável - mesmo artigo.
  • Duração do preenchimento da barra. O tempo de relógio que uma barra de volume leva para preencher é um recurso utilizável para um modelo de tick; os geradores que o produzem estão em Tipos de barras e métodos de agregação.

Uma coisa que vale a pena declarar explicitamente porque a versão original deste rascunho errou: um salto de 50,0% para 50,5% de precisão direcional não é evidentemente lucrativo. O ponto central do LOBFrame, discutido no artigo do DeepLOB, é que um movimento previsto deve ser grande o suficiente para limpar o spread antes que a precisão signifique alguma coisa, e o resultado negativo honesto neste blog é o que acontece quando você assume o contrário.

Linha de base

Codificação de evento sequencial de linha de base

Suponha um CNN-Inception-LSTM estilo DeepLOB como o codificador de linha de base; a arquitetura, os números verificados da configuração 2 do FI-2010 (F1 83,40 / precisão 84,47 em k=10k=10), as advertências do LOBFrame e uma reimplementação funcional do PyTorch estão todas em DeepLOB: Deep Learning on Limit Order Books. Nada abaixo altera esse codificador - a questão toda é o que é adicionado à sua representação de entrada.

Três maneiras de codificar tempo irregular

Codificações alternativas de tempo irregular

Opção A: delta_t como um recurso simples

A resposta trivial. Acrescentar Δti=titi1\Delta t_i = t_i - t_{i-1} (transformado em log, pontuação z) como mais uma coluna no vetor de recursos, ao lado de OFI e desequilíbrio contábil, e mantém a incorporação posicional aprendida padrão. Não custa nada, adiciona uma dimensão de entrada e é o que a maioria dos modelos de ticks de produção realmente fazem.

Este é o braço que toda proposta mais sofisticada deve vencer, e é o braço que é omitido dos documentos que propõem alternativas mais sofisticadas.

Opção B: codificação posicional de tempo contínuo

Substitua a incorporação posicional discreta por uma função senoidal de tempo decorrido, em escalas de tempo que podem ser aprendidas:

TE(Δt)=[sin(Δtτ1),cos(Δtτ1),,sin(Δtτd),cos(Δtτd)]\text{TE}(\Delta t) = \left[\sin\left(\frac{\Delta t}{\tau_1}\right), \cos\left(\frac{\Delta t}{\tau_1}\right), \ldots, \sin\left(\frac{\Delta t}{\tau_d}\right), \cos\left(\frac{\Delta t}{\tau_d}\right)\right]

onde τ1,,τd\tau_1, \ldots, \tau_d são parâmetros de escala de tempo que podem ser aprendidos, inicializados com espaçamento de log de microssegundos a segundos. O efeito pretendido é que a atenção possa ponderar os eventos pela relevância temporal e não pelo índice de slot – uma grande negociação de 200 microssegundos atrás deveria ser acessível de forma diferente de uma pequena negociação de 50 milissegundos atrás.

A parte que pode ser aprendida é a parte interessante. Se você inicializar escalas de tempo com espaçamento logístico de 1 microssegundo a 10 segundos e treinar, onde as escalas de tempo terminam é uma medida: se elas entrarem em colapso no final do milissegundo, o modelo está lhe dizendo que tudo além de alguns milissegundos é intercambiável, e isso é uma descoberta sobre o mercado, não sobre a arquitetura.

import numpy as np
import torch
import torch.nn as nn

class ContinuousTimeEncoding(nn.Module):
    """Sinusoidal encoding for irregular inter-arrival times."""
    def __init__(self, d_model: int, num_timescales: int = 64):
        super().__init__()
        log_timescales = torch.linspace(
            np.log(1e-6), np.log(10.0), num_timescales
        )
        self.log_timescales = nn.Parameter(log_timescales)
        self.proj = nn.Linear(num_timescales * 2, d_model)

    def forward(self, delta_t: torch.Tensor) -> torch.Tensor:
        """
        Args:
            delta_t: (batch, seq_len) inter-arrival times in seconds
        Returns:
            (batch, seq_len, d_model) time encoding
        """
        timescales = torch.exp(self.log_timescales)  # (num_timescales,)
        scaled = delta_t.unsqueeze(-1) / timescales.unsqueeze(0).unsqueeze(0)
        encoding = torch.cat([torch.sin(scaled), torch.cos(scaled)], dim=-1)
        return self.proj(encoding)

Colocado em um codificador padrão, ele substitui exatamente uma linha - a adição de incorporação posicional:

class TickTransformer(nn.Module):
    def __init__(self, input_dim: int, d_model: int = 128,
                 nhead: int = 8, num_layers: int = 4, num_classes: int = 3):
        super().__init__()
        self.feature_proj = nn.Linear(input_dim, d_model)
        self.time_encoding = ContinuousTimeEncoding(d_model)
        encoder_layer = nn.TransformerEncoderLayer(
            d_model=d_model, nhead=nhead,
            dim_feedforward=d_model * 4,
            dropout=0.1, batch_first=True
        )
        self.encoder = nn.TransformerEncoder(
            encoder_layer, num_layers=num_layers
        )
        self.head = nn.Linear(d_model, num_classes)

    def forward(self, features: torch.Tensor,
                delta_t: torch.Tensor) -> torch.Tensor:
        h = self.feature_proj(features) + self.time_encoding(delta_t)
        h = self.encoder(h)
        return self.head(h[:, -1, :])

O padrão do codificador em si não é novidade - o mesmo nn.TransformerEncoderLayer scaffolding já está publicado como Arquitetura 2 em modelagem de propagação. Apenas ContinuousTimeEncoding e o argumento da escala de tempo aprendível são.

Opção C: estado latente contínuo entre ticks (ODE-RNN)

A opção mais baseada em princípios trata o estado latente como um processo de tempo contínuo modelado por uma EDO Neural (Chen et al., 2018). Entre os ticks, o estado oculto evolui de acordo com uma equação diferencial aprendida:

dhdt=fθ(h(t),t)\frac{d\mathbf{h}}{dt} = f_\theta(\mathbf{h}(t), t)

Quando chega um tick, o estado é atualizado com a observação:

h(ti+)=Update(h(ti),xi)\mathbf{h}(t_i^+) = \text{Update}(\mathbf{h}(t_i^-), \mathbf{x}_i)

Esta é a estrutura ODE-RNN. Ele lida com espaçamentos irregulares estruturalmente e não como um recurso de entrada: o solucionador integra exatamente Δti\Delta t_i entre eventos, sem preenchimento, sem interpolação e sem etapa de reamostragem para perder informações.

O custo é computacional. Os solucionadores de EDO são sequenciais e difíceis de paralelizar, o que torna este o braço com menor probabilidade de sobreviver a um orçamento de latência — consulte a disciplina de latência estabelecida em The IPC Tax e the backtest engine speed ladder para saber como tais afirmações devem ser medidas antes de serem feitas. Ele está incluído aqui como o limite superior do que a modelagem de tempo explícita pode comprar, e não como um candidato à implantação.

Atenção ponderada por evento

Campo de atenção ponderada do evento

Uma segunda ideia, ortogonal: nem todos os ticks são igualmente informativos. Uma negociação de 100 ações na oferta é rotineira. Uma negociação que varre três níveis de preços é uma mudança de regime. Podemos injetar isso diretamente na atenção. Defina uma pontuação de importância do evento:

wi=softplus(α1log(qi)+α2Δpi/σ+α31[sweepi])w_i = \text{softplus}\left(\alpha_1 \cdot \log(q_i) + \alpha_2 \cdot |\Delta p_i| / \sigma + \alpha_3 \cdot \mathbb{1}[\text{sweep}_i]\right)

onde qiq_i é o tamanho do comércio, Δpi\Delta p_i a mudança de preço, σ\sigma volatilidade recente, e sweepi\text{sweep}_i sinaliza uma varredura multinível. Adicione-o aos logits de atenção antes do softmax:

Attention(Q,K,V)=softmax(QKTdk+W)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + \mathbf{W}\right) V

com Wij=wj\mathbf{W}_{ij} = w_j. O modelo mantém a capacidade de aprender padrões de atenção arbitrários, mas começa a ser tendencioso para negociações que movimentaram o mercado.

Esta é uma fórmula inventada. A forma funcional, a escolha de três termos e o softplus são todas suposições, e nada aqui mostra que o viés ajuda, em vez de apenas queimar capacidade.

Cabeças multi-horizontes

Faixas de previsão multihorizonte

Diferentes horizontes informam diferentes decisões, um codificador compartilhado com múltiplas saídas de horizonte supera modelos separados por horizonte, e a perda conjunta se regulariza — esse argumento, mais saídas quantílicas e interpretabilidade, é feito em Temporal Fusion Transformer for Trading. A única parte específica do tick é o conjunto de horizontes: 1, 10, 50 e 100 eventos em vez de dias, o que significa que os horizontes se sobrepõem fortemente no tempo do relógio durante as rajadas e quase nada durante os períodos de silêncio - uma complicação com a qual a literatura do horizonte diário nunca tem que lidar.

A purga deve ser medida em eventos

Intervalo de exclusão do espaço de eventos

A validação walk-forward eliminada é abordada de ponta a ponta em Walk-Forward Optimization (CV ancorado, rolante, combinatorial purgado, WFER, taxa de degradação) e um trabalho purged_walk_forward() com uma eliminação explícita e uma lacuna de embargo enviada em modelagem de propagação. A taxonomia de preconceito antecipado quantifica o que vazamentos desse tipo fazem ao relatado Sharpe.

A única coisa que é específica para dados de ticks: ticks adjacentes separados por milissegundos são quase duplicados, portanto, um intervalo de purga dimensionado em dias não tem sentido quando uma explosão coloca 500 amostras quase idênticas dentro de um segundo. A lacuna deve ser dimensionada em eventos, e o tamanho certo é uma questão empírica sobre a estrutura de burst do seu instrumento, não uma constante para copiar de um papel.

Essa afirmação é barata de testar – varrer a lacuna de eliminação nos eventos e traçar a validação F1 contra ela. Se a validação F1 cair à medida que a lacuna aumenta e depois se achata, o ponto de achatamento é a sua lacuna; se nunca cair, o vazamento do carrapato adjacente não foi o problema que você pensava.

O experimento que decide isso

Avaliação de modelo temporal controlado

Tudo acima é arquitetura. Nada disso é evidência. O artigo não limpa a barra deste blog até que o seguinte seja executado:

Configuração. Corrija um conjunto de dados (as negociações BTC/USDT são o conjunto de dados interno), um codificador, uma definição de rótulo e uma divisão eliminada. Varie exatamente uma coisa.

Três braços.

Braço Informações de tempo Codificação posicional
Um Δt\Delta t como um recurso de entrada bruto incorporação posicional aprendida simples
B nenhum, além da codificação ContinuousTimeEncoding (prazos que podem ser aprendidos)
C Δt\Delta t como um recurso e codificação de tempo contínuo ContinuousTimeEncoding

O que relatar.

  1. F1 por classe, não precisão — sob um rótulo de zona morta, a classe FLAT domina e a precisão não é informativa exatamente pelo motivo fornecido pelo artigo do DeepLOB.
  2. Um intervalo de confiança, de execuções repetidas com sementes diferentes. Uma distância F1 de 0,4 pontos entre os braços não significa nada sem ela.
  3. Os prazos ajustados. Imprimir torch.exp(model.time_encoding.log_timescales) após o treino. O local onde eles se instalam é o número mais interessante do experimento e custa uma linha para ser obtido.
  4. Custo de hardware e relógio de parede por braço, no estilo de The IPC Tax — medido, em hardware divulgado, mediana sobre N. Se o braço B custa 3x o tempo de inferência do braço A por uma fração de um ponto F1, essa é a resposta.

Relate o resultado negativo, se houver. "A codificação em tempo contínuo não compra nada em relação à alimentação Δt\Delta t como recurso, em 30 dias de ticks BTC" é uma postagem mais útil do que uma pesquisa de três arquiteturas que ninguém mediu. Também seria consistente com a descoberta geral neste blog de que bordas cuidadosamente construídas tendem a evaporar sob validação honesta.

Onde isso está

Caminho de pesquisa em tempo contínuo

A questão descoberta é real: modelos de sequência alimentados com eventos espaçados irregularmente ainda codificam a posição em vez do tempo, e a cobertura existente do blog - incluindo o codificador Transformer na modelagem de propagação - usa uma incorporação posicional aprendida simples. Codificações de tempo contínuo, estado latente ODE-RNN e atenção ponderada por evento são três maneiras de corrigir isso.

O que falta é qualquer evidência de que consertar isso seja importante. Todos os três são atualmente tópicos, não descobertas. A medição decisiva é uma ablação de três braços em um codificador fixo e uma divisão purgada fixa, reportando F1 por classe com um intervalo de confiança e as escalas de tempo ajustadas – e não foi executada.

blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Fique à frente do mercado

Assine nossa newsletter para insights exclusivos sobre trading com IA, análises de mercado e atualizações da plataforma.

Respeitamos sua privacidade. Cancele a inscrição a qualquer momento.