Strasmore Research
Deep dive investigation Matt ConnorBy Matt Connor · Updated 2026-07-25

Feb 24, 2022: War Open, Green Close for US Stocks

February 24, 2022: Russia invade Ukraine, US stocks gap down but close green. See di full reversal, plus oil, gold, defense stocks, bonds and wetin happen after.

For early hours of February 24, 2022, Russia start dia full-scale invasion of Ukraine — and di US stock market produce one of di most-studied sessions of di decade. Index futures fall well-well overnight, di Nasdaq-100 ETF QQQ open -3.2% down — and close +3.4%. Dis page dey receipt di whole event: di reversal minute by minute, wetin di S&P 500 and Dow do, where oil, gold, defense stocks, Treasuries and volatility go, and wetin di weeks after be like. Every number na stored query; expand any panel for di SQL.

Before market open: how night take waka

Di invasion no just show from nowhere. For late 2021 and early 2022, Russia gada plenty troops near Ukraine border — Western estimates for dat time talk say e pass 100,000 — and markets don dey trade di risk for weeks. On Monday, February 21, Moscow come recognize di two separatist republics wey dem don declare for eastern Ukraine; US markets close dat day because of Washington Birthday holiday, so di first session wey fit price di news na Tuesday 22nd, and e red well well. Di first batch of Western sanctions land dat same Tuesday, plus Germany halt di certification of Nord Stream 2 pipeline.

Den, small before 6 a.m. Moscow time on Thursday, February 24 — wey be around 10 p.m. Wednesday evening for New York — Russia president announce di operation, and within one hour, dem start hear explosions for different Ukrainian cities. US index futures, wey dey trade through night, sell off sharp sharp. By sunrise, di only question wey remain na how far below Wednesday close di 9:30 a.m. opening auction go print.

Di day, for one row

One row get di whole answer — prior close, gap, low, high, close, and volume:

QueryQQQ for February 24, 2022 — di invasion-day reversal, wey don receipt
The exact SQL behind every number
WITH
    (
        SELECT argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'QQQ'
          AND window_start >= toDateTime('2022-02-23 00:00:00') AND window_start < toDateTime('2022-02-24 04:00:00')
    ) AS prior_rth_close
