Skip to content

Instantly share code, notes, and snippets.

@anthonymorast
Created November 28, 2021 02:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anthonymorast/43038e9cd67a96f90b9d4719f38fa84b to your computer and use it in GitHub Desktop.
Save anthonymorast/43038e9cd67a96f90b9d4719f38fa84b to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <vector>
#include "matplotlib.h" // plotting
#include "yfapi.h" // data API
namespace plt = matplotlibcpp;
using namespace std;
/*
Transforms a primitve array into a std::vector of the
approriate type.
*/
vector<float> array_to_vector(float* arr, size_t size)
{
vector<float> vec;
for(int i = 0; i < size; i++)
{
vec.push_back(arr[i]);
}
return vec;
}
/*
Makes the closing data indepent of the actual trading price
of the ETFs by squeezing the values between 0 and 1.
*/
float** normalize_close(datatable::DataTable<float> data)
{
float* cdata = data.get_column("Close");
float min = MAXFLOAT, max = -MAXFLOAT;
for(int i = 0; i < data.nrows(); i++)
{
min = cdata[i] < min ? cdata[i] : min;
max = cdata[i] > max ? cdata[i] : max;
}
delete cdata;
float** new_data = new float*[1];
float* close = data.get_column("Close");
for(int i = 0; i < data.nrows(); i++)
{
close[i] = (close[i] - min) / (max - min);
}
new_data[0] = close;
return new_data;
}
/*
An easy way to retrieve the data from the API, normalize the close prices, and
reformat into a matplotlibcpp acceptable format.
*/
vector<float> get_close_vector_for_ticker(string ticker, string start_date, string end_date, yfapi::YahooFinanceAPI api)
{
datatable::DataTable<float> data = api.get_ticker_data(ticker, start_date, end_date);
float** normal_data = normalize_close(data);
vector<float> vec_data = array_to_vector(normal_data[0], data.nrows());
delete[] normal_data;
return vec_data;
}
int main(int argc, char* argv[])
{
yfapi::YahooFinanceAPI api;
int number_tickers = 4;
string start_date = "2021-01-01", end_date = "2021-12-31";
string tickers[number_tickers] = { "XRT", "SOXX", "VDE", "VHT" };
// get the baseline data: price data from the SPY ETF which tracks the S&P 500
vector<float> spy = get_close_vector_for_ticker("spy", start_date, end_date, api);
int min = spy.size(); // used to determine how many points there are in common with the other ETFs
for(int i = 0; i < number_tickers; i++)
{
cout << "Processing " << tickers[i] << endl;
// get the data for the ticker
vector<float> ticker_data = get_close_vector_for_ticker(tickers[i], start_date, end_date, api);
// divergence array will use all of the data that is available in both ETFs
min = min < ticker_data.size() ? min : ticker_data.size();
// calculate divergence and fill up some plotting arrays
float* divergence = new float[min];
vector<int> fillx, filly1, filly2, zero;
for(int j = 0; j < min; j++)
{
divergence[j] = ticker_data[j] - spy[j];
fillx.push_back(j); // used to plot; x-values
zero.push_back(0); // used to fill red and green areas
filly1.push_back(1); // used to fill green section (divergence < 0)
filly2.push_back(-1); // used to fill red section (divergence > 0)
}
// plot the current sector ETF
plt::plot(ticker_data, {{"label", tickers[i]}});
plt::plot(spy, {{"label", "SPY"}}); // plot SPY
plt::plot(array_to_vector(divergence, min), {{"label", "Divergence"}}); // plot the divergence line
plt::axhline(0, 0, 1, {{"color", "black"}}); // draw the line at y = 0
// matplotlibcpp's way of passing extra parameters to the plot
map<string, string> fill_parameters;
fill_parameters["color"] = "green";
fill_parameters["alpha"] = "0.2";
plt::fill_between(fillx, zero, filly1, fill_parameters); // green fill
fill_parameters["color"] = "red";
plt::fill_between(fillx, zero, filly2, fill_parameters); // red fill
plt::xlabel("Days");
plt::ylabel("Price");
plt::legend();
//plt::show();
plt::save("plots/" + tickers[i] + ".png"); // save the plot
plt::clf(); // clear the plot
delete divergence; // don't leak memory
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment