Simple model examples

Here are some simple model examples. Please feel free to use them, but only subject to the disclaimer that you do so at your own risk, verdigris makes no representations as to their correctness, and takes no responsibility for their use.

Simple debt corkscrew.mortgage style

Simple debt corkscrew.equal principal repayments

Simple property rental model

Sickness decrement model: We put this together for interest to understand what sort of drivers the rate of infections for COVID19 has. The model is extremely sensitive to changes in assumptions (of which there are several). Due to the sensitivity, and to lack of available data for determining the assumptions, it probably doesn’t make a good predictor for infection rates. The influence of a future vaccine is also ignored. If you’re interested, play with the number of contacts per person per day, and the probability of transfer given contact with a sick person. It’s clear from playing with these just how sensitive the infection rate is to very small changes.

Modelling an infrastructure portfolio

Infrastructure investors may over time acquire a portfolio of assets, whether they be equity or debt investors. In South Africa, this is happening in the renewable energy space, with different investors acquiring sizable portfolios of wind and solar projects. Sometimes investments into individual projects may be quite small in comparison to the full portfolio, but the work associated with managing an investment into a project is, unfortunately, not proportional to the size of the investment.

Investors will likely need to value their investments periodically – for example, when they are completing their annual financial statements. They may also need to manage their liquidity, and therefore need to identify what future capital commitments they may have, or debt payments or equity distributions they may receive.

These exercises require a project model for each project in the portfolio. Usually the project model will be the lenders’ base case model (also the bid model in South Africa). As a result the investor will need to maintain several different models, updating each of them for each valuation or exercise. Clearly this becomes more onerous as more projects are added to the portfolio, particularly since each model may have its own idiosyncrasies.

So what steps can such an investor take to simplify the modelling requirements for their portfolio of assets?

I wrote a proof-of-concept portfolio consolidation model recently. Here is the approach I took:

1)    Write a generic project model which does away with much of the complexity required for a full bid model and a full bankers’ base case model. In my case, I was looking at operational projects, so I removed construction-period functionality. I also removed all bid-related functionality.

2)    Assumptions for the model will be either constant over the full project life (eg name plate capacity), or time-based (eg interest rate curves, CPI curves, debt sculpting). Constant assumptions should be in a single column in the assumptions sheet, which should contain references to the curves applicable to that project. Because assumptions are in a single column, it is possible for the model to include assumptions for multiple projects, each in its own column. I also created a single column for the assumptions which feed through to the active selected case using a lookup to the active project’s assumptions column.

No alt text provided for this image

Time-based assumptions, or curves, should be in a separate sheet. I wrote a macro which creates named ranges for each curve item, so that I can then pull a curve into my model dynamically using Excel’s INDIRECT function.

No alt text provided for this image

3)    The generic project model should be in a single sheet, to the extent possible. By selecting the project in the Assumptions sheet, the calculations will update to represent that project. Given that projects may be structured differently, it may be necessary to have some functionality which is superfluous to some projects, but necessary in others. Examples of this may include multiple debt facilities, a mezzanine facility, O&M bonuses which are structured in a particular fashion, different lease arrangements, and so on. It is necessary that you be able to zero each of these without breaking the model.

No alt text provided for this image

4)    I created functionality to pull time-based tariffs and balance sheet items into the model. This is because as these change over time, the future distributions to capital providers change too. For example, an increase in tariff (relative to the original base case) will increase the distributions to shareholders. Similarly, a change in the tax depreciation schedule will influence the amount of tax paid in the future and therefore CFADS. It is important that these be included only in the time-based assumptions, and that no changes are made in the calculation sheet, since we will iterate through the projects when working at a portfolio level, and hard-coded figures in the working will clearly break this functionality. You can see an example of these in the Curves sheet in the image above.

5)    Now that we have a full project model which is able to represent multiple different project by changing only the assumptions, and the ability to switch between different projects by selecting which set of assumptions to use, it is possible to iterate through the projects using a macro by selecting the relevant project, resolving any circular references, and hard-copying the desired output into a portfolio view for each project. Since each project can have different length and starting-month periods, I used a monthly timeline and a lookup to copy distributions to shareholders (the output I chose for my proof of concept) into a table.

No alt text provided for this image

I also created basic error checking, focusing on whether the circular references had been resolved in each iteration, and whether the assumptions in the relevant project were different at the time of running the portfolio consolidation macro to those presently persisting in the model assumptions, using a checksum of the model assumptions.

6)    Finally, I aggregated these results into more usable time periods (eg annual), and calculated a range of NPVs.

No alt text provided for this image

The approach described here has a few significant advantages:

  • Most obviously, the investor only has to understand and maintain a single model.
  • This also means that the single model can be audited at much lower cost than auditing several models.
  • Implementing scenarios across all projects simultaneously is trivial – for example if the house view on CPI changes, or the VAT rate changes.
  • Implementing structural layers, such as structurally-subordinated funding, is also fairly trivial.

Overall, these amount to a significant decrease in the amount of time required to perform any function requiring the project model(s), better operational risk management, reduced costs, and to better understanding of the portfolio.

Valuing infrastructure projects

From time to time an infrastructure project or its [potential future] shareholders may need to know the value of the project’s equity. Generally this will be for the purposes of a sale or purchase, or possibly for a listing.

It is most common to use a discounted cash flow methodology when conducting such a valuation. Most of the time this is fairly easy, as the project is likely to have a project model which produces distributions to shareholders at the bottom of the cash flow waterfall.

However, there are a few considerations to take into account when conducting a valuation:

Starting balances

Unless you are conducting the valuation as at financial close, the project will have built up certain actual balances during the construction period and any operations period that has elapsed. These will include the likes of cash in bank, debtors, creditors and plant and equipment. It is best to source these from the most recent set of financial accounts or management accounts available, as these will be the most accurate figures available. These balances will need to be incorporated into the project model such that in due course they feed through to the cash flow waterfall accurately. For example, a debtor balance will, via the model’s working capital assumptions, feed through into the cash flow waterfall and ultimately to distributions.

Starting balances, even cash balances, should not be included as stand-alone sums in the valuation. This is because the timing of distributions creates a material difference to the valuation, and generally any balance lacks this information unless it feeds through the waterfall. For example, a cash balance may result from a debt covenant lock up, which may only be cured in several months’ time.

More information about incorporating balances into the project model is available here: Operationalising Project Models.

