Full options quote history: clean NBBO bid/ask snapshots for any US option contract at the interval you choose, by SQL API, $79 a month.See the options quotes plan
Strasmore Research
Learn Matt ConnorBy Matt Connor · Updated 2026-11-01 · data as of November 1, 2026 · refreshed weekly

Stock Split Calendar From a Free SQL API

Build a stock split calendar with one curl call and one SQL query: upcoming forward and reverse splits, ratios, effective dates, and splits per month.

A stock split calendar is a dated list of the share splits companies have carried out recently and the ones already scheduled ahead. Each row carries four things: a ticker, an effective date, a ratio written new-for-old, and a label saying whether the split is forward or reverse. This page rebuilds that calendar from scratch with one curl call, then extends it with your own SQL over global_markets.stocks_splits, the corporate-actions table behind our upcoming stock splits page.

Everything below runs in a fresh Ubuntu container with two packages on it and nothing else:

apt-get update -qq && apt-get install -y --no-install-recommends curl jq

One curl call for the upcoming split calendar

The keyless demo endpoint answers a fixed set of questions over the same data these panels read. One of them is the split calendar. Pipe it through jq and you have the calendar as tab-separated text, ready for a spreadsheet or a cron job:

curl -sS 'https://ai.strasmore.com/api/demo?q=upcoming_splits' \
  | jq -r '.rows[] | [.execution_date, .ticker, .split_ratio] | @tsv'

The response is a JSON object with a columns array naming the fields and a rows array of objects, one per split. Write your check against that shape rather than against how many splits happen to be pending on the day you run it, since the pending count turns over every few weeks:

curl -sS 'https://ai.strasmore.com/api/demo?q=upcoming_splits' \
  | jq -e '(.rows | type) == "array"
           and ((.columns | index("execution_date")) != null)
           and ((.columns | index("split_ratio")) != null)' > /dev/null \
  && echo 'calendar shape ok'

That is the whole dependency list: curl, jq, and a URL. No key, no client library, no signup.

What the split calendar actually contains

Here is the same calendar read straight from the table, covering the last three weeks alongside everything already dated ahead. The worked-example column does the arithmetic for a 100-share position, which is the fastest way to see what a ratio means.

QueryThe stock split calendar: recent and scheduled
24 rows (showing 20)
day_labeltickerdirectionratioworked_example
Jan 13, 2027IBDSFreverse split2-for-1100 shares becomes 200
Dec 17, 2026DPUreverse split1-for-50100 shares becomes 2
Dec 2, 2026LARKreverse split1-for-1100 shares becomes 105
Nov 30, 2026JZreverse split1-for-15100 shares becomes 6.67
Nov 27, 2026DAFVFforward split4-for-1100 shares becomes 400
Nov 27, 2026MPHSFreverse split1-for-10100 shares becomes 10
Nov 27, 2026TKPTFforward split3-for-1100 shares becomes 300
Nov 23, 2026NWSZFforward split11-for-10100 shares becomes 110
Nov 20, 2026NTCLreverse split1-for-10100 shares becomes 10
Nov 19, 2026LICNreverse split1-for-100100 shares becomes 1
Nov 18, 2026ANCMFreverse split101-for-100100 shares becomes 101
Nov 16, 2026AOHYreverse split1-for-5100 shares becomes 20
Nov 16, 2026CARYreverse split1-for-3100 shares becomes 33.33
Nov 16, 2026MBSreverse split1-for-7100 shares becomes 14.29
Nov 16, 2026YMTreverse split1-for-10100 shares becomes 10
Nov 13, 2026ENVXreverse split5-for-4100 shares becomes 125
Nov 13, 2026RCTreverse split1-for-20100 shares becomes 5
Nov 13, 2026SGRXreverse split1-for-10100 shares becomes 10
Nov 10, 2026JOBreverse split1-for-30100 shares becomes 3.33
Nov 10, 2026LFBCFforward split112-for-100100 shares becomes 112
The exact SQL behind every number
SELECT
    formatDateTime(execution_date, '%b %e, %Y')                             AS day_label,
    ticker,
    any(if(adjustment_type = 'forward_split', 'forward split', 'reverse split')) AS direction,
    concat(toString(toInt32(any(split_to))), '-for-',
           toString(toInt32(any(split_from))))                              AS ratio,
    concat('100 shares becomes ',
           toString(round(100 * toFloat64(any(split_to)) / toFloat64(any(split_from)), 2))) AS worked_example
FROM global_markets.stocks_splits
WHERE execution_date >= today() - 21
  AND split_from > 0
  AND split_to > 0
  AND ticker NOT IN ('SPCX')
GROUP BY execution_date, ticker
ORDER BY execution_date DESC, ticker
LIMIT 24
Run this yourself

