Recent Posts

Wednesday, August 23, 2017

Implementing Foreign Exchange In sfc_models

The sfc_models package is a Python framework that automatically generates the equations for stock-flow consistent (SFC) models. This article discusses how foreign exchange transactions are represented within the framework. It is an unedited draft section from my upcoming book on sfc_models; some technical details may be harder to follow for readers unfamiliar with the framework. At the end of the article, I discuss the difference in modelling strategy between sfc_models and that used by Godley and Lavoie in their text Monetary Economics.


The implementation of foreign currency transactions within sfc_models is embedded in the ExternalSector class. This class is a subclass of Country, and it creates special objects that are subclasses of Sector to handle the various aspects of international transactions. The user is not expected to add objects to this abstract “country,” although that might change because of extensions to the code base.

(The name ExternalSector is somewhat unfortunate as it is technically not a Sector subclass; however, the name seemed to be the most natural from the standpoint of economics jargon.)

In order to allow a model to support international transactions; the user needs to create an ExternalSector object, passing it a Model into which it is embedded.

obj = ExternalSector(model_object)

(It is not even necessary to assign to the variable obj if it is not accessed; the ExternalSector object will be embedded into model_object within the constructor.)

Creating the ExternalSector will also create three Sector objects embedded within it.

  1. An ExchangeRates object, with code XR. This class holds the various exchange rates within the model; the user can call GetCrossRate() to get the variable name for the exchange rate between two currencies. The embedded exchange rate variables can be adjusted to generate model scenarios.
  2. A ForexTransactions object, with code FX. This object does the bulk of the work for the external sector, setting up the equations associated with cross-currency capital flows. The user will not normally deal with this object; instead, the framework will call it when cross-currency currency flows arise. (Either because of Market interactions or by registering cash flows.) If user wants to extend the framework, an understanding of how this class operates would become a necessity.
  3. An InternationalGold object, with code GOLD. This object handles gold transactions, which involve both flows stated in currency or volume (ounces) terms. The GoldStandardCentralBank and GoldStandardGovernment objects automatically set up their gold transactions, but the user may wish to add other sectors that interact with the gold market. This is done by calling the SetGoldPurchases() method, which registers a variable within a sector as representing  the flow of gold purchases in local currency terms. (Gold sales are represented by negative purchases.)

The ExternalSector simplifies international transactions in multicurrency models by having it acting as the intermediary for all cross-currency financial flows.

The left part of the figure above shows the original configuration of international financial flows in a three-country model. The diagram on the right shows how this is implemented within sfc_models: each original flow first enters the external sector, and then leaves the external sector to go to the original recipient. As a result, each country only has to look at its net flow versus the external sector, and not worry about aggregating across multiple bilateral relationships.

(This is not a simplification if we indeed are only examining a two-currency model. It would be possible to create a bilateral foreign exchange object that emulates the behaviour of ExternalSector, but only allows for two currencies within the model. The resulting equations should be simpler. However, my preference was to implement the general multi-currency object before covering special cases.)

Having all transactions intermediated by this single abstract country greatly simplifies the thorny problem of keeping track of currency values, particularly in a multi-currency model. If we know that the exchange rate between the Australian dollar (AUD) and the Canadian dollar (CAD) is 1:1, and 1 CAD purchases 2 U.S. dollars (USD), we know that 1 AUD also purchases 2 USD. (We say that there is an arbitrage relationship between currency pairs.) Real world currency quotes incorporate a bid-offer spread, and so there is a small error bar around the ideal arbitrage-determined currency rates, but nobody can buy and sell at a price far removed from the theoretical fair value for very long without going out of business.

Even if we are not convinced by arbitrage arguments, we need to keep our currency values consistent if we want consistent accounting. For example, if we were not careful, we might set the bilateral exchanges rates between CAD and USD as:

  • 1 CAD buys 1 USD; and
  • 2 USD buys 1 CAD.

The values of financial flows are determined by multiplying the foreign currency value by the cross-currency rate (USD to CAD, or CAD to USD, depending on the direction of the flow). If we use incoherent prices like the above, the accounting will not add up. Effectively, some sector will have exchanged currency at the “wrong” value, and has suffered a capital gain or loss as a result. This gain or loss would effectively be pocketed by an unknown intermediary. The model accounting would therefore break down if the intermediary does not explicitly appear within the model.

Rather than force the user to make sure that exchange rate changes are coherent, the framework uses a simplification: all currency values are expressed versus a single unit of account. In the financial and economic literature, this single unit of account is known as a numéraire. As a result, the currency of the ExternalSector object is ‘NUMERAIRE,’ which has a currency value of 1 for all time by definition. Other currencies are then specified by a single time series, which is the number of units of NUMERAIRE than can be purchased for 1 unit of the currency. The time series of these currencies is a variable within the exchange rate object (‘XR’), with a variable name equal to the currency code.