Input assumptions

There are three main sources of assumptions available to the valuer:

  • The Project Documents and the Finance Documents. Good examples of such assumptions are base tariffs prior to inflation and interest margins. These assumptions will, all things being equal, hold for the life of the project, and consequently the valuer should leave them unchanged in the base case project model.

 

  • Expert information. Certain technical and macroeconomic assumptions may have been set by experts at the beginning of the project life or subsequently. An example of such would be future fx or inflation assumptions. These are best sourced from a (reputable and justifiable) expert source. Some technical assumptions may not change considerably over the life of the project, and may therefore be left alone without significantly effecting the valuation. An example of this might be power plant capacity.

Note that some project models may have a lenders’ base case and an equity base case. Typically it is most appropriate to use the equity base case (eg P50 energy yield assumptions) since it is the distributions which are being valued.

 

  • Actual experience. The performance of the project may differ to the original expected performance, in which case, in the absence of a reason to the contrary, the assumptions should be updated to reflect the most recent experience. Experience should be of reasonable duration – 12 months might be a good starting point to incorporate a reasonable sample size and any seasonality effects. Non-contracted opex inputs are a good example here, as is recent technical performance. Obviously when updating assumptions to reflect recent performance, one needs to apply a reasonability filter. Updating opex or technical assumptions to reflect an abnormally good or bad year will create bias in the valuation. One also needs to ensure that the experience is adjusted to account for the model’s inflation from the base date of the assumptions to the present.

A critical valuation assumption which deserves particular mention is the risk discount rate used to discount the distributions back to the valuation date. There are different means of arriving at, and influences upon, the appropriate discount rate for the valuation, and often some judgement will be required. These may include the following:

  • If the valuation is part of a sale negotiation, the risk discount rate may have been negotiated in advance, with the monetary valuation flowing from the risk discount rate as a result;
  • There may be recent sales which provide discount rate market benchmarks;
  • The project may have been structured so as to arrive at a reasonable risk discount rate for the risk profile of the project, as at the date of development;
  • The project may have experienced certain milestones and events which increase or decrease risk. An obvious one of these is the project completing construction and reaching Commercial Operation Date successfully. Another is the acquisition of an operating track record of a statistically significant sample length;
  • For completeness, there are theoretical models for determining an appropriate risk discount rate using the market risk free rate and the project’s beta and leverage – the Capital Asset Pricing Model (CAPM). Such a model is perhaps less relevant for an infrastructure project than for a normal operating company.

If a particular assumption has considerable uncertainty and has a significant effect on the distributions of the project – eg if plant output is very uncertain in the future for some reason – then it may make sense to model that assumption into the project’s future explicitly, rather than by modifying the risk discount rate to reflect the additional uncertainty. This allows greater understanding of the change in the valuation resulting from poor performance relating to the assumption in question. A good example of an assumption like this may be the traffic experience in a toll road project.

 

Valuation date

The date of the valuation may have considerable impact upon the valuation. In particular, moving the valuation date later by a month will have the following effect:

  • The valuation will increase by approximately 1/12th of the discount rate; and
  • The valuation will decrease by any distribution that was in the valuation period before the date change, but is no longer in the date change.

Consequently, if distributions are semi-annual, the valuation can move as much as 41% of the discount rate from a 5-month change in valuation date.

 

Termination amount

If one simply discounts the distributions in the project model, it is possible to miss the residual value of the project at the end of the project term (usually the end of the offtake contract term). This may be completely appropriate, for example in the case of a Build Own Operate Transfer project. However, in other instances it may not be appropriate at all, such as in the case where it may be feasible to enter into another subsequent offtake contract, or dispose of some of the project’s assets for a sum. Conversely, a rehabilitation cost may be applicable at the end of the term. Such an amount may be modeled explicitly by discounting the sales price or rehabilitation cost, or by extending the term of the modeled operations period using a new set of (possibly conservative) assumptions.

 

Sensitivities

The valuer may be asked to provide a single valuation figure, but it is nonetheless good practice to provide sensitivities to those assumptions which either:

  • Have considerable uncertainty;
  • To which the valuation outcome is very sensitive; or
  • Both.

The purpose of the sensitivities is to help the client in any final negotiations or decisions around the final price or valuation. If the final report is a public document, or shared with the other side of the negotiating table, these sensitivities could be removed from the final public version of the valuation report.

Operationalising project models

Why do it?

Once a project has been through its financing and construction phases, the project may want to operationalise the project model. This can have the following benefits for the project:

  • The model can be simplified, making it more tractable to use, since much of the financing-related functionality is no longer necessary;
  • The construction period can be removed, further simplifying the model;
  • We can incorporate actual experience, making the stepping-off point for projections much more valid than under the original base case model;
  • We can integrate the model into the project’s existing administration systems; and
  • We can incorporate new line items which were not considered relevant at the financing stage – in particular, new opex items are common.

Operationalising a model may be more important for a project if the project’s reality has evolved in a fashion which is significantly different to that portrayed by the original model. Such an eventuality may necessitate frequent reconciliations between model and accounts, explanations of budgets and justification of covenant ratios.

Starting point

The inputs required to operationalise a model include the following, assuming the modeler has some familiarity with the project:

  • The original model;
  • At least two sets of financial statements and/or management accounts (or general ledger and mappings from the ledger to the fields in the model);
  • An indication of what new functionality is desired, if any;
  • An indication of how frequently the project would like to incorporate actuals into the model, in order to determine the period of the new model.

I recommend that the modeler start afresh or use a template for the new model, rather than trying to modify or simplify the existing model. This is because simplifying an existing model comes with any baggage associated with that model, and it can therefore be cumbersome. A simplified model may end up with inputs and calculations with no dependents, and may incorporate logic errors which were overlooked in the original model build.

Process

I recommend splitting the process into three main sections:

Stage 1: Replication and simplification

Replicate the existing model in a simplified manner. There will be much functionality which is no longer required, such as being able to select between different facility types (eg mortgage-style vs equal principal repayments). In this example the project has now fully determined which is applicable, so abandon the other. Another example may be excess facilities penciled in in case they were required, or construction period functionality.

