For any asset management business, the ability to determine whether an investment portfolio is performing well is key. But equally important is the ability to deliver that information to the people who need it in an easy-to-use format, such as an interactive application.

In this three-part series, I’ll be demonstrating how to build a Shiny application in RStudio that allows a user to build a portfolio and visualize its Sortino ratio, or the return he or she is likely to get from a given level of risk. You can see the final application below — and try it out yourself — but before you start building your own, let’s talk about why the Sortino ratio is important and how to calculate it.

Why is the Sortino Ratio Important?

The Sortino ratio is an important tool for evaluating the risk-adjusted returns of a portfolio, as well as the skill of the portfolio manager. A higher Sortino ratio indicates a portfolio manager who is generating higher returns per unit of risk absorbed.

Identifying better performing portfolios — and portfolio managers — is a crucial skill for all enterprise-level participants in the world of asset management, including quantitative analysts, data scientists, investment advisers, and many others. From a data science perspective, this is best accomplished using a reproducible workflow and an appealing end product. As someone who used to work in finance and now works at RStudio, I find a Sortino ratio Shiny app to be a thrilling combination of portfolio theory, statistical analysis, and data visualization. Let's get to it!

Here is the equation for the Sortino ratio:

The denominator in this equation (called the downside deviation, semideviation, or downside risk) can be thought of as the deviation of the returns that fall below some target rate of return for the portfolio. That target rate is called the minimum acceptable rate, or MAR. The numerator is the mean portfolio return minus the MAR, which can be thought of as excess returns.

The theory behind the Sortino ratio is that the riskiness of a portfolio is better measured by the deviation of returns* *below a target return, instead of by the standard deviation of all returns. This stands in contrast to the more commonly used Sharpe ratio, which calculates risk-adjusted return by the ratio of returns above the risk-free rate divided by the standard deviation of all returns. Today, analysts commonly prefer to use the Sharpe ratio to evaluate low-volatility investment portfolios, and the Sortino ratio to evaluate high-volatility portfolios.

Getting Started: The Sortino Ratio ProjectThis project has three distinct steps:

- Build a portfolio and calculate the Sortino ratio using three different methods
- Visualize the Sortino ratio using ggplot and highcharter
- Wrap into an interactive Shiny app

When working with the Sortino ratio, there are two critical choices you must make: how to construct the portfolio using assets and weights, and which MAR to use. By the end of this project, the Shiny application you build will allow a user to make these changes and see how the Sortino ratio changes as a result.

For this purposes of this project, let's use the following assets and weights:

- SPY (S&P500 fund), weighted 25%
- EFA (a non-US equities fund), weighted 25%
- IJS (a small-cap value fund), weighted 20%
- EEM (an emerging-mkts fund), weighted 20%
- AGG (a bond fund), weighted 10%

We will also use a MAR that is equal to .008 or 0.8%. Just a note, we are holding this portfolio to a higher standard than normal — typically, you'd just want the rate to be above 0%.

First, load the packages that are not already installed in your environment:

```
# install.packages("tidyverse")
# install.packages("tidyquant")
# install.packages("timetk")
library(tidyverse)
library(tidyquant)
library(timetk)
```

Next, import daily prices for the five exhange-traded funds (ETFs), using the R package `getSymbols`

to grab the data, `map(~Ad(get(.)))`

to select adjusted prices only, and `reduce(merge)`

to mash the five prices into one xts object.

```
# The symbols vector holds our tickers.
symbols <- c("SPY","EFA", "IJS", "EEM","AGG")
# The prices object will hold our raw price data
prices <-
getSymbols (symbols, src = 'yahoo', from = "2005-01-01",
auto.assign = TRUE, warnings = FALSE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(symbols)
```

Choose asset weights and assign them to the variable `w`

. You will also assign the MAR of .008 to the variable.

```
w <- c(0.25, 0.25, 0.20, 0.20, 0.10)
MAR <- .008
```

Next, you will use two methods to convert those asset weights to monthly log returns. For the first method, we will stay in the `xts`

world.

```
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)
asset_returns_xts <- na.omit(Return.calculate(prices_monthly, method = "log"))
```

Invoke the function `Return.portfolio(asset_returns_xts, weights = w)`

from `PerformanceAnalytics`

