Financial Portfolio rebalancing with Elixir.

What’s a portfolio?

A portfolio is a grouping of financial assets such as stocks, bonds, commodities, currencies and cash equivalents, as well as their fund counterparts, including mutual, exchange-traded and closed funds. A portfolio can also consist of non-publicly tradable securities, like real estate, art, and private investments.

Source: investopedia

The “Permanent Portfolio”

The “Permanent Portfolio” was created by Harry Browne in the 1980s. It assumes the economy has four possible states:

Distribution

Based on those economic conditions, Browne identified the most volatile asset classes, proposing the following distribution:

The self-regulation factor of the “Permanent Portfolio” is one of the fundamental concepts of Browne’s idea. It covers the most different scenarios of the economy, looking for ways to compensate losses and increase returns. This concept makes the “Permanent Portfolio” appealing to people who don’t want to be actively managing a portfolio on a daily (or even monthly) basis.

Let’s take a look at the historical prices of Gold and S&P500 (an index that measures the stock performance of the 500 large companies listed on stock exchanges in the United States).

Source: Yahoo Finance

In 2008, the year of the global financial crisis, stock investors definitively got worried about the market, and as a result, the value of the S&P index plunges. For 4 years, the S&P value stayed low, only getting back to its pre-crisis value after 2013. In case your investments were purely stocks, it wouldn’t be a fun ride.

At the same time, around 2008, the price of gold has started rising. When comparing it to the S&P value at the same time, its behaviour presents almost an inverted shape. The gold value has not only covered the stock losses but also has contributed to a profitable year.

While many investors were incredibly affected by the 2008 crisis, “Permanent Portfolio” holders had the following returns:

Despite a small glitch in 2013, the returns from the “Permanent Portfolio” were always positive. Considering the whole period between 2008 and 2014, the portfolio had an average return of 7% per year.

That’s one of the properties of the “Permanent Portfolio”, which makes its usage so appealing to more risk-averse humans like myself.

Fast forward to 2019, many people are concerned about a new financial crisis. Germany (where I live) is about to declare “technical recession” (two consecutive quarterly contractions in the economy). If you look at the chart, you can again see the unbalanced form between S&P and gold.

Of course that by looking at this chart, I (an amateur investor) can’t draw any conclusions about whether there’s a recession coming next or not. What’s essential to highlight is that the behaviour of the “Permanent Portfolio” is again supporting a potential crisis scenario.

Rebalancing a portfolio

The portfolio distribution (Stocks: 25%, Gold: 25%, Long term government bonds: 25%, Cash: 25%), will change over time. Some individual classes will increase, while others will decrease. That change shifts the asset classes desired allocation.

The “Permanent Portfolio” embraces the fact that the market is cyclical. There will be prosperity times where stocks value will rise and gold will plunge, but there will also be times where the stock market is not the best option.

Rebalancing a portfolio means getting the asset classes back to their desired allocations (25% each), by selling the ones that are overweight and buying the underweight ones.

The financial crisis in 2008 has created an unbalanced portfolio situation. It “forced” the portfolio holder to sell parts of the gold and use the profits to buy stocks (at an extremely low value) to balance it back to the desired weights.

In the long run (remember the market is cyclical), by continuously rebalancing a portfolio, you are using the built-in volatility of the portfolio to “buy cheap and sell high”.

Using Elixir to rebalance a “Permanent Portfolio”

Let’s use Elixir to rebalance a permanent portfolio. Those are the essential points when thinking about the optimal rebalancing strategy:

Let’s imagine the following interface:

allocations = %{"IAU" => 10, "TLT" => 10, "VGSH" => 10, "VTI" => 10}
orders = Rebalancex.rebalance_portfolio(allocations)
    

Based on a number of allocations (the amount of units that a specific item has), you can call the Rebalancex.rebalance_portfolio, which will return a number of orders to be performed.

Those orders contain information if a given symbol must be bought, sold or kept as it is:

[
  [:sell, "IAU", 4],
  [:sell, "TLT", 1],
  [:sell, "VGSH", 1],
  [:buy, "VTI", 8]
]
    

