Strasmore Research
Market recaps wey dey break am down Matt ConnorBy Matt Connor · Updated 2026-09-05 · data as of September 5, 2026 · refreshed weekly

Biggest Stock Gainers and Losers for 2026

See the 2026 stocks wey gain and lose pass, ranked from exchange tape liquidity. Stock splits and leveraged funds no dey inside the list.

The stocks wey perform pass for 2026 so far na SNDK dey lead, with gain of 536.4% from the first trading session of the year reach the latest session wey don complete. This page rank the stocks wey gain and lose pass for 2026 among names wey genuinely dey trade. The measurement come from exchange tape, no be vendor summary, and the page dey refresh as the year dey go on. We remove stock splits and leveraged funds before we rank anything. Na for this part most year-to-date lists dey quietly get am wrong.

Biggest stock gainers of 2026

Every name wey dey below first pass liquidity floor before dem rank am: average of at least $100 million worth of stock changing hands for each completed trading session over the past month. Big percentage for stock wey nobody dey trade na quote, e no be result.

QueryBiggest stock gainers of 2026: top ten year to date among heavily traded names
tickerytd return pctavg daily dollar m
SNDK536.415431
MRNA3995598
TWST305.4202
DELL301.83566
TXG287.5142
AEHR262.8208
MXL233.4114
AXTI226.9525
MU224.820455
AMLX183.5131
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
universe AS (
    SELECT ticker,
           sum(toFloat64(close) * toFloat64(volume)) / uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS adv
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 21 DAY
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= today() - 20
      AND toDate(toTimeZone(window_start, 'America/New_York')) IN (SELECT d FROM complete)
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY ticker
    HAVING adv >= 100000000
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
      AND ticker NOT IN ('KORU','SOXL','SOXS','SOXY','TQQQ','SQQQ','QQQU','SPXL','SPXS','UPRO','SPXU','SPYU','LABU','LABD','FAS','FAZ','TNA','TZA','YINN','YANG','UDOW','SDOW','BOIL','KOLD','UCO','SCO','USD','SSO','SDS','QLD','QID','ERX','ERY','DRN','DRV','CURE','MUU','SNXX','UVXY','SVXY','UVIX','SVIX','BULZ','WEBL','WEBS','DPST','DRIP','GUSH','AGQ','ZSL','GDXU','GDXD','FNGU','FNGD','DUST','JNUG','JDST','NUGT','BITX','BITU','SBIT','ETHU','ETHT','NVDL','NVDS','NVD','NVDX','NVDU','NVDD','NVDQ','TSLL','TSLQ','TSLZ','TSLR','TSLT','TSLS','TSDD','AAPU','AAPD','MSFU','MSFD','GGLL','GGLS','AMZU','AMZD','METU','METD','PLTU','PLTD','SMCX','SMCZ','CONL','CONI','MSTX','MSTU','MSTZ','BRKU','AMDL','AMUU','AMDD','ELIL','ELIS','HOOX','AVGX','AVGU','TSMX','TSMZ','MULL')
      AND ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits
                         WHERE execution_date BETWEEN toDate('2026-01-01') AND today())
    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
)
SELECT e.ticker AS ticker,
    round((e.latest_close / e.year_open - 1) * 100, 1) AS ytd_return_pct,
    round(u.adv / 1e6, 0) AS avg_daily_dollar_m
FROM edges AS e
INNER JOIN universe AS u ON e.ticker = u.ticker
WHERE e.year_open >= 10
ORDER BY (e.latest_close / e.year_open) DESC
LIMIT 10
Run am yourself

SNDK lead the year with 536.4%, while MRNA follow with 399% and TWST come third with 305.4%. AMLX, wey dey tenth place for the table, still rise 183.5%. So the whole table don run far pass any broad index.

The dollar column beside each move carry as much information as the percentage. AMLX dey record average daily turnover of about $131 million. SNDK, wey dey top the table, average $15431 million. Every name here clear $100 million per day, and the range above that floor wide enough say the same headline percentage fit mean two different things for the two ends. Thinly traded stock easier to push, and e harder to exit at the price wey dey show for the screen.

Biggest stock losers of 2026

The identical measure, in reverse: the steepest year-to-date declines among names clearing the same liquidity floor.