and pass in your asset returns and weights. This will give you portfolio returns in `xts`

format.

`portfolio_returns_xts <- Return.portfolio(asset_returns_xts, weights = w) `

You now have an `xts`

object of portfolio returns called `portfolio_returns_xts`

.

Now, you will perform the same transformations in the tidy world, starting with the transformation of daily prices to monthly asset returns.

```
# Tidyverse method, to long, tidy format
asset_returns_long <-
prices %>%
to.monthly(indexAt = "last", OHLC = FALSE) %>%
tk_tbl(preserve_index = TRUE, rename_index = "date") %>%
gather(asset, returns, -date) %>%
group_by(asset) %>%
mutate(returns = (log(returns) - log(lag(returns))))
```

For portfolio returns, call the `tq_portfolio`

function from `tidyquant`

.

```
portfolio_returns_tidy <-
asset_returns_long %>%
tq_portfolio(assets_col = asset,
returns_col = returns,
weights = w,
col_rename = "returns")
```

You now have a tidy `tibble`

object of portfolio returns called `portfolio_returns_tidy`

. Take a quick peek at both of the objects you just created for a quick check.

```
head(portfolio_returns_xts)
head(portfolio_returns_tidy)
```

There is one big difference that we will handle below: For January 2005, `portfolio_returns_tidy`

contains `0.00`

, and `portfolio_returns_xts`

excludes the observation completely. That will make a difference because 0.00 is below our MAR.

On to the Sortino analysis. Calculating the Sortino ratio in the `xts`

world is very convenient. Call:

`SortinoRatio(portfolio_returns_xts, MAR = MAR)`

Then pass the portfolio returns and MAR to the built-in function from `PerformanceAnalytics`

.

```
sortino_xts <-
SortinoRatio(portfolio_returns_xts, MAR = MAR) %>%
`colnames' <- ("ratio")
```

From a substantive perspective, you could stop here and start visualizing with `highcharter`

.

Instead, I would suggest you run the calculation by hand, implementing the equation for the Sortino Ratio via pipes and `dplyr`

. It's not a verbose piped workflow. In short, you would call:

` summarise(ratio = mean(returns - MAR)/sqrt(sum(pmin(returns - MAR, 0)^2)/nrow(.)))`

Note the use of `slice(-1)`

to remove the first row. You want to delete that first 0.00 for January 2005 to be consistent with the `xts`

operations, but that is an important choice and one that could be questioned. Perhaps you should instead re-wrangle your `xts`

object to make it consistent? Either way, you want to be explicit about your choice so that others can reproduce your work later.

```
sortino_byhand <-
portfolio_returns_tidy %>%
slice(-1) %>%
summarise(ratio = mean(returns - MAR)/sqrt(sum(pmin(returns - MAR, 0)^2)/nrow(.)))
sortino_byhand
```

Now on to `tidyquant`

, which allows you to apply the `SortinoRatio`

function from `PerformanceAnalytics`

to a `tibble`

. As long as you are passing it the same data as you passed originally with the `xts`

object, you should get the same result.

```
sortino_tidy <
portfolio_returns_tidy %>%
slice(-1) %>%
tq_performance(Ra = returns,
performance_fun = SortinoRatio,
MAR = MAR,
method = "full") %>%
`colnames<-`("ratio")
```

Compare your three Sortino objects.

You have consistent results from ** xts**,

`tidyquant`

, and your by-hand piped calculation. It might feel like a lot of work to get the same result three times, but it forces you to look under the hood of the built-in functions, which might serve you well in the future should you have data or a project that fits better with one of the three methods.In the next installment, I will walk you through how to visualize the Sortino ratio and its data slicing implications using `ggplot2`

and `highcharter`

. Thanks for reading!

About the AuthorJonathan Regenstein leads RStudio's financial services practice and works with data science teams at a variety of financial institutions. He studied International Relations as an undergraduate at Harvard, worked in finance at JPMorgan Chase & Co, and did graduate work in Political Economy at Emory University before joining RStudio. He is the author of the forthcoming book

*Reproducible Finance with R*(to be published by CRC Press in early 2018). His code and Shiny apps can be found at reproduciblefinance.com.

*Enjoy this post? Check out some of our other content:*