Strasmore Research
Market Recap

Marktoverzicht H1 2026

Matt ConnorBy Matt Connor Updated 2026-07-24

De eerste helft van 2026 bestond uit twee verschillende markten: een eerste kwartaal waarin elke belangrijke index ETF daalde of gelijk bleef, en een tweede kwartaal dat dit meer dan goedmaakte. SPY sloot de helft af met een stijging van 8.8%; QQQ steeg met 18.7%; en de 21.3% van IWM was de beste eerste helft die deze small-cap ETF heeft laten zien in onze dataset — de resultaten staan hieronder, opnieuw berekend tegenover elk vorig jaar in één query. De rentemarkt vertelde een eigen verhaal: de 2s10s spread vlakte gedurende de helft af van 72 basis points naar 30 zonder ooit te inverteren. Deze pagina bevat het volledige overzicht van de helft — de score, de historische rangschikking, de maandelijkse ontwikkeling, de volledige yield curve per looptijd, de elf sectoren, de maandelijkse evolutie van de options tape en de opvallende individuele aandelen van de helft. Elk getal hier is het resultaat van een opgeslagen query; klik op een paneel voor de SQL.

De helft op het bord

QueryH1 2026: half, Q1 en Q2 returns voor de vier index ETFs — berekend in één query
De exacte SQL achter elk getal
SELECT ticker,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-01-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS h1_return_pct,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-03-31') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-01-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q1_return_pct,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-04-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q2_return_pct,
    round(argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS h1_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
  AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY ticker
ORDER BY ticker

De verdeling over twee quarters bepaalt de vorm van de helft: SPY -5.2% gevolgd door 14.1%; QQQ -6.9% gevolgd door 26.5%. IWM was de stille leider van de helft in 21.3% — small caps presteerden beter dan elke large-cap index gedurende de zes maanden. De details per quarter staan in de Q2 recap. Een opmerking over de rekenkunde van halve jaren: de 8.8% van SPY voor de zes maanden is veel lager dan alleen het Q2, aangezien de helft een drawdown en een herstel combineert — de compounding van -5.2% en 14.1% komt overeen met de tabel, en elke kop over het 'rendement in het eerste halfjaar' verbergt die volledige beweging.

De helft tegen elke eerste helft op de tape

Is een 8.8% helft ongebruikelijk? De onderstaande panelen berekenen HETZelfde eerste-helft rendement — van de opening tot de sluiting tijdens reguliere handelsuren, van januari tot juni — voor elk jaar aan minuten-historie. Dit gebeurt in één query per ETF-paar met identieke rekenmethode voor elk jaar, waarna deze helft wordt gerangschikt tegenover de rest. De vroegste datum van de minuten-tape is verifieerd in de onderstaande methodologie; de eerste volledige eerste helft in de database is de helft die in de gegevens wordt genoemd.

QueryElke eerste half op de tape: SPY en QQQ, identiek herberekened per jaar (per-year session counts getoond)
De exacte SQL achter elk getal
SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
       ticker,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
       round((argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100, 1) AS h1_return_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
  AND window_start >= toDateTime('2003-01-01 00:00:00')
  AND window_start < toDateTime('2026-07-01 00:00:00')
  AND toMonth(toTimeZone(window_start, 'America/New_York')) <= 6
  AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY y, ticker
HAVING sessions >= 100
ORDER BY y ASC, ticker ASC
QueryDe rank receipts: deze half tegenover elke voorgaande half (SPY en QQQ; rank 1 = best; zelf uitgesloten)
De exacte SQL achter elk getal
SELECT ticker,
       round(anyIf(ret, y = 2026), 1) AS h1_2026_pct,
       arrayCount(x -> x > anyIf(ret, y = 2026), groupArrayIf(ret, y != 2026)) + 1 AS rank_best,
       count() AS halves_compared,
       min(y) AS first_year,
       anyIf(sessions, y = 2026) AS sessions_2026
FROM (
    SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
           ticker,
           uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
           (argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100 AS ret
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'QQQ')
      AND window_start >= toDateTime('2003-01-01 00:00:00')
      AND window_start < toDateTime('2026-07-01 00:00:00')
      AND toMonth(toTimeZone(window_start, 'America/New_York')) <= 6
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY y, ticker
    HAVING sessions >= 100
)
GROUP BY ticker
ORDER BY ticker ASC

De 8.8% van SPY staat op de 6e plaats van 23 eerste helften sinds 2004 (rang 1 = beste) — de bovenste derde, maar geen record. De 18.7% van QQQ staat op de 3e plaats van 16 vergelijkbare helften — de QQQ-reeks is korter — het fonds handelde gedurende enkele jaren onder een andere root symbol — en elk jaar met minder dan honderd eerste-helft sessies voor een symbool wordt uitgesloten door een limiet op het aantal sessies, zoals getoond in de tabel; uitsluitingen zijn dus zichtbaar in plaats van onzichtbaar.

QueryElke eerste half op de tape: DIA en IWM, dezelfde rekenmethode
De exacte SQL achter elk getal
SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
       ticker,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
       round((argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100, 1) AS h1_return_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('DIA', 'IWM')
  AND window_start >= toDateTime('2003-01-01 00:00:00')
  AND window_start < toDateTime('2026-07-01 00:00:00')
  AND toMonth(toTimeZone(window_start, 'America/New_York')) <= 6
  AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY y, ticker
HAVING sessions >= 100
ORDER BY y ASC, ticker ASC
QueryDe rank receipts: DIA en IWM tegenover elke voorgaande eerste half (rank 1 = best; zelf uitgesloten)
De exacte SQL achter elk getal
SELECT ticker,
       round(anyIf(ret, y = 2026), 1) AS h1_2026_pct,
       arrayCount(x -> x > anyIf(ret, y = 2026), groupArrayIf(ret, y != 2026)) + 1 AS rank_best,
       count() AS halves_compared,
       min(y) AS first_year,
       anyIf(sessions, y = 2026) AS sessions_2026
FROM (
    SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
           ticker,
           uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
           (argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100 AS ret
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('DIA', 'IWM')
      AND window_start >= toDateTime('2003-01-01 00:00:00')
      AND window_start < toDateTime('2026-07-01 00:00:00')
      AND toMonth(toTimeZone(window_start, 'America/New_York')) <= 6
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY y, ticker
    HAVING sessions >= 100
)
GROUP BY ticker
ORDER BY ticker ASC

De rij voor small-cap is het belangrijkste resultaat: IWM staat op de 1e plaats van 23 eerste helften sinds 2004 — het beste resultaat in de geschiedenis voor dit fonds, hoger dan elke andere herstel-helft in de tabel. De 8.4% van DIA staat op de 4e plaats van 23. De basis, simpel uitgelegd: de prestatie van de opening tot de sluiting tijdens reguliere handelsuren binnen elke kalender-eerste-helft, met een identieke rekenmethode voor elk jaar. De bovengrens is vastgesteld op het einde van deze periode, zodat de vergelijkingsset niet ongemerkt groeit wanneer latere jaren worden toegevoegd.

Maand voor maand

QueryDe half, maand voor maand (SPY en QQQ, identiek herberekend in één query)
De exacte SQL achter elk getal
SELECT toString(toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York')))) AS period_start, ticker,
    round((argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / argMinIf(toFloat64(open), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS month_return_pct,
    round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS month_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
  AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY period_start, ticker
ORDER BY period_start, ticker

De koers beweegt licht omhoog, daalt, daalt, stijgt scherp, stijgt, daalt licht: april was het omslagpunt van de helft (SPY 9.9%, QQQ 14.8% — de beste maand voor QQQ in deze zes maanden), en juni sloot de helft rustig af op -1.2% voor SPY. Een overzicht van juni, inclusief de marktbreedte achter dat rustige cijfer, vindt u hier. De tabel maand voor maand gelezen: het jaar begon nagenoeg vlak (SPY 0.9% in januari), daalde gedurende februari (-0.5%) en maart (-4.2%), waarna april de trend in één maand omkeerde, mei deze voortzette (4.9%) en juni afvlakte. Drie van de zes maanden waren negatief — een verdeling van vijfzig-vijftig voor een helft die solide positief eindigde, wat de gebruikelijke vorm van equity-periodes is en relevant is wanneer één enkele maand als definitief oordeel wordt gezien.

Rentes: de volledige curve, per looptijd

De Treasury curve vertoonde gedurende de helft een twist in plaats van een verschuiving. Het uiterste begin van de curve — de looptijden die de rentepolitiek het nauwst volgen — bewoog nauwelijks; de tweejaarige steeg met twee derde van een percentagepunt; de dertigjarige bleef vrijwel ongewijzigd. Het panel presenteert de volledige curve, van het begin van de helft tot het einde.

QueryZeven maturities: yield aan het begin van de half versus het einde, en de verandering
De exacte SQL achter elk getal
SELECT maturity, start_pct, end_pct, round((end_pct - start_pct) * 100, 0) AS change_bp FROM (
    SELECT '1-month' AS maturity, (SELECT round(argMin(yield_1_month, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_1_month)) AS start_pct, (SELECT round(argMax(yield_1_month, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_1_month)) AS end_pct, 1 AS o
    UNION ALL SELECT '3-month', (SELECT round(argMin(yield_3_month, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_3_month)), (SELECT round(argMax(yield_3_month, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_3_month)), 2
    UNION ALL SELECT '1-year', (SELECT round(argMin(yield_1_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_1_year)), (SELECT round(argMax(yield_1_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_1_year)), 3
    UNION ALL SELECT '2-year', (SELECT round(argMin(yield_2_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_2_year)), (SELECT round(argMax(yield_2_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_2_year)), 4
    UNION ALL SELECT '5-year', (SELECT round(argMin(yield_5_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_5_year)), (SELECT round(argMax(yield_5_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_5_year)), 5
    UNION ALL SELECT '10-year', (SELECT round(argMin(yield_10_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_10_year)), (SELECT round(argMax(yield_10_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_10_year)), 6
    UNION ALL SELECT '30-year', (SELECT round(argMin(yield_30_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_30_year)), (SELECT round(argMax(yield_30_year, date), 2) FROM global_markets.treasury_yields WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30') AND isNotNull(yield_30_year)), 7
) ORDER BY o

Lees de kolom met de verandering van boven naar beneden en de twist is onmiskenbaar: de 1-month bewoog -2 basis points in zes maanden, terwijl de 2-year steeg met 67 en de 30-year slechts met 5. Een parallelle shift verplaatst elke looptijd gelijktijdig; deze helft bewoog het midden van de curve en hield beide uiteinden vast — de korte rentes bleven verankerd nabij de rentepolitiek, terwijl de lange rentes nauwelijks werden herprijsd.

What that did to the slope

QuerySlope receipts: begin, einde, minimum — de spread is deze half nooit geïnverteerd
De exacte SQL achter elk getal
SELECT
    round((argMin(yield_10_year - yield_2_year, date)) * 100, 0) AS start_bp,
    round((argMax(yield_10_year - yield_2_year, date)) * 100, 0) AS end_bp,
    round(min((yield_10_year - yield_2_year)) * 100, 0) AS min_bp,
    count() AS prints
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30')
  AND isNotNull(yield_10_year) AND isNotNull(yield_2_year)

The short end rising faster than the long end is what a flattening IS: the 2s10s spread ground down from 72 to 30 basis points across 124 prints — and its lowest print of the half was 27, so the curve flattened without ever inverting. Whether a flatter curve "means" anything about what comes next is a forecast, and this table doesn't make forecasts.

QueryDe 2s10s spread, elke print van de half
De exacte SQL achter elk getal
SELECT toString(date) AS d, round((yield_10_year - yield_2_year) * 100, 0) AS spread_2s10s_bp
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30')
  AND isNotNull(yield_10_year) AND isNotNull(yield_2_year)
ORDER BY date

The daily series shows the flattening was not one event but a grind — 124 prints stepping down through the half, with the spread starting the year at 72 basis points and ending at 30.

Sectoren: de dispersie die de index verborg

Welke onderdelen van de markt hebben het geld van de eerste helft daadwerkelijk opgeleverd? De elf SPDR sector ETF's, verdeeld over de helft en het kwartier, één query.

QueryDe elf sector ETFs: H1 2026 return, Q1 en Q2 split, en H1 dollar volume
De exacte SQL achter elk getal
SELECT ticker,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-01-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS h1_return_pct,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-03-31') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-01-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q1_return_pct,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-04-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q2_return_pct,
    round(sumIf(toFloat64(close) * toFloat64(volume), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / 1e9, 1) AS h1_dollar_bn
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('XLB', 'XLC', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')
  AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY ticker
ORDER BY ticker

De dispersie is de kern: technologie (XLK) sloot de helft met een stijging van 30.8% — met een 42% tweede kwartaal — terwijl communication services (XLC) op -9.3% eindigde, een spread van ongeveer veertig procentpunt tussen de beste en slechtste sector in zes maanden. "De markt" bezitten betekende beide uitersten bezitten. Energie (XLE) dient als waarschuwing voor lange periodes: XLE laat een gezonde 18.8% helft zien — opgebouwd uit een 36.9% eerste kwartaal gevolgd door een -11% tweede. Het was de sterkste grote sector in het kwartaal waarin de indexes daalden, en behoorde tot de zwakste in het kwartaal waarin ze herstelden. Financials (XLF) vertoonde hetzelfde verloop in omgekeerde volgorde: -9.9% in Q1, gevolgd door 7.7% in Q2. Eén enkel H1-cijfer vlakt beide bewegingen af; de verdeling per kwartaal geeft het eerlijke beeld.

De kosten voor het verhandelen van elke sector

Rendementstabellen zijn overal aanwezig; quote tapes niet. Dit paneel meet de mediane bid-ask spread van elke sector ETF gedurende één volledige representatieve sessie — 123 sessies in het halfjaar, waarbij 29 juni de sessie is die hier wordt gemeten en als zodanig is gelabeld — gebaseerd op elke NBBO-update van die dag.

QueryMediane quoted spread per sector ETF, één representatieve session (29 juni 2026), regular hours
De exacte SQL achter elk getal
SELECT ticker,
    round(quantileDeterministicIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, toUInt64(toUnixTimestamp64Micro(sip_timestamp)), bid_price > 0 AND ask_price >= bid_price), 2) AS med_spread_bps,
    round(count() / 1e6, 2) AS quote_updates_m,
    countIf(NOT (bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price)) AS invalid_dropped
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('XLB', 'XLC', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')
  AND sip_timestamp >= toDateTime64('2026-06-29 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-06-29 20:00:00', 9)
GROUP BY ticker
ORDER BY med_spread_bps

Elke van de elf quotes ligt op enkele basis points of minder — de laagste is 0.62 bps (XLV), de hoogste is 2.23 bps (XLRE) — wat de praktische betekenis is van "sector ETF's zijn liquide": de kosten voor het aangaan van een sectorpositie worden gemeten in honderdsten van een procent. Ter vergelijking met individuele aandelen, meet de diepgaande analyse van 29 juni de spread van een minder liquide aandeel op honderden malen deze niveaus, binnen dezelfde sessie.

Breedte over de helft

De breedte op halve schaal bestaat hier uit twee componenten. De grove component: SPY noteerde 64 stijgende sessies tegenover 59 dalende sessies over de 123 van de helft — bijna een 50/50 verdeling van dagen binnen een solide positieve helft, wat kenmerkend is voor een langzame stijging in de dagelijkse koersverloop. De fijne component — waarbij elke ticker wordt meegeteld — bevindt zich op maandelijkse schaal: de advancer/decliner verhouding van juni staat in het juni overzicht (daar vielen meer tickers dan dat ze stegen), en de telling voor de kwartaalgrens staat in het Q2 overzicht. Een volledige scan van de markt-brede advancers over zes maanden overschrijdt het querybudget dat deze pagina genereert; die limiet wordt hier vermeld in plaats van de selectie stilzwijgend te verkleinen.

QuerySPY sessions up vs down gedurende de half, één goedkope receipt
De exacte SQL achter elk getal
SELECT countIf(day_ret > 0) AS up_sessions,
       countIf(day_ret < 0) AS down_sessions,
       countIf(day_ret = 0) AS flat_sessions,
       count() AS sessions_total
FROM (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           round((argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100, 2) AS day_ret
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND window_start < toDateTime('2026-07-01 00:00:00')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
)

De options tape, maand voor maand

Wat een halfjaaroverzicht kan laten zien: de evolutie van de options tape zelf. Elk paneel hieronder bevat een volledige scan van een maand — het totale contractvolume en het aandeel dat op de eigen expiratiedag werd verhandeld (0DTE). De trend: het volume steeg van 1316.1 miljoen contracten in januari naar 1477.9 miljoen in juni — de drukste maand voor options in het halfjaar — en het aandeel van same-day-expiry steeg van 26.5% in januari naar 34.3% in juni, de hoogste maand van het halfjaar. Een derde van het optionsvolume in juni werd verhandeld in contracten die op diezelfde dag afliepen.

QueryJanuari: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-01-01 00:00:00')
  AND window_start < toDateTime('2026-02-01 00:00:00')
QueryFebruari: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-02-01 00:00:00')
  AND window_start < toDateTime('2026-03-01 00:00:00')
QueryMaart: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-03-01 00:00:00')
  AND window_start < toDateTime('2026-04-01 00:00:00')
QueryApril: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-04-01 00:00:00')
  AND window_start < toDateTime('2026-05-01 00:00:00')
QueryMei: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-05-01 00:00:00')
  AND window_start < toDateTime('2026-06-01 00:00:00')
QueryJuni: whole-tape options contract volume en same-day-expiry share (één scan)
De exacte SQL achter elk getal
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
       round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
       uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-06-01 00:00:00')
  AND window_start < toDateTime('2026-07-01 00:00:00')

De handelskosten, maandelijks gesampled

QuerySPY median quoted spread op één gelabelde sample session per maand (tweede woensdag), elke NBBO update
De exacte SQL achter elk getal
SELECT toDate(toTimeZone(sip_timestamp, 'America/New_York')) AS session,
       round(quantileDeterministicIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, toUInt64(toUnixTimestamp64Micro(sip_timestamp)), bid_price > 0 AND ask_price >= bid_price), 3) AS med_spread_bps,
       round(count() / 1e6, 2) AS quote_updates_m,
       countIf(NOT (bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price)) AS invalid_dropped
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY'
  AND ((sip_timestamp >= toDateTime64('2026-01-14 14:30:00', 9) AND sip_timestamp < toDateTime64('2026-01-14 21:00:00', 9))
    OR (sip_timestamp >= toDateTime64('2026-02-11 14:30:00', 9) AND sip_timestamp < toDateTime64('2026-02-11 21:00:00', 9))
    OR (sip_timestamp >= toDateTime64('2026-03-11 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-03-11 20:00:00', 9))
    OR (sip_timestamp >= toDateTime64('2026-04-15 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-04-15 20:00:00', 9))
    OR (sip_timestamp >= toDateTime64('2026-05-13 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-05-13 20:00:00', 9))
    OR (sip_timestamp >= toDateTime64('2026-06-10 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-06-10 20:00:00', 9)))
GROUP BY session
ORDER BY session ASC

De mediane quoted spread van SPY op de tweede woensdag van elke maand: 0.145 bps in de januari-sample, 0.144 in februari, ongeveer het dubbele gedurende de samples in het voorjaar, en 0.409 bps in de juni-sample — de breedste van de zes. Basis: dit zijn single labeled sample sessies (de tweede woensdag van elke maand), geen medianen over de gehele maand — een scan van de hele quote-tape gedurende zes maanden overschrijdt het querybudget van deze pagina. De sample-data staan in de tabel, en ongeldige quotes worden daar geteld in plaats van dat ze stilzwijgend worden verwijderd.

De meest opvallende namen van het halfjaar

Gemeten op basis van relevantie, niet op redactionele keuze: de onderstaande lijst bevat de top van de dollar-volume leaderboard voor dit kwartaal. Deze lijst is hier opnieuw berekend voor verificatie, en elke naam die een diepgaande analyse heeft, linkt daarnaar.

QueryQ2 regular-hours dollar volume, whole tape (één lijst met hergebruikte symbolen uitgesloten in afwachting van entiteitsverificatie)
De exacte SQL achter elk getal
SELECT ticker,
    round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 1) AS dollar_bn,
    round(100 * sum(toFloat64(close) * toFloat64(volume)) / max(sum(toFloat64(close) * toFloat64(volume))) OVER (), 1) AS pct_of_leader
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= toDateTime('2026-04-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
  AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
  AND ticker NOT IN ('SPCX')
GROUP BY ticker
ORDER BY dollar_bn DESC
LIMIT 8

MU had een groter handelsvolume dan SPY in het tweede kwartaal ($2047.5 miljard tegenover $2032 miljard) — dezelfde gegevens als in de Q2 recap. Voor de zes individuele aandelen in die toplijst voor het halfjaar:

QueryDe leader set's half en Q2 returns plus half dollar volume — één ticker-gefilterde query
De exacte SQL achter elk getal
SELECT ticker,
    round((argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS h1_return_pct,
    round((argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
         / argMinIf(toFloat64(open), window_start, window_start >= toDateTime('2026-04-01 00:00:00') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q2_return_pct,
    round(sumIf(toFloat64(close) * toFloat64(volume), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / 1e9, 1) AS h1_dollar_bn
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('MU', 'NVDA', 'TSLA', 'SNDK', 'AMD', 'INTC')
  AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY ticker
ORDER BY ticker

De geheugen- en halfgeleiderssector domineert het halfjaar: SNDK leverde 830.1% rendement in zes maanden, MU 290% — deze analyse dissecteert de juni-prestaties tick voor tick — en INTC 269.3%. NVDA, de grootste in de set met een halfjaarlijkse omzet van $3287.9 miljard, leverde 5.2% rendement — een enkel cijfer terwijl de geheugen-aandelen zich vermenigvuldigden; deze juni deep-dive bevat die divergentie per sessie. TSLA is de enige daler in de set met -8.2%. De grote notering van juni wordt verhandeld onder een hergebruikt symbool en is uitgesloten van de leader scans in afwachting van verificatie van de entiteit — deze eerste maand heeft een eigen post per transactie. Basis: de leader SET is gekozen op basis van de dollar volume tijdens reguliere handelsuren in Q2 (de bovenstaande scan); de rendementscolommen betreffen het halfjaar, van de eerste opening tot de laatste sluiting tijdens reguliere handelsuren.

De IPO-golf van het eerste deel, maand voor maand

QueryNieuwe listings per maand gedurende de half
De exacte SQL achter elk getal
SELECT toString(toStartOfMonth(listing_date)) AS m, count() AS listings
FROM global_markets.stocks_ipos
WHERE listing_date >= toDate('2026-01-01') AND listing_date <= toDate('2026-06-30')
GROUP BY m
ORDER BY m

De golf van beursgangen was aan het begin geconcentreerd en ongelijkmatig: februari was de drukste maand van het deel met 47 listings en maart de rustigste met 17 — de bekende mega-listing in juni vond plaats in een maand met verder een normale volume (35 listings).

De kalender van het halve jaar

QueryH1 2026 corporate kalender (alle drie de maandelijkse filing-index gaps onthuld)
De exacte SQL achter elk getal
SELECT
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-01-01') AND ex_dividend_date <= toDate('2026-06-30')) AS ex_div_events,
    (SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-01-01') AND execution_date <= toDate('2026-06-30')) AS splits,
    (SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-01-01') AND listing_date <= toDate('2026-06-30')) AS ipos,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date >= toDate('2026-01-01') AND filing_date <= toDate('2026-06-30')) AS h1_filings,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-03-31')) AS filings_mar31,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-04-30')) AS filings_apr30,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-30')) AS filings_jun30

205 bedrijven gingen in het halve jaar naar de beurs — een golf van beursgangen waarbij de grootste debuut in juni een eigen overzicht per ontvangst heeft — naast 830 splits en 28356 ex-dividend gebeurtenissen. Ter vergelijking: dit is meer dan één nieuwe beursgang per handelsdag gedurende het halve jaar. Het totaal aantal indieningen bevat een drievoudige discrepantie: de SEC-index is vrijwel leeg op elke maand-einde van het halve jaar waarvan de laatste kalenderdag een werkdag was (55 indieningen op 31 maart, 34 op 30 april, en 31 op 30 juni, tegenover duizenden op de omliggende dagen), waardoor de aantallen indieningen voor het halve jaar worden onderschat totdat de feed wordt aangevuld — het maand-einde gat heeft een eigen diagnostische notitie.

Het sessieoverzicht

Query123 sessions in de half, geverifieerd van de tape
De exacte SQL achter elk getal
SELECT
    (SELECT uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) FROM global_markets.delayed_stocks_minute_aggs
     WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')) AS h1_sessions

Datanotities

Volledige datanotities
  • Short interest eindigt op de settlement van 15 juni op het moment van generatie (de print van eind juni is nog in afwachting — volledige toelichting in de juni recap; dit bericht wordt opnieuw gegenereerd zodra deze beschikbaar is).
  • Drie maandelijkse indieningsdagen voor 2026 zijn nagenoeg leeg (31 maart, 30 april, 30 juni — elke maandelijkse afsluiting van het halfjaar waarvan de laatste kalenderdag een werkdag was); de gegevens zijn opgenomen bij de tellingen, zoals geanalyseerd in de maandelijkse gap note. De maandelijkse afsluitingen van het voorgaande jaar bevatten duizenden indieningen, dus dit is een gat in de feed en geen feestdag voor indieningen.
  • De leaderboard op half jaar schaal is begrensd: een marktbrede scan over zes maanden overschrijdt het querybudget dat deze pagina genereert, dus de set met belangrijke namen wordt gekozen op basis van de getoonde kwartaal-schaal scan, en de rendementen voor het halfjaar worden berekend voor deze vaste set — de basis hiervoor wordt vermeld waar deze wordt gebruikt. De Q2 en juni recaps bevatten de volledige leader tables op hun respectievelijke schalen.
  • De marktbrede breadth op half jaar schaal is eveneens begrensd — de dagelijkse verdeling wordt getoond; de tellingen op ticker-niveau zijn beschikbaar op maand- en kwartaalschaal en zijn gekoppeld in de breadth sectie.
  • De QQQ historie serie is korter dan die van SPY: het fonds werd gedurende een periode van jaren verhandeld onder een andere root symbol; de sessie-count guard sluit die jaren zichtbaar uit (sessie-aantallen per jaar staan in de tabel).
  • De zes optie panels zijn maandelijkse scans van de volledige tape en de spread trend samples één gelabelde sessie per maand — beide worden via het batch pad uitgevoerd; de sample bases worden ter plaatse vermeld.
  • Microstructure is opgenomen in de deep-dive van 29 juni.

Methodologie

  • De periode betreft 1 januari – 30 juni 2026 — 123 sessies, geverifieerd op basis van geobserveerde bars. De returns worden berekend van de opening van de reguliere handel tot de sluiting van de reguliere handel binnen elk venster, conform de getoonde queries.
  • Historische vergelijkingen worden LIVE opnieuw berekend tegen de volledige minutenhistorie op het moment van generatie — er wordt nooit gelezen uit opgeslagen waarden. Diepteverificatie: de vroegste datum van de minuten-bar in de vertraagde weergave die hier wordt gebruikt, komt overeen met de basis tabel (september 2003), gecontroleerd tijdens de redactie; de eerste volledige eerste helft in de database is die van 2004. Elke historie-query stelt de bovengrens vast op de einddatum van deze periode (de vergelijkingsset kan niet groeien wanneer latere jaren worden toegevoegd) en hanteert een minimum-sessie limiet met de getoonde sessie-aantallen per jaar.
  • Timestamps worden opgeslagen in UTC met ruwe UTC-grenzen. Meerjarige historie-blokken filteren de reguliere uren op basis van de Eastern wall clock (9:30–15:59, per rij geconverteerd — de enige DST-veilige conventie over decennia heen); blokken met één venster in EDT-only ranges gebruiken de equivalente ruwe UTC-band. Beide conventies worden hier vermeld.
  • De generatie vindt plaats via het beveiligde read-only pad; de publieke pagina voert nooit live queries uit. Status van het warehouse per 5 juli 2026.

Dit is de eerste editie van de periodieke halfjaarlijkse recap; de editie voor het volledige jaar volgt in januari. Kwartaaldetails: Q2 2026. De macro-cijfers waartegen de helft is verhandeld, staan in het macrobeeld.