Tutorials & Documentation
Oct 31, 2023

How to understand token prices with onchain data

For a deeper dive into AMMs, I check out the Uniswap v2 Explainer which covers the most popular AMM model in crypto and its math on slippage and price impact.

Prices are everywhere

You can get token prices from centralized exchanges, 3rd parties like Coingecko, and data providers like us here at Flipside:

(Check out our Ethereum Core Fact Hourly Token Prices Table for data like the above.)

But sometimes you want more granularity. This report details an on-chain pricing methodology for historical block level pricing.

This report (full view w/ code and interactives) seeks to combine the best of blending (using multiple price sources) with the best of on-chain access (the calculation is consistent and reproducible without needing off-chain data) to recommend a useful mechanism for assigning a price to a single block for historical analysis.

Get granular

Our Methodology is:

  1. Grab the most popular Uniswap v3 pools (you could go broader and use all the DEXes we have in our EZ_SWAPs table)
  2. Treat the stablecoins as 1 USDC = 1 USDT = 1 DAI for now
  3. Measure all the trades in/out of those pool as ETH/stablecoin at the block level
  4. Get the Volume-Weighted Average ETH/stable Price ("VWAP", ETH_WAVG_PRICE) for the block.
  5. Infill missing blocks by persisting the previous block's VWAP (this should make sense, if there's no trades in a block, then the price in the pools haven't changed either)
  6. Look back 100 blocks and get the Median VWAP; call this the Market Price

How is this useful?

The motivation for this methodology is 3-fold:

  1. Historical Prices should be usable for analysis of small time-windows, e.g., < 60 minutes.
  2. Historical Prices should be “realistic”, that is, we should believe that our price could have been realized somewhere in the ecosystem within the small time-window.
  3. Historical Prices should be smooth in normal times, but reactive to sustained volatility that did occur.

Since it's block-level let's consider (1) passed. But (2) and (3) need some clarification.

What is a realistic price?

A realistic historic price is one that we could have traded at around the time we're applying it. If we claim the historical prices from Block a to Block b is 1,500 - 1,550 USD per ETH, but the volume weighted average prices (VWAP) from Block a to Block b have a range of 1,600 - 1,700; we should be concerned.

We looked at this two different ways. First, we wanted to identify broadly that Market Price consistently flows through VWAP.

If we say the Market Price from Block a to Block b ranges from 1,550 to 1,650; and the VWAP in the same Block a to Block b window ranges from 1,500 to 1,700; then we can feel a little better that the more chaotic VWAP chart crosses our Market Price chart over the time window.

Our Market Price from block 15,000,501 to 15,000,504 is 1,120.4 USD / ETH. While the VWAP over the same range is 1,119.62 to 1,120.72. This crossing validates the idea that the 1,120.4 Market Price was possible to trade at over the range.

We identify that about 10% of blocks in our 1 Million block same have a cross between VWAP and Market Price. 90% of the time, there is a cross within 20 blocks (we label this "realized").

But note, traders and financial analysts might see this and think we're saying something about the forecast-ability of Market Price.

This Market Price methodology is not for forecasting. In a flash crash situation, a single Market Price, Mi] may be strictly above all VWAP in a range from Block a to Block b where a < i < b. Similarly in sudden rise situation, a single Market Price Mi] be be strictly below all VWAPa, b].

In fact, this has to be true for some range, because this is how local minimum and maximum (i.e., the "top" and "bottom") are defined for a range.

In August 2022, around block 15,369,840 there was a flash crash where ETH VWAP went straight down from 1810 to 1760 USD/ETH. It took our Market Price >100 blocks to cross, and in that time a Market Price deviated from VWAP by as much as ~4%!

(Quick spikes are safely smoothed; but real crashes can trick us.)

For those that are curious about how a single Market Price, Mi] can forecast, we included a forward look of 100 and 1,000 blocks. 75% of the time, a single Market Price, Mi] is crossed by VWAPi, i+100].

And 93% of the time, crossed by VWAPi, i + 1000]. Expectedly, this would be a lower measure of "realistic", but still pretty good as 100 blocks is only 20 minutes; so this block level price can still be useful where single hourly prices miss signal.

How smooth is smooth?

On-chain trading is chaotic. 1 big trade can have a lot of price impact, or a misconfigured trade can allow a crazy amount of slippage and get exploited by a MEV bot ("sandwich attack").

Volume Weighted Average Price, while objectively an accurate measure of what happened on-chain, is just not smooth and this chaos can make analysis that is not price-specific distorted by outliers. For example, if you were tracking DAO treasury valuations over time, you probably wouldn't want to see a 25% dip in under 1 minute (Block 15,288,204 to 15,288,206).

Chaotic spikes, in some context are noise while in other contexts sustained price changes are actually signal. Our Market Price should be smooth but reactive to sustained volatility.

The good news is, 98% of the time, we're within 1% of VWAP. Short term, noisy, spikes being smoothed out is a good thing.

When thinking of smoothness you may immediately think variance, or its square root, the standard deviation.

We checked and crypto is still high variance crypto. In these 1 Million blocks the standard deviation (sqrt of variance) for VWAP is 218.899 while for Market Price it is 218.878, an only marginal difference.

We instead thought of the problems of random walk and momentum trading.

Price going up just because it went up recently only matters if it is sustained or has a good reason (e.g., big relevant news or Macro changes like the Federal Reserve Funds Rate). Again, noise vs signal.

So, we measured the partial autocorrelation of both VWAP and Market Price to see how much they reacted to (extremely short term) recent history. If you over-listen to noise, you'll get more chaos than is really warranted.

VWAP has over 10% partial autocorrelation going back 5 blocks. Too reactive to noise, while Market Price never has over 10% partial autocorrelation.

This makes total sense, because it looks back 100 blocks and calculated the median, which is much more resistant to low-value spikes than a smaller lookback and/or calculating the average.

Summary

There are times when you need a little more granularity than hourly or daily token prices. While you can ask central exchanges or 3rd parties for their numbers, we wanted to develop a method that was fully on-chain.

The somewhat simplistic methodology here doesn't use machine learning or much statistics, but it removes noise, feels realistic, and can be used for block-level token prices.

Here is the chart for the full sample period. And as always, for those who like code, we have the full report with interactive visuals and it is fully open source and reproducible via github.