Анализ микроструктуры рынка за 29 июня 2026 года
Подробный разбор данных ленты сделок и котировок за 29 июня 2026 года: исправления объема через словарь и анализ наносекундных данных с учетом файлов FINRA.
Этот материал дополняет обзор рынка за 29 июня 2026 года: это необработанные данные, стоящие за минутными барами — 156.1 миллионов отдельных сделок и 505.38 миллионов обновлений котировок NBBO за одну обычную сессию в понедельник. Каждое число является результатом сохраненного запроса (разверните любую панель, чтобы увидеть точный SQL-код). В статье подробно описаны два ключевых вывода дня: исправление объема, требуемое словарем кодов ленты сделок, и файл поставщика, который неожиданно обрывается на букве S.
Торговая лента, сделка за сделкой
Сначала проводится проверка сессии, предположения недопустимы: календарь праздников биржи содержит 0 строк на 29 июня 2026 года, а SPY сформировал ровно 390 минутных баров в рамках регулярной сессии — полный торговый день с 9:30 до 16:00 по нью-йоркскому времени. За пределы регулярной сессии консолидированная лента зафиксировала 156.1 миллионов отдельных сделок.
Точный SQL-код для каждого числа
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% всех сделок были неполными лотами — сделки объемом менее 100 акций, — однако они составили лишь 8.79% от общего объема акций — нескорректированный итог, который сокращается в разделе ниже «Анализ объема». Медианная сделка составила 21 акций, измеренная с помощью самопроверяемого скобочного зонда — кумулятивный подсчет в диапазоне от девятнадцати до двадцати трех акций, — который возвращает 0, если значение не попадает в диапазон, и ограничен так, чтобы промах фиксировал последнее значение. 17.9 миллионов сделок были объемом ровно в одну акцию, а 4.73% имели дробные размеры — такая структура характерна для розничных приложений, совершающих сделки по одной части, когда маркетмейкеры выступают контрагентами.
Анализ объема: получение «сопоставленного объема» на основе словаря
Если суммировать поле размера в каждой сделке, то за 29 июня объем торгов составит 24.79 миллиарда акций. Этот показатель неверен, и сама лента сделок это подтверждает. Каждая сделка содержит коды условий, а SIP — Securities Information Processor, который объединяет данные со всех площадок в один поток, — публикует словарь. В этом словаре для каждого кода указано, должен ли он обновлять консолидированный объем. Некоторые сообщения являются административными повторными трансляциями объема, который уже был учтен один раз. Вместо того чтобы использовать жестко заданный список «известных» кодов, в данной статье набор исключений выводится непосредственно из словаря:
Точный SQL-код для каждого числа
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 условий продажи имеют параметр updates_volume = false в консолидированном потоке: 15 Market Center Official Close · 16 Market Center Official Open · 38 Corrected Consolidated Close (per listing market). Вот извлеченный урок: в предыдущем черновике ежедневного обзора коды 15 и 16 — два официальных сообщения об открытии и закрытии, которые упоминаются в каждом справочнике данных, — были прописаны вручную, при этом код 38 был полностью упущен. Источником истины является словарь, а не список запомненных кодов.
Использование двух блоков намеренно: скалярный подзапрос по словарю внутри сканирования 156.1 миллионов строк превышает наш лимит в 30 секунд. Поэтому верхний блок выводит набор данных в одну строку — с ограничением по количеству кодов и контрольной суммой id (69), — а нижний блок применяет полученные литералы. Если данные в словаре изменятся, контрольная сумма укажет на необходимость проверки статьи; литералы никогда не станут неактуальными без уведомления.
Точный SQL-код для каждого числа
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'Исправленный расчет: 24.79 миллиарда акций (сырые данные), 20.66 миллиарда (по данным SIP), 4.13 миллиарда исключено в рамках 91175 административных сделок. Одно точное определение: «сопоставленный объем» означает объем, который правила условий SIP включают в общий консолидированный итог — не более того. Мы не оцениваем экономическую значимость сделок; мы применяем правила учета самой ленты сделок.
Анализ крупнейших сделок
Крупнейшие сделки дня — это случаи, когда коды условий перестают быть второстепенными:
Точный SQL-код для каждого числа
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 10Рассмотрим верхние строки в качестве примера. Крупнейшая сделка дня — 61.69 млн акций CAG (Conagra) по цене $13.98, что составляет примерно $862.5 млн, зафиксированная в 16:04:53 ET с кодами 8, 41 (8 Closing Prints, 41 Trade Thru Exempt) — это результат закрытого аукциона NYSE, опубликованный после 16:00. Данная сделка учитывается в объеме только один раз. Те же 61.69 млн акций затем снова появляются под кодом 15 (Market Center Official Close): это повторный отчет, который исключается из словаря и входит в состав вышеуказанных 4.13 млрд. Строка с кодом 15 намеренно удалена из таблицы выше, поэтому для нее выделена отдельная информационная панель:
Точный SQL-код для каждого числа
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'Крупнейшее из 6 сообщений об официальном закрытии по CAG составляет 61.69 млн акций — ровно 61.69 млн по аукциону (разница: 0) — зафиксировано в 16:04:53 ET по идентификатору биржи 10 (NYSE в справочнике акций): это повторное подтверждение аукциона биржей листинга.
Остальные CAG строк относятся к другой категории. Сделка объемом 15.17 млн акций с кодами 12, 2 (12 Form T / extended hours, 2 Average Price Trade) и еще две сделки с кодом 12 — это пост-аукционные сделки, переданные через FINRA, чьи условия имеют параметр updates_volume = true. Система SIP учитывает их как реальные сделки, как и наш сопоставленный показатель.
В других местах код 9 обозначает закрывающие пересечения Nasdaq — пересечение NVDA на сумму $3389.5 млн является крупнейшей сделкой в таблице по стоимости, — а коды в сделке SNAP (53, 41) включают 53 (Qualified Contingent Trade).
Время: десять минут определяют день
При поминутном анализе торговая лента концентрируется почти полностью в моменты открытия и закрытия сессии:
Точный SQL-код для каждого числа
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За 15:59 ET минуту было совершено 3.98 миллионов сделок — более шестидесяти тысяч в секунду. Является ли распределение остальных десяти позиций вблизи открытия и закрытия закономерностью, можно определить по одной строке:
Точный SQL-код для каждого числа
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 из десяти позиций приходятся на первые десять минут сессии или на последние десять минут перед закрытием. Единственное исключение — 10:15 ET, когда было зафиксировано 0.88 миллионов сделок — представляет собой аномальный всплеск в середине утра; причина этого явления по данным показателям не установлена, и мы не будем ее выдумывать. Это же время повторится ниже.
Поток котировок: полмиллиарда обновлений
Показатель National Best Bid and Offer — лучшие цены покупки и продажи на всех биржах, обновляемый при каждом изменении — зафиксировал 505.38 миллионов обновлений 29 июня при 156.1 миллионах сделок.
Точный SQL-код для каждого числа
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'В структуре котировок преобладают индексные продукты: только QQQ зафиксировал 5.23 миллионов обновлений, в то время как у NVDA — 1.8 миллионов. NVDA стала самой часто цитируемой отдельной акцией из проверенных нами — она опережает следующую по популярности бумагу на 0.67 миллионов обновлений. Полный перечень всех листингов по каждому тикеру не уместился бы в 30-секундный лимит, поэтому приведенная ниже таблица является проверенным набором данных, а не исчерпывающим рейтингом:
Точный SQL-код для каждого числа
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 возглавил проверенный список с показателем в 5.23 миллионов обновлений; в топе находятся индексные фонды и их кредитные аналоги, а не широко известные акции.
Анализ SPY: наносекундные данные и двусторонний спред
Точный SQL-код для каждого числа
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 orderedВ рамках только регулярных торговых сессий котировки SPY менялись 3.98 миллионов раз. Самая активная секунда — 10:15:43 ET, внутри отмеченной 10:15 минуты — содержала 1461 обновлений. Минимальный интервал между последовательными обновлениями составил 1375 наносекунд, медианный — 245.6 микросекунд, а 75138 пар последовательных обновлений имели идентичные наносекундные метки — даже наносекундного разрешения недостаточно для полной сортировки современного потока данных.
Эти наносекунды позволяют измерять бид-аск спред. Если учитывать каждое обновление равнозначно, средний спред SPY составил 2.72 цента; с учетом времени удержания каждой котировки он составил 2.34 цента. Механический показатель на одно обновление на 0.38 цента шире: обновления группируются именно в моменты, когда спред велик и нестабилен, в то время как неподвижный ордер существует в обычном временном измерении. При анализе статистики спреда важно понимать, по каким часам она рассчитана. Данные переписи открыты: 1544 обновлений в регулярные часы имели пересекающиеся цены (цена предложения ниже цены спроса из-за смешивания котировок с разных площадок), а 0 имели нулевой бид или аск; статистика спреда исключает оба этих случая и учитывает только то, что не попало в исключения.
Спред зависит от времени
Если распределить спред SPY по получасовым интервалам, микроструктура рынка превращается в график, пригодный для анализа:
Точный SQL-код для каждого числа
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_timeМедианное значение составляет 8 цента в интервале 04:00 ET (премаркет), 3 цента в интервале 09:30 (открытие) и 2 цента к 14:00. Покупка одной и той же акции на открытии премаркета обходится примерно в четыре раза дороже, чем исполнение ордера в начале послеобеденного периода. Спред не является константой; он подчиняется графику.
Анализ данных: файл, обрывающийся на букве S
Перед публикацией данных из ежедневного файла вендора мы проводим проверку на полноту: подсчитываем количество тикеров, проверяем алфавитный диапазон и сравниваем данные с соседними днями. Файл FINRA по внебиржевым коротким объемам от 29 июня служит примером необходимости такой проверки:
Точный SQL-код для каждого числа
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 dateФайл от 26 июня содержит 15052 тикеров, от A до ZYME. Файл от 29 июня содержит 5489 тикеров, от A до SSUS — он просто обрывается на именах, начинающихся на S. Все тикеры, идущие по алфавиту после этого момента, включая TSLA (на 29 июня — 0 строк против 1 на 26 июня), отсутствуют. К 30 июня количество тикеров в файле возвращается к 15362. Проверка на полноту — это не более чем сравнение ежедневных показателей; это разница между публикацией статистики и публикацией ошибочных данных.
С учетом этого уточнения приводится расчетное соотношение: объем маркированных коротких продаж составляет 45.85% от заявленного внебиржевого объема 29 июня, по сравнению с 46.89% 26 июня и 48.82% 30 июня. Показатель за 29 июня охватывает только сегмент от A до S, поэтому его следует рассматривать как неполные данные. Доля коротких продаж, близкая к половине, является стандартным уровнем для всех соседних сессий, и ежедневный объем коротких продаж не является short interest.
Примечания к данным
Полные примечания к данным
- Затишье в котировках с 17:00 до 18:00. Поток котировок SPY практически останавливается в получасе 17:00 ET (обновления 233) и возобновляется к 18:00 (40608). Это закономерность сессии и потока данных по всем тикерам, а не пропуск данных.
- Дробные акции встречаются повсеместно. 4.73% сделок имеют нецелые объемы; объем необходимо суммировать с учетом десятичных дробей.
- Словарь кодов использует одни и те же идентификаторы для разных типов. Идентификатор 15 является одновременно условием продажи (Market Center Official Close) и условием котировки (Closed). Каждый запрос к словарю в данном материале фильтрует по параметрам asset_class = 'stocks' AND type = 'sale_condition'. Поиск только по id приводит к неверной классификации кодов.
- Исключения по качеству котировок учитываются внутри данных. Данные по пересекающимся котировкам и нулевым спредам (bid/ask) содержатся в панели микроскопа SPY выше; статистика спреда не скрывает эти пропуски.
- Сканирование всей ленты доступно только в пакетном режиме. Рыночные блоки здесь измерялись примерно по 30 секунд каждый при холодном кэше (истекший по времени блок запрашивается повторно один раз; при прогретом кэше ограничение снимается); они запускаются один раз в момент подготовки материала через защищенный путь чтения; данные результаты являются окончательными.
Методология
- Временные метки хранятся в формате UTC и фильтруются по необработанным границам UTC (регулярные часы 29 июня — с 13:30 до 20:00 UTC); функция toTimeZone используется только в списках SELECT.
- Тип сессии проверяется по календарю праздников и фактическому 390-баровому окну регулярных торгов; тип сессии не определяется по умолчанию.
- «Объем, учтенный SIP (сопоставленный)» — это объем, который правила условий SIP включают в консолидированный итог; набор исключений выводится из словаря и ограничен контрольной суммой, а не прописан жестко.
- Статистика спреда на каждое обновление взвешивает каждое обновление NBBO одинаково; взвешенная по времени статистика взвешивает каждую котировку в зависимости от длительности ее действия. Оба метода раскрывают свои исключения.
- Столбцы десятичных цен/размеров суммируются нативно и преобразуются в 64-битные числа с плавающей запятой перед любыми арифметическими операциями (отношение или цена, умноженная на размер).
- Таблицы тиков сохраняют полную историю без скользящего срока действия; эти сохраненные версионные результаты являются окончательными данными. Состояние хранилища по состоянию на 3 июля 2026 года.
Каждая панель выше представляет собой один сохраненный объект — график, таблицу и SQL-запрос вместе. Вы можете открыть любой из них, скопировать запрос и продолжить работу в терминале Strasmore.