Causality in CryptoMarkets

In this article: We discuss causality in crypto markets. Specifically, when is a good time to buy / sell a cryptocurrency; this analysis will be conducted from (at the time) live data from ProjectPiglet.com.


Intro to Trends on ProjectPiglet.com

For this article, we will be applying Granger Causality to a few cryptocurrencies for the past few months. We’ll use live trend and pricing data from ProjectPiglet.com, between April 1, 2017 and December 1, 2017.

The goal of ProjectPiglet.com is to provide insights from experts to the masses; bubble up the knowledge, if you will. In the case of crypto-markets, it’s often the reverse, where the masses tell the experts how they feel. Specifically, (crypto)currencies are massively impacted by how confident masses feel. This is part of the reason for the federal reserve in the U.S., as it stabilizes the U.S. Dollar. In contrast, cryptocurrencies have no such system, so a boom-bust cycle is inevitable.

Luckily, with ProjectPiglet.com we can use this to our advantage, particularly by reviewing the Trend Data / Chart (as it provides insights about the masses):

From ProjectPiglet.com

If you’re interested in the specifics regarding the chart, feel free to checkout our explanation. In summary, trend’s are the normalized volume of discussions between 0 and 1, as tracked by ProjectPiglet.com.

Code for Granger Causality

Now, lets get to the fun part – coding!

First, we create a function that takes in trend and pricing data, normalizes the data using zscore, and formats the data for the granger causality function we will be using (from the python package statsmodels):

From there it’s relatively easy to ingest into the Granger Causality function (from the python package statsmodels). The only part we have left to do is defining the “max lag”, or how far back in time should be assessed by the function. In this case, 60 days was chosen as we are only looking at a few months of data. Just make sure it is less than one third of the data’s size (I recommend choosing <10% of the data set size):

With the output from that function it is possible to pull out the F-test and p-value from the “gc” variable (Granger Causality). Both the F-test and p-value are used for determining correlations, however I wont dive into that at the moment. The full documentation on the “grangercausalitytest” function is here, and the full code (in the github, below) will provide further insights.

In addition to the F-test and p-value, the Granger Causality function will provide us with a list of “lags”, which is let us know the offset to look for. For this example, the “lag” is how many days prior a change in trend will impact the price.

With this code it is now possible to run our Granger Causality assessment!

Trend and Price Causality in CryptoCurrencies

Using trend data from ProjectPiglet.com, we will review the following cryptocurrencies from April 1, 2017 to December 1, 2017 for “probable causality” (i.e. Granger Causality) based on trend and price data:

  • Bitcoin (BTC)
  • Ethereum (ETH)
  • Litecoin (LTC)
  • Bitcoin Cash (BTC)
  • Ripple (XRP)
  • Monero (XRM)

When we run a modified version of code above; we end up with the following chart representing the number of days lag in price after a trend event, for the six cryptocurrencies above:

Correlations between Trend and Price (based on offset of days)

For reference, a p-value < 0.05 is typically considered the threshold for the correlation, between datasets. In this case, there’s also what we are calling a “Strong Correlation” which is a p-value < 0.01. The strange part is the uniform band of “Strong Correlations” at the bottom.

Upon inspection, it appears that one cryptocurrency in particular is the culprit Bitcoin Cash (BCH):

Zscore BCH Trend & Price

The large amount of no data leading to a high amount of correlation. This is one of the common pitfalls we mentioned Limits of Granger Causality, and is an excellent example of why you always verify your data sets! Once we remove BCH from our dataset we now have the following cryptocurrencies we are searching for Granger Causality:

  • Bitcoin (BTC)
  • Ethereum (ETH)
  • Litecoin (LTC)
  • Bitcoin Cash (BTC)
  • Ripple (XRP)
  • Monero (XRM)

We then appear with the following chart representing the number of days lag in price after a trend event:

Correlations between Trend and Price (based on offset of days)

I’ve personally verified each of the remaining datasets. I believe there is indeed a probable causality (where the trend impacts the price). You’re welcome to do the same with the code / data provided below.

Causality in Crypto Markets

The more specific outputs (i.e. which currencies have causality) from our code are as follows:

Output of Granger Causality

Importantly, it appears there is a pattern – i.e. something we can trade off of. Most of the currencies show a strong movement roughly five days after there is a trend event; averaging major cryptomarket movements eleven days after a trend event and with standard deviation of 7 days.

Further, the one outlier Ripple (XRP) is mostly owned by a single entity. Meaning it might make sense there is no correlation between the price of Ripple (XRP) and the number of people discussing Ripple (XRP); where as the other currencies are mostly owned by various groups / the masses.