QueryBiggest stock losers of 2026: worst ten year to date among heavily traded names
tickerytd return pctavg daily dollar m
TTD-60.5192
WING-54.4103
APP-54.11257
CSGP-52.8144
FLUT-52.7140
STLA-51.5105
BSX-51763
KLAR-50.4145
RBLX-49.1303
JOBY-48.8153
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
universe AS (
    SELECT ticker,
           sum(toFloat64(close) * toFloat64(volume)) / uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS adv
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 21 DAY
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= today() - 20
      AND toDate(toTimeZone(window_start, 'America/New_York')) IN (SELECT d FROM complete)
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY ticker
    HAVING adv >= 100000000
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
      AND ticker NOT IN ('KORU','SOXL','SOXS','SOXY','TQQQ','SQQQ','QQQU','SPXL','SPXS','UPRO','SPXU','SPYU','LABU','LABD','FAS','FAZ','TNA','TZA','YINN','YANG','UDOW','SDOW','BOIL','KOLD','UCO','SCO','USD','SSO','SDS','QLD','QID','ERX','ERY','DRN','DRV','CURE','MUU','SNXX','UVXY','SVXY','UVIX','SVIX','BULZ','WEBL','WEBS','DPST','DRIP','GUSH','AGQ','ZSL','GDXU','GDXD','FNGU','FNGD','DUST','JNUG','JDST','NUGT','BITX','BITU','SBIT','ETHU','ETHT','NVDL','NVDS','NVD','NVDX','NVDU','NVDD','NVDQ','TSLL','TSLQ','TSLZ','TSLR','TSLT','TSLS','TSDD','AAPU','AAPD','MSFU','MSFD','GGLL','GGLS','AMZU','AMZD','METU','METD','PLTU','PLTD','SMCX','SMCZ','CONL','CONI','MSTX','MSTU','MSTZ','BRKU','AMDL','AMUU','AMDD','ELIL','ELIS','HOOX','AVGX','AVGU','TSMX','TSMZ','MULL')
      AND ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits
                         WHERE execution_date BETWEEN toDate('2026-01-01') AND today())
    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
)
SELECT e.ticker AS ticker,
    round((e.latest_close / e.year_open - 1) * 100, 1) AS ytd_return_pct,
    round(u.adv / 1e6, 0) AS avg_daily_dollar_m
FROM edges AS e
INNER JOIN universe AS u ON e.ticker = u.ticker
WHERE e.year_open >= 10
ORDER BY (e.latest_close / e.year_open) ASC
LIMIT 10
Run am yourself

The steepest year-to-date decline na belong to TTD at -60.5%, followed by WING at -54.4%. JOBY dey tenth for the list, at -48.8%. Several names for here na large, widely held companies, no be speculative micro caps. Na this part of loser list dey surprise people. Liquidity and analyst coverage no fit put floor under share price. Anybody wey hold one of these stocks as oversized part of portfolio collect the full move. The risk of holding one stock page dey measure this with volatility and drawdown numbers.

How much of the market dey up for 2026

Leaderboard only dey show the two extremes. Breadth dey show the main body: how the whole screened universe, including index funds, dey split between names wey dey rise and names wey dey fall, based on how big the move be.

QueryYear-to-date breadth: how the screened universe is distributed across return buckets
bucketnamesside share pct
Down 40%+1835.5
Down 20-40%6935.5
Down 10-20%7835.5
Down 0-10%16235.5
Up 0-10%15264.5
Up 10-25%19864.5
Up 25-50%14264.5
Up 50%+10364.5
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
universe AS (
    SELECT ticker,
           sum(toFloat64(close) * toFloat64(volume)) / uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS adv
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 21 DAY
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= today() - 20
      AND toDate(toTimeZone(window_start, 'America/New_York')) IN (SELECT d FROM complete)
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY ticker
    HAVING adv >= 100000000
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
      AND ticker NOT IN ('KORU','SOXL','SOXS','SOXY','TQQQ','SQQQ','QQQU','SPXL','SPXS','UPRO','SPXU','SPYU','LABU','LABD','FAS','FAZ','TNA','TZA','YINN','YANG','UDOW','SDOW','BOIL','KOLD','UCO','SCO','USD','SSO','SDS','QLD','QID','ERX','ERY','DRN','DRV','CURE','MUU','SNXX','UVXY','SVXY','UVIX','SVIX','BULZ','WEBL','WEBS','DPST','DRIP','GUSH','AGQ','ZSL','GDXU','GDXD','FNGU','FNGD','DUST','JNUG','JDST','NUGT','BITX','BITU','SBIT','ETHU','ETHT','NVDL','NVDS','NVD','NVDX','NVDU','NVDD','NVDQ','TSLL','TSLQ','TSLZ','TSLR','TSLT','TSLS','TSDD','AAPU','AAPD','MSFU','MSFD','GGLL','GGLS','AMZU','AMZD','METU','METD','PLTU','PLTD','SMCX','SMCZ','CONL','CONI','MSTX','MSTU','MSTZ','BRKU','AMDL','AMUU','AMDD','ELIL','ELIS','HOOX','AVGX','AVGU','TSMX','TSMZ','MULL')
      AND ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits
                         WHERE execution_date BETWEEN toDate('2026-01-01') AND today())
    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
),
rets AS (
    SELECT e.ticker AS ticker, (e.latest_close / e.year_open - 1) * 100 AS ret
    FROM edges AS e
    INNER JOIN universe AS u ON e.ticker = u.ticker
    WHERE e.year_open >= 10
)
SELECT bucket,
       names,
       round(100 * sum(names) OVER (PARTITION BY side) / sum(names) OVER (), 1) AS side_share_pct
