Correlation Part 2
Implications For Trading
Yesterday, right after I posted a Substack article on the mathematics of correlation, an intelligent analysis looking at the correlation between Gold And Interest Rates appeared in the popular ZeroHedge financial blog (where yours truly is an occasional guest author).
This article touches on a number of key points:
Correlations between asset classes can remain stable over long periods of time, only to break down in periods of crisis
Correlation between one asset class Gold vs. Bonds — can be very different from the correlation between a closely matched asset pair, namely, Gold vs. Inflation.
The mismatch between correlations can be interpreted as a psychological factor which can be traded.
Skipping to the conclusion in the Zero Hedge article, because of the conflicting correlation estimates, the ZeroHedge author (Alec Zimeck-Parkinson) believes that the Gold price is overvalued and is currently in “bubble” territory. Although he does not provide a recommended trade to capture this anomaly, subscribers to this Substack can probably produce a half dozen or so highly leveraged options trades off the top of their head that would make huge profits if this scenario materializes.
But what if there is a different explanation for the correlation mismatch?
One possible explanation is that instead of being an anomaly, the two correlations are indeed strongly related but represent a single underlying signal displaced in time. This introduces the concept of cross correlation, which looks for relationships within a single signal in a time series. Cross correlation is usually covered in signal analysis university classes and not covered in math classes related to probability, statistics, or calculus.
The classic use of cross correlation occurs in radar signal processing, where a source signal is compared to its reflection and used to detect various objects (planes, missiles, tree cover, etc) by comparing the difference between the original signal and its reflection.
In the Gold vs Bond example in ZeroHedge, the alternative explanation is that Gold vs Inflation is working on time delay, and is not an indicator that Gold is in a bubble. This of course implies a very different set of trading strategies.
What should readers do, to better understand how correlation works in the real world?
Here is a set of computer source code to calculate both correlation and cross correlation from financial time series. Free subscribers to this Substack can use daily market data from Yahoo Finance to calculate the correlations. Paid subscribers can hook up real time signals from the Nuclear Option Market Data API and calculate the correlations and cross correlations intraday to test 0DTE strategies.
One Last Tip:
The ZeroHedge article discusses Ian Fleming and his role with the Bank of England. It does not mention another aspect of Fleming’s career, when he was a financial journalist for Reuters, allegedly before he began his intelligence career as a spy for Britain’s MI6. Keep this in mind when reading financial “journalism” from mainstream, reputable sources.
// Corrlation / Cross Correlation HEADER FILE
#include <vector>
#include <iostream>
#include <stdlib.h>
using namespace std;
typedef vector<double> DoubleVec;
class CorrelationChannel
{
public:
CorrelationChannel() { _initialized = false; }
~CorrelationChannel() {}
void initialize(size_t size);
bool initialized() { return _initialized; };
void clear();
void update();
void store();
void snapshot();
DoubleVec& crossCorrelation() { return _crossCorrelation_OUT; }
double correlation(const DoubleVec& x, const DoubleVec& y);
void setInputChannelA(const DoubleVec& dVec) { _channel_A_IN = dVec; }
void setInputChannelB(const DoubleVec& dVec) { _channel_B_IN = dVec; }
private:
DoubleVec _channel_A_IN;
DoubleVec _channel_B_IN;
DoubleVec _channel_A_StdDev_OUT;
DoubleVec _channel_B_StdDev_OUT;
DoubleVec _crossCorrelation_OUT;
double _correlation;
bool _initialized;
private:
double calcMean(const DoubleVec& vec);
double calcDenominator(const DoubleVec& x, const DoubleVec& y);
void calcCrossCorrelation(const DoubleVec& x, const DoubleVec& y, DoubleVec& result);
double calcCorrelation(const DoubleVec& x, const DoubleVec& y);
};
// CPP FILE
#include "CorrelationChannel.h"
#include "IndexToken.h"
#include <math.h>
void
CorrelationChannel::initialize(size_t size)
{
_channel_A_IN.reserve(size);
_channel_B_IN.reserve(size);
_channel_A_StdDev_OUT.reserve(size);
_channel_B_StdDev_OUT.reserve(size);
_crossCorrelation_OUT.reserve(size * 2);
_initialized = true;
}
double
CorrelationChannel::calcMean(const DoubleVec& vec)
{
double sum = 0.0;
for (int i=0; i < vec.size(); i++)
sum += vec[i];
double mean = sum / vec.size();
return mean;
}
double
CorrelationChannel::calcDenominator(const DoubleVec& x, const DoubleVec& y)
{
if (x.size() != y.size()) {
cout << "vector size mismatch " << x.size() << " vs " << y.size() << endl;
exit(1);
}
double mx = calcMean(x);
double my = calcMean(y);
double sx = 0.0;
double sy = 0.0;
for (int i=0; i < x.size(); i++) {
sx += ( x[i] - mx ) * ( x[i] - mx );
sy += ( y[i] - my ) * ( y[i] - my );
}
double denom = sqrt(sx * sy);
return denom;
}
/** Pearson Correlation Calcuation for Input Vectors x, y */
double
CorrelationChannel::correlation(const DoubleVec& x, const DoubleVec& y)
{
if (x.size() != y.size()) {
cout << "vector size mismatch " << x.size() << " vs " << y.size() << endl;
exit(1);
}
double mx = calcMean(x);
double my = calcMean(y);
double numerator = 0.0;
double denominator = 0.0;
for (int i=0; i < x.size(); i++) {
double diffProduct = (x[i] - mx) * (y[i] - my);
numerator += diffProduct;
}
double diffXsquared = 0.0;
double diffYsquared = 0.0;
for (int i=0; i < x.size(); i++) {
diffXsquared += (x[i] - mx) * (x[i]- mx);
diffYsquared += (y[i] - my) * (y[i]- my);
}
denominator = sqrt( diffXsquared * diffYsquared );
double result = numerator / denominator;
return result;
}
void
CorrelationChannel::calcCrossCorrelation(const DoubleVec& x, const DoubleVec& y, DoubleVec& result)
{
double mx = calcMean(x);
double my = calcMean(y);
double denom = calcDenominator(x,y);
int maxDelay = x.size() - 1;
result.reserve(x.size() *2);
for (int delay = -maxDelay; delay < maxDelay; delay++) {
double sxy = 0.0;
for (int i=0; i < x.size(); i++) {
int j = i + delay;
if (j < 0 || j >= x.size())
continue;
else
sxy += (x[i]-mx) * (y[j] - my);
}
double r = sxy / denom;
result.push_back(r);
}
}
int main(int argc, char** argv)
{
if (argc < 3) {
cout << "usage : ./correlation_channel <time series 1 file><time series 2 file>" << endl;
exit(1);
}
ifstream xFile(argv[1]);
if (!xFile) {
cout << "file " << argv[2] << " not found, exiting." << endl;
}
ifstream yFile(argv[1]);
if (!yFile) {
cout << "file " << argv[2] << " not found, exiting." << endl;
}
vector<double> xVec;
vector<double> yVec;
string line;
while (getline(xFile, line, '\n')) {
IndexToken tok(line, "\t");
if (tok.tokenCount() < 5)
continue;
double closingPrice = atof(tok[4].c_str());
xVec.push_back(closingPrice);
}
while (getline(yFile, line, '\n')) {
IndexToken tok(line, "\t");
if (tok.tokenCount() < 5)
continue;
double closingPrice = atof(tok[4].c_str());
yVec.push_back(closingPrice);
}
CorrelationChannel correlationChannel;
double correlation = correlationChannel.correlation(xVec, yVec);
cout << "correlation is : " << correlation << endl;
return 0;
}
Disclaimer : All Content on the Nuclear Option Substack is for Education and Information Purposes only. It does not a soliciatation or recommendation to buy or sell any security. Before trading, consult with your Professional Financial Advisor and read the booklet Characteristics and Risks of Standardized Options Contracts, available from the Options Clearing Corporation.~

