Pular para o conteúdo
ZYNQORALABS
FX · Demonstração interna

Tessera RiskGateway de risco pré-negociação

Arquitetura de referência para validar cada ordem contra limites de tamanho, posição, banda de preço e frequência antes do roteamento, com estado reconstruível a partir de um log de eventos. Testada contra um simulador de bolsa.

Tecnologias
Rust · Event sourcing · PostgreSQL · Simulator
Demonstra
  • Risco pré-negociação
  • Estado auditável por eventos
  • Replay determinístico
  • Falha em modo seguro

O desafio

  1. 01

    A checagem precisa estar no caminho crítico de toda ordem, sem se tornar o gargalo.

  2. 02

    Cada decisão (aprovar ou rejeitar) precisa ser explicável depois, com o estado exato do momento.

  3. 03

    Se os dados de mercado ficarem desatualizados, as bandas de preço perdem sentido e o sistema precisa reagir.

Restrições

  • Latência previsível
  • Auditoria completa
  • Falha em modo seguro

Arquitetura

Caminho da ordem (centro) e log de eventos que permite reconstruir e auditar o estado de risco.Fig. 01 · Tessera Risk

Componentes

Strategy / OMS
Origem das ordens: estratégias ou operadores.
Order gateway
Normaliza o protocolo e atribui sequência às ordens.
Market data
Último preço e timestamp para bandas de preço.
Risk engine
Um único escritor por conta, sem locks; checagens ordenadas por custo.
Router
Encaminha ordens aprovadas ao destino.
Venue simulator
Simulador de bolsa usado nos testes; não é uma conexão real.
Event log
Registro append-only de ordens, decisões e execuções.
Drop copy
Confirmações de execução que atualizam a posição.

Decisões de engenharia

D1Um escritor por conta

Escolha
As contas são distribuídas em shards; cada shard é processado por uma única thread com estado em memória.
Alternativa descartada
Estado compartilhado protegido por locks.
Por quê
Sem disputa de locks, a latência fica previsível e a ordem de processamento é determinística, o que torna o replay exato.

D2Estado derivado de eventos

Escolha
Posições e limites consumidos são reconstruídos a partir do log de eventos.
Alternativa descartada
Gravar apenas o estado atual no banco.
Por quê
Auditoria e investigação exigem responder “por que esta ordem foi aceita às 10:31:07?”. O log responde, um snapshot não.

D3Falhar fechado com dados velhos

Escolha
Se o preço de referência estiver desatualizado além do limite, ordens a mercado são rejeitadas.
Alternativa descartada
Usar o último preço conhecido indefinidamente.
Por quê
Uma banda de preço calculada sobre dados velhos aprova exatamente as ordens que deveria barrar.

D4Checagens ordenadas por custo

Escolha
Kill switch e tamanho máximo primeiro; cálculos de exposição por último.
Alternativa descartada
Ordem arbitrária.
Por quê
A maior parte das rejeições acontece nas regras baratas, então o caso comum fica rápido.

Detalhes de implementação

Cada regra é uma função pura que recebe a ordem e o estado da conta e devolve aprovação ou um motivo de rejeição. O motor executa as regras em sequência e para na primeira falha.

O estado vive em memória dentro do shard. Na inicialização, ele é reconstruído pelo replay do log; em operação, cada decisão é anexada ao log antes da resposta ao gateway.

Os testes incluem replay determinístico: o mesmo log, processado duas vezes, precisa produzir exatamente as mesmas decisões.

risk/checks.rsTrecho representativo
pub fn evaluate(order: &Order, acct: &AccountState, mkt: &MarketView, now: Nanos) -> Decision {
    // Ordered by cost: cheap, frequent rejections first.
    if acct.kill_switch { return Decision::reject(Reason::KillSwitch); }
    if order.qty > acct.limits.max_order_qty { return Decision::reject(Reason::MaxOrderQty); }
    if !acct.rate.allow(now) { return Decision::reject(Reason::RateLimit); }

    let Some(reference) = mkt.last_price_fresh(order.instrument, now, STALE_AFTER) else {
        return Decision::reject(Reason::StaleMarketData); // fail closed
    };
    if !within_band(order.price.unwrap_or(reference), reference, acct.limits.price_band_bps) {
        return Decision::reject(Reason::PriceBand);
    }
    let projected = acct.position(order.instrument) + order.signed_qty();
    if projected.abs() > acct.limits.max_position { return Decision::reject(Reason::PositionLimit); }
    Decision::Accept
}

Resultados

Não aplicável. Por ser uma demonstração interna, não há métricas de produção verificadas a relatar, e não publicamos números estimados como se fossem resultados.

Tem um problema parecido?

Conte o contexto. Discutimos a arquitetura antes de qualquer proposta comercial.

Próximo estudoRelay MeshHub de integração orientado a eventos
01Quem é você

Usamos apenas para responder a esta solicitação.

02O projeto

O problema, o que já existe hoje e o que seria sucesso. Não inclua senhas ou dados pessoais de terceiros.

03Escopo

Usamos estes dados apenas para avaliar e responder à sua solicitação. Não vendemos nem compartilhamos com terceiros para marketing. Detalhes na política de privacidade.