FROM (
    SELECT tup.1 AS bucket, tup.2 AS names, tup.3 AS ord, tup.4 AS side
    FROM (
        SELECT arrayJoin([
            ('Down 40%+',   countIf(ret < -40),               1, 'down'),
            ('Down 20-40%', countIf(ret >= -40 AND ret < -20), 2, 'down'),
            ('Down 10-20%', countIf(ret >= -20 AND ret < -10), 3, 'down'),
            ('Down 0-10%',  countIf(ret >= -10 AND ret < 0),   4, 'down'),
            ('Up 0-10%',    countIf(ret >= 0 AND ret < 10),    5, 'up'),
            ('Up 10-25%',   countIf(ret >= 10 AND ret < 25),   6, 'up'),
            ('Up 25-50%',   countIf(ret >= 25 AND ret < 50),   7, 'up'),
            ('Up 50%+',     countIf(ret >= 50),                8, 'up')
        ]) AS tup
        FROM rets
    )
)
ORDER BY ord
Run am yourself

64.5% of the screened names dey higher for the year, while 35.5% dey lower. Na this distribution top-ten table dey hide. 18 names dey inside the Down 40%+ bucket for one end, while 103 dey inside the Up 50%+ bucket for the other end, compared with 162 inside Down 0-10% and 152 inside Up 0-10% on both sides of unchanged. For any given year, most of the market dey make ordinary moves. The names for the two tables above na the exceptions wey the averages come from.

Wetin the market itself dey do

One stock performance for the year fit look different when you compare am with the market own. The four major index ETFs, for exactly the same period:

QueryThe four major index ETFs, year to date, over the same measured window
labelytd return pctmeasure am from datemeasure am reach date
Russell 2000 (IWM)19.22026-01-022026-09-03
Nasdaq 100 (QQQ)15.72026-01-022026-09-03
S&P 500 (SPY)12.72026-01-022026-09-03
Dow (DIA)11.42026-01-022026-09-03
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
)
SELECT multiIf(ticker = 'SPY', 'S&P 500 (SPY)', ticker = 'QQQ', 'Nasdaq 100 (QQQ)',
               ticker = 'DIA', 'Dow (DIA)', ticker = 'IWM', 'Russell 2000 (IWM)', ticker) AS label,
    round((latest_close / year_open - 1) * 100, 1) AS ytd_return_pct,
    (SELECT toString(min(d)) FROM complete) AS measured_from_date,
    (SELECT toString(max(d)) FROM complete) AS measured_through_date
FROM edges
ORDER BY ytd_return_pct DESC
Run am yourself

Both boards and the panel wey dey above use one period: the first full session of 2026 (2026-01-02) reach the latest completed session (2026-09-03). For this period, Russell 2000 (IWM) return na 19.2%, while Dow (DIA) return na 11.4%. Every name for the gainers table beat all four by wide margin. Na the arithmetic of an index cause this: hundreds of holdings dey average into one line, so individual moves fit cancel each other partly. The spread under that line wide pass the line itself, and the sector scorecard for the first half rank all eleven sectors against each other.

The stock split wey dey fake year-to-date move