Verification of Granger Causality

For safe measure, I typically will do an additional assessments to verify theories and confirm Granger Causality is working. Searching for correlations between trends for each of the cryptocurrencies and a “random walk” (i.e. random data), which outputted the following chart:

Trend of CryptoCurrencies compared to Random Walk

For comparison purposes, it’s clear there is no pattern at all; where as the live data has a clear pattern we can follow. In addition, it’s highly recommended to review the output of the individual timeseries datasets being compared. It’s extremely common to get results such as we did with Bitcoin Cash (BCH).

Conclusion

Our goal in sharing our analysis using Granger Causality was two fold:

  1. Help explain Granger Correlations and how to use them
  2. Intice you to try ProjectPiglet.com! (Use coupon code: pigletblog2018 – 25% off for 12 months)

We hope we’ve done both!

The github repo with all the code and example data is here. Feel free to leave comments, tweet, emails, or leave issues on the repo itself.

We’d love feedback and/or to help if you need it.

Limits of Granger Causality

In this article: We discuss Granger Causality works and some of the common issues, drawbacks, and potential ways to improve the method(s). Building primarily off our previous article Pitfalls of Backtesting and insights gained from building ProjectPiglet.com.


One of the most common forms of analysis on the stock market is Granger Causality, which is a method for indicating one signal possibly causes another signal. This type of causality is often called “predictive causality”, as it does not for certain determine causality – it  simply determines correlations at various time intervals.

Why Granger Causality? If you search “causality in the stock market“, you’ll be greeted with a list of links all mentioning “granger causality”:

Search on DuckDuckGo

In other words, it’s popular and Clive Granger won a Nobel on the matter[1]. That being said, there are quite a few limitations. In this article, we’ll be covering a brief example of Granger Causality, as well as some of the common pitfalls and how brittle it can be.

What is Granger Causality?

Granger Causality (from Wikipedia) is defined as:

A time series X is said to Granger-cause Y if it can be shown, usually through a series of t-tests and F-tests on lagged values of X (and with lagged values of Y also included), that those X values provide statistically significant information about future values of Y.

In other words, Granger Causality is the analysis of trying to find out if one signal impacts another signal (such that it’s statistically significant). Pretty straightforward, and is even clearer with an image:

From Wikipedia

In a sense, it’s just one spike in a graph causing another spike at a later time. The real challenge with this is that this needs to be consistent. It has to repeatedly do this over the source of the entire dataset. This brings us to the next part: one of the fragile aspects of this method is that it often doesn’t account for seasonality.

Granger Causality and Seasonality

One common aspect of markets is that they are seasonal. Commodities (as it relates to the futures market) related to food are extremely impacted by seasonality[2]. For instance, if there is a drought across Illinois and Indiana during the summer (killing the corn crop), then corn prices from Iowa would likely rise (i.e. the corn from Iowa would be worth more).

From Wikipedia

In the example, there may be decades where some pattern in the market holds and Granger Causality is relevant. For instance, during summer heat waves in Illinois, corn prices in Iowa increase. On the other hand, with the advent of irrigation methods that deliver water underground, heat waves may no longer impact crops[3]. Thus, the causality of heat waves in Illinois may no longer impact the corn prices in Iowa.

If we then attempt to search for Granger Causality on the entire time range (a) pre-irrigation and (b) post irrigation, we will find there is no causality!

However, during the pre-irrigation time range we will find probable causality, and for post-irrigation time range we likely won’t find probable causality. Any time you combine two timeframes like this, the default is no Granger Causality (unless it’s a very small portion of the dataset). Bringing us to the conclusion, that:

Granger Causality is very sensitive to timeframe(s)

Just a few data points in either direction can break the analysis. This makes sense, as it is a way to evaluate if two time series are related. However, it does lead one to note how brittle this method can be.

Granger Causality and Sparse Datasets

Yet another potential issue with Granger Causality is sparse datasets. Let’s say we have dataset X and dataset Y: if dataset X has 200 data points and data set Y as 150 data points, how do you merge them? Assuming they are in (datetime, value) format, if we do an inner join on “datetime”, we get something that looks like the following:

From W3School

Then we will have 150 data points in a combined X and Y dataset, i.e.: (datetime, x, y). Unforunately, this also means if the data is continuous (as most timeseries data is), then we have completely broke our Granger Causality analysis. In other words, we are just skipping over days, which would break any causality analysis.

