Strasmore Research
Learn Matt ConnorBy Matt Connor

Tax-Loss Harvesting Deadlines: The Real Dates

Tax-loss harvesting deadlines, in order: the last trading session of the year, the 61 day wash sale window, and the purchase dates that quietly reopen it.

Tax-loss harvesting deadlines come in pairs, and the second one is the one that bites. A sale that books a loss in a given tax year has to be executed on or before the last regular trading session of that calendar year. The wash sale rule then reaches 30 days backward and 30 days forward from the sale date, which puts a late-December harvest under constraint from purchases going back into November and forward into late January. Everything below is US federal mechanics, current as of October 2026, and none of it is tax advice.

Which tax-loss harvesting deadlines actually bind

Four dates govern a single harvest, and only one of them is the famous one.

  • The execution date of the sale. For stock and ETF shares, the trade date controls the tax year.
  • The settlement date, one business day later under T+1 settlement. It never moves the loss into another tax year, and it is the practical cutoff for telling a broker which tax lot was sold.
  • The 30 calendar days before the sale. A purchase of substantially identical stock inside that stretch counts as a replacement purchase.
  • The 30 calendar days after the sale, under the same test.

A December 31 execution that settles in January is still a December loss. The wash sale window, by contrast, cares nothing about the tax year boundary. It runs straight through it.

When is the last day to sell for a tax loss?

The last regular session of the calendar year, whichever weekday that turns out to be. The exchange calendar decides it, and the back end of December carries the year's densest cluster of shortened sessions. The panel below counts regular-hours one-minute bars in SPY, the S&P 500 ETF, across the final stretch of December 2025. A full session prints 390 of them, which is six and a half hours at sixty bars an hour.

QueryRegular-session minutes in the last two weeks of December 2025 (SPY)
session_datesession_labelweekdayregular_minutesfull_session_pct
2025-12-15Dec 15, 2025Mon390100
2025-12-16Dec 16, 2025Tue390100
2025-12-17Dec 17, 2025Wed390100
2025-12-18Dec 18, 2025Thu390100
2025-12-19Dec 19, 2025Fri390100
2025-12-22Dec 22, 2025Mon390100
2025-12-23Dec 23, 2025Tue390100
2025-12-24Dec 24, 2025Wed21154.1
2025-12-26Dec 26, 2025Fri390100
2025-12-29Dec 29, 2025Mon390100
2025-12-30Dec 30, 2025Tue390100
2025-12-31Dec 31, 2025Wed390100
The exact SQL behind every number
SELECT
    toString(d)                            AS session_date,
    formatDateTime(d, '%b %e, %Y')         AS session_label,
    formatDateTime(d, '%a')                AS weekday,
    toUInt32(bars)                         AS regular_minutes,
    round(toFloat64(bars) / 390 * 100, 1)  AS full_session_pct
FROM
(
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS d,
        count()                                              AS bars
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2025-12-14 00:00:00'
      AND window_start <  '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
)
ORDER BY d
Run this yourself

The final session of that year, Dec 31, 2025, printed 390 regular-session minutes, a full day. One session in the same stretch, Dec 24, 2025, printed 211, which is 54.1% of a normal day. That is the 1:00 p.m. ET Christmas Eve close. In a year where an early close lands on the final session, a harvest planned against a 4:00 p.m. close loses three hours of liquidity. Trades printed in the extended session after the regular close still carry that day's trade date, though the thin book there is its own problem.

How long is the wash sale window?

Sixty-one calendar days: the 30 before the sale, the sale date itself, and the 30 after. The count is in calendar days, not sessions, which is why the window reads more plainly once it is converted into the sessions it actually spans.

QueryThe 61 day wash sale window around each late-December 2025 session
sale_datesale_labelwindow_openswindow_closessessions_beforesessions_after
2025-12-22Dec 22, 2025Nov 22, 2025Jan 21, 20261919
2025-12-23Dec 23, 2025Nov 23, 2025Jan 22, 20262019
2025-12-24Dec 24, 2025Nov 24, 2025Jan 23, 20262119
2025-12-26Dec 26, 2025Nov 26, 2025Jan 25, 20262018
2025-12-29Dec 29, 2025Nov 29, 2025Jan 28, 20261920
2025-12-30Dec 30, 2025Nov 30, 2025Jan 29, 20262020
2025-12-31Dec 31, 2025Dec 1, 2025Jan 30, 20262120
The exact SQL behind every number
WITH sessions AS
(
    SELECT DISTINCT toDate(toTimeZone(window_start, 'America/New_York')) AS d
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2025-11-18 00:00:00'
      AND window_start <  '2026-02-02 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
)
SELECT
    toString(s.d)                           AS sale_date,
    formatDateTime(s.d, '%b %e, %Y')        AS sale_label,
    formatDateTime(s.d - 30, '%b %e, %Y')   AS window_opens,
    formatDateTime(s.d + 30, '%b %e, %Y')   AS window_closes,
    countIf(t.d >= s.d - 30 AND t.d < s.d)  AS sessions_before,
    countIf(t.d > s.d AND t.d <= s.d + 30)  AS sessions_after
