As interest rates continues to drop we are seeing a flood of available cheap debt. This paper explores if investing in equity using ambitious gearing can be a worth while endeavor in order to take advantage of the available liquidity. Between start of January 2010 and end of June 2016 the Oslo Stock Exchange Benchmark Index (OSEBX) has increased by 58.6%, at an annualized rate of return of 7.4%. At the same time we’re seeing gearing opportunities with as low as 2% interest rate. Does the cheap debt offset the risk of gearing up?
Warning: The following analysis is only provided as an academic analysis, and should not be construed as financial advice in any way. As always, past performance does not guarantee future results.
This paper concludes that there is indeed increased profitability from low interest rates, and that lower interest rates improve risk adjusted returns (Sharpe Ratio). However, even at 1% interest rate it does not beat the risk adjusted return of the non-gearing scenario. It makes intuitive sense that lower interest rates make geared investment’s risk adjusted return approach but not exceed the non-geared investment’s risk adjusted return. It implies that gearing simply increases return at the expense of risk, while you incur a liquidity cost (interest) which makes it less preferable from a risk neutral perspective.
Methodology and Setup
As part of this analysis an R script was developed. In addition to the underlying instrument price history, the script takes the following inputs: Annualized interest rate, monthly allowance, gearing factor, sampling period, investment period, confidence level, and simulation count. It then simulates market conditions using bootstrapping in order to output prediction bands (i.e., intervals) and a probability of margin call. The simulation period and the sampling period are decoupled. Meaning the period we draw simulated returns from doesn’t have to be the same period we run the simulation on. Interest costs are accrued at the end of the month, while allowances are released at the beginning of the month and immediately invested with gearing.
For our analysis we will run the simulation over a period of two years, between July 2014 and June 2016, while sampling OSEBX returns for 16.5 years, from January 2000 to June 2016. Daily price data is extracted from Netfonds. In case that service goes down, a data dump can be found here. The monthly allowance is set to NOK 20,000. Bootstraping simulation is done 10000 times, and we use a prediction interval of 90%. This last part means that we would expect returns to fall within the created prediction bands 90% of the time. An expected median return is also measured. The remaining input parameters, i.e., gearing factor and interest rate, will be governed by the five scenarios under study:
ID | Description | Details |
---|---|---|
HxLi | High Gearing, Low Interest Rate |
2.0x gearing factor with 2.0% annual interest rate. |
HxHi | High Gearing, High Interest Rate |
2.0x gearing factor with 6.0% annual interest rate. |
LxLi | Low Gearing, Low Interest Rate |
0.5x gearing factor with 2.0% annual interest rate. |
LxHi | Low Gearing, High Interest Rate |
0.5x gearing factor with 6.0% annual interest rate. |
Nx | No Gearing | 0.0x gearing factor with arbitrary interest rate. |
The primary study case is the HxLi (i.e., High Gearing, Low Interest Rate) scenario, where we have a gearing factor of 2.0x and an annual interest rate of 2.0%.
In addition to these scenarios we’ll look at a special stress test case, lets call it the HxLiC scenario, where we both sample and simulate on data from the Financial Crisis of 2007–09 using the standard HxLi scenario. We’re measuring this period over two years, from July 2007 to June 2009. For comparison, let’s also include a scenario NxC where we don’t gear during the Financial Crisis.
After imputation of missing values the the price dataset used for sampling daily returns has 6026 observations. Imputation (e.g., filling inn blank data) is done by using the previous days prices. Margin Call is determined if the loaned amount exceeded the current asset balance. In order to account for margin call during a particular day, the low price of a day is used to determine the asset balance. That said, the close price is used to calculate the rate of return if margin call isn’t done on a particular day. At a margin call event all assets are liquidated and loans repayed to the fulles extent. Investments resume the next month when a new allowance is issued. Gearing also continues if the scenario warrants it.
Results and Findings
For sake of brevity we will not explore every aspect of the generated data. We’ll focus the HxLi case and see how it compares to other alternative scenarios. For completeness sake all generated charts can be found here: output.zip
Change in Gearing Factor
First lets look at how accumulation of allowances (investments) look without gearing and with high gearing (2x).


