@@ -14,6 +14,7 @@ namespace plt = matplotlibcpp;
14
14
15
15
using namespace boost ::property_tree;
16
16
17
+ // Financial Modeling Prep API address
17
18
std::string fmp_address (std::string ticker){
18
19
std::string url = " https://financialmodelingprep.com" ;
19
20
std::string key = " " ;
@@ -56,8 +57,11 @@ std::string Request(const std::string& url) {
56
57
return readBuffer;
57
58
}
58
59
60
+ // Pulls stock data on an inputted ticker
59
61
std::vector<double > PullStockData (std::string ticker){
60
62
std::vector<double > close;
63
+
64
+ // Fetches stock price data and parses it as JSON using Boost
61
65
std::string response = Request (fmp_address (ticker));
62
66
std::stringstream ss (response);
63
67
ptree dataset;
@@ -67,29 +71,36 @@ std::vector<double> PullStockData(std::string ticker){
67
71
for (ptree::const_iterator jt = it->second .begin (); jt != it->second .end (); ++jt){
68
72
for (ptree::const_iterator kt = jt->second .begin (); kt != jt->second .end (); ++kt){
69
73
if (kt->first == " adjClose" ){
74
+ // Pulls adjusted close data into a single vector
70
75
close.push_back (kt->second .get_value <double >());
71
76
}
72
77
}
73
78
}
74
79
}
75
80
}
81
+ // Get the oldest price first and newest price last
76
82
std::reverse (close.begin (), close.end ());
77
83
return close;
78
84
}
79
85
86
+ // Fetches latest stock price
80
87
double stockPrice (std::vector<double > close){
81
88
return close[close.size () - 1 ];
82
89
}
83
90
91
+ // Generates parameters for SABR model with inuptted close prices
84
92
std::map<std::string, double > Parameters (std::vector<double > close){
93
+
94
+ // Computes the average value of a given vector
85
95
auto mean = [](std::vector<double > x){
86
96
double average = 0 ;
87
97
for (auto & i : x){
88
98
average += i;
89
99
}
90
100
return average / (double ) x.size ();
91
101
};
92
-
102
+
103
+ // Computes the standard deviation of a given vector
93
104
auto stdev = [&](std::vector<double > x){
94
105
double mu = mean (x);
95
106
double volatility = 0 ;
@@ -98,49 +109,62 @@ std::map<std::string, double> Parameters(std::vector<double> close){
98
109
}
99
110
return pow (volatility / ((double ) x.size () - 1 ), 0.5 );
100
111
};
112
+
113
+ // Calculates the rate of returns
101
114
std::map<std::string, double > result;
102
115
std::vector<double > ror;
103
116
for (int i = 1 ; i < close.size (); ++i){
104
117
ror.push_back (close[i]/close[i-1 ] - 1.0 );
105
118
}
119
+
120
+ // Calculates the volatilty of the entire returns vector
106
121
double ivol = stdev (ror);
122
+
123
+ // Calculates the rolling volatility of the returns
107
124
double window = 100 ;
108
125
std::vector<double > store_vol;
109
126
for (int i = window; i < ror.size (); ++i){
110
127
std::vector<double > hold = {ror.begin ()+i-window, ror.begin ()+i};
111
128
store_vol.push_back (stdev (hold));
112
129
}
130
+
131
+ // Computes the volatility of the volatility
113
132
double vvol = stdev (store_vol);
114
133
result[" iv" ] = ivol;
115
134
result[" sv" ] = vvol;
116
135
return result;
117
136
}
118
137
138
+ // Generates 3D grid based on the Strike Price, Forward Price, and Time till Expiration
119
139
std::map<std::string, std::vector<std::vector<double >>> GRID (std::vector<double > x, std::vector<double > y, std::vector<double > T){
120
140
std::map<std::string, std::vector<std::vector<double >>> result;
121
141
for (int i = 0 ; i < x.size (); ++i){
122
142
std::vector<double > tempx;
123
143
std::vector<double > tempy;
124
144
std::vector<double > tempz;
125
145
for (int j = 0 ; j < y.size (); ++j){
146
+ // Build row grid
126
147
tempx.push_back (x[i]);
127
148
tempy.push_back (y[j]);
128
149
tempz.push_back (T[j]);
129
150
}
151
+ // Build matrix
130
152
result[" Strikes" ].push_back (tempx);
131
153
result[" Forward" ].push_back (tempy);
132
154
result[" Expiry" ].push_back (tempz);
133
155
}
134
156
return result;
135
157
}
136
158
159
+ // Calculates the implied volatility at each point
137
160
double ImpliedVol (double iv, double vvol, double rho, double Ft, double K, double beta){
138
161
double z = (vvol/iv)*pow (Ft*K, (1 - beta)/2.0 )*log (Ft/K);
139
162
double xz = log ((pow (1 - 2.0 *rho*z + pow (z, 2 ), 0.5 ) + z - rho)/(1 - rho));
140
163
double adj = (pow (1 - beta, 2 )/24.0 )*(pow (iv, 2 )/pow (Ft*K, 1 -beta))+(rho*beta*iv*vvol)/(4.0 *pow (Ft*K, (1 -beta)/2.0 ))+(pow (vvol, 2 )*(2 - 3 *pow (rho, 2 )))/24.0 ;
141
164
return (iv/pow (Ft*K, (1 - beta)/2.0 ))*(z/xz)*(1 +adj);
142
165
}
143
166
167
+ // Computes the implied volatility surface based on the strike prices and forward prices and the beta (the beta defines curvature or linear)
144
168
std::vector<std::vector<double >> VolSurface (std::map<std::string, std::vector<std::vector<double >>> xy, double iv, double vvol, double rho, double beta){
145
169
std::vector<std::vector<double >> vs;
146
170
std::vector<double > ts;
@@ -154,6 +178,7 @@ std::vector<std::vector<double>> VolSurface(std::map<std::string, std::vector<st
154
178
return vs;
155
179
}
156
180
181
+ // Generaes a line of points between a and b for n size
157
182
std::vector<double > linspace (double a, double b, int n){
158
183
std::vector<double > result;
159
184
double dx = (b - a)/(n - 1 );
@@ -165,35 +190,44 @@ std::vector<double> linspace(double a, double b, int n){
165
190
166
191
int main ()
167
192
{
193
+ // Declare stocks and 3D plots
168
194
std::vector<std::string> tickers = {" MSFT" ," AAPL" ," AMZN" ," IBM" ," NVDA" ," GOOGL" };
169
195
std::vector<PyObject*> bx;
170
196
for (auto & num : {231 , 232 , 233 , 234 , 235 , 236 }){
171
197
bx.push_back (plt::chart (num));
172
198
}
173
199
200
+ // Define rho and risk-free rate
174
201
double rho = -0.9 ;
175
202
double r = 0.044 ;
176
203
177
204
for (int k = 0 ; k < tickers.size (); ++k){
178
205
std::string ticker = tickers[k];
179
206
PyObject * ax = bx[k];
207
+
208
+ // Fetch stock price data and grab latest stock price
180
209
std::vector<double > close = PullStockData (ticker);
181
210
double S = stockPrice (close);
182
211
212
+ // Generate parameters
183
213
std::map<std::string, double > VOL = Parameters (close);
184
214
215
+ // Calculate the forward prices off of time in the range of 7 days to 2 years
185
216
std::vector<double > T = linspace (7 /365.0 , 2.0 , 100 );
186
217
std::vector<double > Fr;
187
218
for (int t = 0 ; t < T.size (); ++t){
188
219
Fr.push_back (S*exp (r*T[t]));
189
220
}
190
-
221
+
222
+ // Set a range for strike prices
191
223
std::vector<double > K = linspace (0.5 *S, 1.5 *S, 100 );
192
-
224
+
225
+ // Set a beta and return the Implied Volatility Surface stored in ZVol
193
226
double beta = 0.3 ;
194
227
std::map<std::string, std::vector<std::vector<double >>> grid = GRID (K, Fr, T);
195
228
std::vector<std::vector<double >> ZVol = VolSurface (grid, VOL[" iv" ], VOL[" sv" ], rho, beta);
196
229
230
+ // Plot the Volatility surface for each stock in their respective 3D chart
197
231
plt::PlotTitle (ax, ticker);
198
232
plt::surface3DMap (ax, grid[" Strikes" ], grid[" Expiry" ], ZVol, " jet" , 0.8 );
199
233
plt::Chart3DAxesNames (ax, " Strike Price" , " Expiry" , " Implied Volatility" );
@@ -205,6 +239,9 @@ int main()
205
239
}
206
240
207
241
/* PART ONE
242
+
243
+ This is the animated version where the beta is changed and the vol surface reacts to the change
244
+
208
245
int main()
209
246
{
210
247
std::string ticker = "MSFT";
@@ -238,4 +275,4 @@ int main()
238
275
239
276
return 0;
240
277
}
241
- */
278
+ */
0 commit comments