This convention means that a larger currency value in the time series corresponds to a stronger currency. For example, if CAD goes from 1 to 2, it is stronger, since a single Canadian dollar can now purchase 2 ‘NUMERAIRE’ instead of 1.

Cross-rates have a variable name based on the two currencies, and they are calculated as the corresponding ratio of the two currencies versus NUMERAIRE. Since there is no trade with the ExternalSector object, all sector economic behaviour should be based upon the cross-rates with “real” currencies.

This currency-naming scheme could trip up foreign currency experts. Currency rates can either be specified by naming the pair in full (“USD-GBP” for the U.S. dollar-to-British Pound exchange rate), or by just specifying a non-dollar currency for the rate versus the U.S. dollar (which would be “GBP” for the previous example). That is, the U.S. dollar is treated as the numéraire, and not a fictitious currency. Unfortunately, the convention used (whether the rate specifies 1 USD versus x foreign, or x USD versus 1 foreign) appears random to the casual observer. (The conventions were determined by historical developments.) It would be ridiculous to emulate this haphazard approach, and so the sfc_models framework uses a consistent quote convention versus the NUMERAIRE.

Therefore, all that is needed to adjust currency values is to set the value of the currency versus the numeraire; cross-rate values will automatically adjust.

For example, we can do the following:

model_object.SetExogenous('EXT_XR', 'CAD', '[1.]*5 + [1.2]*100')

This sets the variable CAD in the XR sector of EXT to be 1.0 for the first five periods (k=0,..,4) and 1.2 thereafter. This will cause CAD to appreciate versus all other currencies in the model (assuming the other currencies are themselves unchanged.)

As for international cash flows, these are normally handled within the framework; the user only needs to create an ExternalSector object. (If the object was not created, cross-currency cash flows will trigger a LogicError exception. We do not want to create the object if the user did not actually intend to have a cross-currency flow.)

There are two normal sources of cross-currency flows.

  1. International sectors (exporters) may supply markets; the Market object will handle the cross-currency implications automatically. (There is currently no support for demand sectors to cross currency zones.)
  2. The RegisterCashFlow() method of the Model object may be called, with the source and target sectors in different currency zones. The Model code detects that this is a cross-currency flow, and handles it accordingly. (Once again, it will throw a LogicError if the ExternalSector object was not created by the time cash flows are being processed.)

The following code uses RegisterCashFlow to create a cross-currency flow, it is probably the simplest possible way of generating such a flow.

from __future__ import print_function
from sfc_models.objects import *
from sfc_models.sector import Sector

mod = Model()
ExternalSector(mod)
ca = Country(mod, 'CA', currency='CAD')
us = Country(mod, 'US', currency='USD')

hh_ca = Sector(ca, 'HH', has_F=True)
hh_ca.AddVariable('GIFT', 'Sending money..', '5.')
hh_us = Sector(us, 'HH', has_F=True)
mod.RegisterCashFlow(hh_ca, hh_us, 'GIFT')
mod.main()
mod.TimeSeriesCutoff=1
series_list = ('CA_HH__F', 'US_HH__F', 'EXT_FX__NET_CAD', 'EXT_FX__NET_USD')
for s in series_list:
    print(s, mod.GetTimeSeries(s)[1])

What this code does is create two sectors, one in Canada, and the other in the United States. The variable GIFT is created, and set to be a constant 5.0. Then, a cash flow is registered, using the variable name GIFT as the value of the flow. (The value is in the source currency.)

The output is as follows:

CA_HH__F -5.0
US_HH__F 5.0
EXT_FX__NET_CAD 5.0
EXT_FX__NET_USD -5.0

When run, we see that the financial assets (F) in the Canadian sector are falling by 5.0 per period, while it is rising by 5.0 in the United States. (The exchange rates are set to 1 by default.)

However, something is wrong. The Canadian sector sends out 5 CAD, while the sector in the United States receives 5 USD. How was this possible?

Examination of the NET_CAD and NET_USD variables indicate the problem: they are non-zero. These variables indicate the net flows in each currency. If they are anything other than zero, there is an imbalance in foreign exchange transactions by the objects in the model.

One interpretation is that a non-modelled entity has acted as a financial intermediary for the modelled sectors, and so it ends up with net currency positions.

We can create GoldStandardGovernment objects in both countries to fix this imbalance. These sectors automatically balance the foreign exchange market, implicitly following the Gold Standard rules described in this article.