Having the original model available is very helpful in understanding what the mechanics are for the transaction, and also to check numbers against. In particular, numbers which are point-in-time (such as revenue received in a period) as opposed to cumulative (such as cash balance) are ideal to check against the original model at this stage. I tend to check these as I work through the model build, and colour code my checked values to easily see which are exactly the same as the original model, which are similar, and which differ. Doing this will also help model users (lenders, for example) reconcile the new model back to the original model. This is helpful because it’s very likely that they made themselves comfortable with the original model, which was probably audited. It will also assist with model audit, if such is required.

Stage 2: Incorporating actuals

I like to incorporate a full new sheet which only contains actuals (i.e. figures that have actually occurred, and can therefore be found under existing sources of macroeconomic data (eg inflation) or in the project’s financial statements or general ledger). The benefits of this are:

  • That the project / model users do not have to search through all your calculations to determine where to fill in their actuals;
  • This in turn means that there is a reduced possibility of modifying the model’s calculations and thereby breaking it;
  • Actuals are all in one place, and can be located with appropriate mappings so that new line items can be more easily incorporated into the model in the future. It should therefore also be evident if one or more actuals are omitted.

Actuals on a single sheet, incorporating mapping information

Depending on what the client wants, the actuals to include may be a full dump of the management accounts, general ledger or financial statements, or a subset of that information. Since the project will be updating this sheet periodically, it needs to be clear what each actuals line item incorporates, and how that information is to be sourced in subsequent periods.

If a subset of the management accounts is acceptable, it’s usually sufficient to use a combination of balance sheet and income statement items. Cash flow statement items can typically be implied from these.

As implied above, the actuals sheet may also include a series of mappings. This is because the model is likely to have less detail, aggregating several rows from the AFS or general ledger into fewer lines. The mappings, in conjunction with a SUMIF function, can effect this.

From the Actuals sheet, I typically import the aggregated/mapped rows straight into the top of my Working (i.e. main calculations) sheet. These then feed down into the model’s projection calculations using a formula similar to the following: =IF(actual <> “”, actual, projection). You may also need to infer certain revenue items or expenses from the balance sheet items which you import. This is necessary to minimize the size of any balancing items. I also tend to place conditional formatting in my worksheet to indicate where the figure observed has been pulled through from actuals, or is a projected figure.

Conditionally-formatted actuals pulling into the Working sheet

Finally, one or two balancing figures will probably be required. If you import actual cash balance at the end of the period, it is unlikely that the cash flow waterfall will balance, since some items will be projections/ calculated values and some will be actuals. A balancing cash flow is therefore required to reconcile the starting balance and sum of all cash flows in the period with the ending balance. This balancing cash flow should automatically be zero in periods which have no actuals being pulled through. Obviously this should be as small as possible. Another balancing figure may be required to reconcile starting balance sheet figures plus income statement items with the actual end-of-period balance sheet position. Again, this should be as small as possible. However, note that this balancing figure will persist (without changing, otherwise something is wrong with your model) into projected periods.

Stage 3: Importing actuals

Finally, you should import at least two periods’ worth of actuals into your model. This will ‘settle’ the figures, since the first period sets the base line, and the second period creates the first accurate set of the implied / calculated values which result from the previous accumulated position and the present period’s actuals.

As a corollary, many of the calculated figures in the first period may be incorrect / spurious. This is because the model is moving from one basis (projections) to another (actuals). Any accumulated values (such as cash balance) may differ significantly between the two bases.

A second advantage of incorporating multiple sets of actuals into the model is that it will provide a better base for model users to compare against when they first need to incorporate actuals without the benefit of having the modeler present to assist.

Amount of work required

Operationalising a model is significantly less work than building a project model in the first instance. This is not so much because there is less functionality (although that may be partially true if the new model is much simpler than the old model), but because there are fewer moving parts to the project itself, and because the old model provides as good a set of assumptions and inputs as a modeler is likely to receive.

 

Framework for writing a trading algorithm

I’ve been lucky enough to have some spare time to look at projects of my own this year, so I researched and implemented a number of trading algorithms on various crypto currency exchanges.

Investing vs trading:

Before we start, though, a quick disclaimer: I’m undecided on the merits of crypto currency as an asset class. My intention here was to implement one or more algorithms to hunt arbitrage opportunities and, upon finding them, make the trades that would implement them. Where I have taken exposure to crypto currencies, I have both won and lost. Consequently, I don’t consider myself to be invested in crypto currencies, as I can’t foretell the future of the asset class with sufficient certainty for my somewhat risk-averse predilections. I’m happy to trade it, though – particularly if I can do so in a manner which minimises my exposure.

Why crypto currencies, not traditional exchanges:

For me there are three reasons which made crypto currencies a good learning ground for this sort of exercise:

  1. It’s generally accepted that the crypto currency markets are fairly inefficient, meaning that arbitrage opportunities abound. This may be because the asset class (without discussing the merits of such a label) is in its relative infancy, and it may also be because there are a large number of new, as-yet relatively unexplored exchanges.
  2. Crypto currencies are extremely volatile, which means they’re likely to move faster and further than traditional asset classes. Arbitrage is based on the differentials between prices or returns on (typically correlated) assets. More movement means a greater frequency of those differentials occurring.
  3. Crypto currency exchanges are created by IT people, and their APIs (Application Programming Interfaces) are fairly unrestricted. I’m not sure about all traditional exchanges, but as an example, the JSE does a full code review of any code which hooks into their exchange. The wild-west of crypto exchanges don’t. It’s also pretty cheap to register and start trading – no monthly stock broker’s fees, etc.

Where to start:

There are two possible places I can see to start with creating a trading algorithm (or algo). These are:

  1. The theoretical framework for the trade; and
  2. Collating the data.

Theoretical framework:

I did a lot of reading about different types of arbitrages to determine what might be suitable. In reality, I suspect that just about any trade which exists in a given traditional market could be implemented in a different market (whether traditional or not).

The more complex the theoretical framework for the trade you want to look at, the greater the difficulty in implementing it, and the possibility that it could go wrong. On the other hand, complex trades are likely to be less prolific than trades which are simpler or more vanilla.

The sort of behaviour we’re looking for is [statistical] predictability. This could be in the form of correlation of leading and lagging indicators, it could be a stationary process, it could be misaligned prices, mean reversion, momentum, or, for that matter, anything else which you hypothesize may give you an edge.

The common element in all of the above is that we want to have a better than 50:50 chance of predicting the next move in the price of whatever it is that we’re trading. Sometimes that behaviour is statistical in nature, such as stationary processes (used in pairs trading, for example) and sometimes it’s more simply a function of efficiency in markets, such as misaligned prices.