Split dey change share count and per-share price, but e no change wetin the holding worth. For window wey long reach like this, many companies dey do split. If calculation no adjust for am, e go read the change for per-share price as performance. Every name below get 2026 split or stock dividend wey big enough to move that price by at least one-fifth. Every one still pass the same liquidity floor. So dem fit enter the boards above before split filter remove dem.

QueryExcluded from the boards: 2026 splits large enough to fake a year-to-date move
tickerunadjusted ytd pctsplit price effect pctsplit typesplit date
BKNG-96.4-96forward split2026-04-06
KLAC-86.3-90forward split2026-06-12
VGT-84.1-87.5forward split2026-04-21
CVNA-82.6-80forward split2026-05-08
VUG-81.9-83.3forward split2026-04-21
HDV-75.6-80forward split2026-04-29
IWF-74.1-75forward split2026-04-29
VO-71.7-75forward split2026-04-21
CRWD-54.6-75stock dividend2026-07-02
MNST-42.5-50stock dividend2026-08-11
APH-40.1-50stock dividend2026-09-03
MVLL4.3-66.7forward split2026-06-26
HON6.1100reverse split2026-06-29
DD224.3200reverse split2026-06-24
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
universe AS (
    SELECT ticker,
           sum(toFloat64(close) * toFloat64(volume)) / uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS adv
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 21 DAY
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= today() - 20
      AND toDate(toTimeZone(window_start, 'America/New_York')) IN (SELECT d FROM complete)
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY ticker
    HAVING adv >= 100000000
),
split_terms AS (
    SELECT ticker,
        argMax(split_to, execution_date) AS new_shares,
        argMax(split_from, execution_date) AS old_shares,
        round((old_shares / new_shares - 1) * 100, 1) AS split_price_effect_pct,
        replaceAll(argMax(adjustment_type, execution_date), '_', ' ') AS split_type,
        toString(max(execution_date)) AS split_date
    FROM global_markets.stocks_splits
    WHERE execution_date BETWEEN toDate('2026-01-01') AND today()
    GROUP BY ticker
    HAVING new_shares > 0 AND old_shares > 0
       AND greatest(new_shares / old_shares, old_shares / new_shares) >= 1.25
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
      AND ticker NOT IN ('KORU','SOXL','SOXS','SOXY','TQQQ','SQQQ','QQQU','SPXL','SPXS','UPRO','SPXU','SPYU','LABU','LABD','FAS','FAZ','TNA','TZA','YINN','YANG','UDOW','SDOW','BOIL','KOLD','UCO','SCO','USD','SSO','SDS','QLD','QID','ERX','ERY','DRN','DRV','CURE','MUU','SNXX','UVXY','SVXY','UVIX','SVIX','BULZ','WEBL','WEBS','DPST','DRIP','GUSH','AGQ','ZSL','GDXU','GDXD','FNGU','FNGD','DUST','JNUG','JDST','NUGT','BITX','BITU','SBIT','ETHU','ETHT','NVDL','NVDS','NVD','NVDX','NVDU','NVDD','NVDQ','TSLL','TSLQ','TSLZ','TSLR','TSLT','TSLS','TSDD','AAPU','AAPD','MSFU','MSFD','GGLL','GGLS','AMZU','AMZD','METU','METD','PLTU','PLTD','SMCX','SMCZ','CONL','CONI','MSTX','MSTU','MSTZ','BRKU','AMDL','AMUU','AMDD','ELIL','ELIS','HOOX','AVGX','AVGU','TSMX','TSMZ','MULL')
      AND ticker IN (SELECT ticker FROM split_terms)
    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
),
ranked AS (
    SELECT e.ticker AS ticker,
        round((e.latest_close / e.year_open - 1) * 100, 1) AS unadjusted_ytd_pct,
        s.split_price_effect_pct AS split_price_effect_pct,
        s.split_type AS split_type,
        s.split_date AS split_date
    FROM edges AS e
    INNER JOIN split_terms AS s ON e.ticker = s.ticker
    WHERE e.year_open >= 10 AND e.ticker IN (SELECT ticker FROM universe)
)
SELECT ticker, unadjusted_ytd_pct, split_price_effect_pct, split_type, split_date
FROM (
    SELECT ticker, unadjusted_ytd_pct, split_price_effect_pct, split_type, split_date,
           row_number() OVER (ORDER BY unadjusted_ytd_pct ASC) AS rn_low,
           row_number() OVER (ORDER BY unadjusted_ytd_pct DESC) AS rn_high
    FROM ranked
)
WHERE rn_low <= 14 OR rn_high = 1
ORDER BY unadjusted_ytd_pct ASC
Run am yourself