The panel holds 24 rows. The furthest-out entry on it is IBDSF, a 2-for-1 reverse split dated Jan 13, 2027. The last row in view is NEXR on Nov 6, 2026, a split that has already taken effect. Ratios read new-for-old throughout: 3-for-1 turns one share into three, and 1-for-20 turns twenty shares into one.

Two columns do all the work. split_to is the new share count and split_from is the old one, so the multiple applied to your position is simply one divided by the other. adjustment_type carries the vendor's forward or reverse label.

How many stock splits happen per month?

This is the question that keeps readers on the splits page, and it is one line of SQL away. Counting by month over the last three completed years gives both series on one chart.

QueryForward and reverse splits per month, last 36 months
36 rows (showing 20)
monthmonth_labelforward_splitsreverse_splits
2023-11-01Nov 2023476
2023-12-01Dec 20231987
2024-01-01Jan 2024875
2024-02-01Feb 2024975
2024-03-01Mar 20244480
2024-04-01Apr 20243095
2024-05-01May 20249100
2024-06-01Jun 20242086
2024-07-01Jul 2024984
2024-08-01Aug 20241193
2024-09-01Sep 20243881
2024-10-01Oct 20244291
2024-11-01Nov 202412132
2024-12-01Dec 20242470
2025-01-01Jan 2025789
2025-02-01Feb 202518110
2025-03-01Mar 20252592
2025-04-01Apr 20251694
2025-05-01May 202514108
2025-06-01Jun 202522113
The exact SQL behind every number
SELECT
    toString(toStartOfMonth(execution_date))               AS month,
    formatDateTime(toStartOfMonth(execution_date), '%b %Y') AS month_label,
    countIf(direction = 'forward')                         AS forward_splits,
    countIf(direction = 'reverse')                         AS reverse_splits
FROM
(
    SELECT
        execution_date,
        ticker,
        any(if(adjustment_type = 'forward_split', 'forward', 'reverse')) AS direction
    FROM global_markets.stocks_splits
    WHERE execution_date >= addMonths(toStartOfMonth(today()), -36)
      AND execution_date <  toStartOfMonth(today())
      AND split_from > 0
      AND split_to > 0
    GROUP BY execution_date, ticker
)
GROUP BY month, month_label
ORDER BY month
Run this yourself

The panel covers 36 completed months. The earliest, Nov 2023, recorded 4 forward splits alongside 76 reverse ones. The most recent completed month, Oct 2026, recorded 24 and 103. Both series sit on the same axis, so the mix is readable at a glance rather than through a table. For the longer-run version of this count, see how often stocks split.

The inner query deduplicates on the pair of effective date and ticker before counting. Corporate-action feeds can carry a row more than once, and a raw count() would quietly inflate a month.

To run this one yourself you need the keyed endpoint, which accepts arbitrary read-only SQL. The URL and your free key are printed on the free SQL API page. Export both, then post the query as JSON:

SQL_URL='<endpoint from the free SQL API page>'
SQL_KEY='<your free key>'

SQL="SELECT toString(toStartOfMonth(execution_date)) AS month,
            countIf(direction = 'forward') AS forward_splits,
            countIf(direction = 'reverse') AS reverse_splits
     FROM (
       SELECT execution_date, ticker,
              any(if(adjustment_type = 'forward_split', 'forward', 'reverse')) AS direction
       FROM global_markets.stocks_splits
       WHERE execution_date >= addMonths(toStartOfMonth(today()), -24)
         AND execution_date <  toStartOfMonth(today())
         AND split_from > 0 AND split_to > 0
       GROUP BY execution_date, ticker
     )
     GROUP BY month
     ORDER BY month"

jq -n --arg sql "$SQL" '{sql: $sql}' \
  | curl -sS "$SQL_URL" \
      -H "Authorization: Bearer $SQL_KEY" \
      -H 'Content-Type: application/json' \
      --data-binary @- \
  | jq -r '.. | objects | select(has("month"))
           | [.month, (.forward_splits | tostring), (.reverse_splits | tostring)] | @tsv'

The free tier covers two years of history, so the window here is 24 months. The .. walk in the final jq filter picks out every object carrying a month key wherever the envelope puts it, which keeps the command working if the response wrapper ever gains a field. The same pattern drives our ex-dividend calendar recipe.

One shape assertion is worth adding to any scheduled job. This one says the month key parses as a date and the two counts are non-negative integers, with no reference to today's numbers:

jq -e 'first(.. | objects | select(has("month")))
       | (.month | strptime("%Y-%m-%d") | type) == "array"
         and (.forward_splits >= 0) and (.reverse_splits >= 0)' > /dev/null \
  && echo 'monthly shape ok'

Forward or reverse: checking the label against the arithmetic

The direction label and the two ratio columns are separate pieces of data, and a careful calendar checks one against the other. A forward split should always have split_to above split_from. Counting how often that holds is a two-line query.

