ETF Price Puzzles: Examples Showing Tiingo’s Raw and Adjusted Series Don’t Always Differ

As I was preparing an analysis of a buy‑sell model for several major ETFs, I stumbled across some unexpected puzzles in the price data.  Tiingo provides both raw and adjusted price series, but for certain ETFs the two are identical — even across known split dates.

This post explains how I discovered these puzzles in selected ETF ticker prices from Tiingo.  The post also describes why the puzzles matter, and how you can adjust for them when performing ETF analyses with Tiingo data.

Where I Discovered Tiingo ETF Price Puzzles

I was analyzing a model based on EMA proper orders for prices when I first noticed ETF price puzzles.  Any ETF price series can have multiple EMAs depending on their period lengths.  No matter what the period length for an EMA, it is always dependent on its underlying price data.  For any trading date, EMAs with shorter period lengths that have higher price values than EMAs with longer period lengths are in EMA proper order.

The raw prices for a security, such as an ETF, are generally based on the demand for the security among traders and investors.  When the demand declines, the raw ETF price declines.  Conversely, when the demand increases, the raw ETF price increases.

Corporate actions, such as when an ETF sponsor initiates a stock split, can also cause raw ETF prices to change.  For example, a 2-for-1 forward stock split means the number of shares doubles for each shareholder.  While the number of shares doubles, the raw price drops by 50% on the day of the stock split.  To compensate for this halving on the day of the split and additional days going forward, the historical price values before the split are also decreased by 50%.  The modified historical prices are referred to as adjusted prices.  To properly compare prices before and after a split (or EMAs before and after a split) you need to use adjusted prices instead of raw prices before and after the split.

A reverse split works in the opposite direction of a forward split. Instead of increasing the number of shares and lowering the price, the ETF sponsor reduces the number of shares outstanding while proportionally increasing the raw price. For example, in a 1‑for‑3 reverse split, every three shares are consolidated into one, and the raw price triples on the effective date. Just as with forward splits, the historical series is adjusted so that pre‑split prices reflect the new share count, ensuring continuity across the time series. Whether the split is forward or reverse, the adjusted series is designed to remove the artificial jumps (sometimes called price discontinuities) caused by corporate actions, allowing analysts to focus on genuine price movements driven by market demand.

No matter what buy-sell model or trading strategy you are examining, you do not want stock splits disrupting the continuity of prices over time.  Instead, you want adjusted price series that are based on trader and investor demand for shares.

When I was examining model performance for TQQQ adjusted price data from Tiingo, I discovered discontinuities.  These discontinuities caused the buy-sell model to underperform because they caused price trends to be impacted by stock splits instead of investor and trader demand trends before and after a split forward.

The following screenshot displays raw and adjusted TQQQ price values based on downloads from Tiingo.com.  The tradedate values begin on 2014-01-16  and end on 2014-01-30.  Notice the discontinuity in prices between 2014-01-23 and 2014-01-24.

I initially checked historical market data to discover if the discontinuity was driven by some news or market action factors on the part of investors and traders.  However, that search did not lead to any plausible explanation for the discontinuity.

Next, I compared price discontinuities with historical records for stock splits.  For these comparisons there was a strong and consistent pattern between stock splits and price discontinuities.  There was a 2-for-1 forward stock split for TQQQ shares on January 24, 2014.  Notice that both rawclose and adjustedclose column values dropped by about fifty percent on January 24 relative to the preceding trading date, which is generally consistent with the outcome of a 2-for-1 stock split.  These price declines are puzzling because the TQQQ sponsor did not actually decrease the market value of aggregate TQQQ shares.  Instead, the share price was cut in half to offset the doubling of share volume.

 

 

History of Stock Splits for Four Tickers

The history of stock splits for a ticker is important because stock splits are a root cause of the stock puzzles that motivate the release of this blog post.  I include in this section a brief history of stock splits that document the stock split history for four tickers (QQQ, TQQQ, SPY, SPXL).  The table values are based on Google Search and Copilot prompt replies for split history.  Buy-sell choices for these four tickers will be modeled with an EMA proper order criterion in an upcoming blog post with the correction factors covered in this post for migrating data from raw stock prices to valid adjusted stock prices.

 

Stock Splits for QQQ, TQQQ, SPY, and SPXL

Ticker

Date(s)

Split Ratio

Type

QQQ

Mar 20, 2000

2‑for‑1

Forward Split

TQQQ

Feb 25, 2011

2‑for‑1

Forward Split

 

May 11, 2012

2‑for‑1

Forward Split

 

Jan 24, 2014

2‑for‑1

Forward Split

 

Jan 12, 2017

2‑for‑1

Forward Split

 

May 24, 2018

2‑for‑1

Forward Split

 

Jan 21, 2021

2‑for‑1

Forward Split

 

Jan 13, 2022

2‑for‑1

Forward Split

SPY

None

N/A

N/A

SPXL

Apr 2, 2013

1‑for‑3

Reverse Split

 

May 1, 2017

4‑for‑1

Forward Split

 

Jan 12, 2022

2‑for‑1

Forward Split

 