Considering the points above, that’s the code responsible for rebalancing the portfolio:

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
defmodule Rebalancex do
  alias Rebalancex.Quote

  @underweight 0.25
  @overweight 0.27

  def rebalance_portfolio(allocations, quote_service \\ Quote) do
    portfolio = %{cash: 0, allocations: allocations}
    prices = get_prices(allocations, quote_service)

    new_portfolio = do_rebalance_portfolio(portfolio, prices)
    create_order(portfolio, new_portfolio)
  end

  defp do_rebalance_portfolio(portfolio, prices) do
    positions = get_positions(portfolio.allocations, prices)
    weights = get_weights(positions)

    underweight_symbol = get_underweight(weights)
    overweight_symbol = get_overweight(weights)

    portfolio
    |> maybe_buy_underweight(underweight_symbol, prices)
    |> maybe_sell_overweight(overweight_symbol, prices)
    |> maybe_rebalance_again(underweight_symbol, overweight_symbol, prices)
  end

  defp get_prices(allocations, quote_service) do
    allocations
    |> Enum.reduce(%{}, fn {symbol, _}, acc ->
      Map.put(acc, symbol, quote_service.price_for(symbol))
    end)
  end

  defp get_price(prices, symbol) do
    Map.fetch!(prices, symbol)
  end

  defp get_positions(portfolio, prices) do
    portfolio
    |> Enum.reduce(%{}, fn {symbol_name, units}, acc ->
      Map.put(acc, symbol_name, get_price(prices, symbol_name) * units)
    end)
  end

  defp get_weights(positions) do
    total_value = Enum.reduce(positions, 0, fn {_, position}, acc -> position + acc end)

    positions
    |> Enum.reduce(%{}, fn {symbol_name, position}, acc ->
      Map.put(acc, symbol_name, position / total_value)
    end)
  end

  defp get_underweight(weights) do
    {symbol, _weight} =
      weights
      |> Enum.filter(fn {_, value} -> value < @underweight end)
      |> Enum.min_by(fn {_, value} -> value end, fn -> {nil, nil} end)

    symbol
  end

  defp get_overweight(weights) do
    {symbol, _weight} =
      weights
      |> Enum.filter(fn {_, value} -> value > @overweight end)
      |> Enum.max_by(fn {_, value} -> value end, fn -> {nil, nil} end)

    symbol
  end

  defp maybe_buy_underweight(portfolio, nil, _) do
    portfolio
  end

  defp maybe_buy_underweight(portfolio, symbol, prices) do
    price = get_price(prices, symbol)
    maybe_buy_underweight(portfolio, symbol, price, portfolio.cash)
  end

  defp maybe_buy_underweight(portfolio, symbol, price, cash) when cash > price do
    portfolio
    |> incr(symbol)
    |> withdraw(price)
  end

  defp maybe_buy_underweight(portfolio, _symbol, _price, _cash) do
    portfolio
  end

  defp maybe_sell_overweight(portfolio, nil, _prices) do
    portfolio
  end

  defp maybe_sell_overweight(portfolio, symbol, prices) do
    price = get_price(prices, symbol)

    portfolio
    |> decr(symbol)
    |> deposit(price)
  end

  defp maybe_rebalance_again(portfolio, nil, nil, _prices) do
    portfolio
  end

  defp maybe_rebalance_again(portfolio, _, _, prices) do
    do_rebalance_portfolio(portfolio, prices)
  end

  defp incr(%{allocations: allocations} = portfolio, symbol) do
    new_allocations = Map.put(allocations, symbol, allocations[symbol] + 1)
    %{portfolio | allocations: new_allocations}
  end

  defp decr(%{allocations: allocations} = portfolio, symbol) do
    new_allocations = Map.put(allocations, symbol, allocations[symbol] - 1)
    %{portfolio | allocations: new_allocations}
  end

  defp deposit(%{cash: cash} = portfolio, amount), do: %{portfolio | cash: cash + amount}

  defp withdraw(%{cash: cash} = portfolio, amount), do: %{portfolio | cash: cash - amount}

  defp create_order(%{allocations: old_allocations}, %{allocations: new_allocations}) do
    Enum.map(old_allocations, fn {symbol, old_units} ->
      cond do
        new_allocations[symbol] > old_units ->
          [:buy, symbol, new_allocations[symbol] - old_units]

        new_allocations[symbol] < old_units ->
          [:sell, symbol, old_units - new_allocations[symbol]]

        true ->
          [:keep, symbol]
      end
    end)
  end
end
    

Some things to point out:

Demo

I created a project to visualize the evolution of a “Permanent Portfolio” value over time. Starting with the amount of $10k, you can change different variables like monthly deposits, rebalancing strategy, region and see the impact on the final value.

The demo project is:

Visit https://elviovicosa.com/permanent-portfolio to test it live.

If you enjoyed this, you might also like

Elvio Vicosa

I’m a full-stack software developer based in Berlin, Germany. I’ve spent the last 10+ years working in a wide range of software projects, from internal web dashboards to real-time applications used by millions of people.

More about me