In contrast, we could do an outer join:

From W3School

We will have 200 data points in a combined X and Y dataset. Again, there’s an issue – it means we probably have empty values (Null, NULL, None, NaN, etc. ) where the Y data set didn’t have data (recall Y only had 150 data points). The dataset would then have various entries that look as such: (datetime, x, NULL).

To fix the empty values, we can attempt to use a forward or back fill technique. A forward/back fill technique is where you fill all the empty values with the previous or following location(s) real value.

This code could look like the following:

From the sound of it, this method sounds promising! You’ll end up with something that’s continuous with all real values. You’ll actually get a graph like this:

Change in BCH price vs Random Walk (with NaNs)

As you can see, there are large sections of time where the data is flat. Recall the seasonality issue with Granger Causality? This method of outer joins + forward / back filling will definitely cause issues, and lead to minimal to no meaningful correlations.

Sparse datasets make it very difficult (or impossible) to identify probable causality.

Granger Causality and Resampling

There is another option for us, and that is “resampling”. Where instead of just filling the empty values (Nulls / NaNs) with the previous or following real values, we actually resample the whole series. Resampling is a technique where we fill the holes in the data with what amounts to a guess of what we think the data could be.

Although there are quite a few techniques, in this example we’ll use the python package Scipy, with the Signal module.

At first glance, this appears to have solved some of the issues:

Change in Bitcoin Price vs Random Walk

However, in reality it does not work; especially if the dataset starts or ends with NaN’s (at least when using the Scipy package):

Change in BCH price vs Random Walk (with NaNs)

If you notice, prior to the ~110 data point, the values are just oscillating up and down. The resampling method Scipy is using does not appear to be functional / practical with so few data points. This is because I selected data set for Bitcoin Cash (BCH) and the date range is prior to Bitcoin Cash (BCH) becoming a currency (i.e. there is no price information).

In a sense, this indicates it’s not possible (at least given the data provided) to attempt Granger Causality on the given date ranges. Small gaps in time can have dramatic impacts on whether or not “probable causality” exists.

When determining Granger Causaily it is extremely important to have two complete overlapping datasets.

Without two complete datasets, it’s impossible to identify whether or not there are correlations over various time ranges.

Resampling can cause artifacts that impact the Granger Causality method(s).

In fact, the most recent example was actually positive for Granger Causality (p-value < 0.05)… That is the worst scenario, as it is a false positive. In the example, the false positive occurs because when both datasets are resampled they had a matching oscillation… it wouldn’t have even been noticed if the raw data sets weren’t being reviewed.

This is probably the largest issue with Granger Causality: every dataset needs to be reviewed to see if it makes sense. Sometimes what at first appears to make sense, in reality the underlying data has been altered in some way (such as resampling).

Granger Causality and Non-Linear Regression

Changing gears a bit (before we get to a real-world ProjectPiglet.com example), it’s important to note that most Granger Causality uses linear regression. In other words, the method is searching for linear correlations between datasets:

From austingwalters.com

However, in many cases – especially in the case of markets – correlations are highly likely to be non-linear. This is because markets are anti-inductive[5]. In other words, every pattern discovered in a market creates a new pattern as people exploit that inefficiency. This is called the Efficient Market Hypothesis.

Ultimately, this means most implementations of Granger Causality are overly simplistic; as most correlations are certainly non-linear in nature. There are a large number of non-linear regression models, below is an example of Gaussian Process Regression:

From Wikipedia

Similar, non-linear regression techniques do appear to improve Granger Causality[6]. This is probably due to most linear correlations already being priced into the market and the non-linear correlations will be where the potential profits are. It remains to be seen how effective this can be, as most research in this area is kept private (increasing profits of trading firms). What we can say is that non-linear methods do improve predictions on ProjectPiglet.com. They also require a larger dataset than their linear regression counterparts.

Conclusion

Overall, Granger Causality has quite a few potential pitfalls. It is useful for indicating a potential correlation, but is only a probable correlation. It can help to identify market inefficiencies and open the opportunity to make money, but will probably require more finesse than simple linear regression.

All that being said, hope you’ve found some of the insights useful!

Perils of Backtesting

One thing considered absolutely essential when developing trading strategies or models is backtesting. Backtesting is the term used to test trading strategies/models on historic data, and can also be applied to other fields such as oceanography or meteorology[1].

I am a cynic at heart. So, typically I evaluate issues with a method prior to starting an implementation. In backtesting, there are a lot of issues. Unforunately, it’s also the best we have.

