This is not investment advice. I am not a financial advisor. I am not responsible for any losses you may incur. Do your own research and due diligence before investing.
Intro
I am looking to forecast the price growth of a NFT relative to the market. There are several use cases if this works:
- Recommend NFTs to buy based on their price growth potential. This avoids you trawling through lots of confusing indicators.
- Algorithmic trading of NFTs based on signals from the model. This is similar to how quantitative hedge funds trade stocks.
I will be using a machine learning approach to forecast the price growth of NFTs. I will be using on-chain data from Nansen Query.
Data
There are over 250k NFTs within the Ethereum ecosystem but a lot of them have no liquidity and are hence not investible. To filter out relevant NFT collections, I will be using the following criteria:
I select collections where based on secondary market sales since 1st April 2021 (excluding wash trades) there are:
- Min 25 unique sellers
- Min 25 unique buyers
- Min 50 trades
- 3 sales a week for at least 50% of the weeks since NFT was deployed.
After filtering, I am left with approx 3,400 NFTs.
Feature Engineering
The features used for this model are derived from sales and the ownership characteristics of the collection. Some of the features are derived from segments developed by Nansen.
Price Returns
As each token is unique we have to choose an index to track the price growth of each collection over time. The return of this price index will be used for training and validation of our model. Usually, floor price of a collection is used as the price index. However, floor price is not always a good proxy for the trading price of a collection.
Consider 2 NFTs from the same collection: A is listed for 10 ETH and B for 20 ETH. So, the floor price is 10 ETH. The last sale of a token from the collection was at 10 ETH. Suppose NFT A sells at the best offer for 7 ETH, now with just NFT B listed, the floor has doubled to 20 ETH, but the actual return is -30% with the last two trades at 10 ETH and 7 ETH.
Since the listing floor is a bit flaky, we will instead use sales floor as our price index. The sales floor is the minimum trading price of a NFT from a collection based on last N sales after removing outliers. The threshold N varies by collection size. It is more difficult to manipulate sales floor since its derived from multiple on-chain trades rather than a single listing price. This expands on the work I did while building the Chainlink Oracle for Damien Hirst’s Currency NFT.
See below the sales floor of Fidenza vs the listing floor price. As you can see, the sales floor (in blue) correlates well with the listing floor (orange).
From the sales floors we can get a price return over each week for all collections. The target variable for the model is excess market return which is calculated by subtracting the market return from the collection return for the week. We will build time sliced features based on data from the time before the week of the price return.
For example, when we are predicting price growth for week 1, we will use data from week 0. When we are predicting price growth for week 2, we will use data from week 0 and week 1.
Predictors
I use raw features and lagged features for prediction. As you will see next I use a very simple xgBoost model. Since the model natively handles interaction there is no complex feature engineering to be done on top of this.
Sales
Within sales we use the following features:
- Floor Price - Current sales floor in ETH
- Sales change 3/7d - The change in sale count in the last 3/7 days
- Floor price change 3/7d - The change in floor price in the last 3/7 days
- Running average of sales per day
Ownership
We know the number of unique owners of a NFT at each point in time. We can use this to calculate the following features:
- Number of owners
- Number of Smart Owners labelled by Nansen
- Number of Smart NFT Owners labelled by Nansen
- 3/7d change in the above
Token Balances
In addition to number of owners, we can also use the number of tokens owned by each owner. We can use this to calculate the following features:
- Number of owners with 1 token
- Average balance of owner/smart owner/smart nft owner.
- 3/7d change in the above
Project Metrics
The time since project’s first secondary market sale is used as a proxy for project age.
Selection criteria
Our set of 3000 NFTs contains selection bias as we have filtered out NFTs based on data out of sample. Hence we apply a further selection criteria to select projects to be included only when they pass the criteria.
For each project we calculate the first date at which all of the following criteria are met:
- Floor price > 0.5 ETH - I rarely buy NFTs below this price as a quality filter.
- Running average daily sales > 10 - Need liquidity before NFT is declared investible.
- 7 days since the first secondary market sale. - Need to wait for the hype to die down.
As you can see the algorithm adds 5-10 projects a week to our investible set.
After adding the selection criteria we are left with around 900 NFTs since the start of Jan 2023.
Target Variable
As discussed previously our target variable is the price growth of the NFT floor price over a week relative to the market.
The chart below plots the week against the average price return of all NFTs in our investible set. We can see the large bull run in the middle of 2021 but recently the price returns have been negative. Since January prices have been falling down further at a faster rate.
After removing the market price growth from each NFT/week we are left with the excess returns. The chart below shows the distribution of excess returns. As expected the distribution follows a bell shaped curve with a mean of 0 and sd of 0.26. We can see a fatter tail on the right hand side of the distribution.
Exploratory Data Analysis
The charts below shows a line of best fit (using the LOESS model) for each feature against the excess returns. It is useful in seeing what the relationship is between each feature and excess returns. The grey bands show the 95% confidence interval and if they entirely cover the solid black line then the feature is probably not useful for forecasting (in a linear setting at least).
Note: the x-axis are on log scales and since some features are below 0 (eg. changes in sales) I have added 1 to all the values to make them log safe. Eg. due to this the minimum value for owners/smart owners etc is 1 not 0.
The features that seem to have the strongest relationship with excess returns are the ones relating to smart owners and floor prices.
Model
I tried linear models to start with, but due to complex interactions between the features xgBoost was the best performing model. I used the xgboost package in R.
Validation
I use time slicing to validate the model. The training set uses data until week D
and test set uses data from week D+1
. I train a model for each week D
from October 2022 to March 2023. This gives us 25 weeks of prediction data to evaluate the model on.
Note: to prevent selection bias I again perform the filters set out in the Data section above. To recap, based on sales until week D
I only include projects where
- Min 25 unique sellers
- Min 25 unique buyers
- Min 50 trades
- 3 sales a week for at least 50% of the weeks since NFT was deployed.
Performance
To see if the model works I evaluate the average price return of a portfolio made of top 25, 50 and 100 NFTs against the market. I have filtered for NFTs with floor below 25 ETH as I don’t intend to invest in NFTs with a floor price above this. I also filtered out collections that did not trade in the 1 week prior to the prediction week.
To mimic real life portfolio, I calculate a price weighted average returns for both the market and the portfolio of top 25/50/100 NFTs. Practically this gives the performance of a portfolio where you buy 1 NFT from each collection. I also subtract trading costs of 1%, assuming all projects recommended are royalty free.
Returns of model vs market
The chart below shows the change in value of a portfolio that holds 1 NFT from each collection in the top 25/50/100. The portfolio is rebalanced weekly. The market portfolio is a portfolio that holds 1 NFT from each collection in the investible set. The market portfolio is also rebalanced weekly.
Note: the portfolio returns are an approximation as it assumes we can always trade at the sales floor.
The chart below shows the weekly excess return of each portfolio. The excess return is the return of the portfolio minus the return of the market.
Overall, the performance of all subsets of recommendations are much better than the market. This shows that it is indeed possible to forecast price growth of NFTs and the recommendations from the model can be used to build a portfolio that outperforms the market.
Top trades
The table below shows the top 10 buys made by the model in the 25 weeks tested above.
Collection | Bought at | Sales floor at buy | Sales floor at sell | Profit (ETH) |
---|---|---|---|---|
Gazers Art Blocks Curated | 27 Oct 22 | 14.99 | 25.00 | 10.01 |
Bamboo Color | 16 Mar 23 | 0.68 | 7.74 | 7.05 |
Essence | 09 Mar 23 | 0.45 | 5.41 | 4.96 |
DenDekaDen Genesis Omikuji | 02 Feb 23 | 1.50 | 3.80 | 2.30 |
Meta Monopoly NFT | 09 Mar 23 | 1.41 | 3.65 | 2.23 |
Meridian Art Blocks Playground | 05 Jan 23 | 8.00 | 10.12 | 2.12 |
Meta Monopoly NFT | 22 Dec 22 | 0.96 | 3.07 | 2.11 |
Fontana Art Blocks Curated | 24 Nov 22 | 4.97 | 7.06 | 2.09 |
Memories of Qilin Art Blocks Curated | 03 Nov 22 | 6.09 | 7.94 | 1.85 |
Gazers Art Blocks Curated | 24 Nov 22 | 24.25 | 26.01 | 1.77 |
Worst trades
The table below shows the top 10 biggest loss making trades.
Collection | Bought at | Sales floor at buy | Sales floor at sell | Loss (ETH) |
---|---|---|---|---|
Gazers Art Blocks Curated | 03 Nov 22 | 25.00 | 19.49 | -5.51 |
Meridian Art Blocks Playground | 09 Feb 23 | 9.74 | 6.00 | -3.74 |
PROOF Collective | 02 Feb 23 | 20.72 | 18.00 | -2.72 |
PROOF Collective | 09 Feb 23 | 18.00 | 15.90 | -2.10 |
GentsCroquetClub | 09 Feb 23 | 8.99 | 6.94 | -2.06 |
Mutant Ape Yacht Club | 16 Mar 23 | 13.61 | 11.85 | -1.75 |
BoredApeKennelClub | 12 Jan 23 | 8.48 | 6.86 | -1.62 |
Castaways - The Islands | 27 Oct 22 | 3.92 | 2.52 | -1.41 |
DigiDaigaku | 16 Mar 23 | 6.42 | 5.04 | -1.38 |
Anticyclone Art Blocks Curated | 30 Mar 23 | 9.69 | 8.46 | -1.23 |
Model Interpretability
The model is a black box and it is difficult to understand why the model is making the predictions it is. I use the DALEX package in R to try and understand the model. The package allows you to calculate feature importance and partial dependence plots.
The chart below shows the relative importance of the feature. The features at the top have the highest impact in improving predictions, whilst one at the bottom have the least impact.
It is also interesting to see why a particular NFT had a high or low prediction. The chart below shows the most important features for the particular NFT’s prediction. The values on the y axis after the feature name is the value of the feature and the corresponding bar on the x axis is the positive (green) or negative (red) impact of the feature on predicting how well the NFT will do in the next week.
Next Steps
The model has been consistently outperforming the market for the 25 weeks since October 2022. However, the model is not perfect and there are many things that can be improved.
Firstly I would like to test the model’s effectiveness on algorithmic trading. The trading algo will go out there and buy any NFT that is recommended by the model and sell it a week later at a reasonable price (floor?). This will give a better idea of how well the model performs in real life.
Secondly, I would like to train the model with a 2 week or 1 month prediction horizon, since I don’t have time to trade every week and am generally looking for longer term investments.
Finally, there are countless features that can be added to the model. I have only used a small subset of features that I thought would be useful. I will write a follow up post after I spent more time evolving the model.