The new code is:

mod = Model()
ExternalSector(mod)
ca = Country(mod, 'CA', currency='CAD')
us = Country(mod, 'US', currency='USD')
gov_ca = GoldStandardGovernment(ca, 'GOV')
gov_us = GoldStandardGovernment(us, 'GOV')
# The need for the next step may be fixed...
gov_ca.AddVariable('T', 'Taxes', '0.')
gov_us.AddVariable('T', 'Taxes', '0.')


hh_ca = Sector(ca, 'HH', has_F=True)
hh_ca.AddVariable('GIFT', 'Sending money..', '5.')
hh_us = Sector(us, 'HH', has_F=True)
mod.RegisterCashFlow(hh_ca, hh_us, 'GIFT')
mod.main()
mod.TimeSeriesCutoff=1
series_list = ('CA_HH__F', 'US_HH__F', 'EXT_FX__NET_CAD', 'EXT_FX__NET_USD')
print('Net balance fixed')
for s in series_list:
    print(s, mod.GetTimeSeries(s)[1])

series_list = ('CA_GOV__GOLDPURCHASES', 'US_GOV__GOLDPURCHASES', )
print('Net balance fixed')
for s in series_list:
    print(s, mod.GetTimeSeries(s)[1])

The output is:

Net balance fixed
CA_HH__F -5.0
US_HH__F 5.0
EXT_FX__NET_CAD 8.93918681035e-05
EXT_FX__NET_USD -4.46959340517e-05
Net balance fixed
CA_GOV__GOLDPURCHASES -4.99995530407
US_GOV__GOLDPURCHASES 4.99991060813

We see that the net positions in CAD and USD are effectively zero (there is a small residual error in the model solution). This is achieved by the Canadian central bank selling 5 units of gold (PURCHASES are -5, that is, sales of gold) to the United States (PURCHASES are +5).

With this background material in place, it is now easier to explain the difference in the treatment of gold sales between Godley and Lavoie’s Monetary Economics and sfc_models.

If we have a non-intermediated flow between two sectors that lie in different currency zones, there are two imbalances in aggregate balance sheets created.
  1. The net flow financial assets across the currency zone is no longer zero, as one currency zone is losing financial assets, and the other gaining.
  2. The net flows in currencies are unbalanced.
The strategy in Monetary Economics is to argue that net flows in currencies are always zero by definition, and so not model them. Instead, the central bank buys or sells gold in order to keep the stock of financial assets balanced. (Since the central bank is the supplier of money, this is explained in terms of stocks of money and bills.) The fact that gold sales and purchases are balanced is an implicit result of accounting identities.

The strategy in sfc_models is for the gold standard governments to use gold sales to balance currency flows, and ignoring the domestic financial assets, as the foreign exchange transactions will implicitly cause the net flows of financial assets to net to zero.

The strategy of explicitly modelling the foreign exchange flows reflects the nature of the sfc_models package. As discussed in Chapter 7, sfc_models is meant to be used by researchers who will extend its capabilities. This requires flexibility, including the ability to modify any equation directly. As a result, it is to be expected that balance sheets identities will be violated, particularly during the development cycle. If the researcher causes financial assets to disappear from a domestic sector, that will show up in an imbalance in net financial assets. Effectively, there is a fictitious error flow implicitly created within the model. However, if the central bank automatically intervenes to balance domestic flows, there will be an imbalance created in the foreign exchange markets (since there was no international counterpart to the fictitious error flow). The researcher could then lose considerable time debugging the external components of the model they are building, not realising that it was a bug in the domestic sector construction that caused the problem.

(c) Brian Romanchuk 2017

5 comments:

  1. Brian, I have a question about the FX sector accounting mechanics in the aggregate system. Are levels on the aggregate bank balance sheets altered by the foreign sector interactions? Are levels on the central bank or government balance sheets altered? Or is there a side-accounting for currency swap deals that amount to a change of ownership of pre-existing financial instruments in each country?

    ReplyDelete
    Replies
    1. There's presently no private banks in the framework. Even if added, currency swaps are unlikely to appear.

      Delete
  2. Ideally you would want to have financial dealer sector that would do currency and other financial sector arbitrage conditions endogenously. This would clearly show the importance of dealer balance sheets, and things like the recent breakdown in covered interest parity would be easy to model.

    ReplyDelete
    Replies
    1. Although interesting, it would be difficult to incorporate that level of detail in a macroeconomic model. If one wanted, it would be possible to extend the sfc_models framework to cover that level of detail, but it is a topic that I would probably not have time to look at.

      Delete
  3. This comment has been removed by a blog administrator.

    ReplyDelete

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.