Use the slider to compare the left (no gearing) and right (2x gearing) graph. What we are looking at here is the increase in assets over time. The red line is the original allowance of NOK 20 000 given each month in aggregate. Performance above this line produce profits. The expected (i.e., median) line is teal colored and marked as “Asset Mid (50%)”. We expect the assets to fall 50% of the time above and under this line. Between the remaining upper and lower lines encloses an area we can expect the assets to fall within 90% of the time. This means that 5% of the time the asset level will go above the upper line, and 5% of the time it will fall below the lower line. Thus we are looking at a 90% prediction band (i.e., series of intervals) generated from the 10 000 simulations. Sometimes people mistakenly call these confidence intervals or bands, but that’s something related but different.
It is clear that we see a enormousness change in possible outcomes when we gear up. Because the balance itself might occlude the performance lets look at the same scenarios, but only looking at profits.


Notice that we’ve changed the red line to mean the actual performance during the selected period. It shows what you would actually have gotten in profit if you traveled back in time and applied the strategy on real data.
During the two year period we have invested NOK 480 000. If we do not gear up we see (from the tables in the appendix and the graph above) that the 5% Value at Risk (VaR) downside is NOK 106849. This means we expect our losses to never exceed NOK 106849 more often than 5% of the time. If we gear up 2x then things change dramatically. The 5% VaR then produces a NOK 355 164 possible downside. That said our upside also changes from an expected profit of NOK 39970 without gearing to a profit of NOK 102411 with 2x gearing.
In absolute terms these numbers might be hard to interpret, so lets look at them from a percentage point of view.


Here we see that 2x gearing gives a 5% VaR downside of -73.99% (-49% annualized) and expected return of 21.34% (10.15% annualized). No gearing gives a 5% VaR downside of -22.26% (-11.83% annualized) and an expected return of 8.33% (4.08% annualized). This looks like dire odds, but keep in mind the 5% upside. You are just as likely to get a 154.15% (59.42% annualized) upside as the -73.99% (-49% annualized) downside.
Finally we should mention the probability of getting a margin call during the period. Without gearing it’s naturally a likelihood of 0% to get a margin call, but with 2x gearing this spikes to 5.87%. If you have a gearing of 0.5x this falls down to about 0% again.
Change in Interest Rate
Now that we’ve looked at how gearing affects the investment we should explore what impact a higher interest rate has on gearing. The analysis from the previous section used a low interest rate of 2%, here we will pump it up to 6%.


Looking closely on the above graph, and sliding back and forth, you can barely see a change. But there is one. The expected return goes from 21.34% (10.15% annualized) to 12.46% (6.05% annualized). That’s a 4.1 percentage point drop in annualized returns. In cash terms it’s goes from an expected profit of NOK 102411 to only NOK 59823 over the two years. You can see it more closely if we bring up the profit charts:


As we can see you do lose some money from a higher interest rate. But is it an argument for gearing up? Well, ultimately the money lost in interest seems to be trivial to the increase in risk. In the grand scheme of things you can see the increase relative to the asset holdings:


Let’s look closer at the alternatives in terms of risk adjusted return. The following table shows the Sharpe ratio over the two year period.
Measure | Nx | LxLi | LxHi | HxLi | HxHi |
---|---|---|---|---|---|
Standard Deviation | 22.77% | 34.91% | 34.39% | 69.90% | 69.10% |
Risk Free Return | 1.00% | 1.00% | 1.00% | 1.00% | 1.00% |
Return | 8.33% | 10.88% | 9.17% | 21.34% | 12.46% |
Risk Adjusted Return | 0.32 | 0.28 | 0.24 | 0.29 | 0.17 |
The annual risk free asset is set to about 0.5% or about 1.0% biannually. This is inspired by the current 3 year Norwegian government bond. Here we see that the risk adjusted return for the non-gearing scenario is preferred. However, we should notice that a low interest rate definitely makes gearing more attractive. When we go from the HxHi scenario (6% interest rate) to the HxLi scenario (2% interest rate) the risk adjusted return gos from 0.17 to 0.29, not far from the non-gearing (Nx) scenario of 0.32. Because this is so close, we’ll add a last scenario HxTi: High gearing (2x) and a tiny interest rate of 1%.
The HxTi scenario produced a expected return of 22.69% and standard deviation of 69.46% thus the risk adjusted return is 0.312 just under the non-gearing scenario (Nx). Thus in general it does not seem that gearing is preferable given a risk neutral outlook.
Stress Testing Using Data From the Financial Crisis
Now that we’ve explored how gearing and interest rate affects our investment, let’s do some stress tests. The previous analysis was done through sampling of data throughout the last 16.5 years. This means our simulations reflect a typical year. What if we did our gearing during the financial crisis? The following stress test uses data from only during the financial crisis.
Let first look at the difference between the two sampling periods. The following compares a typical year versus a financial crisis year – both without gearing.