In this article, we might break hearts, but we will explain some methods for mitigating issues.

The Multiple Comparisons Problem

In the case of backtesting, likely the largest issue is the Multiple Comparisons Problem, best described as follows:

The more inferences are made, the more likely erroneous inferences occur.

It is a well known issue and has been written about by large companies and small blogs, such as the Price Action Lab Blog:

The fundamental problem of backtesting for the purpose of finding an edge in the markets is that it it introduces a dangerous form of data-mining bias caused by the reuse of data to test many different hypotheses.

Regardless of what name it goes by (Multiple Comparison Problem or Data-Mining Bias), there is an issue with searching historic data for predictors. The more we think we find, the higher likelihood we are just seeing something erroneous.

Problematic Backtesting Example – Technical Analysis

It’s the same reason why “Technical Analysis” of stock trends are pretty questionable. The lines drawn on a chart, are essentially just making things up (might be right some of the time, but we don’t know). Here’s an exacmple, from stockcharts.com:

From Stockcharts.com

These kinds of “Technical Analysis” methods originally developed in the 1920’s and 1930’s[2]. All evaluations had to be done by hand, and they are prone to hindsight bias in their stock selection. Personally, I highly doubt it’s effectiveness overall. The real-life research into the field of “Technical Analysis” has had mixed results and seems to be fairly split on the methodology and outcomes[3].

The Efficient-Market Hypothesis

You are probably asking yourself, what’s the alternative!? I watnt to prove my trading strategy, financial engine or AI financial advisor works!

Unfortunately – there really isn’t a better way to test any sort of model or strategy.

In fact, there is the Efficient-Market Hypothesis which essentially states:

Stocks always trade at their fair value, making it impossible for investors to either purchase undervalued stocks or sell stocks for inflated prices. As such, it should be impossible to outperform the overall market through expert stock selection or market timing, and that the only way an investor can possibly obtain higher returns is by chance or by purchasing riskier investments.

From Wikipedia

The truth is, we know it’s possible to gain some advantage; if you have more information or can execute a trade faster. For instance, you can gather information through ProjectPiglet.com as we track, in real-time, experts, insiders, and the public. That’s really the key to ProjectPiglet.com‘s success, although you might not make money on every trade, we improve your chances by providing more information (until we saturate the market).

Which brings us to the next issue related to backtesting…

Today, have more information now about any historic event or price than we did at the time. This is one of the causes of the Data-Mining Bias, where we use data that we didn’t have or didn’t even exist.

More important, historic stock prices were set using prior information and prior algorithms and strategies. Meaning, the strategy being backtested may have already been discovered (at a date after our backtesting data)! There is no way we would know, and it would effectively make the strategy or algorithm in question obsolete.

For reference, this has been dubed anti-inductive[3][4] – meaning as soon as a pattern is discovered the market creates a more complex pattern, correcting for said pattern. Personally, I like to call this market entropy.

Mitigating the Issues

Although there issues with backtesting, there are ways to mitigate the issue(s).

One such mitigation is called a Bonferroni Correction, and it is used to mitigate the Multiple Comparisons Problem. The purpose of the Bonferroni Correction is to reduce the likelihood of rejecting the null hypothesis prematurely (due to the increased number of tests). In other words, it’s a way to reduce the likelihood your strategy isn’t just getting lucky.

In addition, there are also methods for mitigating the Efficient-Market Hypothesis (although honestly, to a minimal extent). This can be accomplished identifying / indicating causality between two timeseries events, such as Granger Causality:

Granger CausilityFrom Wikipedia

This is useful for indicating there is a predictable event, and is useful over various time ranges to ensure the inefficiency in the market is still present. An interesting application of this method is also discovering when the market identifies some pattern. Granger Causality works best on linear regression, and is difficult to use for the nonlinear case (AKA it’s most useful for basic causality comparisons).

Conclusion

Backtesting is difficult, error prone, and will not gurantee success; however it is the best we have. Generally, it’s the only way to test if a strategy has any merit, but any insights should be reviewed carefully.

Over the next several articles we will explain our methods for mitigating the issues, as well as share our results. To-date our results typically beat or match what’s called “buy and hold strategies”, but we bias towards reducing risk, as opposed to maximizing potential profit; another whole domain.

If you’re interested in using ProjectPiglet.com, use the coupon code: pigletblog2018

It’s 25% off for 6 months!

Beginning a Dev & Investment Diary

Per the suggestion of remirezg on Reddit.com, we’ve decided to start a “Dev Diary” and “Investment Diary”! In our case, it’ll be a bit unique, as we’ll be exploring the development of not only our system, but the accuracy and usage of our algorithms.