FROM
(
    SELECT d
    FROM sessions
    WHERE d >= '2025-12-22'
      AND d <  '2026-01-01'
) AS s
CROSS JOIN sessions AS t
GROUP BY s.d
ORDER BY s.d
Run this yourself

Take the last row, the final session of the year. A loss sale on Dec 31, 2025 opens a window on Dec 1, 2025 and closes it on Jan 30, 2026, covering 21 trading sessions ahead of the sale and 20 after it. A purchase of substantially identical stock anywhere inside that span disallows the loss in proportion to the shares replaced.

Does buying before the sale count?

Yes, and that is the half nobody spells out. The provision covers purchases within 30 days before the sale in the same terms as purchases within 30 days after. Adding to a position in early December and then selling the older, losing lot on the year's last session is a wash sale in exactly the way that selling first and buying back a week later is. Order of operations is irrelevant to the rule.

The doubling-up sequence that clears the test runs on a 31 day clock: buy the extra shares, let more than 30 days pass, then sell the old lot. A harvest on the final session of the year means that buy leg had to land in late November at the latest.

When the rule does apply to stock, the loss is deferred rather than destroyed. The disallowed amount is added to the basis of the replacement shares, and the holding period of the sold shares is tacked onto them. Which lot was sold, and which lot carries that adjusted basis, is a cost-basis election made at the sale; see FIFO versus specific lot identification. Options sit on top of all this, since a call you bought or a put you wrote on the same name can be the replacement property. The wash sale rule and options handles that case on its own.

How losses net, and what the $3,000 limit does

The arithmetic after the sale runs in a fixed order. Short-term losses net against short-term gains and long-term against long-term, then the two net figures offset each other. If a net capital loss remains, up to $3,000 of it offsets ordinary income for the year, or $1,500 for a married taxpayer filing separately. The remainder carries forward indefinitely for an individual and keeps its short or long character. Those dollar figures are statutory and current as of October 2026. A number Congress sets is a number Congress can change.

One consequence of that ordering is worth stating plainly: a loss harvested in a year with large realized gains is absorbed at the full size of those gains, while the same loss in a year with none drains at $3,000 a year.

The purchases that reopen the window

The trap is rarely a deliberate repurchase. It is a standing instruction. Dividend reinvestment buys shares on the pay date, and the pay date can sit weeks after the ex-dividend date it belongs to.

QueryEx-date to pay-date lag for household payers, December 2025 into January 2026
tickerex_date_labelpay_date_labeldays_ex_to_pay
SPYDec 19, 2025Jan 30, 202642
PEPDec 5, 2025Jan 6, 202632
XOMNov 14, 2025Dec 10, 202526
MSFTNov 20, 2025Dec 11, 202521
HDDec 4, 2025Dec 18, 202514
JNJNov 25, 2025Dec 9, 202514
KODec 1, 2025Dec 15, 202514
MCDDec 1, 2025Dec 15, 202514
IVVDec 16, 2025Dec 19, 20253
VOODec 22, 2025Dec 24, 20252
The exact SQL behind every number
SELECT
    ticker,
    formatDateTime(ex_dividend_date, '%b %e, %Y')  AS ex_date_label,
    formatDateTime(pay_date, '%b %e, %Y')          AS pay_date_label,
    dateDiff('day', ex_dividend_date, pay_date)    AS days_ex_to_pay
FROM global_markets.stocks_dividends
WHERE ticker IN ('SPY', 'IVV', 'VOO', 'KO', 'JNJ', 'PG', 'MSFT', 'XOM', 'VZ', 'MCD', 'PEP', 'HD')
  AND pay_date >= '2025-12-01'
  AND pay_date <= '2026-01-31'
GROUP BY ticker, ex_dividend_date, pay_date
ORDER BY days_ex_to_pay DESC, ticker
Run this yourself