SPY is an example of a ticker that does not need to be checked for puzzling price continuities because it has no stock splits in its history from its inception date through when the date price data was collected for this blog post.  On the other hand, QQQ has just one stock split in its history.  TQQQ and SPXL stock split ticker history has a more extensive set of stock splits.  As the next section shows, the process for generating custom adjusted price values based on Tiingo raw prices grows more complex as the number of historical stock splits grow.

A T-SQL Script for Computing Custom Adjusted Prices

The following T-SQL script rebuilds a stock splits table (dbo.splits) with historical split data for QQQ, TQQQ, SPY, and SPXL.  It then uses that table to calculate custom adjusted closing prices for each ticker in dbo.ticker_date_prices. The adjustment ensures continuity across split dates by scaling historical prices with the cumulative product of split factors even if the data provider’s adjusted prices do not properly adjust historical adjusted prices for stock splits.

The core logic is contained in a final select statement using a Common Table Expression (CTE) named cumulative.  This query uses a correlated scalar subquery against the custom dbo.splits table, together with the price table (dbo.ticker_date_prices), to calculate the adjustedclose column values.  It uses a scalar subquery to find the cumulative product of all future split factors and multiplies this cumulative factor by the raw closing price to determine the corrected, split-adjusted historical price. This process effectively scales all historical prices backward in time to account for subsequent splits.

The scalar subquery runs once per row in dbo.ticker_date_prices. For large datasets, this can be expensive in runtime, but I did not observe long run times for the dataset used in this blog post.  If you were running this script for hundreds or even thousands of tickers in dbo.ticker_date_prices, you may prefer to precompute cumulative factors and then join them by ticker and date to dbo.ticker_date_prices.

 

use SecurityTradingAnalytics

go

 

-- Create a fresh copy of the splits table

drop table if exists dbo.splits;

go

 

create table dbo.splits (

    Ticker      varchar(10),

    SplitDate   date,

    SplitRatio  varchar(10),   -- e.g. '2-for-1', '1-for-3'

    Factor      decimal(18,4)  -- numeric multiplier

);

 

 

-- populate the splits table

insert into dbo.splits (Ticker, SplitDate, SplitRatio, Factor) values

-- QQQ

('QQQ', '2000-03-20', '2-for-1', 0.5),

 

-- TQQQ

('TQQQ', '2011-02-25', '2-for-1', 0.5),

('TQQQ', '2012-05-11', '2-for-1', 0.5),

('TQQQ', '2014-01-24', '2-for-1', 0.5),

('TQQQ', '2017-01-12', '2-for-1', 0.5),

('TQQQ', '2018-05-24', '2-for-1', 0.5),

('TQQQ', '2021-01-21', '2-for-1', 0.5),

('TQQQ', '2022-01-13', '2-for-1', 0.5),

 

-- SPY

-- No splits, so no rows needed

 

-- SPXL

('SPXL', '2013-04-02', '1-for-3', 3.0),

('SPXL', '2017-05-01', '4-for-1', 0.25),

('SPXL', '2022-01-12', '2-for-1', 0.5);

 

 

-- optionally display dbo.splits

select * from dbo.splits;

 

-- return custom adjusted close values for all tickers

with cumulative as (

    select

        p.ticker,

        p.[date],

        p.[close] as rawclose,

        p.[close] * exp(

            isnull(

                (

                    select sum(log(s.factor))

                    from dbo.splits s

                    where s.ticker = p.ticker

                      and s.splitdate > p.[date]

                ), 0

            )

        ) as adjustedclose

    from dbo.ticker_date_prices p

)

select

    ticker,

    date,

    rawclose,

    adjustedclose

from cumulative

order by ticker, date;

 

The following screenshot displays an excerpt from the result set from the preceding script with rawclose and adjustedclose column values for dates that match the result set pictured in the “Where I Discovered Tiingo ETF Price Puzzles” section.  The result set from the “Where I Discovered Tiingo ETF Price Puzzles” section shows adjustedclose column values derived from Tiingo.com.  The result set from the following screenshot shows custom adjustedclose column values.

As you can see, there is no major discontinuity in the adjustedclose column values between  2014-01-23 and 2014-01-24.  In contrast, the result set from the “Where I Discovered Tiingo ETF Price Puzzles” section shows a noticeable decline in adjustedclose values between 2014-01-23 and 2014-01-24.  This outcome confirms the effectiveness of the preceding script at removing discontinuity after a stock split relative to the reported adjustedclose column values from Tiingo.  A slightly reduced discontinuity effect shows for several days after the stock split relative to the earlier result set values from Tiingo.

 

 

Concluding Comments

This blog post alerts you to the fact that you can return improperly corrected adjusted price data from Tiingo (and perhaps other ohlcv end-of-day data providers).  It is important to detect and correct invalid adjusted price series because they can result in faulty conclusions about a buy-sell model or a strategy for buying and selling ticker shares.  This post reveals how to detect improperly adjusted price data from a data provider when the errors derive from stock splits.  The post also presents a T-SQL script that shows how to calculate alternative adjusted price data as a workaround for the problem of improperly returned adjusted price data from a data provider.

Comments

Popular posts from this blog