BKNG go print -96.4% for unadjusted screen after forward split move its per-share price by -96%, while KLAC go print -86.3% after forward split move its price by -90%. No holder of either one lose anything on the day the split take effect. Dem divide the per-share price and multiply the share count by the same factor. Split effect column dey show the price change wey the split alone cause. Na that part unadjusted screen dey read as performance.

The last row for the panel go the other way: DD dey show 224.3% after reverse split lift its per-share price by 200%, so the price rise instead of fall. Any list wey skip this step go publish fiction for both top and bottom at the same time. Na why the screen dey set split tickers aside instead of trying to patch their prices. Fund fit enter this panel just like company. Index funds dey split their shares too, and this screen cover both.

How dem dey measure this screen

Each stage for the screen, plus how many names remain after am:

QueryThe screen, stage by stage: how many names survive each filter
screen stepnames
Traded the first and the last full session4471
Averaging $100m+ a day over the past month1000
Opened 2026 above $10 a share970
Not on the excluded-fund list938
No split or stock dividend in 2026922
The exact SQL behind every number
WITH complete AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2026-01-01 00:00:00')
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY d
    HAVING count() >= 380
),
universe AS (
    SELECT ticker
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 21 DAY
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= today() - 20
      AND toDate(toTimeZone(window_start, 'America/New_York')) IN (SELECT d FROM complete)
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
    GROUP BY ticker
    HAVING sum(toFloat64(close) * toFloat64(volume)) / uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) >= 100000000
),
edges AS (
    SELECT ticker,
        argMinIf(toFloat64(open), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS year_open,
        argMaxIf(toFloat64(close), toTimeZone(window_start, 'America/New_York'), toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS latest_close,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT min(d) FROM complete)) AS bars_open,
        countIf(toDate(toTimeZone(window_start, 'America/New_York')) = (SELECT max(d) FROM complete)) AS bars_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ((window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-01-10 00:00:00'))
        OR (window_start >= now() - INTERVAL 8 DAY))
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960

    GROUP BY ticker
    HAVING bars_open >= 100 AND bars_close >= 100
),
flagged AS (
    SELECT ticker,
        year_open,
        ticker IN (SELECT ticker FROM universe) AS liquid,
        ticker NOT IN ('SPCX','KORU','SOXL','SOXS','SOXY','TQQQ','SQQQ','QQQU','SPXL','SPXS','UPRO','SPXU','SPYU','LABU','LABD','FAS','FAZ','TNA','TZA','YINN','YANG','UDOW','SDOW','BOIL','KOLD','UCO','SCO','USD','SSO','SDS','QLD','QID','ERX','ERY','DRN','DRV','CURE','MUU','SNXX','UVXY','SVXY','UVIX','SVIX','BULZ','WEBL','WEBS','DPST','DRIP','GUSH','AGQ','ZSL','GDXU','GDXD','FNGU','FNGD','DUST','JNUG','JDST','NUGT','BITX','BITU','SBIT','ETHU','ETHT','NVDL','NVDS','NVD','NVDX','NVDU','NVDD','NVDQ','TSLL','TSLQ','TSLZ','TSLR','TSLT','TSLS','TSDD','AAPU','AAPD','MSFU','MSFD','GGLL','GGLS','AMZU','AMZD','METU','METD','PLTU','PLTD','SMCX','SMCZ','CONL','CONI','MSTX','MSTU','MSTZ','BRKU','AMDL','AMUU','AMDD','ELIL','ELIS','HOOX','AVGX','AVGU','TSMX','TSMZ','MULL') AS not_geared,
        ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits
                       WHERE execution_date BETWEEN toDate('2026-01-01') AND today()) AS no_split
    FROM edges
)
SELECT tup.1 AS screen_step, tup.2 AS names
FROM (
    SELECT arrayJoin([
        ('Traded the first and the last full session', count()),
        ('Averaging $100m+ a day over the past month', countIf(liquid)),
        ('Opened 2026 above $10 a share', countIf(liquid AND year_open >= 10)),
        ('Not on the excluded-fund list', countIf(liquid AND year_open >= 10 AND not_geared)),
        ('No split or stock dividend in 2026', countIf(liquid AND year_open >= 10 AND not_geared AND no_split))
    ]) AS tup
    FROM flagged
)
Run am yourself