This looks pretty bad. On the left you see the typical case, while the right shows the stress test case. Typically you’d expect a return of 8.33% (4.08% annualized), but during the financial crisis you’d rather expect a -23.54% (-12.56% annualized) return. Note that we’re not talking about a 5% VaR here, mathematically speaking we’re talking about the 50% VaR. The 5% VaR says that you 1 out 20 times will get a return worse than -54.63% (-32.64% annualized) during the financial crisis, as opposed to the typical case of -22.26% (11.83% annualized). To make this more tangible lets look at the asset build-up, or rather tear-down:


It’s safe to say that this period of time was disastrous, even without gearing. What if we were 2x geared?


On the left you see the typical development with 2x gearing, while the right shows 2x gearing during the financial crisis. The red line shows actual development during the time, if you had employed the gearing strategy. Notice that real data actually wipes you out with a margin call. It might be reasonable to look closer at the margin call probabilities later. In any case, the 5% VaR is a whopping -102.73% for the two years. It’s actually not mathematically possible to calculate an annualized version. But you can see it lies at 100% loss from the 6th month on. You actually owe money after getting wiped out. This is due to the margin being call at the worst price of the day.
Let look at the asset balance to get it more tangible.


This doesn’t look good. Expected losses for the two years is NOK 350812 during the financial crisis, as opposed to an expected profit of NOK 102411 during normal times. In relative terms this is an expected loss of -73.09% (48.13% annualized) versus an expected profit of 21.34% (10.15% annualized), respectively.
Probability of Margin Call
The likelihood of getting a margin call during the simulated scenarios is generally pretty low, close to zero, except for when you’re highly geared or during a recession. The probability of margin call is 5.87% during the HxLi scenario where we have high gearing (2x) and low interest rate (2%). It goes up to 8.40% for the HxHi scenario where we have a higher interest rate (6%). During the financial crisis with 2x gearing the probability of margin call is 78.87%. In practice you might even get multiple margin calls if you continue to gear 2x after being wiped out.
These numbers aren’t annualized, and can’t be easily annualized without changing the code. Thus future work includes measuring probability of margin call for particular periods of the simulation, say every year.
Appendix
Tables
Long Term
Measure | Nx | LxLi | LxHi | HxLi | HxHi |
---|---|---|---|---|---|
Days | 731 | 731 | 731 | 731 | 731 |
Gearing Factor | 0.0x | 0.5x | 0.5x | 2.0x | 2.0x |
Interest Rate | 2.00% | 2.00% | 6.00% | 2.00% | 6.00% |
Crash | FALSE | FALSE | FALSE | FALSE | FALSE |
Prob. of Margin Call | 0.00% | 0.00% | 0.00% | 5.87% | 8.40% |
Cum. Return Standard Deviation | 22.77% | 34.91% | 34.39% | 69.90% | 69.10% |
Cum. Return Lower (5%) | -22.26% | -34.13% | -36.00% | -73.99% | -82.04% |
Cum. Return Mid/Expected (50%) | 8.33% | 10.88% | 9.17% | 21.34% | 12.46% |
Cum. Return Upper (95%) | 51.37% | 78.21% | 76.13% | 154.15% | 145.27% |
Sharp Ratio | 0.0200 | 0.0202 | 0.0199 | 0.0205 | 0.0205 |
Cum. Profit Standard Deviation | 109305 | 167585 | 165072 | 335517 | 331679 |
Cum. Profit Lower (5%) | -106849 | -163831 | -172778 | -355164 | -393784 |
Cum. Profit Mid/Expected (50%) | 39970 | 52213 | 44013 | 102411 | 59823 |
Cum. Profit Upper (95%) | 246593 | 375414 | 365438 | 739902 | 697298 |
Acc. Allowance | 480000 | 480000 | 480000 | 480000 | 480000 |
Crash Stress Test
Measure | Nx | HxLi | NxC | HxLiC |
---|---|---|---|---|
Days | 731 | 731 | 731 | 731 |
Gearing Factor | 0.0x | 2.0x | 0.0x | 2.0x |
Interest Rate | 2.00% | 2.00% | 2.00% | 2.00% |
Crash | FALSE | FALSE | TRUE | TRUE |
Prob. of Margin Call | 0.00% | 5.87% | 0.00% | 78.87% |
Cum. Return Standard Deviation | 22.77% | 69.90% | 28.91% | 66.57% |
Cum. Return Lower (5%) | -22.26% | -73.99% | -54.63% | -102.73% |
Cum. Return Mid/Expected (50%) | 8.33% | 21.34% | -23.54% | -73.09% |
Cum. Return Upper (95%) | 51.37% | 154.15% | 36.09% | 84.30% |
Sharp Ratio | 0.0200 | 0.0205 | -0.0255 | -0.0259 |
Cum. Profit Standard Deviation | 109305 | 335517 | 138783 | 319555 |
Cum. Profit Lower (5%) | -106849 | -355164 | -262248 | -493121 |
Cum. Profit Mid/Expected (50%) | 39970 | 102411 | -112982 | -350812 |
Cum. Profit Upper (95%) | 246593 | 739902 | 173210 | 404619 |
Acc. Allowance | 480000 | 480000 | 480000 | 480000 |
Charts
All generated charts can be found here: output.zip
Source Code
The author and copyright holder of the following source code is André Christoffer Andersen. The source code is provided under the following Creative Commons license: Attribution-NonCommercial-ShareAlike 4.0 International. Please contact the author for commercial use.
Use at own risk.
Scenario file: scenarios.csv
Data file: osebx.csv (mirror)
Output charts: output.zip
Output text dump: run_dump.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# This source code is provided under the following Creative Commons license: # Attribution-NonCommercial-ShareAlike 4.0 International # https://creativecommons.org/licenses/by-nc-sa/4.0/ # Please contact the author for commercial use: andre@andersen.im # Fixed parameters exchange <- 'OSE' instrument <- 'OSEBX' p_level = 0.90 allowance <- 20000 sim_count <- 10000 risk_free_return <- 0.0056 # STATSOBL-3Y-EFF Last updated: Thursday 25. August 09:10 # Setting up the different scenarios destfile <- 'scenarios.csv' scenarios <- read.csv(file=destfile, strip.white=TRUE) scenarios$sample_start <- as.Date(scenarios$sample_start) scenarios$sample_end <- as.Date(scenarios$sample_end) scenarios$invest_start <- as.Date(scenarios$invest_start) scenarios$invest_end <- as.Date(scenarios$invest_end) # Defining functions for simulation and data processing build_period <- function(sample_start_date, sample_end_date){ library(lubridate) period <- as.data.frame(seq(sample_start_date, sample_end_date, by="days")) names(period) <- 'quote_date' period$eom <- period$quote_date == period$quote_date - days(day(period$quote_date)) + 1 + months(1) - 1 period$som <- period$quote_date == period$quote_date - days(day(period$quote_date)) + 1 return(period) } fetch_dataset <- function(start_date, end_date, exchange, instrument){ period <- build_period(start_date, end_date) url <- paste0('http://www.netfonds.no/quotes/paperhistory.php?paper=',instrument,'.',exchange,'&csv_format=csv') destfile <- 'osebx.csv' if(!file.exists(destfile)){ download.file(url,destfile) } dataset <- read.csv(file=destfile) dataset$quote_date <- as.Date(as.character(dataset$quote_date), "%Y%m%d") dataset <- dataset[order(dataset$quote_date),] previous_row_date <- max(dataset$quote_date[dataset$quote_date < start_date]) data_fields <- c('paper','exch','open', 'high', 'low', 'close', 'volume', 'value') previous_row <- dataset[dataset$quote_date==previous_row_date,data_fields] dataset <- merge(x=period, y=dataset, by='quote_date', all.x=TRUE) for(i in 1:nrow(dataset)) { row <- dataset[i,] if(is.na(row$close) || is.na(row$low)){ dataset[i,data_fields] <- previous_row } else { previous_row <- dataset[i, data_fields] } } dataset_size <- nrow(dataset) ror <- diff(dataset$close)/dataset$close[-dataset_size] ror <- append(ror, 0, 0) dataset$ror <- ror ror_low <- diff(dataset$low)/dataset$low[-dataset_size] ror_low <- append(ror_low, 0, 0) dataset$ror_low <- ror_low dataset <- subset(dataset, select = c('quote_date', 'som', 'eom', 'ror', 'ror_low')) return(dataset) } sample_df = function(df,n){ return(df[sample(nrow(df),n),]) } resample <- function(dataset_invest, dataset_sample){ sample_df = function(df,n){ # http://stackoverflow.com/a/8273414/604048 return(df[sample(nrow(df),n,replace=TRUE),]) } dataset_resampled <- sample_df(dataset_sample, nrow(dataset_invest)) dataset_resampled$quote_date <- dataset_invest$quote_date dataset_resampled$som <- dataset_invest$som dataset_resampled$eom <- dataset_invest$eom rownames(dataset_resampled) <- 1:nrow(dataset_resampled) return(dataset_resampled) } simulate <- function(dataset, allowance, gearing_factor, interest_rate){ loan_flow <- allowance * gearing_factor cash_flow <- allowance + loan_flow interest_rate_monthly <- ((1+interest_rate) ^ (1/12))-1 dataset$loan_balance <- 0 dataset$accrued_interest <- 0 dataset$accrued_allowance <- 0 dataset$asset_balance <- 0 dataset$margin_call <- FALSE loan_balance <- 0 accrued_interest <- 0 accrued_allowance <- 0 asset_balance <- 0 for(i in 1:nrow(dataset)) { if(dataset[i,'som']){ asset_balance <- asset_balance + cash_flow loan_balance <- loan_balance + loan_flow accrued_allowance <- accrued_allowance + allowance } if(dataset[i,'eom']){ intrest <- loan_balance * interest_rate_monthly accrued_interest <- accrued_interest + intrest loan_balance <- loan_balance + intrest } asset_balance <- asset_balance * (1 + dataset[i,'ror']) asset_balance_low <- asset_balance * (1 + dataset[i,'ror_low']) equity_low = asset_balance_low - loan_balance if(equity_low <= 0){ loan_balance <- loan_balance - asset_balance_low asset_balance <- 0 dataset[i, 'margin_call'] <- TRUE } dataset[i,'asset_balance'] <- asset_balance dataset[i,'loan_balance'] <- loan_balance dataset[i,'accrued_interest'] <- accrued_interest dataset[i,'accrued_allowance'] <- accrued_allowance } dataset$equity <- dataset$asset_balance - dataset$loan_balance dataset$cumulative_profit <- dataset$equity - dataset$accrued_allowance return(dataset) } run_simulations <- function( dataset_invest, dataset_sample, allowance, gearing_factor, interest_rate, p_level, sim_count, resample, simulate){ library("parallel") library("foreach") library("doParallel") core_count <- detectCores() - 2 cl <- makeCluster(core_count) registerDoParallel(cl, cores = core_count) simres = foreach(i = 1:sim_count, .combine = rbind) %dopar% { try({ dataset_resampled <- resample(dataset_invest, dataset_sample) dataset_resampled <- simulate(dataset_resampled, allowance, gearing_factor, interest_rate) cumulative_profit <- dataset_resampled$cumulative_profit margin_called <- any(dataset_resampled$margin_call) final_entry <- tail(dataset_resampled,1) final_cumulative_return <- final_entry$cumulative_profit / final_entry$accrued_allowance final_cumulative_profit <- final_entry$cumulative_profit ror_mean <- mean(dataset_resampled$ror) ror_var <- var(dataset_resampled$ror) res <- list(margin_called, cumulative_profit, final_cumulative_return, final_cumulative_profit, ror_mean, ror_var) return(res) }) } stopCluster(cl) margin_call_prob <- sum(unlist(simres[,1]))/sim_count cumulative_profits <- unlist(simres[,2]) cumulative_return_sd <- sd(unlist(simres[,3])) cumulative_profit_sd <- sd(unlist(simres[,4])) ror_mean <- mean(unlist(simres[,5])) ror_sd <- sqrt(mean(unlist(simres[,6]))) dataset_invest_size <- nrow(dataset_invest) profit_matrix <- matrix(cumulative_profits, ncol = dataset_invest_size, byrow = TRUE) p_lower <- (1-p_level)/2 p_upper <- 1-p_lower p_interval <- c(p_lower, 0.5, p_upper) bands <- data.frame(t(apply(profit_matrix, 2, quantile, p_interval, na.rm=TRUE))) names(bands) <- c('cumulative_profit_lower', 'cumulative_profit_mid', 'cumulative_profit_upper') bands$quote_date <- dataset_invest$quote_date return(list(bands, margin_call_prob, cumulative_return_sd, cumulative_profit_sd, ror_mean, ror_sd)) } # Run scenarios for(i in 1:nrow(scenarios)){ scenario <- scenarios[i,] scenario_id <- as.character(scenario$id) dataset_sample <- fetch_dataset(scenario$sample_start, scenario$sample_end, exchange, instrument) dataset_invest <- fetch_dataset(scenario$invest_start, scenario$invest_end, exchange, instrument) simres <- run_simulations( dataset_invest, dataset_sample, allowance, scenario$gearing_factor, scenario$interest_rate, p_level, sim_count, resample, simulate) bands <- simres[[1]] margin_call_prob <- simres[[2]] cumulative_return_sim_sd <- simres[[3]] cumulative_profit_sim_sd <- simres[[4]] daily_ror_mean <- simres[[5]] daily_ror_sd <- simres[[6]] dataset <- simulate(dataset_invest, allowance, scenario$gearing_factor, scenario$interest_rate) dataset <- merge(x=dataset, y=bands, by='quote_date', all.x=TRUE) days <- nrow(dataset) dataset$cumulative_return <- dataset$cumulative_profit / dataset$accrued_allowance dataset$cumulative_return_lower <- dataset$cumulative_profit_lower / dataset$accrued_allowance dataset$cumulative_return_mid <- dataset$cumulative_profit_mid / dataset$accrued_allowance dataset$cumulative_return_upper <- dataset$cumulative_profit_upper / dataset$accrued_allowance daily_risk_free_return <- (1+risk_free_return) ^ (1/365) - 1 #365 days becuase we are including all days of the year in the ror_mean and ror_sd calculations. daily_sharp_ratio <- (daily_ror_mean - daily_risk_free_return) / daily_ror_sd # Output last_entry <- tail(dataset,1) print(scenario_id) print(paste0('<tr><td>Days</td><td>',days,'</td></tr>')) print(paste0('<tr><td>Gearing Factor</td><td>',format(round(scenario$gearing_factor,1),nsmall=1),'x</td></tr>')) print(paste0('<tr><td>Interest Rate</td><td>',format(round(scenario$interest_rate*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Crash</td><td>',substring(scenario_id, nchar(scenario_id)) == "C",'</td></tr>')) print(paste0('<tr><td>Estimated Probability of Margin Call</td><td>',format(round(margin_call_prob*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Cum. Return - Standard Deviation</td><td>',format(round(cumulative_return_sim_sd*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Cum. Return - Lower (5%)</td><td>',format(round(last_entry$cumulative_return_lower*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Cum. Return - Mid/Expected (50%)</td><td>',format(round(last_entry$cumulative_return_mid*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Cum. Return - Upper (95%)</td><td>',format(round(last_entry$cumulative_return_upper*100,2),nsmall=2),'%</td></tr>')) print(paste0('<tr><td>Sharp Ratio</td><td>',format(round(daily_sharp_ratio,4),nsmall=4),'</td></tr>')) print(paste0('<tr><td>Cum. Profit - Standard Deviation</td><td>NOK ',round(cumulative_profit_sim_sd,0),'</td></tr>')) print(paste0('<tr><td>Cum. Profit - Lower (5%)</td><td>NOK ',round(last_entry$cumulative_profit_lower,0),'</td></tr>')) print(paste0('<tr><td>Cum. Profit - Mid/Expected (50%)</td><td>NOK ',round(last_entry$cumulative_profit_mid,0),'</td></tr>')) print(paste0('<tr><td>Cum. Profit - Upper (95%)</td><td>NOK ',round(last_entry$cumulative_profit_upper,0),'</td></tr>')) print(paste0('<tr><td>Accrued Allowance</td><td>NOK ',round(last_entry$accrued_allowance,0),'</td></tr>')) library(scales) library(ggplot2) library(grid) library(gridExtra) library(gtable) ret_plot <- ggplot() + geom_line(data = dataset, aes(x=quote_date, y=cumulative_return, colour = "Actual"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_return_lower, colour = "Lower (5%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_return_mid, colour = "Mid (50%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_return_upper, colour = "Upper (95%)"), size=1) + labs(x="Time", y="Cumulative Return", colour="") + scale_y_continuous(labels = percent, breaks = seq(scenario$ret_low, scenario$ret_high, by = scenario$ret_step), limits = c(scenario$ret_low, scenario$ret_high)) + scale_x_date(date_breaks = "2 month", date_labels="%b %y") + theme(legend.position="bottom") + ggtitle(paste0(scenario_id,": Cumulative Returns")) prof_plot <- ggplot() + geom_line(data = dataset, aes(x=quote_date, y=cumulative_profit, colour = "Actual"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_profit_lower, colour = "Lower (5%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_profit_mid, colour = "Mid (50%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=cumulative_profit_upper, colour = "Upper (95%)"), size=1) + labs(x="Time", y="Profit", colour="") + scale_y_continuous(labels = comma, breaks = seq(scenario$prof_low, scenario$prof_high, by = scenario$prof_step), limits = c(scenario$prof_low, scenario$prof_high)) + scale_x_date(date_breaks = "2 month", date_labels="%b %y") + theme(legend.position="bottom") + ggtitle(paste0(scenario_id,": Profit & Loss")) bal_plot <- ggplot() + geom_line(data = dataset, aes(x=quote_date, y=accrued_allowance, colour = "Accrued Allowance"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=accrued_allowance+cumulative_profit_lower, colour = "Assets Lower (5%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=accrued_allowance+cumulative_profit_mid, colour = "Assets Mid (50%)"), size=1) + geom_line(data = dataset, aes(x=quote_date, y=accrued_allowance+cumulative_profit_upper, colour = "Assets Upper (95%)"), size=1) + labs(x="Time", y="Balance", colour="") + scale_y_continuous(labels = comma, breaks = seq(scenario$bal_low, scenario$bal_high, by = scenario$bal_step), limits = c(scenario$bal_low, scenario$bal_high)) + scale_x_date(date_breaks = "2 month", date_labels="%b %y") + theme(legend.position="bottom") + ggtitle(paste0(scenario_id,": Balances")) ret_grob <- ggplotGrob(ret_plot) prof_grob <- ggplotGrob(prof_plot) bal_grob <- ggplotGrob(bal_plot) maxWidth = grid::unit.pmax(ret_grob$widths[2:5], prof_grob$widths[2:5], bal_grob$widths[2:5]) ret_grob$widths[2:5] <- maxWidth prof_grob$widths[2:5] <- maxWidth bal_grob$widths[2:5] <- maxWidth ggsave(filename = paste0('output/return_', i, '_', scenario_id, '.png'), ret_grob) ggsave(filename = paste0('output/profit_', i, '_', scenario_id, '.png'), prof_grob) ggsave(filename = paste0('output/balance_', i, '_', scenario_id, '.png'), bal_grob) } |