Collecting data:

You can almost always find relatively clean data to purchase, if you wish to go that route. It has many advantages: It’s easier, possibly cleaner and almost certainly has a better (longer) history than you could get yourself. On the downside, you’re spending your seed capital which you could have used for trading instead! Also, you don’t necessarily have oversight on how the provider has cleaned the data, and the granularity may be incorrect for your purposes.

If you choose instead to collect your own data, bear in mind that historical data may not be easily available, or available at all. This means you might want to start collecting as early on in the process as possible, so that you have something against which to test your trading hypotheses.

I chose to collect my own data. If you’re looking for historical data for traditional markets, you can download dumps from various sources, such as google finance (stocks, currencies), xe.com (currencies), various reserve banks, etc… For traditional markets, I found that this was helpful in trying to understand the data better, but not particularly helpful in testing trading hypotheses. This was almost all down to the lack of granularity of data available for free. However, I understand that traditional market data is available at fine granularity through the likes of Reuters, Bloomberg and other such providers – but read up on how they collect and clean it!

On the crypto currency exchanges, I hooked into multiple exchanges using their APIs and downloaded order book information for relevant instruments (currency pairs, underlying vs future vs option) at a granularity of around a minute, typically. My little downloading app runs on my pc pretty much 24-7, pulling data from a dozen exchanges each minute. I also collect fx data by screen scraping, although I have run into occasional rate limit issues, which seems fair enough to me, albeit it’s frustrating when it happens.

When I first started looking at crypto currencies I found an excellent project on github called ccxt, which is an open source integration into, at time of writing, 115 different crypto exchanges. This allowed me to do a very quick and dirty download of tick data to try and find correlations and misalignment between different exchanges, instruments etc. I used python (anaconda / Jupyter notebooks) for this exercise and stored my data in a Microsoft SQL Server database. (Both of these are free downloads, although there are some limitations on free SQL Server.)

What data to fetch:

If you haven’t decided exactly trade you’re going to implement, and therefore don’t have sight of your specific data requirements, I recommend fetching per-minute tick data from an assortment of exchanges which may be relevant to you (because you think they’re safe, the instruments being traded are of interest, the geographies work and the volume and liquidity on the exchange is sufficient for your purposes, for example). Collect data for instruments which are of interest – rather too much than too little, since you can always delete it, but can’t go back and collect it again. Initially I started collecting the market ticker information, but I abandoned that fairly soon in favour of only order book data – or at least the top several levels. I currently fetch ten order book levels, although that may be overkill, since I’ve yet to actually use anything other than the top level of the book. As mentioned above, I also collect the fiat fx rate for each order book fetch which has a fiat side (eg USD-BTC) back to a common currency. As I’m based in South Africa, that was ZAR, but you should use whatever works for you, obviously. Given that you’ll be making dozen’s of order book fetches every minute, I recommend storing the fiat fx rate locally periodically and referencing that (or pay for a service provider that doesn’t mind you hammering their server).

You’ll probably also want to fetch any underlying for any derivative instruments you’re collating information on – such as the index for a futures contract.

Finally, I recommend multi-threading your data collection. Although it’s more complex than a single-threaded application, this allows the time differential between data fetches on different exchanges to be smaller. By way of example, a single-threaded application might fetch data at 10:00:00 on exchange A, 10:00:05 on exchange B…. 10:00:30 on exchange Z. If you want to identify price misalignment between exchange A and Z, you will not know what portion of any misalignment you identify results from differences between the exchanges, and what results from change in the underlying price between 10:00:00 and 10:00:30.

Admittedly, you could be a bit obsessive about this. Spurious Accuracy and all of that…

Hypothesis testing:

We now have a gross hypothesis, and the data to test it. So how do we go about doing so?

In the simplest form, we need to simulate the trade we wish to do. However, a trade will be dependent upon some detailed assumptions and decisions (i.e. parameters). We should therefore find and test these parameters. This is something of an iterative process.

Parameterisation:

Firstly, what sort of parameters are we envisaging here? Examples that come to mind include:

  • The period of the data we’re looking at to determine the behaviour of the next tick (Last month’s worth? Last hour’s?)
  • The granularity of the data (minute, hour, day, second, microsecond)?
  • The underlying instruments we’ll be trading (base token (which currency pair?), future (which strike date?), option (put, call?))
  • The exchanges we’ll be looking at
  • The measures we’ll be using (standard deviation, correlation coefficients, mean return, direction, SMA, EWMA… many many to chose from)

There will be a number of different ways to determine and optimise the parameters for our trade. Remember that we’re looking for predictive relationships, which implies that correlation (or covariance) is a great place to start. If that’s a starting point you’d like to try, then you want to sort your data into leading indicators (input data) and lagging variables (the subject of your investigation). I found Anaconda python, numpy and SciKit Learn to be  fantastic tools for this (A quick aside: I am constantly amazed and gratified by the number of super-clever people out there who create these tools and then make them available to everyone for no cost!). I found that identifying the covariance between leading and lagging indicators was a good starting point and then testing whether than might translate into a trade using simple regression worked pretty well for me.

A few points about this stage of the process: I found several warning references in literature regarding overfitting. I did try out various machine learning frameworks (Keras and Tensorflow’s neural networks and recurrent neural networks, for example.) However, I eventually abandoned them in favour of simpler methods. I’m not saying that I won’t go back to them, but it felt a bit like smashing a nut with a sledge hammer – the tools may have been a bit overpowered for what I wanted to do, and I was not able to predict the problems that might arise – which clearly you want to avoid if there’s real money on the line.

Simulating the trade (or “backtesting”):

Having identified a starting set of parameters, the next stage is to simulate the trade. You can do this with various levels of cleanliness, and it’s good practice to start dirty and then clean up if the trade looks like it might work.

Given we’re trying to implement an algo, your simulation should look something like this:

Start loop through time (t):

—If some condition exists:

——Execute trade 1

—If another condition exists:

——Execute trade 2

…etc…

Move to next time step