QueryDo the direction labels agree with the ratio columns?
directionsplitsto_above_fromfrom_above_to
forward split7807800
reverse split36255473078
The exact SQL behind every number
SELECT
    direction,
    count()                             AS splits,
    countIf(new_shares > old_shares)    AS to_above_from,
    countIf(old_shares > new_shares)    AS from_above_to
FROM
(
    SELECT
        execution_date,
        ticker,
        any(if(adjustment_type = 'forward_split', 'forward split', 'reverse split')) AS direction,
        toFloat64(any(split_to))   AS new_shares,
        toFloat64(any(split_from)) AS old_shares
    FROM global_markets.stocks_splits
    WHERE execution_date >= today() - 1095
      AND split_from > 0
      AND split_to > 0
    GROUP BY execution_date, ticker
)
GROUP BY direction
ORDER BY direction
Run this yourself

Over the last three years the table holds 780 deduplicated rows labelled forward split. Of those, 780 have a new share count above the old one and 0 run the other way. The reverse split rows mirror it: 3078 of 3625 shrink the share count. That is the check to automate, since it tests meaning rather than volume and stays valid for years.

Which split ratios are most common?

Ratios cluster hard. A handful of shapes cover most of the calendar, and the tail is long and thin.

QueryMost common split ratios, last three years
labelsplits
reverse 1-for-10679
reverse 1-for-1288
reverse 1-for-20280
reverse 1-for-5237
forward 2-for-1221
reverse 1-for-4148
forward 3-for-1145
reverse 1-for-15136
reverse 1-for-25131
reverse 1-for-3119
reverse 1-for-100113
forward 5-for-1110
The exact SQL behind every number
SELECT
    concat(direction, ' ', ratio) AS label,
    count()                       AS splits
FROM
(
    SELECT
        execution_date,
        ticker,
        any(if(adjustment_type = 'forward_split', 'forward', 'reverse')) AS direction,
        concat(toString(toInt32(any(split_to))), '-for-',
               toString(toInt32(any(split_from))))                       AS ratio
    FROM global_markets.stocks_splits
    WHERE execution_date >= today() - 1095
      AND split_from > 0
      AND split_to > 0
    GROUP BY execution_date, ticker
)
GROUP BY label
ORDER BY splits DESC
LIMIT 12
Run this yourself

The leader is reverse 1-for-10 with 679 of them. Twelfth place, forward 5-for-1, still shows 110. Round forward ratios sit at one end of the chart and deep reverse ratios at the other, which is the practical difference between the two events: a forward split hands you more shares at a lower price, and a reverse split does the reverse, often at companies working to lift a quoted price back over an exchange listing threshold. Whether the price then goes anywhere is a separate question, covered in does a stock go up after a split.

What a split calendar cannot tell you

A scheduled row is a plan, not a settled fact. An announced ratio can be revised, and a split can be withdrawn outright, at any point before the effective date arrives. The table stores the current state of that plan and keeps no memory of what it said last week, so a row that changes overnight changes silently.

Two habits handle it. Snapshot the calendar on the day you pull it and keep the file, which gives you the revision history the table does not carry. And re-pull anything dated ahead close to its effective date rather than trusting a week-old copy. There is also no announcement date on these rows, so the calendar cannot tell you how much notice a split carried.

Field notes on the splits table

Rows are keyed by effective date and ticker, and duplicates do occur, so group before you count. split_from and split_to are the old and new share counts; the position multiple is split_to / split_from. adjustment_type carries the forward or reverse label. historical_adjustment_factor is the cumulative factor used to restate older prices, which matters when you join splits onto a price series. Every panel above excludes rows with a zero or missing share count on either side.

FAQ

How do I find upcoming stock splits?

Query the corporate-actions table for rows with an effective date at or beyond today, or call the keyless demo endpoint shown above, which returns the same list as JSON. Both give you ticker, effective date, and ratio for each scheduled split.

What does a 1-for-10 reverse split mean?

Ratios are written new-for-old. A 1-for-10 reverse split turns every ten shares you hold into one share, at roughly ten times the per-share price, leaving the value of the position unchanged at the moment it takes effect. A 10-for-1 forward split runs the opposite way.

Can I get a stock split calendar for free?

Yes. The demo endpoint in this post needs no key and no account, and a free account adds arbitrary read-only SQL over two years of history at 100 queries a day. The wider catalogue of what the free tier reaches is listed on our free stock market data API page.

Can an announced split ratio change before the effective date?

It can. Ratios are revised and splits are cancelled ahead of their effective dates, and a calendar row reflects only the latest state of the announcement. Re-pull dated rows near their effective date rather than relying on an older copy.


Every panel here ships with the exact SQL beneath it. Expand one, change the window, and it is your query. To ask for a variant in plain English, put the question to the Strasmore terminal.