The method, fully explained:

  • The window. The first complete trading session for 2026 reach the latest complete session for the tape. Dem read both endpoints from minute bars. A session only count if e get the full regular-hours bar count. So, session wey never finish no go count as completed.
  • The return. Dem compare the first regular-session open for the year with the last regular-session close, using minute bars. Premarket and after-hours prints no enter. These na price returns. Dividends no add back, so high-yield name go look slightly worse here than total-return figure go show.
  • The liquidity floor. Average regular-hours turnover per session for the last 20 calendar days must reach at least $100 million. Only sessions wey run from start to finish count. If partial session enter, part of one day’s dollars go divide by a full day, and that go understate every name’s turnover. This one filter reduce the field from 4471 tickers to 1000.
  • The price floor. The stock must open the year above $10 per share. Names below $10 fit produce big percentages from small price movements.
  • Leveraged and inverse funds no enter, based on a curated list. Dem print the full list inside the SQL under every table. E cover index-geared funds and single-stock funds wey multiply one company’s daily move. Geared fund fit top any raw movers list without one piece of company news. Person dey maintain the list by hand, and na the weakness be that: fund wey launch this month no go exclude until person add am.
  • Ordinary funds no dey filtered out. Unlevered index or sector ETF wey pass the liquidity and price floors dey rank here together with operating companies, and e dey inside the breadth counts too. Fund na basket of names wey dem don already count for the same universe. So, read those rows as wetin the basket do, no be as one company’s result for the year.
  • Splits. Any ticker wey get split or stock dividend wey take effect during 2026 dey set aside, no matter how small the ratio be. Na the conservative choice be this. E remove some genuine performers from the board, but e no go ever publish share-count change as return. The panel above show the excluded names wey their split big enough to make movement look fake.
  • Late listings. Company wey list after the first session of the year no get January price, so e no dey these tables. This na real gap for year wey get plenty new listings.
  • The result. Dem rank 922 names, and the top and bottom ten among dem na the two boards for this page.

The same question for three windows

Year to date na one step for ladder, and price move fit look different depending on how long you check am. The week view na the biggest stock gainers and losers this week, the month view na the biggest stock movers this month, while this page na for the year. The screening rules no be the same for each step: this page dey use average of $100 million traded per day for the past month, while the week and month pages dey use total dollar value traded inside their own periods. So one stock fit pass one board but miss another. Stock wey lead the weekly board after one earnings reaction fit dey middle of the table when you check the full year. For the bigger story about how the year don go so far, the first-half market recap get the index, rates and sector details, while how leveraged ETFs work explain why we leave the geared funds for here.

FAQ

2026 performance wey stock perform pass na which one?

Among names wey dey average at least $100 million trading every day, open the year above $10, no carry 2026 split, and no dey the leveraged-fund list, SNDK na the best-performing stock for 2026 so far. E don rise 536.4% from the first trading session of the year. MRNA dey second with 399%.

Which stocks don drop pass for 2026?

TTD na the worst-performing stock for 2026 for this screen, at -60.5%. WING follow am at -54.4%. The complete list of the biggest stock losers for 2026 dey the second table above, and dem dey refresh am as the year dey go.

How dem dey calculate year-to-date stock return?

Year-to-date return dey compare the latest price with the price for the beginning of the calendar year, then show the change as percentage. For here, na the first regular-session open for 2026 dem measure against the close of the most recent completed session. Stocks wey split during the year dey excluded instead of adjustment, so no adjustment factor dey between the reader and the tape.

Leveraged ETFs dey inside the 2026 gainers list?

No. Leveraged or inverse fund dey multiply the daily move of an index or single stock. So e fit regularly top a raw movers list even when no company news dey behind am. Dem remove those funds by name before ranking, and the list dey visible for the SQL under each table. Ordinary index and sector ETFs na different matter: dem still need meet the same floors as any stock, and dem dey rank dem here. So fund fit show for either board.


Every table for here na stored query with the SQL attached. Open any panel to audit the screen, or rebuild am with your own floors for the Strasmore terminal.

#market movers#gainers and losers#year to date#stock splits#market breadth