Initially, I recommend that you don’t bother with fees, volumes, lag times for hitting the exchange, etc – just see if the decisions that you make to trade result in a profit or loss, and what the variability of that profit or loss is. If you make a profit, but first lost more than your capital, then the trade may be too risky to implement. You can also use risk-adjusted return measures, such as a Sharpe Ratio, to measure the success of your trade. Ideally you want a profit curve that slopes consistently upwards, with any downward swings being limited in size (obvious, I know!) My point is that certain trades may be very profitable, but just too risky – I abandoned a number of trades which are more profitable than the ones I landed up implementing because of this.

You also want to watch out for spurious profits – eg, if my algo was simply a decision to buy BTC under any circumstances, and I backtested my decision to buy BTC over 2017, my algo would have looked immensely successful. If I had then implemented it in live in 2018, I would have been crushed.

Once you have done your simple back test, and if the results are encouraging, you should increase the detail of the back test. In particular, you should implement the fees. Other things to look at include:

  • The amount of collateral or margin you’re using relative to your available limits – you should limit your maximum position such that the probability that your margin requirement increases above your available margin is below an acceptable probability;
  • The volume available at the prices that trigger your decisions to trade – if there’s almost no volume available at those prices, then no matter how high the return of your trade, the trade won’t be able to execute sufficiently to justify the time spent in coding it;
  • Lag times for hitting the exchange – if you are not going to be able to hit the exchange with zero lag upon the conditions for trading becoming true, what is the impact of the delay?

Tools for backtesting:

I like two (or maybe three) different tools for backtesting.

  1. I mentioned above that I use SQL Server to store my data. I also use it to create the data dump which I will simulate my trade on. SQL allows me to slice, dice and order the data, build simple comparisons or functions on the data, and to exclude anomalous data. It’s not ideal for detailed loops, though…
  2. Python: Python has lots of libraries which assist in financial data analysis (like Numpy). If you’re not au fait with any particular tool, and are going to have to learn one to get started, you could do a whole lot worse than Python for this. Python also allows you to save your data in pickles, so you don’t need a database at all, if that’s what works for you.
  3. Excel and VBA: I discussed using Excel and VBA for my backtesting with a family member who is an algorythmic trading programmer, and was nearly laughed out of the room. (Thanks Steve!) However, there are a few things which Excel has to recommend for itself. I feel that the familiarity of the environment helps you get started quickly, although you will very likely need VBA, so this may be moot if you’re not familiar with it. Not that you can’t do the same with Python, but I also liked creating functions which put out the result of my simulations, and then calling them from tables which laid out the profit with different combinations of input parameters to create a heat map with conditional formatting (which you can also do in Python, now that I think about it).

Python is much quicker at crunching this sort of data than Excel, for a given quality of code.

Fine tuning parameters:

I like to create visual representations of my outputs so I can home in on success and risk easily. Heat maps are good for this.

Here’s an example:

The heat map tells us where there are (relatively) successful combinations of input parameters (halfway down on the left) vs unsuccessful (on the right). When choosing parameters based on the heat map, you ideally want to choose a parameter which is not only optimal, but also surrounded by good outcomes. Should the true underlying conditions of the trade change slightly, this should maximise the chances that the outcome will still be relatively optimal. Consequently, in the above map, I would posit that an outcome in the center of the green would be better than a (hypothetical) outcome with an even better profit surrounded by red (i.e. poor) outcomes. The particular algo I was looking at in this example has 6 or so parameters, while clearly you can only (easily) represent two in the heat map. That’s okay – ideally your algo should have local profit maxima with respect to each parameter which are relatively independent of the other parameters. If not, you run the risk that interactions between your parameters may create risk which you don’t understand and cause your algo to lose money. Test this by creating multiple heat maps for parameters outside of the table and seeing if the profit transitions from one table to another in a relatively smooth fashion.

I touched on the dangers of overfitting above very briefly. I don’t think that optimising parameters constitutes overfitting, if you have already chosen your algorithm. However, remain vigilant, particularly if your algo is complex and requires many parameters. (If it is, go and read up on overfitting!)

A second output of my analysis is always a tick-by-tick graph of the profit, showing when trades occurred, what my open position is (to track margin requirements if I’m looking at derivatives), and my current balance (PnL). I usually only create this for trade/parameter sets which are successful / optimal, since I’m not interested in the others anyway. This allows me to identify the track my algo took to get to the optimal outcome. As I mentioned earlier, if I had to lose $1000 first in order to eventually make $100, then the algo is extremely risky relative to the outcome, and probably not worth implementing.

Implementation:

Right, so we’ve now identified a likely-looking trade and we’re ready to implement it.

I initially tried to write a generic framework which I could parameterise to implement any algo. Although this had some success, I became worried that it added more complexity than it was worth – leading to higher latency and greater possibility of error.

I settled on an intermediate approach. I write relatively generic ‘ExchangeMethods’ which hide the complexity of actual interactions with each exchange, but look similar to the rest of my code. Examples of my exchange methods include:

  • Market Order
  • Limit Order
  • Get top price and volume
  • Cancel order
  • Get open position from exchange
  • Get open orders on exchange
  • Get collateral balances on exchange

I then write the algo execution code (this will look similar to our pseudo code above) which:

Fetches the [order] data from the exchange

Checks to see if the conditions for opening or closing a position are now true

If so, implements the trades which will open/close the position

loops back to the top and repeats indefinitely

In theory, if I want to use a different exchange or instrument, I can then simply swap out the parameters for my ExchangeMethods and off we go. This is not quite true in practice, but I have managed to implement similar algos to pre-existing ones on new exchanges in under a day, so there is some merit in the approach.

I chose to use C# for my implementation, as I had some pre-existing familiarity with .Net, if not C# itself. However, I would suggest that Python or Java would have been better, because they seem to be more popular, with the result that more of the example code for connecting to different exchanges exists in those languages than C#. For obvious reasons, this can reduce your time-to-delivery for writing exchange methods. I have, however, found C# to be perfectly adequate. It has plenty of literature available, and does everything I need of it. I also like the slightly more structured environment (SDE).

As with data collection, I recommend multi-threading your exchange methods. This allows multiple trades to be placed in the order book at the same time, which may be important if:

  1. We are trying to trade only when the conditions which trigger our trade are true – they may have changed if we delay our trades; and
  2. Perhaps even more importantly, if our trade conditions relate to a (possibly calculated) differential between the prices of two or more different instruments. We wouldn’t want to trade one at the ‘correct’ price, but not the other.