10 of those household payers had a distribution payable between early December 2025 and the end of January 2026. The widest lag belongs to SPY, at 42 days from its ex-dividend date to a pay date of Jan 30, 2026. A holder with reinvestment switched on collects new shares on that pay date, deep inside the forward half of a year-end window, usually without opening a statement.

A fractional share counts. The rule carries no de minimis floor, and a partial replacement disallows the loss only on the shares replaced, which leaves a position holding two lots with different basis treatment. Automatic monthly contributions behave the same way, as does a purchase in a spouse's account.

The retirement-account version is the one that ends badly. Under Rev. Rul. 2008-5, published in 2008, selling at a loss in a taxable account and buying substantially identical stock in your own IRA or Roth IRA inside the window disallows the loss, and the IRA's basis in the new shares is not increased. Nothing is deferred there. The deduction is gone for good. Funds carry extra timing wrinkles on the sale side, covered in selling mutual funds at a loss.

What does substantially identical mean?

The phrase sits in the statute and is nowhere defined for funds. The settled ground is narrow. A security is substantially identical to itself, and bonds or preferred shares with materially different terms have long been treated as distinct. Two index funds from different sponsors tracking one index sit in open country, with no ruling and no safe harbor as of October 2026. What can be measured is how closely they move. The panel compares each fund's open-to-close percent move against SPY's on the same session, in basis points, over the second half of 2025.

QueryDaily open-to-close gap versus SPY, in basis points, July to December 2025
tickermedian_gap_bpsmax_gap_bps
VOO0.86.7
IVV0.84
QQQ16.6121.4
RSP27.9120.8
The exact SQL behind every number
WITH moves AS
(
    SELECT
        ticker,
        date,
        toFloat64(close) / toFloat64(open) - 1 AS pct_move
    FROM global_markets.stocks_daily_aggs
    WHERE ticker IN ('SPY', 'IVV', 'VOO', 'RSP', 'QQQ')
      AND date >= '2025-07-01'
      AND date <= '2025-12-31'
      AND open > 0
)
SELECT
    f.ticker AS ticker,
    round(quantileDeterministic(0.5)(abs(f.pct_move - b.spy_move) * 10000, toUInt64(f.date)), 1) AS median_gap_bps,
    round(max(abs(f.pct_move - b.spy_move)) * 10000, 1)                                          AS max_gap_bps
FROM moves AS f
INNER JOIN
(
    SELECT date, pct_move AS spy_move
    FROM moves
    WHERE ticker = 'SPY'
) AS b USING (date)
WHERE f.ticker != 'SPY'
GROUP BY f.ticker
ORDER BY median_gap_bps
Run this yourself

VOO and IVV sit at the tight end, a median 0.8 and 0.8 basis points a session away from SPY, with worst sessions of 6.7 and 4 basis points. Both track the same index SPY tracks. RSP, built on a different index, sits a median 27.9 basis points away. A gap of a basis point or two is a price measurement, not a legal test, and no authority has said where on this scale the line falls. The cautious reading treats same-index funds from different issuers as live risk. The aggressive reading leans on the separate sponsor and separate prospectus.

FAQ

What is the last day to sell stock for a tax loss?

The last regular trading session of the calendar year. Trade date controls for stock and ETFs, so an execution on that session books the loss in that year even though it settles the next business day. The exchange calendar sets the exact date, and that session is sometimes a shortened one.

Does the wash sale rule count calendar days or trading days?

Calendar days. Thirty before the sale, thirty after, plus the sale date itself, for 61 days in total. Weekends and holidays fall inside the count, which is why the 30 days before a year-end sale cover only 21 trading sessions.

Does buying shares before the sale count as a wash sale?

Yes. A purchase of substantially identical stock in the 30 days before the loss sale is a replacement purchase under the same provision that covers a purchase after it. Buying first and selling the old lot second is caught exactly as the reverse order is.

Can I sell at a loss and buy it back inside my IRA?

Rev. Rul. 2008-5 disallows the loss, and the IRA's basis in the new shares is not increased. Unlike an ordinary wash sale in a taxable account, that loss is permanently lost rather than deferred.

How much capital loss can offset ordinary income?

Up to $3,000 a year for most filers, or $1,500 for a married taxpayer filing separately, after losses have netted against gains by character. Anything left carries forward with no expiration. Both figures are current as of October 2026.


Every panel here ships with the exact SQL underneath it. To count the trading sessions inside a 61 day window around any date, or find which session closed a given year, ask it in plain English on the Strasmore terminal.