This article is a draft that will be incorporated into my book describing my Python Stock-Flow Consistent (SFC) modelling framework, but this may also be of interest to people who are new to the concept and wish to understand how to model portfolio returns.
Weights Versus Dollars
At the minimum, financial institutions report the dollar values of the investments in your portfolios. (Or the local currency of the account; I cannot think of a currency-neutral version of "dollar value" that is not hopelessly vague.) However, these reports are often supplemented by percentage weightings.The weighting of an asset of a portfolio is the dollar market value of the asset holding divided by the
net portfolio market value. By implication, the sum of all asset weightings equals 1. This means that we need only specify N-1 weights in a portfolio of N assets.
The fact that we use market values and not face values is a point that can catch hurried fixed income analysts. It is fairly common to get portfolio reports that just give the face value of bond positions from accounting systems; you cannot mix up the face value with the market value. (I think I did that once or twice on the first pass of coding; I caught the problems long before the analysis tools were to be used. I hope.)
If a portfolio does not use leverage, all weightings will lie between 0 and 1. However, we can allow for borrowing, and those liabilities are treated as negative assets. For example, we could borrow $50 on margin from our broker to buy $150 in stocks.
- The net value of the portfolio is $100.
- The weighting of stocks is 1.5 (150%).
- The weighting of the margin borrowing is -50%.
Returns
When discussing returns, I am exclusively referring to total returns. The total return includes all sources of investment return, such as dividend and interest payments. This is different than price returns, which only looks at the price of the assets. The only reason price returns are discussed is that it is easy to get stock and stock index prices, while total return indices are usually costly to obtain.
For example, if a stock was at $100 in June 2017, and its price goes to $101 in June 2018, it has a 1% price return. If it also paid a $2 dividend in June 2018, it had a total return of 3% ($2 dividend plus $1 price gain is 3% of the initial price). If the dividend was paid earlier, we would need to incorporate the value of reinvesting the dividend during the accounting period.
The return of a portfolio during an accounting period is equal to the weighting of each asset in the portfolio, times the asset's return.
From a coding perspective, it is safest to calculate the portfolio return by directly applying this rule to period returns. However, we could work directly on total return indices if we are only interested in a single accounting period. This is discussed next.
Another point to keep in mind when coding return calculations in a time series context is that the weightings in a period interact with the change in the total return index between that period and the next one; that is, there is a lag. If you do not incorporate that lag, your weightings are influenced by future total returns. The end result is a trading rule that looks very good in back history (and fails if actually implemented).
Effects of Rebalancing
A portfolio that is following fixed weightings acts differently than a portfolio where asset holdings are fixed. This difference shows up when constructing code to analyse trading rules where you buy or sell assets in fixed position sizes based on some rule.
We will take an example of two stocks with the following price history.
- Both start at $1.00.
- In period 1. stock #1 goes to $1.10, stock #2 remains at $1.00.
- In period 2, stock #1 drops to $1.00, and stock #2 remains at $1.00.
Case #1: Fixed Position Sizes. If you buy 50 shares at the start, and hold those positions the entire time, your portfolio value is as follows.
- Starts at $100.
- Rises to $105 (=$55 + $50).
- Drops back to $100.
Case #2: Fixed Weighting. In this case, we keep a 50% market value weighting at all times.
- We start out the same as the previous case, with 50 shares of both companies.
- In period 1, we have $105. In order to keep a 50/50 weighting, we need to sell some of stock #1 and buy stock #2. In particular, we buy 47.73 shares of stock #1, and 52.5 shares of stock #2.
- In period 2, our portfolio value is $100.23 ($47.73 of stock #1, and $52.5 for stock #2).
Although the two strategies looked similar at the beginning, the strategy with portfolio rebalancing outperformed in this case. This is because we "sold the winner, and bought the loser," and in this case, the outperformance reverted.
Portfolio rebalancing will not always outperform fixed weights; if in period #2, stock #1 outperformed again, the rebalanced portfolio would have underperformed, as it sold the stock that was on a winning streak. In summary, you want to rebalance when market relative performance is moving up and down ("volatile"), and not when there are trends.
(From a coding perspective, if you multiply total returns by percentage weights, you implicitly have a fixed weight portfolio. It only has the same total return as a rebalanced portfolio for the first period.)
Derivatives
The addition of derivatives like swaps or futures makes weighting-based calculations meaningless. The Net Present Value of a new on-market swap is zero, but it can have a large dollar amount impact on the portfolio value. In order to analyse portfolios with derivatives, we need to revert to discussing dollar amounts. For example, most internal discussions of portfolio sensitivity revolve around the DV01 (dollar value of a basis point), not duration. (Duration is used as a shorthand for discussing bullishness and bearishness of strategies.)
Portfolio Weights in the Python SFC Framework
The sfc_models framework needs to incorporate the desired asset weightings of the household sector. Within the Model PC code (based on the model from Chapter 4 of Monetary Economics) found in sfc_models.gl_book.chapter4.py, this is accomplished by the following block. [UPDATE: The syntax for the GenerateAssetWeighting call has been updated.]
r = dep.GetVariableName('r') eqn = 'L0 + L1 * {0} - L2 * (AfterTax/F)'.format(r) hh.GenerateAssetWeighting({'DEP': eqn}, 'MON')
In plain English, this code accomplishes the following.
- Get the full variable name of the interest rate r from the deposit market. We cannot assume that it is 'r', since there may be other countries added to the model -- which country's 'r' does that refer to? So we get the full variable name by querying the country's DepositMarket object; for that deposit market, the interest rate is always locally defined as 'r'.
- Define the variable eqn, which is a string. It wants to implement the standard deposit (Treasury bill) demand function:bill weighting/total financial assets = L0 + L1*(interest rate) + L2*(ratio of household disposable income to household financial assets (F)).
The variables L0, L1, L2 stand in for the lambda's that are standard in the mathematical SFC literature. (Monetary Economics discusses the history of this bill demand function.)
The interest rate variable is substituted into the equation, replacing the '{0}', by the format method. - The asset weighting equation information is embedded into the Household sector object hh, by a call to the GenerateAssetWeighting method. (Functions embedded in objects are technically known as methods.) This method is described next.
The method GenerateAssetWeighting handles the asset allocation among N financial assets by having the user specify weighting equations for the first N-1 assets, and the user then specifies a residual asset that gets the remaining weighting.
- The first parameter is a Python dict object, which is a set of (key, value) pairs. The keys are the codes associated with the assets, and the associated values are the (right-hand side) of the demand equations for those assets. In this case, the single demand equation in variable eqn is associated with the 'DEP' (deposit) financial asset. If there were two entries in this parameter (implying that there were three assets in the allocation), the syntax would look like:
{'CODE1': eqn1, 'CODE2': eqn2}. - The second parameter is just the code of the residual asset ('MON' for money). The weighting equation is set automatically to be 1 less the other weightings.
This method means that the results are immune to errors in setting the equation for the residual asset weighting. Otherwise, it would be possible to specify that 60% of financial assets are one asset, and the other asset gets 60%. (The framework would find a solution, but we would implicitly define a ghost asset that represents -20% of the sector's financial assets.)
(In the future, it may be possible to specify the weighting as an absolute dollar amount; this functionality is low priority and not implemented.)
Example of the Money Demand Function
The chart above shows the evolution of the rate of interest on deposits (bills) in Model PC. At period 10, the interest rate goes from 2.5% to 3.5%.
The figure above shows the deposit weighting in the portfolio. The weighting jumps at period 10, in response to the higher rate of interest. This is the result of the interest rate sensitivity term in the demand equation. (After period 10, the weighting is changing slowly as a result of the third term in the equation, but these changes are not visible.)
For completeness, the weighting of money (currency) in the household portfolio is given above. As can be seen, it is indeed 1 minus the deposit weighting, and falls as a result of the rise in the rate of interest.
(c) Brian Romanchuk 2017
No comments:
Post a Comment
Note: Posts are manually moderated, with a varying delay. Some disappear.
The comment section here is largely dead. My Substack or Twitter are better places to have a conversation.
Given that this is largely a backup way to reach me, I am going to reject posts that annoy me. Please post lengthy essays elsewhere.