Skip to content

Commit aeb1c69

Browse files
authored
Update hfund.cpp
1 parent 61b0043 commit aeb1c69

File tree

1 file changed

+82
-9
lines changed

1 file changed

+82
-9
lines changed

Hedge/hfund.cpp

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace plt = matplotlibcpp;
1414

1515
using namespace boost::property_tree;
1616

17+
// Fetches the stock price data from Financial Modeling Prep
1718
std::string fmp_address(std::string ticker){
1819
std::string url = "https://financialmodelingprep.com";
1920
std::string key = "";
@@ -56,6 +57,7 @@ std::string Request(const std::string& url) {
5657
return readBuffer;
5758
}
5859

60+
// Matrix Multiplication Function
5961
std::vector<std::vector<double>> MMULT(std::vector<std::vector<double>> x,
6062
std::vector<std::vector<double>> y)
6163
{
@@ -77,6 +79,7 @@ std::vector<std::vector<double>> MMULT(std::vector<std::vector<double>> x,
7779
return result;
7880
}
7981

82+
// Matrix Transpose Function
8083
std::vector<std::vector<double>> TRANSPOSE(std::vector<std::vector<double>> z)
8184
{
8285
std::vector<std::vector<double>> X;
@@ -91,6 +94,7 @@ std::vector<std::vector<double>> TRANSPOSE(std::vector<std::vector<double>> z)
9194
return X;
9295
}
9396

97+
// Inverse Matrix Function using Gaussian Elimination
9498
std::vector<std::vector<double>> INVERSE(std::vector<std::vector<double>> x)
9599
{
96100
std::vector<std::vector<double>> I;
@@ -142,6 +146,7 @@ std::vector<std::vector<double>> INVERSE(std::vector<std::vector<double>> x)
142146
return I;
143147
}
144148

149+
// Multiplies a matrix by a coeffecient
145150
std::vector<std::vector<double>> FACTOR(double a, std::vector<std::vector<double>> x)
146151
{
147152
for(int i = 0; i < x.size(); ++i){
@@ -152,6 +157,7 @@ std::vector<std::vector<double>> FACTOR(double a, std::vector<std::vector<double
152157
return x;
153158
}
154159

160+
// Adds or Subtracts a matrix from a matrix with sign = -1 or 1
155161
std::vector<std::vector<double>> ADDSUB(std::vector<std::vector<double>> a, std::vector<std::vector<double>> b, double sign)
156162
{
157163
for(int i = 0; i < a.size(); ++i){
@@ -162,6 +168,7 @@ std::vector<std::vector<double>> ADDSUB(std::vector<std::vector<double>> a, std:
162168
return a;
163169
}
164170

171+
// Calculates the rate of return matrix of a given matrix of stock prices
165172
std::vector<std::vector<double>> RateOfReturn(std::vector<std::vector<double>> x)
166173
{
167174
std::vector<std::vector<double>> y;
@@ -176,82 +183,104 @@ std::vector<std::vector<double>> RateOfReturn(std::vector<std::vector<double>> x
176183
return y;
177184
}
178185

186+
// Fetches the stock price data and stores them into a map with the key being the stock ticker and the value being the vector of close prices
179187
std::map<std::string, std::vector<double>> Cyclone(std::vector<std::string> tickA, std::vector<std::string> tickB){
180188
std::map<std::string, std::vector<double>> prices;
181189

190+
// Fetches stocks
182191
for(auto & ticker : tickA){
192+
// Fetch the stock data
183193
std::string resp = Request(fmp_address(ticker));
184194
std::stringstream ss(resp);
185195
ptree df;
196+
// Parse string to JSON using Boost
186197
read_json(ss, df);
187198
for(ptree::const_iterator it = df.begin(); it != df.end(); ++it){
188199
if(it->first == "historical"){
189200
for(ptree::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt){
190201
for(ptree::const_iterator kt = jt->second.begin(); kt != jt->second.end(); ++kt){
191202
if(kt->first == "adjClose"){
203+
// Store adjusted close prices in map vector based on stock ticker
192204
prices[ticker].push_back(atof(kt->second.get_value<std::string>().c_str()));
193205
}
194206
}
195207
}
196208
}
197209
}
210+
// Reverse prices so oldest price is first and newest price is last
198211
std::reverse(prices[ticker].begin(), prices[ticker].end());
199212
}
213+
214+
// Fetches hedging instruments
200215
for(auto & ticker : tickB){
216+
// Fetches data from Financial Modeling Prep
201217
std::string resp = Request(fmp_address(ticker));
202218
std::stringstream ss(resp);
203219
ptree df;
220+
// Parses response as JSON with Boost
204221
read_json(ss, df);
205222
for(ptree::const_iterator it = df.begin(); it != df.end(); ++it){
206223
if(it->first == "historical"){
207224
for(ptree::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt){
208225
for(ptree::const_iterator kt = jt->second.begin(); kt != jt->second.end(); ++kt){
209226
if(kt->first == "adjClose"){
227+
// Stores adjusted close prices in map
210228
prices[ticker].push_back(atof(kt->second.get_value<std::string>().c_str()));
211229
}
212230
}
213231
}
214232
}
215233
}
234+
// Oldest prices first, newest prices last
216235
std::reverse(prices[ticker].begin(), prices[ticker].end());
217236
}
218237
return prices;
219238
}
220239

240+
// Calculates the Minimum Variance Portfolio
221241
std::vector<double> MinVariancePortfolio(std::vector<std::vector<double>> ror, int lookback)
222242
{
243+
// Generates a set of weights for each inputted portfolio returns snapshot
223244
auto solver = [](std::vector<std::vector<double>> x){
245+
246+
// Sets bounds
224247
int m = x.size();
225248
int n = x[0].size();
226249
std::vector<std::vector<double>> mu, cov, temporary;
250+
251+
// Calculates the mean vector
227252
for(int i = 0; i < m; ++i){
228253
mu.push_back({1.0});
229254
}
230255
mu = FACTOR(1.0/((double) m), MMULT(TRANSPOSE(mu), x));
256+
257+
// Subtracts mean from returns matrix
231258
for(int i = 0; i < m; ++i){
232259
for(int j = 0; j < n; ++j){
233260
x[i][j] -= mu[0][j];
234261
}
235262
}
263+
264+
// Calculates the covariance matrix
236265
cov = FACTOR(1.0/((double) m - 1), MMULT(TRANSPOSE(x), x));
237-
/*
238-
((2E, 1),
239-
(1, 0)) (0, 1)
240-
241-
*/
242266

267+
// Multiplies covariance matrix by 2.0 for the MinVariance matrix
243268
cov = FACTOR(2.0, cov);
244269
std::vector<double> ones, weights;
245270
mu.clear();
271+
272+
// Adds 1.0 to each column in the matrix
246273
for(int i = 0; i < n; ++i){
247274
cov[i].push_back(1.0);
248275
ones.push_back(1.0);
249-
mu.push_back({0.0});
276+
mu.push_back({0.0}); // Necessary for matrix multiplication
250277
}
278+
// Adds 1.0 to each row in the matrix
251279
ones.push_back(0.0);
252280
cov.push_back(ones);
253281
mu.push_back({1.0});
254282

283+
// Computes the weights of the portfolio by taking the inverse matrix and multiplying it by zeros
255284
temporary = MMULT(INVERSE(cov), mu);
256285
for(int i = 0; i < n; ++i){
257286
weights.push_back(temporary[i][0]);
@@ -261,9 +290,15 @@ std::vector<double> MinVariancePortfolio(std::vector<std::vector<double>> ror, i
261290

262291
std::vector<double> result;
263292

293+
// Takes a rolling snapshot of the rate of returns matrix and inputs it into the solver to generate min-variance weights
264294
for(int i = lookback; i < ror.size(); ++i){
295+
// Returns snapshot
265296
std::vector<std::vector<double>> hold_items = {ror.begin() + (i - lookback), ror.begin() + i};
297+
298+
// Allocated weights
266299
std::vector<double> weights = solver(hold_items);
300+
301+
// Summation to generate weighted portfolio from inputted stocks
267302
double total = 0;
268303
for(int j = 0; j < ror[0].size(); ++j){
269304
total += weights[j]*ror[i][j];
@@ -277,13 +312,17 @@ std::vector<double> MinVariancePortfolio(std::vector<std::vector<double>> ror, i
277312
return result;
278313
}
279314

315+
// Uses the Kalman Filter to calculate a hedging ratio along with its test statistic to test significance
280316
std::vector<double> HedgingRatio(std::vector<double> x, std::vector<double> y){
281317
std::vector<double> result;
318+
319+
// Used for building a quick vector off just x[i]
282320
auto bx = [](double ux){
283321
std::vector<std::vector<double>> result = {{1.0}, {ux}};
284322
return result;
285323
};
286324

325+
// Calculates the mean of a given vector
287326
auto mean = [](std::vector<double> q){
288327
double total = 0;
289328
for(auto & i : q){
@@ -292,39 +331,58 @@ std::vector<double> HedgingRatio(std::vector<double> x, std::vector<double> y){
292331
total /= ((double) q.size());
293332
return total;
294333
};
295-
334+
296335
std::vector<std::vector<double>> B, Bp, Pp, Q, P, Yp, K, DK, deltaB;
297336
double R = 0;
298337

338+
// Set initial parameters to Kalman Filter inputs
299339
B = {{0.1}, {0.1}};
300340
Bp = {{0.1}, {0.1}};
301341
Pp = {{1.0, 0.0}, {0.0, 1.0}};
302342
Q = {{1.0, 0.0}, {0.0, 1.0}};
303343
P = {{1.0, 0.0}, {0.0, 1.0}};
304344

345+
// Kalman Filter Processing
305346
for(int i = 0; i < x.size(); ++i){
347+
// Iterate newest beta
306348
Bp = B;
349+
350+
// Add Q and P
307351
Pp = ADDSUB(Q, P, 1.0);
352+
353+
// Generate Yhat for current point
308354
Yp = MMULT(TRANSPOSE(Bp), bx(x[i]));
355+
356+
// Compute the R parameter which is the average residual
309357
if(i > 2){
310358
R = 0;
311359
for(int t = 0; t < i; ++t){
312360
R += pow(y[t] - (Bp[0][0] + Bp[1][0]*x[t]), 2);
313361
}
314362
R = R / ((double) i - 1);
315363
}
364+
365+
// Compute Kalman Gain
316366
K = MMULT(Pp, bx(x[i]));
317367
DK = MMULT(TRANSPOSE(K), bx(x[i]));
368+
369+
// Add R to and divide Kalman Gain
318370
DK[0][0] += R;
319371
for(int t = 0; t < K.size(); ++t){
320372
K[t][0] /= DK[0][0];
321373
}
374+
// Add beta to error multiplied by Kalman gain
322375
B = ADDSUB(Bp, FACTOR(y[i] - Yp[0][0], K), 1.0);
376+
377+
// Update P by subtracting Pp by the multiplication of Kalman gain by X and Pp
323378
P = ADDSUB(Pp, MMULT(K, MMULT(TRANSPOSE(bx(x[i])), Pp)), -1.0);
379+
380+
// Update Q by multiplying the error between beta and predicted beta
324381
deltaB = ADDSUB(B, Bp, -1.0);
325382
Q = MMULT(deltaB, TRANSPOSE(deltaB));
326383
}
327384

385+
// Compute test statistic off the residual sum of squares and the sum squared of x minus its mean
328386
double rss = 0;
329387
double bottom = 0;
330388
double mux = mean(x);
@@ -334,6 +392,8 @@ std::vector<double> HedgingRatio(std::vector<double> x, std::vector<double> y){
334392
}
335393

336394
rss /= ((double) x.size() - 2);
395+
396+
// Generate test statistic and return hedging ratio with it
337397
double t_stat = B[1][0] / sqrt(rss/bottom);
338398

339399
result.push_back(B[0][0]);
@@ -346,6 +406,7 @@ std::vector<double> HedgingRatio(std::vector<double> x, std::vector<double> y){
346406

347407
int main()
348408
{
409+
// Initialize stock and hedging instrument tickers
349410
std::vector<std::string> port_ticks = {"AAPL","MSFT","NVDA","GOOGL"};
350411
std::map<std::string, std::string> hedge_items = {
351412
{"VDC","Vangaurd Consumer Staples ETF"},
@@ -355,10 +416,12 @@ int main()
355416
};
356417
std::vector<std::string> hedge_ticks = {"VDC","IXJ","SHY","GLDM"};
357418

419+
// Fetch all price data
358420
std::map<std::string, std::vector<double>> prices = Cyclone(port_ticks, hedge_ticks);
359421

360422
std::vector<std::vector<double>> closePort, closeHedge, rorPort, rorHedge;
361423

424+
// Split up stocks and hedging instrument prices
362425
for(auto & tick : port_ticks){
363426
closePort.push_back(prices[tick]);
364427
}
@@ -367,18 +430,22 @@ int main()
367430
closeHedge.push_back(prices[tick]);
368431
}
369432

433+
// Transpose matrices in order to easily compute the rate of returns
370434
closePort = TRANSPOSE(closePort);
371435
closeHedge = TRANSPOSE(closeHedge);
372436

373437
rorPort = RateOfReturn(closePort);
374438
rorHedge = RateOfReturn(closeHedge);
375439

440+
// Transpose hedging instruments back so they are easier to loop through for the kalman filter
376441
rorHedge = TRANSPOSE(rorHedge);
377442

378443
int lookback = 100;
379444

445+
// Generate the Minimum Variance Portfolio from the stock data returns
380446
std::vector<double> PortfolioReturns = MinVariancePortfolio(rorPort, lookback);
381447

448+
// Calculate regression line x-axis off the portfolio returns min and max
382449
auto min_p = std::min_element(PortfolioReturns.begin(), PortfolioReturns.end());
383450
auto max_p = std::max_element(PortfolioReturns.begin(), PortfolioReturns.end());
384451

@@ -393,13 +460,17 @@ int main()
393460
for(int i = 0; i < line_length; ++i){
394461
XP.push_back(x0 + i*dX);
395462
}
396-
463+
464+
// Generate plots
397465
std::vector<PyObject*> plots;
398466
for(auto & place : {221, 222, 223, 224}){
399467
plots.push_back(plt::chart2D(place));
400468
}
401469

470+
// Generate hedging parameters and construct regression to be plotted
402471
for(int i = 0; i < hedge_ticks.size(); ++i){
472+
473+
// Adjust hedging data to match portfolio returns dimensions
403474
rorHedge[i] = {rorHedge[i].begin() + lookback, rorHedge[i].end()};
404475
std::vector<double> hp = HedgingRatio(PortfolioReturns, rorHedge[i]);
405476

@@ -410,9 +481,11 @@ int main()
410481
YP.push_back(hp[0] + hp[1]*XP[t]);
411482
}
412483

484+
// Plot the points and regression line
413485
plt::scatter2D(plots[i], PortfolioReturns, rorHedge[i], "red");
414486
plt::plot2D(plots[i], XP, YP, "blue");
415487

488+
// Prints out whether each hedging instrument has a significant ratio or not
416489
std::cout << hedge_ticks[i] << " has a test-statistic of " << hp[2] << std::endl;
417490
}
418491

@@ -421,4 +494,4 @@ int main()
421494

422495

423496
return 0;
424-
}
497+
}

0 commit comments

Comments
 (0)