I recommend putting a lot of logging into your code, and particularly into your Exchange Methods. This will help you with debugging, and also with determining why your trade is successful or not. Log each decision you’re about to make, and the outcome. Log (nearly) every interaction you make with the exchange (I maxed out by database size logging 100 price fetches per second – hence the ‘nearly’). Log the conditions that apply when you trade, and log the prices and volumes you think you’re making a trade at (the “trigger price”). Some exchanges allow you to place a user-defined data item into your orders. I recommend filling this with, for example, the trigger price, volume, your open position, your collateral balance and a short but meaningful metric which describes why you’ve made the trade. In due course, you should then be able to download your trades and use the custom data item to show how successful you have been in executing at the conditions you thought prevailed. An obvious example: If your trigger price on a buy market order is 1% higher than the price which you actually bought at, then your execution code is probably too slow.

Is exchange microstructure an issue?

Unequivocally…hell yes.

Different exchanges have different microstructures. These are seldom (never?) documented, let alone well documented. They can wreak havoc upon your best code and intentions. Unfortunately determining what the microstructure is seems to be an almost entirely empirical process. I consequently recommend that you start with only a small balance on any given exchange and trade that for a while. I have been caught out by microstructures, lost money because of them, and abandoned algos that looked promising because of problematic microstructures. They waste time and energy (coding for exceptions / unexpected exchange behaviour is difficult!). If you can, read up as much as you can about an exchange before trading on it. If there are lots of questions from confused algo traders… maybe it’s significant!

Another topic which relates to microstructure (sort of) is latency. It may not be clear where your exchange is hosted. If your algo requires low latency, you may want to do some research on this. Hosting your algo in the cloud in specific geographic locations may be helpful – you can test this empirically. I haven’t yet reached the stage where latency is an issue for me, but there is some literature / discussion online about this sort of issue.

Other things to look into:

Without going into too much detail, I suggest the following things are worth looking out for / understanding more of in the context of your trades:

  • Margining calculations – I’ve been caught out by this one
  • Balancing of equity (collateral) positions, particularly between different exchanges if you’re implementing a trade across more than one exchange – Caught out by this too
  • (Unrestricted) ability to withdraw equity – And this
  • So-called “Socialised Losses” and Insurance Funds (but not this…yet)
  • Rate limits – I’ve had to create lots of extra code to get around rate limits
  • FEES! Actually, big fees are as much of an opportunity as a hindrance, since they almost inevitably result in greater differentials
  • Leverage

Some metrics:

Time spent on this project: 5 months, nearly full time

Exchanges integrated into: 5 for trading, ~double for  data feeds

Algos that worked on paper (or in Excel!) but not on the exchange: Far too many.

Passing shot: Pavlov’s dog

I set a system chime to sound every time my algo traded, which it duly did. However, I initially used the generic Windows system exclamation sound. Which was fine for a while, until I found myself charging off to have a look at my screen every time my wife made an illegal key entry on her laptop. I recommend using a non-standard chime.

 

 

If you have any questions about any of the above, please feel free to contact me – contact details elsewhere on the site.

Exercise on stock pair selection using South African data

The premise for the long/short stock pair arbitrage trade

The long/short stock pair trade is a well-known arbitrage trade, which works as follows:

  1. Identify two highly-correlated and co-integrated stocks.
  2. Establish that each stock and the long-short combination of the two stocks is indeed stationary. Steps 1 and 2 are referred to as the Engle and Granger procedure.
  3. When the two stocks move away from each other, short the stock that has increased in value and go long on the stock that has decreased in value.
  4. Since the two stocks are highly correlated, they should move back towards each other at some point, closing the gap between them.
  5. When they do, close out the positions. At this point, the aggregate value of the long/short pair should be greater than zero, since in order for the gap to have closed, the shorted stock should have decreased in value relative to the value of the long stock (or visa versa).
  6. Since this is a statistical arbitrage strategy, repeat this exercise over as many pairs as is reasonable in order to reduce the possibility of a (hopefully!) low-probability event that the correlation observed to date is simply a statistical fluke which does not continue into the future.

If the premise upon which the trade is based is correct, and the correlated stocks are chosen appropriately, the portfolio should be profitable.

Building the model

I built a model to test this trade based on the more liquid stocks on the Johannesburg Stock Exchange (JSE). Doing so entailed the following steps:

Obtaining stock data:

I downloaded stock data from google finance using excel and vba macros as laid out by Edward Bodmer in his excellent financial model resource website, https://edbodmer.wikispaces.com. To do so, I looped through a list of JSE stockcodes and used the Workbooks.Open (URL) Excel method, where URL is replaced by the URL of the google finance page for the stock I wanted to download. I pushed all of these values into a SQL Server Express database so I could slice and dice the data later when I needed it. Unfortunately google finance doesn’t do adjusted prices (i.e. prices adjusted for share splits and dividends) so this might be a possible augmentation for a later date.

Testing for stationary time series

I filtered my stock data to ensure I only used liquid stocks. Then I generated a list of stock pairs for every combination of liquid stocks. I did this in SQL, before moving each pair into a Python scripting environment where I tested that the change in price of each stock (i.e. ClosePrice today – ClosePrice yesterday) was stationary.  To test that each of these two time series was stationary, I used the Augmented Dickey Fuller test, which is available in the statsmodels python module. I used a 95% probability threshold in my test, rejecting any stocks or pairs which were not stationary with probability of at least 95%. These tests were undertaken on roughly a year’s worth of data (October 2015 – October 2016).

Checking for correlation and co-integration

I randomly split the data for for those stocks which had passed the stationarity test (stationarity is actually a real word!) into an 80% training population and a 20% testing population and  used this to conduct a regression on the stock pair, with one stock being the input (x) value and the other the output (y) value. Again, I used python, using the LinearRegression model in sklearn. I validated the regression using the remaining 20% of the data, saving the accuracy score and the regression coefficients. For example, SBK = 1872.5c + 0.21 * FSR. (A Standard Bank share will cost you roughly R18.72 + 21% of the price of a FirstRand share).

I then generated the modelled prices for the output (y) stock using the data for the training year, subtracted that from the price of the input stock (x) (there’s the long and the short!), and tested the difference for stationarity. If it wasn’t stationary, then, assuming the premise for the pairs trade holds, we couldn’t expect the pair to revert towards each other after they move apart. If it was stationary, then a histogram of the values of the long-short pair (ie the difference) should be approximately normally distributed.