We realized when we started this, trust is everything. With that in mind, by providing insights to our successes and our failures, we hope to gain your trust.

In addition, or rather – to start us off. We will share of where we are at in our Litecoin | LTC investments, which we wrote about previously.

Litecoin Investing Continued

Around January 16th we purchased our first Litecoin using the new short-term advising system (just after release).

From projectpiglet.com

This enabled us to make some pretty substantial gains… or at least would have enabled us. Turns out Capital One, no longer accepts credit card purchases on Coinbase.com. Which lead to me purchasing the litecoin via a bank account.

Now, typically – I’d go, what the hell sounds great. Unfortunately, the next sell date suggested by ProjectPiglet.com was only a few days after – prior to my funds clearing.

From Projectpiglet.com

Now, luckily it was only a soft sell, and I’m actually still holding the Litecoin (LTC), but this really shows a weakness in our “Trade Potential” algorithm. The algorithm does indeed work quite well for short term trades, however I’m really interested in the long term. Everyone, wants to know when the next 100x gains are coming, and right now ProjectPiglet.com does not make it clear.

That isn’t to say we don’t have plans in the works, we do. We’ve even had something in testing for the past six months. The fact is though, it’s a hard problem. I can show individual profits (or reduction of losses), beating a buy and hold strategy nearly every time. However, what we’ve been working towards first is which asset to pick. That’s a hard question, which will make the largest gains (or least losses).

And for that, we still have a while to go.

Closing Remarks

In the mean time, I’ll try to do this as often as I can. My goal is to check ProjectPiglet.com and move money as I see fit – even if it’s against the algorithm. My wife is likely giving birth this week, so I’m wondering if my gains could outpace my babies growth…

My last investment was $500 and lets see how far we can grow it by the end of the year.

From Coinbase.com

Happy Investing!

If you’re interested in using ProjectPiglet.com, use the coupon code: pigletblog2018

It’s 25% off for 6 months!

Adding Data Sources

The bedrock of projectpiglet.com, is the data. Nothing on the site can exist without it and it takes quite a bit of it (although not as much as you might think). Today, Piglet tracks roughly one million separate subjects, and has ingested 18.5 million comments, on 1.5 million stories, from 800,000 authors. When projectpiglet.com started recollecting data a year ago, it started with a mere 4 million comments.

Four-Million, That’s A Lot!

You’re not wrong. Four-million comments is quite a bit. However, when you’re trying to track a one million plus subjects, four-million is a only a drop in the bucket. In fact, the 18.5 million comments it currently has in ingested is still way too small. For instance, on the site today, we can only accurately track popular discussion of around 10% of the S&P 500 and the top 25 or so cryptocurrencies. That’s just too small.

So what would be enough data? Similar to many things in life:

Everything in excess! To enjoy the flavor of life, take big bites. Moderation is for monks.

– Robert A. Heinlein via Jubal Harshaw in Stranger is a Strange Land

But in all seriousness. It depends on whether or not the comments have the subject matter which we wish to be tracking. For example, if the comments are only ever discussing “Trump”, then projectpiglet.com wont be able to track anything related to “Bernie” or “Clinton.”

How to Add More Data

The neat part about projectpiglet.com, is that it was designed from the start to simple point a stream of comments to an ingestion point and BAM new data source.

It really does only take a few minutes. It’s designed to simply take in API calls using the following features:

  • Author – Required
  • Statement/Comment – Required
  • Source – Required
  • Related_Story – Optional
  • Timestamp – Optional

That’s it. The point is from there, Piglet can do everything it needs to ingest, and provide useful insights. It doesn’t even need a related story, as Piglet will parse out the comment for the stories as well.

The hard part has really just been keeping the data limited at this point.

Wait, you’re limiting data?

Yes. Unfortunately, it does costs money to add data sources. Either there needs to be a web scrapper which feeds data into the system, or we need to pay for data streams (such as Twitter). Further, Piglet needs to process the data once its sent and store the data – both of which costs money, albeit not too much.

To date, we’ve kept the data ingestion to a minimum, but enough to prove the Piglets worth. As we grow the user base, we intend to grow the data sources. There’s really no reason we can’t crawl the web in the end. However, until we prove it’s worth, we don’t have the funds to waste.

That being said, Piglet is looking to grow!

If you’re interested in using ProjectPiglet.com, use the coupon code: pigletblog2018

It’s 25% off for 6 months!