Análise de microestrutura de 29 de junho de 2026
Detalhes técnicos do tape de negociações e cotações, correções de volume via dicionário e análise de arquivos da FINRA para o dia 29 de junho de 2026.
Este é o complemento técnico do resumo de mercado de 29 de junho de 2026: o fluxo bruto por trás dos candles de um minuto — 156.1 milhões de negócios individuais e 505.38 milhões de atualizações de cotação NBBO em uma sessão comum de segunda-feira. Cada número é o resultado de uma consulta armazenada (expanda qualquer painel para ver o SQL exato), e as duas descobertas forenses do dia recebem análises completas: uma correção de volume exigida pelo próprio dicionário de código do tape, e um arquivo de fornecedor que termina silenciosamente na letra S.
O registro de negociações, print por print
A verificação da sessão ocorre primeiro, nunca por presunção: o calendário de feriados da bolsa contém 0 linhas para 29 de junho de 2026, e o SPY registrou exatamente 390 barras de um minuto dentro do horário regular — uma sessão completa, das 9:30 às 16:00, horário de Nova York. Durante o pregão estendido, o tape consolidado registrou 156.1 milhões de trades individuais.
O SQL exato por trás de cada número
WITH
(SELECT count() FROM global_markets.stocks_market_holidays WHERE date = '2026-06-29') AS holiday_rows,
(
SELECT countIf(window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00')
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-06-29 00:00:00' AND window_start < '2026-06-30 00:00:00'
) AS spy_bars
SELECT
holiday_rows AS holiday_rows_jun29,
spy_bars AS spy_regular_session_bars,
round(count() / 1e6, 1) AS trades_m,
round(100.0 * countIf(size < 100) / count(), 2) AS odd_lot_pct_of_trades,
round(100.0 * toFloat64(sumIf(size, size < 100)) / toFloat64(sum(size)), 2) AS odd_lot_pct_of_shares,
multiIf(
countIf(size <= 19) >= 0.5 * count(), 19,
countIf(size <= 20) >= 0.5 * count(), 20,
countIf(size <= 21) >= 0.5 * count(), 21,
countIf(size <= 22) >= 0.5 * count(), 22,
countIf(size <= 23) >= 0.5 * count(), 23,
0) AS median_print_shares,
round(countIf(size = 1) / 1e6, 1) AS one_share_trades_m,
round(100.0 * countIf(size != round(size)) / count(), 2) AS fractional_pct_of_trades
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'72.61% de todos os prints foram odd lots — negociações de menos de 100 ações — mas movimentaram apenas 8.79% das ações brutas — o total não corrigido que a seção de análise de volume abaixo ajusta. O print mediano foi de 21 ações, medido com uma sonda de colchetes de autoverificação — contagens cumulativas de 19 a 23 ações — que retorna 0 se o colchete falhar, e é limitada para que uma falha mantenha o valor anterior. 17.9 milhões de prints foram de exatamente uma ação e 4.73% apresentaram tamanhos fracionários — um padrão consistente com aplicativos de varejo executando ordens no tape uma fração por vez, com market makers assumindo o outro lado.
Forense de volume: derivando o "matched volume" a partir do dicionário
Some o campo de tamanho de cada print e o dia 29 de junho mostra 24.79 bilhões de ações negociadas. Esse valor está incorreto, e o próprio tape confirma isso. Cada print carrega códigos de condição, e o SIP — o Securities Information Processor que consolida todas as plataformas em um único fluxo — publica um dicionário que indica, código por código, se um print atualiza o volume consolidado. Algumas mensagens são retransmissões administrativas de volume já contabilizado. Em vez de fixar uma lista de códigos "conhecidos", este post deriva o conjunto de exclusão do próprio dicionário:
O SQL exato por trás de cada número
SELECT
count() AS excluded_codes,
sum(id) AS excluded_id_checksum,
arrayStringConcat(arraySort(groupArray(concat(toString(id), ' ', name))), ' · ') AS codes
FROM global_markets.stocks_condition_codes
WHERE asset_class = 'stocks'
AND type = 'sale_condition'
AND JSONExtractBool(update_rules, 'consolidated', 'updates_volume') = 03 condições de venda apresentam updates_volume = false no feed consolidado: 15 Market Center Official Close · 16 Market Center Official Open · 38 Corrected Consolidated Close (per listing market). Aqui está a lição aprendida: um rascunho anterior do resumo diário fixou os códigos 15 e 16 — as duas mensagens oficiais de abertura/fechamento mencionadas em todos os guias de dados — e ignorou completamente o código 38. O dicionário, e não uma lista de códigos memorizada, é a única fonte de verdade.
O uso de dois blocos é deliberado: uma subquery escalar sobre o dicionário dentro de um scan de 156.1 milhões de linhas ultrapassa nosso limite de 30 segundos. Portanto, o bloco acima deriva o conjunto como uma única linha — com limites de sanidade baseados na contagem de códigos e um checksum de id (69) — e o bloco abaixo aplica os literais derivados. Se o dicionário sofrer qualquer alteração, o checksum sinaliza este post para revisão; os literais nunca ficarão obsoletos silenciosamente.
O SQL exato por trás de cada número
SELECT
round(toFloat64(sum(size)) / 1e9, 2) AS raw_shares_bn,
round(toFloat64(sumIf(size, NOT hasAny(conditions, [15, 16, 38]))) / 1e9, 2) AS matched_shares_bn,
round(toFloat64(sumIf(size, hasAny(conditions, [15, 16, 38]))) / 1e9, 2) AS excluded_shares_bn,
countIf(hasAny(conditions, [15, 16, 38])) AS excluded_prints
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'A contabilidade corrigida: 24.79 bilhões de ações brutas, 20.66 bilhões contados pelo SIP, 4.13 bilhões excluídos em 91175 prints administrativos. Uma definição, declarada com precisão: "matched volume" significa o volume que as próprias regras de condição do SIP contabilizam para o total consolidado — nada mais. Não estamos julgando quais negociações foram economicamente relevantes; estamos aplicando a própria contabilidade do tape.
Decodificando os maiores prints
Os maiores prints do dia mostram quando os códigos de condição deixam de ser apenas curiosidade:
O SQL exato por trás de cada número
SELECT
ticker,
formatDateTime(toTimeZone(sip_timestamp, 'America/New_York'), '%H:%i:%S') AS et_time,
round(toFloat64(size) / 1e6, 2) AS shares_m,
toFloat64(price) AS price,
round(toFloat64(size) * toFloat64(price) / 1e6, 1) AS notional_usd_m,
round(100 * (toFloat64(size) * toFloat64(price)) / max(toFloat64(size) * toFloat64(price)) OVER (), 1) AS pct_of_biggest_dollar_print,
arrayStringConcat(arrayMap(c -> toString(c), conditions), ', ') AS condition_id
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
AND size >= 10000000
AND NOT hasAny(conditions, [15, 16, 38])
ORDER BY size DESC
LIMIT 10Leia as primeiras linhas como um exemplo prático. O maior print do dia — 61.69 milhões de ações de CAG (Conagra) a $13.98, aproximadamente $862.5 milhões, registrados às 16:04:53 ET sob os códigos 8, 41 (8 Closing Prints, 41 Trade Thru Exempt) — é o resultado do leilão de fechamento da NYSE publicado após as 16:00. Ele conta para o volume exatamente uma vez. As mesmas 61.69 milhões de ações reaparecem sob o código 15, Market Center Official Close: um re-report que o dicionário exclui, parte dos 4.13 bilhões removidos acima. Essa linha do código 15 é removida da tabela acima por design, por isso seu registro recebe seu próprio painel de uma linha:
O SQL exato por trás de cada número
SELECT
round(toFloat64(maxIf(size, has(conditions, 8))) / 1e6, 2) AS auction_print_shares_m,
round(toFloat64(maxIf(size, has(conditions, 15))) / 1e6, 2) AS official_close_reprint_shares_m,
round(toFloat64(maxIf(size, has(conditions, 8))) - toFloat64(maxIf(size, has(conditions, 15))), 2) AS share_difference,
formatDateTime(toTimeZone(argMaxIf(sip_timestamp, size, has(conditions, 15)), 'America/New_York'), '%H:%i:%S') AS reprint_et,
argMaxIf(exchange, size, has(conditions, 15)) AS reprint_exchange_id,
countIf(has(conditions, 15)) AS cag_code15_prints
FROM global_markets.stocks_trades
WHERE ticker = 'CAG'
AND sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'O maior das 6 mensagens de fechamento oficial da CAG envolve 61.69 milhões de ações — exatamente os 61.69 milhões do leilão (diferença: 0) — registrados às 16:04:53 ET pela id de exchange 10, NYSE no diretório de ações: o mercado de listagem reiterando seu próprio leilão.
As outras CAG linhas são diferentes — o print de 15.17 milhões de ações sob os códigos 12, 2 (12 Form T / extended hours, 2 Average Price Trade) e mais dois sob o código 12 são prints pós-leilão reportados via FINRA, cujas condições possuem updates_volume = true. O SIP os contabiliza como prints reais, assim como nosso valor correspondente.
Em outros pontos, o código 9 marca os fechamentos da Nasdaq — o cross de $3389.5 milhões da NVDA é o maior print da tabela em dólares — e os códigos no print SNAP (53, 41) incluem o 53, um Qualified Contingent Trade.
O relógio: dez minutos dominam o dia
Em resolução de minuto, o fluxo de negociações concentra-se quase inteiramente nas extremidades da sessão:
O SQL exato por trás de cada número
SELECT
formatDateTime(toTimeZone(toStartOfMinute(sip_timestamp), 'America/New_York'), '%H:%i') AS et_minute,
round(count() / 1e6, 2) AS trades_m
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
GROUP BY et_minute
ORDER BY trades_m DESC
LIMIT 10O minuto 15:59 ET registrou 3.98 milhões de trades — mais de sessenta mil por segundo. Se o restante do top dez se concentra na abertura e no fechamento é uma medida de apenas uma linha:
O SQL exato por trás de cada número
SELECT
countIf(NOT (et_minute BETWEEN '09:30' AND '09:39' OR et_minute BETWEEN '15:50' AND '16:00')) AS entries_outside_open_close,
countIf(et_minute BETWEEN '09:30' AND '09:39' OR et_minute BETWEEN '15:50' AND '16:00') AS entries_in_open_close,
maxIf(et_minute, NOT (et_minute BETWEEN '09:30' AND '09:39' OR et_minute BETWEEN '15:50' AND '16:00')) AS outside_entry_minute,
maxIf(trades_m, NOT (et_minute BETWEEN '09:30' AND '09:39' OR et_minute BETWEEN '15:50' AND '16:00')) AS outside_entry_trades_m
FROM (
SELECT
formatDateTime(toTimeZone(toStartOfMinute(sip_timestamp), 'America/New_York'), '%H:%i') AS et_minute,
round(count() / 1e6, 2) AS trades_m
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
GROUP BY et_minute
ORDER BY trades_m DESC
LIMIT 10
)9 dos dez ativos situam-se nos dez minutos iniciais ou nos dez minutos finais antes do fechamento. A única exceção — 10:15 ET, com um pico de 0.88 milhões de registros — é uma anomalia real de meio de manhã; a causa não é identificável por estes dados, e não iremos inventar uma. O mesmo horário retorna abaixo.
O fluxo de cotações: meio bilhão de atualizações
O National Best Bid and Offer — o melhor preço de compra e venda em todas as bolsas, republicado sempre que há mudança — registrou 505.38 milhões de atualizações em 29 de junho, contra 156.1 milhões de trades.
O SQL exato por trás de cada número
WITH
(
SELECT (round(countIf(ticker = 'QQQ') / 1e6, 2), round(countIf(ticker = 'NVDA') / 1e6, 2),
round(countIf(ticker = 'AAPL') / 1e6, 2), round(countIf(ticker = 'TSLA') / 1e6, 2))
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('QQQ', 'NVDA', 'AAPL', 'TSLA')
AND sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
) AS pinned
SELECT
round(count() / 1e6, 2) AS updates_m,
pinned.1 AS qqq_updates_m,
pinned.2 AS nvda_updates_m,
round(pinned.1 - pinned.2, 2) AS qqq_minus_nvda_updates_m,
round(pinned.2 - greatest(pinned.3, pinned.4), 2) AS nvda_minus_next_single_m
FROM global_markets.cache_stocks_quotes
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'Produtos de índice dominam as cotações: apenas o QQQ registrou 5.23 milhões de atualizações, contra 1.8 milhões da NVDA, a ação individual mais cotada que analisamos — 0.67 milhões de atualizações de vantagem sobre o próximo ticker. Um censo completo por ticker de todos os ativos não cabe no limite de 30 segundos, portanto, o ranking abaixo é um conjunto verificado, não uma classificação exaustiva:
O SQL exato por trás de cada número
SELECT ticker, round(count() / 1e6, 2) AS updates_m
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('QQQ', 'SPY', 'TQQQ', 'IWM', 'SQQQ', 'NVDA', 'AAPL', 'TSLA')
AND sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
GROUP BY ticker
ORDER BY updates_m DESCQQQ liderou o conjunto verificado com 5.23 milhões de atualizações; o topo da lista é composto por fundos de índice e seus equivalentes alavancados, não por ações conhecidas do varejo.
SPY sob o microscópio: registros em nanossegundos e o spread em duas vertentes
O SQL exato por trás de cada número
WITH
(
SELECT (formatDateTime(toTimeZone(toStartOfSecond(sip_timestamp), 'America/New_York'), '%H:%i:%S'), count())
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY' AND sip_timestamp >= '2026-06-29 13:30:00' AND sip_timestamp < '2026-06-29 20:00:00'
GROUP BY toStartOfSecond(sip_timestamp)
ORDER BY count() DESC, toStartOfSecond(sip_timestamp) ASC
LIMIT 1
) AS busiest_sec,
ordered AS (
SELECT
toFloat64(ask_price - bid_price) AS spread,
bid_price,
ask_price,
toFloat64(sip_timestamp - lagInFrame(sip_timestamp) OVER (ORDER BY sip_timestamp, sequence_number)) AS gap_s,
greatest(toFloat64(least(leadInFrame(sip_timestamp, 1, toDateTime64('2026-06-29 20:00:00', 9)) OVER (ORDER BY sip_timestamp, sequence_number ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING), toDateTime64('2026-06-29 20:00:00', 9)) - sip_timestamp), 0) AS dwell_s,
rowNumberInAllBlocks() AS rn
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY' AND sip_timestamp >= '2026-06-29 13:30:00' AND sip_timestamp < '2026-06-29 20:00:00'
)
SELECT
round(count() / 1e6, 2) AS spy_updates_m,
busiest_sec.1 AS busiest_second_et,
toUInt8(startsWith(busiest_sec.1, '10:15')) AS busiest_second_in_1015,
busiest_sec.2 AS busiest_second_updates,
round(minIf(gap_s, rn > 0 AND gap_s > 0) * 1e9) AS min_gap_between_updates_ns,
round(quantileExactIf(0.5)(gap_s, rn > 0) * 1e6, 1) AS median_gap_us,
countIf(rn > 0 AND gap_s = 0) AS identical_timestamp_pairs,
round(sumIf(spread * dwell_s, bid_price > 0 AND ask_price >= bid_price) / sumIf(dwell_s, bid_price > 0 AND ask_price >= bid_price) * 100, 2) AS time_weighted_avg_spread_cents,
round(avgIf(spread, bid_price > 0 AND ask_price >= bid_price) * 100, 2) AS per_update_avg_spread_cents,
round((avgIf(spread, bid_price > 0 AND ask_price >= bid_price) - sumIf(spread * dwell_s, bid_price > 0 AND ask_price >= bid_price) / sumIf(dwell_s, bid_price > 0 AND ask_price >= bid_price)) * 100, 2) AS per_update_premium_cents,
countIf(bid_price > 0 AND ask_price > 0 AND ask_price < bid_price) AS crossed_updates,
countIf(bid_price <= 0 OR ask_price <= 0) AS zero_bid_or_ask_updates
FROM orderedA cotação do SPY mudou 3.98 milhões de vezes apenas durante o horário regular. Seu segundo mais movimentado — 10:15:43 ET, dentro do minuto 10:15 sinalizado acima — registrou 1461 atualizações. O menor intervalo entre atualizações consecutivas foi de 1375 nanossegundos, com a mediana em 245.6 microssegundos, e 75138 pares consecutivos apresentaram o mesmo carimbo de nanossegundos — nem mesmo a resolução de nanossegundos consegue ordenar totalmente o tape moderno.
Esses nanossegundos são essenciais para medir o bid-ask spread. Contando cada atualização de forma igual, o spread médio do SPY foi de 2.72 centavos; ponderando cada cotação pelo tempo de permanência, o valor foi de 2.34 centavos. O valor por atualização é mecanicamente 0.38 centavos mais largo: as atualizações se concentram justamente nos momentos em que o spread está amplo e em movimento, enquanto uma ordem parada permanece no tempo cronológico. Sempre que vir uma estatística de spread, verifique qual relógio a mediu. O censo é divulgado, não ocultado: 1544 atualizações no horário regular apresentaram cruzamento momentâneo (ask abaixo do bid, uma intercalação de cotações de diferentes venues) e 0 apresentaram bid ou ask zero; as estatísticas de spread excluem ambos e contabilizam o que excluem.
O spread tem um cronograma
Agrupar o spread cotado do SPY em intervalos de meia hora transforma a microestrutura em uma curva utilizável por qualquer trader:
O SQL exato por trás de cada número
SELECT
formatDateTime(toTimeZone(toStartOfInterval(sip_timestamp, INTERVAL 30 MINUTE), 'America/New_York'), '%H:%i') AS et_time,
round(quantileExactIf(0.5)(toFloat64(ask_price - bid_price), bid_price > 0 AND ask_price >= bid_price) * 100, 1) AS median_spread_cents,
count() AS quote_updates
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY' AND sip_timestamp >= '2026-06-29 08:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
GROUP BY et_time
ORDER BY et_timeUma mediana de 8 centavos no bucket do premarket das 04:00, 3 centavos no bucket de abertura das 09:30, e 2 centavos até as 14:00 — negociar a mesma ação na abertura do premarket custa aproximadamente quatro vezes o spread de uma ordem no início da tarde. O spread não é constante; é um cronograma.
Evidência forense: o arquivo que parou no S
Todo arquivo diário de fornecedor passa por um teste de integridade antes de publicarmos qualquer número: contamos os tickers, verificamos o intervalo alfabético e comparamos com os dados anteriores. O arquivo de volume de vendas a descoberto (short-volume) da FINRA fora de bolsa de 29 de junho exemplifica o motivo:
O SQL exato por trás de cada número
SELECT
date,
uniqExact(ticker) AS tickers,
min(ticker) AS first_ticker,
max(ticker) AS last_ticker,
countIf(ticker = 'TSLA') AS tsla_rows,
round(100 * sum(short_volume) / sum(total_volume), 2) AS short_pct_of_reported
FROM global_markets.stocks_short_volume
WHERE date BETWEEN '2026-06-26' AND '2026-06-30'
GROUP BY date
ORDER BY dateO arquivo de 26 de junho cobre 15052 tickers, de A a ZYME. O arquivo de 29 de junho cobre 5489, de A a SSUS — ele simplesmente para no meio dos nomes iniciados com S. Todos os tickers alfabeticamente posteriores a esse ponto — incluindo TSLA, com 0 linhas em 29 de junho contra 1 em 26 de junho — estão ausentes; em 30 de junho, o arquivo retorna para 15362 tickers. Um teste de integridade é apenas um recibo de uma linha por dia — a diferença entre publicar uma estatística e publicar um erro de dados.
Com essa ressalva — e apenas com ela — aqui está a proporção: o volume de vendas a descoberto marcado (marked-short) representa 45.85% do volume reportado fora de bolsa em 29 de junho, ao lado de 46.89% em 26 de junho e 48.82% em 30 de junho. O número de 29 de junho cobre apenas o intervalo de A a S, portanto, trate-o como uma leitura parcial. Uma participação de quase metade em vendas a descoberto é o nível rotineiro que todas as sessões vizinhas apresentam — e o volume diário de short não é short interest.
Notas de dados
Notas completas de dados
- A baixa de cotações das 17h às 18h. O fluxo de cotações do SPY quase para na meia hora ET de 17:00 (233) e retoma em 18:00 (40608) — trata-se de um padrão de sessão/feed entre tickers, não de falta de dados.
- Ações fracionárias são comuns. 4.73% das negociações possuem tamanhos não inteiros; o volume deve ser somado como decimais.
- O dicionário de códigos reutiliza ids entre tipos. O id 15 é tanto uma condição de venda (Market Center Official Close) quanto uma condição de cotação (Closed); cada consulta de dicionário aqui filtra asset_class = 'stocks' AND type = 'sale_condition'. Uma busca simples por id rotula os códigos incorretamente.
- Exclusões de qualidade de cotação são contadas diretamente. As contagens de ordens cruzadas e de bid/ask zero constam no painel microscópico do SPY acima; nenhuma estatística de spread esconde essas quedas.
- Varreduras de tape completo são painéis apenas em lote. Os blocos de todo o mercado aqui medidos levam cerca de trinta segundos cada em um cache frio (um bloco com timeout é tentado uma vez; a passagem com cache aquecido remove o limite); eles rodam uma vez no momento da autoria através do caminho de leitura restrito, nunca em tempo real para os leitores, e os resultados armazenados são o registro.
Metodologia
- Os timestamps são armazenados em UTC e filtrados com limites brutos em UTC (o horário regular em 29 de junho é das 13:30 às 20:00 UTC); o comando toTimeZone aparece apenas em listas SELECT.
- O tipo de sessão é verificado com base no calendário de feriados e na janela regular observada de 390 barras — nunca é uma suposição.
- O "volume contado pelo SIP (matched)" é o volume que as regras de condição do próprio SIP contabilizam para o total consolidado; o conjunto de exclusão é derivado do dicionário e limitado por checksum, nunca é fixo no código.
- As estatísticas de spread por atualização atribuem o mesmo peso a cada atualização do NBBO; as estatísticas ponderadas pelo tempo atribuem peso a cada cotação pelo tempo de duração. Ambas divulgam suas exclusões.
- As colunas decimais de preço/tamanho são somadas nativamente e convertidas para floats de 64 bits antes de qualquer aritmética de razão ou preço vezes tamanho.
- As tabelas de ticks mantêm o histórico completo sem expiração rotativa; estes resultados armazenados e versionados são o registro durável. Estado do warehouse em 3 de julho de 2026.
Cada painel acima é um objeto armazenado — gráfico, tabela e SQL juntos. Abra qualquer um deles, copie a query e aprofunde a análise no terminal Strasmore.