At this point, I had a list of stock pairs that passed the three stationarity tests, a set of regression coefficients describing their relationship, and a measure of how well the regression worked (the accuracy score). I also calculated the standard deviation of the long-short pair, for later use.

I ordered my list of pairs by the regression accuracy, moved my data on a year, and simulated a set of trades.

Simulating trades

To simulate the trades, I started at the beginning of my new year and examined the price of the long-short pair (SBK – [1872.5c + 0.21 * FSR] for my example pair above) for each day moving into the future. If the stocks were perfectly correlated, then they would never move apart and the long-short price would remain at zero. If however, in keeping with the trade’s premise, the shares started to deviate in price (hopefully temporarily!) then the long-short price would move up or down.

Correlation graph between SBK and FSR: The first half of the graph shows the period over which the correlation model was trained, and consequently fits really well. The second half is the ‘testing’ period, which shows how well the correlation continues into the future.

I chose the following four rules to generate trades for each stock pair (using our SBK-FSR pair as an example):

  1. Start with a notional cash balance of, say R100,000 (notional because we’re going both long and short… and because it’s fictitious at this point!)
  2. If the long-short price is above 1 standard deviation, and we’re not already long FSR, then SBK’s price has moved up a lot relative to FSR, so go long on FSR and short on SBK. Go long/short the same amount of R100,000, or whatever balance we have if this isn’t the very first trade.
  3. If the long-short price is below 0.3 standard deviations and we’re long, then close out the long/short positions. (I.e. move to cash; add the profit or loss to the new notional cash balance)
  4. If the long-short price is below -1 standard deviation,s and we’re not already short FSR, then SBK’s price has moved down a lot relative to FSR, so go short on FSR and long on SBK. Go long/short the same amount of R100,000, or whatever balance we have if this isn’t the very first trade.
  5. If the long-short price is above 0.3 standard deviations and we’re short, then close out the long/short positions. (I.e. move to cash; add the profit or loss to the new notional cash balance)

A graph of the daily value of the SBK-FSR long short pair (blue) and a single standard deviation of the values (red). The different trades are indicated by the orange lines: Long = 2 above, Short = 4 and Close = 3 and 5. Recall that trading only starts mid way through the graph.

Repeat this across the full year, and for all the stock pairs.

Finally, check the portfolio value relative to the money put in at the beginning.

Did it work?

I got mixed results. If all the pairs had behaved like the SBK-FSR pair then the trade would have done very nicely. However, they didn’t. Here’re the graphs for the Sibanye Gold, Harmony Gold pair:

At the start of the trading period (around day 250) this pair looked very feasible. The graphs correlate nicely over the training period and the big swing and reverse around day 180 looks enticing! So let’s trade…

For this pair, we would have shorted Sibanye and bought Harmony around day 260… and we would have continued to hold Sibanye until the end of the trading period, by which time we would be about 10% down, excluding trading and holding costs.

I see your model and I raise you reality

But why? The correlation looked great, and the trade looked so promising. Simply put, circumstances trumped the correlation:

Google search for Sibanye Gold, limited to the last year (and this is the one we shorted!). Harmony Gold’s looks pretty bad too, with illegal mining, strikes, deaths at the mine and managers being murdered.

Consequently, it looks like you need to be a little bit lucky, or apply a little more than statistical determinants to choosing your stock pairs. This is in agreement with the literature, which speaks to “selecting stocks which have a reason to be correlated”. I.e some judgement is required. It also makes sense in a South African context, since our economy feels fragile and prone to shocks right now.

Consequently, an exercise like the one above might be a good starting point for building a pairs trade, but requires both judgement and quite a bit of model tuning.

 

Afterthoughts:

Any comments or questions are very welcome.

I can think of quite a few model improvements, amongst them:

  • A rolling evaluation over the trading period, using data that is in the past, as at the date of trade (rather than a year stale by the end of the trading period)
  • Stop losses
  • Inclusion of fundamental economic inputs to identify possible reasons for changes in the correlation
  • Portfolio constraints, such as exposure limits
  • Incorporating price adjustments for stock splits and dividends
  • Use of more granular data

 

Using VBA functions and procedures

Functions

Sometimes it may be very tempting to use vba functions in your project model. However, if at all possible, it’s best to avoid doing so.

This is simply because:

  • Vba functions can slow down your spreadsheet considerably, which may become cumbersome when it gets large, and
  • Your model will probably need to go through a model audit prior to financial close, and model auditors don’t like functions – they’re more specialised than vanilla excel.

Procedures

On the other hand, I recommend building a toolbox of procedures and shipping it from project to project. Many of the procedures can be deleted prior to shipping the model off to the auditors, and are therefore not problematic as per bullet two above, but can save significant time during the model build. I make regular use of procedures to do the following:

  • Circular reference resolution
  • Copying the current cell across to the full row, linked to a keyboard shortcut
  • Sculpting debt
  • Sizing debt to fit funding requirements

Dealing with circular references

Circular references arise naturally in project models.

Examples of typical circular references include:

  • The DSRA is funded by a draw down at Commercial Operation Date (COD). The DSRA is sized as equal to the next 6 month’s debt service, which is in turn a function of the total debt amount, which is a function of, inter alia, the size of the DSRA…
  • The interest payable during construction is a function of the amount of debt outstanding, which is a function of, inter alia, the amount of interest already paid…

Sometimes circular references can be dealt with by referencing only past cells, which can solve the circular reference all together. If this is possible, it is the optimal solution to a circular reference.

If such a solution is not possible, it is almost always possible to resolve a circular reference by iterating through successive loops until the difference between successive iterations becomes negligible.

Please (please!) do NOT enable iterative calculations in the Excel Option / Formulas settings to do this. It works, but has the downside that an error can iterate through your circular reference and become impossible to resolve, effectively trashing your model.

A better, but more cumbersome, solution is to create a copy-past values macro. If you are not familiar with VBA, follow these steps to do so:

  • Copy the offending row
  • Paste-values the row immediately below
  • Create a named range for each row – e.g. DSRA_Copy and DSRA_Paste
  • Create a sum of each row on the left (adjacent to the description of the row)
  • Create a named range for each sum – e.g. DSRA_Copy_Sum and DSRA_Paste_Sum
  • Record a macro
    • Turn on macro recording
    • Copy the offending row
    • Paste-values the row immediately below
    • Turn off macro recording
  • Find the macro in the VBA editor (Alt + F11 opens the editor)
  • Modify the macro you just created as follows:

Dim i As Integer

For i = 1 To 100
   Range(“DSRA_Copy”).Select
   Selection.Copy
   Range(“DSRA_Paste”).Select
   Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone,SkipBlanks _:=False, Transpose:=False
   If Abs(Range(“DSRA_Copy_Sum”).Cells(1, 1)-Range(“DSRA_Copy_Paste”).Cells(1, 1)) <= 1 Then Exit For
Next

You already have the copy-paste syntax from the macro recording. The rest is as follows:

  • Dim i as integer tells VBA that i will be a variable of type integer – not a problem in VBA if you leave this line out
  • For i = 1 to 100 … Next is a loop which recurs 100 times. I prefer for-next loops to do-while loops because they can’t result in getting stuck in an infinite loop if the circular reference resolution doesn’t tend towards zero (or if I make a stupid error in the code!)
  • If Abs(…) is a condition which tells VBA to stop executing the loop if the sums of the rows are the same. I use an absolute value because I don’t know whether the past or copy row will be bigger, and I use 1 as an acceptable degree of difference. You can change that to be bigger or smaller depending on how much precision you require

 

  • I recommend creating another formula next to your circular reference resolution with a condition that the absolute value of the difference between the sums is less than an acceptable difference, with output “Circular reference resolved” or “Circular reference unresolved”, and applying some green and red conditional formatting to it.
  • Similarly, it’s good practice to aggregate all circular references checks into a master check at the top of the Working sheet, which should always be visible.
  • If you have more than one circular reference to resolve, it is fine to put more than one copy-paste into the for-next loop, and expand the conditions in the if statement using the AND boolean operator.

Debt corkscrews

An example of a simple Simple debt corkscrew.equal principal repayments can be downloaded here, and you can download a mortgage-style debt corkscrew here.

Debt is usually modelled by means of a debt corkscrew, so named because the principal outstanding at the beginning of the period is equal to the principal outstanding at the end of the previous period, and the principal outstanding at the end of the current period is a function of the principal outstanding at the beginning of the period, plus drawdowns, interest and repayments in the period. This creates a sawtooth (or corkscrew)-shaped dependency pattern.

An example of a Simple debt corkscrew.equal principal repayments can be downloaded here.

Pertinent points relating to the example:

  • Note the monthly period used throughout the model
  • As a consequence, indicators are required for repayment periods and capitalisation periods. I’ve used the modulus function here to identify which months an event occurs in. (Typically repayment and capitalisation periods are the same, although not always, as 3-month interest rates may be cheaper to hedge than 6-month interest rates, as their market is more liquid. I have used different periods to illustrate the point here.)
  • It is helpful to understand when in a period a figure relates to. For short periods (like a month) we use only the beginning and end of a period. Draw downs typically happen at the beginning of a period, while fees, interest and repayments typically accrue or occur at the end of a period.
  • The draw downs in this example are hard-coded. However, in a normal project model, they would feed off the capital requirements, which would in turn be a function of the capex, initial DSRA funding, postage and petties, upfront fees, etc.
  • I have split interest into three rows to account for capitalisation and payment periods being different to the model period. Interest accrued occurs only on principal outstanding at the beginning of the period and draw downs, not on previous interest accrued (at least until it is capitalised, at which point it enters into principal o/s).
  • You’ll note that I use OFFSET functions in calculating capitalised interest. I do this so that changing the input assumptions (B14) will flow through to the model. If the OFFSET is causing a #REF error, check the appropriate indicator using an IF statement. An example of this is in cell B23, where I calculated the equal principal repayment.
  • Day count conventions: I have used an actual / 365 day count convention, which simply means that I’ve calculated the number of days in the period and divided it by 365 [days in a year] when calculating how much interest accrues. Other conventions exist. Be sure you use the correct convention as per the financing documents.
  • You may hear a term such as nacq or nacs. These stand for ‘Notional annual, compounded quarterly’ and ‘Notional annual, compounded semi-annually’. These relate to the compounding convention for the interest rate. It simply means that the interest rate is stated as an annual figure, and that you should add the accrued interest back to the principal (i.e. compound it) quarterly or semi-annually, as applicable.
  • Repayment methods: There are three typical repayment methods in project finance, being equal principal repayments, mortgage-style, or sculpted.
    • The example uses equal principal repayments, the meaning of which is pretty obvious. As a consequence, total repayments (including interest) should be higher at the beginning and reduce over time. This is often a poor match for project cash flows, since the project’s revenues will often increase with time.
    • Mortgage-style repayments imply an equal repayment over both principal and interest in every period. This can be calculated using the PMT function. Note that it is good practice to use forward-looking parameters for mortgage-style repayments, rather than calculating a single repayment from the beginning. This allows sensitivities (e.g. a delay in repayment), as well as different interest rates at different durations. It’s actually good practice for equal principal repayments too, but I didn’t do it in the example! You can download a mortgage-style debt corkscrew here.
    • Sculpted repayments simply imply that the repayment schedule is manually sculpted according to criteria other than those laid out above. An often-encountered example is DSCR, in which, for example, the amount of principal repaid in each repayment period is an amount calculated to make the DSCR equal to a specified target value. Another reason to sculpt payments may be because of increasing revenues: A project may wish to have smaller early-duration repayments and larger payments towards the back end of the debt term.

Model periods

In the past, project models usually had a monthly period during construction, and a quarterly, semi-annual or annual period during operations. This made a lot of sense, because Excel allowed only a limited number of columns, and one didn’t want to run out of columns before the end of the project term!

However, this is not strictly necessary any more, since Excel now allows several thousand columns. Consequently, it is, in my opinion, far easier for the modeller to use the same period throughout the model. For a lenders’ model, I recommend that the period be one month per column. If you nonetheless want to use a multi-month period, you need to ensure that the number of months in the repayment period is divisible by the number of months in your model period.

Having a one-month period will mean that you may need to identify whether a non-monthly event occurs in a given period, such as a quarterly repayment. Modulus is a helpful function in this respect. E.g.

=if(mod(present month – starting month,3)=0,1,0)

could be used as a quarterly repayment indicator.

Period also has an effect on the way interest is calculated. If the interest compounding period is greater than that of the model, you will need to create additional rows to accrue uncompounded interest. More on this point in the Debt corkscrews article