SELECT
    round(prior_rth_close, 2) AS prior_close,
    round(toFloat64(argMinIf(open, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)), 2) AS rth_open,
    round((toFloat64(argMinIf(open, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / prior_rth_close - 1) * 100, 1) AS gap_pct,
    round(minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS rth_low,
    formatDateTime(toTimeZone(argMinIf(window_start, (toFloat64(low), toInt64(toUnixTimestamp(window_start))), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 'America/New_York'), '%H:%i') AS low_et,
    round(maxIf(toFloat64(high), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS rth_high,
    round(toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)), 2) AS rth_close,
    round((toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / prior_rth_close - 1) * 100, 1) AS day_change_pct,
    round((minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / prior_rth_close - 1) * 100, 1) AS low_vs_prior_pct,
    round((toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS trough_to_close_pct,
    round((maxIf(toFloat64(high), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) - 1) * 100, 2) AS close_to_high_pct,
    round((toFloat64(argMinIf(open, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 2) AS open_above_low_pct,
    round(toFloat64(sum(volume)) / 1e6, 1) AS day_shares_m,
    countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS rth_minute_bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'QQQ'
  AND window_start >= toDateTime('2022-02-24 04:00:00') AND window_start < toDateTime('2022-02-24 23:59:00')

Di receipt wey everybody suppose sit with: di session low of $318.26 print for 09:30 ET — di opening minute-3.4% below di prior close. From dat first print, QQQ climb for six and a half hours and finish for $340.65: +3.4% for di day, a 7% swing trough-to-close on 128 million shares. And di close no be fade-into-di-bell: e land just 0.11% under di session high of $341.04, wey mean say di day end essentially for im top. Anybody wey sell for dat first minute of trading sell within 0.18% of di session ultimate low — di actual bottom tick print moments after di opening cross, no be for am (di auction print na $318.84; di low, $318.26).

Di reversal, bucket by bucket

Half-hour buckets show di shape of di climb:

QueryQQQ by half-hour — February 24, 2022 regular session
The exact SQL behind every number
SELECT
    formatDateTime(toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
    round(toFloat64(argMax(close, window_start)), 2) AS bucket_close,
    round(min(toFloat64(low)), 2) AS bucket_low,
    round(toFloat64(sum(volume)) / 1e6, 1) AS shares_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'QQQ'
  AND window_start >= toDateTime('2022-02-24 04:00:00') AND window_start < toDateTime('2022-02-24 23:59:00')
  AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY et_time
ORDER BY et_time

Di staircase no clean perfectly — di 12:00 ET bucket close at $328.03, under di 11:30 close of $330.29 — but di direction never really flip, and di final bucket close at $340.65, di top of di table. Volume trace di usual U: 18.6 million shares for di opening half hour and 15 million for di last one, against 4.7 million around lunch. E be di mirror image of 2011 staircase wey go down. Sessions like dis na why "di market fall on di invasion" retellings dey mislead: di futures fall overnight; di cash session rally from im first minute. Which one you experience depend entirely on when your orders arrive — di theme overnight gaps dey measure on calmer weeks.

No be only Nasdaq: di whole market turn around

If na only one index dem tell you about, you go still dey ask: na only growth-stock get dis kain wahala, or di whole market turn around? Di panel wey dey below put eleven tickers for one measurement — di three major index ETFs, den di assets wey geopolitical-shock playbook dey reach for: energy, gold, long Treasuries, one volatility ETF, and four defense contractors.

QueryEleven tickers for February 24, 2022 — gap, intraday extremes, close (% vs prior close)
The exact SQL behind every number
SELECT
    ticker,
    round(prior_close, 2) AS prior_close,
    round((rth_open / prior_close - 1) * 100, 1) AS gap_pct,
    round((rth_low / prior_close - 1) * 100, 1) AS low_vs_prior_pct,
    round((rth_high / prior_close - 1) * 100, 1) AS high_vs_prior_pct,
    round((rth_close / prior_close - 1) * 100, 1) AS day_change_pct
FROM (
    SELECT
        ticker,
        argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2022-02-23')) AS prior_close,
        argMinIf(toFloat64(open), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2022-02-24')) AS rth_open,
        minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2022-02-24')) AS rth_low,
        maxIf(toFloat64(high), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2022-02-24')) AS rth_high,
        argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2022-02-24')) AS rth_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('QQQ', 'SPY', 'DIA', 'XLE', 'GLD', 'TLT', 'VIXY', 'LMT', 'NOC', 'RTX', 'GD')
      AND window_start >= toDateTime('2022-02-23 00:00:00') AND window_start < toDateTime('2022-02-24 23:59:00')
    GROUP BY ticker
)
ORDER BY indexOf(['QQQ', 'SPY', 'DIA', 'XLE', 'GLD', 'TLT', 'VIXY', 'LMT', 'NOC', 'RTX', 'GD'], ticker)

Di reversal happen for di whole market, but di size no just follow how deep di morning gap be: QQQ gap -3.2% for open and close +3.4%. SPY and DIA gap by almost di same amount — -2.6% and -2.6% each — but SPY close +1.5% against DIA own +0.3%, wey barely green. Di index wey get plenty growth stocks turn around di most; di Dow wey heavy for industrials, di least — na composition, no be gap size, separate SPY from DIA.

Where the money waka go: oil, gold, defense, volatility

Now read the lower rows of the same panel — the "war trade". Energy open for im highs and close red: XLE gapped +2.1%, trade as deep as -3.4% below the prior close intraday, and finish -0.9%. Gold do the same round trip: GLD open +2.4% and close -0.6%. VIXY — na ETF wey hold short-term VIX futures, the closest tradable proxy for the volatility index — gapped +11.1% for open and close -3%, below the prior day close. The classic fear assets peak exactly when the headlines worst and fade alongside the equity recovery: the equity reversal, inverted.

The defense contractors na the exception wey hold. All four close green — LMT +1.7%, NOC +2.4%, RTX +2.1%, GD +1.1% — and Northrop Grumman never print below Wednesday close for the whole session (im intraday low na +1%), the only one of the four wey no touch red.

Treasuries: di safe-haven flow come later

As Treasury yield dey fall, e mean say people dey bid bond prices go up — di textbook safe-haven flow. For di invasion day sef, dat flow no really show for close:

Query2-year and 10-year Treasury yields, February 18 – March 8, 2022 (%)
The exact SQL behind every number
SELECT
    toString(date) AS session,
    round(yield_2_year, 2) AS yield_2_year,
    round(yield_10_year, 2) AS yield_10_year
FROM global_markets.treasury_yields
WHERE date BETWEEN '2022-02-18' AND '2022-03-08'
ORDER BY date

Di 10-year yield close at 1.96% for February 24, e just dey under di 1.99% wey di day before carry. Di real flight come di next week: by 2022-03-01 di 10-year print 1.72% — di lowest close for dis window — and di 2-year fall from 1.58% go 1.31% over di same stretch. TLT, di long-Treasury ETF wey dey di panel up, tell di intraday version of di same story: a +1.8% gap for open wey later fade go +0.2% by di time dem close.

Di days wey surround am

Three weeks of daily closes put di reversal for context — and quietly settle whether e hold:

QueryQQQ daily closes, February 22 – March 14, 2022
The exact SQL behind every number
SELECT
    toString(et_date) AS session,
    close_usd,
    round(if(prev_close = 0, NULL, (close_usd / prev_close - 1) * 100), 1) AS change_pct,
    shares_m
FROM (
    SELECT et_date, close_usd, shares_m,
           lagInFrame(close_usd) OVER (ORDER BY et_date ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
    FROM (
        SELECT
            toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
            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 close_usd,
            round(toFloat64(sum(volume)) / 1e6, 1) AS shares_m
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'QQQ'
          AND window_start >= toDateTime('2022-02-18 00:00:00') AND window_start < toDateTime('2022-03-15 23:59:00')
        GROUP BY et_date
    )
)
WHERE et_date >= toDate('2022-02-22') AND et_date <= toDate('2022-03-14')
ORDER BY et_date

Di sessions before di invasion na red (-1% and -2.6% for February 22–23) as di buildup dominate headlines, and di invasion day itself close +3.4%, follow by another +1.5% di next day. Markets wey dey fall on di threat and rally on di event na pattern wey old reach to get Wall Street proverb attach to am, and dis tape na im cleanest modern receipt. But keep reading di table: e end at $318.21 on 2022-03-14 — below where di invasion morning panic print.

Di rally hold?

No — and now di claim get receipt:

QueryAfter di reversal: when QQQ break di invasion-day low, and how far e fall
The exact SQL behind every number
WITH
    daily AS (
        SELECT
            toDate(toTimeZone(window_start, 'America/New_York')) AS d,
            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 c
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'QQQ'
          AND window_start >= toDateTime('2022-02-24 04:00:00') AND window_start < toDateTime('2023-01-01 00:00:00')
        GROUP BY d
    ),
    (SELECT c FROM daily WHERE d = toDate('2022-02-24')) AS invasion_close,
    (
        SELECT round(minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2)
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'QQQ'
          AND window_start >= toDateTime('2022-02-24 04:00:00') AND window_start < toDateTime('2022-02-24 23:59:00')
    ) AS invasion_low
SELECT
    invasion_close,
    invasion_low,
    toString(minIf(d, c < invasion_low AND d > toDate('2022-02-24'))) AS first_close_below_invasion_low,
    dateDiff('day', toDate('2022-02-24'), minIf(d, c < invasion_low AND d > toDate('2022-02-24'))) AS calendar_days_to_new_low,
    round(minIf(c, d BETWEEN toDate('2022-02-25') AND toDate('2022-03-31')), 2) AS march_low_close,
    toString(argMinIf(d, (c, d), d BETWEEN toDate('2022-02-25') AND toDate('2022-03-31'))) AS march_low_date,
    round((minIf(c, d BETWEEN toDate('2022-02-25') AND toDate('2022-03-31')) / invasion_close - 1) * 100, 1) AS march_low_vs_invasion_close_pct,
    round(minIf(c, d > toDate('2022-02-24')), 2) AS year_low_close,
    toString(argMinIf(d, (c, d), d > toDate('2022-02-24'))) AS year_low_date,
    round((minIf(c, d > toDate('2022-02-24')) / invasion_close - 1) * 100, 1) AS year_low_vs_invasion_close_pct
FROM daily

18 calendar days after di invasion, on 2022-03-14, QQQ close below di $318.26 panic low from di invasion morning opening minute. Dat March low close of $318.21 sit -6.6% under di invasion-day close — and di year still dey go: by 2022-12-28, QQQ close at $260.02, -23.7% below where invasion day end. Di February 24 reversal na real, e violent — and e local. Na di rate-hike cycle, no be di war, set 2022 direction, di same lesson wey di March 2020 crash teach for opposite direction.

How rare e be to see reversal wey big like dis?

If you check every QQQ session from 2003 go reach di end of 2025, you go see exactly 2 sessions wey trade at least 3% below di prior close for intraday and still finish at least 1% above am:

QueryQQQ sessions since 2003: intraday low ≤ −3% vs prior close AND close ≥ +1%
The exact SQL behind every number
SELECT
    toString(d) AS session,
    low_vs_prior_pct,
    close_vs_prior_pct,
    trough_to_close_pct
FROM (
    SELECT
        d,
        round((lo / prev_c - 1) * 100, 1) AS low_vs_prior_pct,
        round((c / prev_c - 1) * 100, 1) AS close_vs_prior_pct,
        round((c / lo - 1) * 100, 1) AS trough_to_close_pct
    FROM (
        SELECT d, c, lo,
               lagInFrame(c) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_c
        FROM (
            SELECT
                toDate(toTimeZone(window_start, 'America/New_York')) AS d,
                argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS c,
                minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS lo
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker = 'QQQ'
              AND window_start >= toDateTime('2003-01-01 00:00:00') AND window_start < toDateTime('2026-01-01 00:00:00')
            GROUP BY d
        )
    )
    WHERE prev_c > 0 AND isFinite(prev_c)
)
WHERE low_vs_prior_pct <= -3 AND close_vs_prior_pct >= 1
ORDER BY session

February 24, 2022 na one. Di oda one na 2022-10-13 — di session wey open one hour after inflation report wey hot pass wetin dem expect, anoda day wey gap down but close green. Di reversal for di invasion day big pass di two: na 7% trough-to-close swing against 5.7%. Twenty-three years of tape, and di two prints show for di same year.

Wetin dis day dey teach

Three strong mechanics dey inside dis tape. First: by di time one event wey everybody dey expect happen, positioning don already happen — di two red sessions before di invasion carry di anticipation. Second: di opening auction na where overnight fear wey don gather dey clear for one single price, and dat price fit be di day extreme for any direction. Third: one violent one-day reversal dey tell you about dat day flows, not di next quarter direction — di weeks after dis session still go new lows anyhow. Event days dey reward person wey sabi di machinery; dem dey punish person wey confuse session shape with regime shape.

Di volume detail dey confirm who dey do wetin: 128.5 million shares make am di heaviest session for di three-week table wey dey up, and heavy volume for one trough-to-close climb mean say di buying na real size wey meet real selling — no be empty-tape drift. Compare di same signature for March 24, 2020 rally, where conviction volume also mark di turn of one panic, and contrast am with thin bounce days wey dey fade di next session.

Invasion day FAQ

Wetin stock market do wen Russia invade Ukraine?

For di day wey e happun — February 24, 2022 — di Nasdaq-100 ETF QQQ open -3.2% down, e drop reach im lowest for di first minute, den e climb all through di session go close +3.4%. Di S&P 500 ETF SPY close +1.5% and di Dow ETF DIA close +0.3%.

Why stock rise wen Russia invade Ukraine?

Dis page no dey give reasons; di record show di order — heavy selling pressure show fully by 9:30 open, and buying control every hour wey follow. Di pattern of falling wen threat show and rallying wen event happun get many examples for history.

Wetin oil and gold do wen Russia invade Ukraine?

Both of dem spike for open and fade: di energy ETF XLE gap +2.1% and close -0.9%, and di gold ETF GLD gap +2.4% and close -0.6%. Defense stocks hold dia gains: all four major ones for di panel above close green.

Di rally after di invasion, e last?

No. QQQ close below im invasion-day panic low 18 calendar days later, on 2022-03-14, and by im 2022 low on 2022-12-28, e stand -23.7% below di invasion-day close.

How rare be reversal like February 24, 2022?

E rare well well. From 2003 reach di end of 2025, na only 2 QQQ sessions trade 3% or more below di prior close intraday and still close at least 1% higher — dis one, and 2022-10-13.


Every panel wey dey above na stored, versioned query over di historical record — expand di SQL to see each measurement. You wan feel dis day instead of read am? E be one of di playable scenarios for di Strasmore Labs trading simulator.

#market history#geopolitics#reversals#qqq