case study代写

Final Project

Case Study: Asset Backed Security Modeling

The final project case study is the concluding piece of this course. The topic of this case study is Asset Backed Security modeling. This will give you the opportunity to satisfyingly apply all of what you’ve learned about Python into a useful project in finance. The project will build upon the Loan classes and functionality you’ve created throughout the course levels.

This project consists of three separate parts, each of which build off the previous. The three parts are described below (with their respective project weights), and will each be explained in detail later. Note that you may choose to opt out of any of the below project parts, at the cost of the grade for that part.

1. Implement the actual asset-backed securities (the liabilities) in addition to the Waterfall mechanism that calculates the cashflows at each time period. The objective is to create well-designed tranche classes which will seamlessly work with your existing Loan classes. The outcome is to be able to take an input CSV of loan data and output a CSV with the all the cashflows at each time period (the Waterfall). This is 50% of the final project grade.

2. Implement metrics on the Waterfall. This includes Internal Rate of Return (IRR), Reduction in Yield (DIRR), and Average Life (AL). The objective and outcome is to be able to calculate and provide useful metrics on the structure. This is 15% of the final project grade.

3. The last part is to value and rate the ABS. This entails creating a Monte Carlo simulation to simulate thousands of different credit default scenarios, all of which help determine the rating of the structure. The objective here is to get a taste of implementing an actual Monte Carlo simulation for finance in Python, utilizing your existing classes, random number generation and multiprocessing. The outcome will be a rate, rating, and Weighted Average Life (WAL) for each tranche of our very simple structure. This is 35% of the final project grade.

The subject of Structured Finance is quite complex. The purpose of this project is not to teach you everything to do with Structured Finance (which is the topic of at least two masters-level MFE courses), but to apply Python concepts and techniques in a useful way, while giving you a taste of the concepts of Structure Finance. Consequently, this project will present an overly simplistic ABS model and will gloss over many of the more involved techniques (such as credit default and prepayment modeling); we will point out situations where the ‘real-world’ approach is more complex or may differ somewhat from this project’s specification. Hopefully, you will come away from this project with a good sense of the power of Python and how it is used in banks, hedge funds, and other financial institutions.

Each part of this project will provide a rough set of steps to follow. Following these steps exactly is not a requirement, if you can come up with a better design, as long as your overall functionality is the same. Moreover, the provided steps are not comprehensive – you will need to make decisions as to which Python techniques to use. You should apply everything you have learned as and when appropriate (i.e., exception handling, logging, list comprehensions, dicts, using your Timer class or decorator to help optimize your code, etc.).

© 2016 All rights reserved

1

Background

Every structured deal consists of a pool of assets (the Loans) and a group of liabilities (the asset-backed securities). The objective of structuring is to create and sell customized securities to investors, which are backed by the pool of loans. The following example demonstrates both the motivation for this and the approach taken to achieve it:

Bank A has made a large number of loans. When Bank A makes these loans, it becomes exposed to two types of risk:

  1. Default risk: The risk that the borrowers will fail to pay back the loan. This can occur if borrowers lose their jobs or some other life event that causes them to be unable to repay the loan. In the extreme case, this can be a result of an economic downturn that causes a large number of borrowers to be unable to repay.
  2. Prepayment risk: The risk that the borrowers will pay back the loan early. This can result in a loss of expected interest income, especially if interest rates have decreased. Note that the most common reason for borrowers to prepay is if they refinance their loan due to lower interest rates. Another, less common reason to prepay, is if borrowers wish to get rid of the debt (i.e., they have a windfall and can afford the large cash payment).

Bank A does not wish to be exposed to these risks for the life of the loans; it just wants to make quick money when making the loan, with little to no risk. To mitigate this risk, it can sell the loans, as structured securities, to investors. Bank A then makes a quick profit on the spread.

Investors are willing to take on the risks of the loans as they hope to receive a decent return on their investment.

The process of creating the securities that are sold to the investors is called ‘structuring’. The following are the (simplified) set of steps for structuring the securities:

1. Aggregate a pool of outstanding loans. Generally, a pool only contains a single class of loans (i.e., all car loans, all mortgages, or all student loans), but can theoretically contain a mixture.

2. Decide on the types and number of securities that will be offered to investors. Each security is called a tranche. A deal may consist of any number and combination of tranches. The entire structure of tranches is called the deal. There are many types of tranches. Here are the basic ones:

o Standard tranches receive both interest and principal payments from the pool of loans.
o Interest Only (IO) tranches (aka IO strips) only receive interest payments from the pool of loans.

These tranches have much more prepayment risk than standard tranches (since a prepayment

means no more interest).
o Principal Only (PO) tranches (aka PO strips) only receive principal payments from the pool of

loans. These tranches are much more sensitive to default risk, as they never receive any interest payments to make up for it.

© 2016 All rights reserved

2

© 2016

All rights reserved

3.

4.

5.

6.

Our model will discuss and contain standard tranches only, for simplicity.

Tranches can also be classified by risk: For example, a deal may contain two (or more) standard tranches, Class A and Class B. The Class B tranche would be a subordinate of the Class A in that it receives its principal payments after Class A; this exposes Class B to higher default risk, since it always receives its principal payments after Class A (and only if there is enough cash left). Of course, this means that Class B investors would expect a better rate of return to compensate for the additional risk.

Allocate principal amounts to each tranche in the structure. The loan pool has a total (aggregated) principal. Each standard tranche in the structure will be allocated a portion of the total principal. For example, if the total loan principal is $10,000,000, Class A may be allocated 80% ($8,000,000) and Class B may be allocated 20% ($8,000,000).

Create a Waterfall cashflow model of the proposed structure. This tracks the cashflows out of the loan pool at each time period (i.e., monthly) and distributes them appropriately to each tranche in the structure. In general, interest payments to each tranche take priority, and principal payments are made with the remaining funds. More details on this later.

Decide on appropriate default and prepayment models that (as accurately as possible) reflect reality. Incorporate these models into the Waterfall. This will affect the cashflows, as a default will lower the monthly payments coming in from the loan pool (resulting in less cash to distribute to the tranches).

The default models will usually follow a distribution (i.e., a lognormal distribution) and have a random component to them.

Every ABS has a Rating (which are usually performed by a credit rating agency, such as Moody’s or S&P). This Rating, the interest rate, and something called Weighted Average Life (WAL) are metrics used by investors to determine whether or not to invest in the securities.

The goal of these metrics is to provide a fair value to both sides of the deal: The seller (Bank A) wants the lowest possible cost and the investors which want the highest return possible. The fair value is one that takes all the risk components into account and neither shortchanges the seller nor rips off the investor.

To generate these metrics, one can run a two-tiered Monte Carlo simulation to simulate the random component of the default risk models. Running thousands of scenarios will (hopefully) arrive at the fair value of the three metrics.

Once the deal is structured, investors can buy the newly structured securities. As mentioned above, each tranche (security) has a notional. An investor can buy an entire tranche or a piece of a tranche. For example, if the Class A standard tranche has a notional of $8,000,000, a single investor can buy the entire tranche for $8,000,000 or a piece of it (i.e., $500,000). Once Bank A sells all the securities, it has fully recouped its money (that it originally lent to the borrowers of the loan pool) and no longer has any risk exposure on these loans.

7.

3

8. At every time period (i.e., monthly), the cashflows from the loan pool are distributed to each tranche, depending on the agreed-upon structure. The hope of each investor is to fully recoup its principal and yield an additional return by the end of the life of the security. Investors who like higher risk for a potential higher return are more likely to invest in a lower-class (riskier) tranche, while those who want a low-risk small return are more likely to invest in a Class A tranche.

© 2016 All rights reserved

4

Part 1: The Waterfall

As touched on in the Background section, the Waterfall tracks all the cashflows through each time period. Essentially, the pool of loans (the assets) will provide a monthly cashflow (resulting from the individual loan monthly payments) and that cashflow is allocated to each of the tranches in the structure (the liabilities).

We’ve already implemented the asset side of the Waterfall. To create the Waterfall, we first need to implement the liabilities (the tranches). The following are the rough guidelines for this implementation (you should implement using all the knowledge and best practices gained throughout the course):

1. Create an abstract base class called Tranche. It should be initialized with notional and rate. Additionally, it should have a subordination flag. This flag can either be letters of the alphabet or numbers.

2. Derive a class called StandardTranche. This will be the only derived-class for this project. However, in practice, you can derive other tranche types (i.e., for IO or PO).

o Standard tranches start off with a certain notional and need to be able to keep track of all payments made to it. More specifically, they need to be able to keep track of all interest payments and all principal payments made to it, and at what time period. To this end, implement the following methods:

  • ▪  increaseTimePeriod: This should increase the current time period of the object by 1 (starts from 0).
  • ▪  makePrincipalPayment: This should record a principal payment for the current object time period. This should only be allowed to be called once for a given time period (raise an error otherwise). Additionally, if the current notional balance is 0, the function should not accept the payment (raise an error).
  • ▪  makeInterestPayment: This should record an interest payment for the current object time period. This should only be allowed to be called once for a given time period (raise an error otherwise). Additionally, if the current interest due is 0, the function should not accept the payment (raise an error).

    One special case that needs handling is what happens if the interest amount is less than the current interest due: In this case, the missing amount needs to be recorded separately as an interest shortfall.

  • ▪  notionalBalance: This should return the amount of notional still owed to the tranche for the current time period (after any payments made). Hint: You can calculate this based on the original notional, the sum of all the principal payments already made, and any interest shortfalls.
  • ▪  interestDue: This should return the amount of interest due for the current time period. Hint: This can be calculated using the notional balance of the previous time period and the rate.
  • ▪  reset: This should reset the tranche to its original state (time 0).

© 2016 All rights reserved

5

3. Create a class called StructuredSecurities. This will be a composition of Tranche objects (similar to how LoanPool is a composition of Loans). It should be initialized with a total Notional amount.

o Create a ‘factory method’ to add tranches to a StructuredSecurity object. This can be called addTranche, and it will instantiate and add the tranche to the StructuredSecurity object’s internal list of tranches. The method needs to know the tranche class (always StandardTranche in this project), the percent of notional, the rate, and the subordination level.

o Add a method that flags ‘Sequential’ or ‘Pro Rata’ modes on the object – more on this in a moment.

o Add a method that increases the current time period for each tranche.
o Create a method called makePayments. This should have a cash_amount parameter. Cycle

through all the tranches, in order of subordination. It should do so within the following guidelines:

  • ▪  It should cycle through all interest payments first, paying each tranche from the available cash_amount. Hint: Ask each tranche how much interest is owed, make the payment, subtract the paid amount from the availableFunds, and move on to the next tranche. If there is not enough cash to pay the interest in either tranche (a ‘shortfall’), it gets added onto the interest owed in the next period (we will naively assume there is no compounding interest on the shortfall).
  • ▪  Assuming there is cash left over after all the interest payments, begin cycling through the tranches to make principal payments. Principal due to the tranches are based on the total principal received from the Loans in a given period (not the total available cash). There are two separate approaches for this, depending on the value of the mode flag on the StructuredSecurity object (see provided Excel workbook for interactive example):
    • Sequential: Cycle through each tranche (in order of subordination), making the maximum principal payment. Hint: Ask each tranche for its balance and pay min(principal received + prior principal shortfalls, available cash, balance). If there is principal leftover after paying a tranche (which implies the tranche is fully paid off), use it to start paying off the next tranche. If there is a shortfall for a tranche, it is used in the next period’s principal due calculation for that tranche.
    • Pro Rata: Each tranche has a percent of the total notional. Use those percentages to allocate the principal received to each one. For example, if principal received is $1,000,000 and available cash is $900,000, Tranche A is 80%, and Tranche B is 20%, Tranche A is due $800,000 and Tranche B is due $100,000 (and has a $100,000 shortfall). Of course, be sure to never overpay a tranche’s balance (keep the extra cash). In other words: min(principal received*tranche% + prior principal shortfalls, available cash, balance) where Tranche A gets paid first. If there is a shortfall for a tranche, it is used in the next period’s principal due calculation for that trance.
  • ▪  Once all interest and principal payments have been made, it’s possible that there is leftover cash. This extra cash goes into a reserve account. This is stored in the StructuredSecurity object, and should be used to supplement the cash_amount at the next, and each following payment. Note that in practice, the reserve account will earn interest, but we will assume 0% interest for simplicity.s

© 2016 All rights reserved

6

o Create a function called getWaterfall that returns a list of lists. Each inner list represents a tranche, and contains the following values for a given time period: Interest Due, Interest Paid, Interest Shortfall, Principal Paid, Balance.

4. Create a standalone function called doWaterfall. This function should take two parameters: A LoanPool object and a StructuredSecurities object. The function should loop through time periods, starting from 0, and keep going until the LoanPool has no more active loans (no more payments coming from the LoanPool). At each time period iteration:

o Increase the time period on the StructuredSecurities object (which will, in turn, increase for all the tranches).

o Ask the LoanPool for its total payment for the current time period.
o Pay the StructuredSecurities with the amount provided by the LoanPool.
o Call getWaterfall on both the LoanPool and StructuredSecurities objects and save the info into

two variables.

After the loop completes (when all loans in the loan pool have zero balance), return all the results saved down from the getWaterfall function (from both variables) as well as any amount left in the reserve account.

Test out your code in detail. The best approach is to test out each class and function individually, to ensure they word as expected (with a single or small number of loans). You can do this in main or using the Python Console. Once you are confident your classes are correct, try the following, in your main:

  1. Create a LoanPool object that consists of 1,500 loans. Use the provided CSV file of loan data to create these Loan objects.
  2. Instantiate your StructuredSecurities object, specify the total notional (from the LoanPool), add two standard tranches (class A and class B in terms of subordination), and specify sequential or pro-rata mode.
    The rates for each tranche can be arbitrary (for now). Note that subordinated tranches should always have a higher rate, as they have increased risk.
  3. Call doWaterfall and save the results into two CSV files (one for the asset side and one for the liabilities side). All the tranches’ data for a given time period should be a single row in the CSV. The reserve account balance should also be in liabilities CSV, for each time period. Each time period gets its own row. Note that you may need to do some clever list comprehensions and string parsing to get this to output correctly.

The goal at this point is to see what happens when running the code for different combinations of tranche input rates: Did each tranche’s balance get successfully paid down to 0? If they did, was there any money left in the reserve account at the end?

Congratulations, you’ve implemented your very first ABS Waterfall! This is the first, and most important, step to valuating ABSs.

© 2016 All rights reserved

7

Part 2: Waterfall Metrics

Now that we’ve created the Waterfall, the next step is to be able analyze it. There are a number of metrics that we (or an investor) can use to perform this analysis:

2.

3.

For this

4.

5. 6.

1.

Internal Rate of Return (IRR): This is the interest rate that results in the present value of all (monthly) cash flows being equal to the initial investment amount. The equation for this is as follows (where C is the payment at time t, T is the total number of periods, and r is the monthly rate):

There is no closed formula to calculate this, since it involves solving the above polynomial equation. There are numerical techniques to calculating IRR, but we will avoid that here by using the numpy.IRR function.
Average Life (AL): When playing around with your Waterfall code, you may have noticed that some tranches get paid down (0 balance) quicker than others, while some never get fully paid down at all. The AL of the security is the average time that each dollar of its unpaid principal remains unpaid. This is a vital metric for investors, to get a sense of how long it will take them to recoup their principal (will they get most of it back early on in the waterfall, or will it take closer to the end)?

In the case when a tranche is never fully paid down, the AL is infinite (no investor would want this security!).
Reduction in Yield (DIRR): This is the tranche rate less the annual IRR. Essentially, the annual tranche rate is the annualized rate of return that the investor expects to earn whereas the IRR is the realized return. DIRR specifies how much the investor lost out on (hence, its maximum is 100% + the tranche rate). Additionally, DIRR is used to give a letter rating to the security.

part, you should implement three new methods in the Tranche base class: IRR, AL, and DIRR:

IRR: This should simply delegate to the numpy.IRR function. You will need to pass in a list with the initial investment’s notional as a negative number, and the total payments for each time period (in order). For example, for a four time period structure with notional 100: [-100, 25, 15, 50, 10]. Multiply the result by 12 to annualize.

DIRR: Simply subtract the IRR from tranche’s rate.
AL: This is the inner product of the time period numbers (0, 1, 2, 3, etc.) and the principal payments, divided by the initial principal. For example, if you have the principal payment list as follows: [10000, 90000, 35000, 0], the AL would be (0*0 + 1*10000 + 2*90000+2*35000+3*35000+4*0)/100000. If the loan was not paid down (balance != 0), then AL is infinite – in this case, return None. Hint: Use the built- in Python reduce function.

Now that you’ve implemented these metrics, modify the doWaterfall function to return the metrics after the Waterfall completes. Use the table from Appendix A to translate a DIRR value to a letter rating. Your main function should now output all these metrics and letter rating to the screen (in addition to creating the CSV files from earlier).

© 2016 All rights reserved

8

Part 3: Valuing the Structure

We’ve implemented the Waterfall and metrics which will help the investors understand the deal. However, those metrics were based on a fatal assumption: The default/prepayment risk being non-existent! To properly value a structured security, one must properly model expected loss due to defaults and prepayments. For this part, for simplicity, we will include defaults but not prepayments (though prepayments are a fact of life).

A loan default curve represents the expected number of loan defaults for a given time period. Here is an example of a loss curve:

Note that most defaults happen somewhere between the early and late time periods (it’s rare to default right away or at the very end).

Until now, we’ve been arbitrarily choosing the tranche interest rates. However, the entire goal of structuring these securities is to come up with fair rates. Fair rates are rates that adequately compensate the investors for the risk level of the tranche (which is determined from the DIRR->Rating which is, in turn, determined by the default curve), but are not higher than they should be either. Implementing code to find these rates (and their associated DIRR->Rating) is the objective of this Part. The goal is to find the set of input rates to the tranches that result in a yield of the same rate, on average. If you arbitrarily choose rates, it is almost certain that the Waterfall will result in yields that are either better or worse than the chosen rates (due to the default curve) – which implies that the deal was incorrectly valuated.

If we would know the exact default curve with 100% certainty, then it would be really simple to value the structure: Just incorporate the exact number of loan defaults into the Waterfall and find the tranche rate that results in an actual yield of the same amount. However, we do not ever know with any certainty what the default curve would look like in real life. Therefore, we need to run a Monte Carlo simulation with thousands of scenarios to simulate different default curves.

In actuality, we need to run two Monte Carlo simulations: The ‘inner’ simulation which tries thousands of default scenarios and gives the average DIRR and WAL across all the scenarios. Then, based on this result, the ‘outer’ simulation calculates the yield, from a specified yield curve (using the DIRR and WAL from the ‘inner’ simulation), tweaks the tranche rates to reflect the new yield, and reruns the inner simulation. The outer simulation keeps doing this until two consecutive runs result in very similar yields (i.e., within a 50 basis point (.005) tolerance).

This all may sound really confusing, but the below steps should help clarify exactly what needs to be done in code:

First, we need to implement loan defaults into the Waterfall. The topic of constructing and using loan default/loss curves is for an entire Masters level course. Therefore, for the purpose of this project, we will be taking an extremely simplistic view of the default curve (which is certainly incorrect and naive in the real world).

© 2016 All rights reserved

9

1. Use the following table to determine the probability of default of a loan for a given time period: Time Period Range Default Probability

1-10

0.0005

11-59

0.001

60-120

0.002

120-180

0.004

180-210

0.002

210-360

0.001

  1. Create a method in the Loan (called checkDefault) class that determines whether or not the loan defaults. The parameter to this method should be a number (see step 3 and 4).
  2. Create a method in LoanPool (called checkDefaults) that generates a list of uniform random integers, one for each Loan. The integer range should be so that the odds of a given number occurring is the same odds as the default probability for the time period (always start the range from zero). This method should then call checkDefault on each Loan, passing in the random number.
  3. checkDefault on each Loan flags the loan as defaulted if the passed-in number is 0 (and should return the recovery value of the Asset). If the loan is defaulted, a flag should be set on the object and the balance becomes 0.
  4. checkDefaults on the LoanPool should be called at each doWaterfall iteration (time period). It should aggregate the recovery values returned by the individual loans, and return that to doWaterfall (to be used as part of the time period’s cashflow). See provided Excel workbook for a basic example of recovery handling.

Run your Waterfall (still choosing arbitrary tranche rates) and notice that each run now results in a different DIRR and WAL for a given set of rates; this is because you’ve incorporated a random component to the loan default model. This random component will enable you to build the Monte Carlo engine to value the structure.

To create the Monte Carlo, you should follow the following rough steps:

• Create a global function called simulateWaterfall. Its input parameters should be a LoanPool, a StructuredSecurities object, and NSIM. NSIM specifies the number of simulations to run, and will be used to tell your loop how many times to iterate.

o All this function needs to do is call doWaterfall NSIM number of times, and collect the resulting DIRR and AL from each iteration. Once NSIM iterations are complete, take the average of all the DIRR and AL values. Note that if AL is ever infinite (due to the tranche not being paid down), you will need to exclude those AL values from the average.

o The function should return the average DIRR and WAL values for each tranche.
Test this function, first with a low number of simulations to ensure it works, then with 2,000 simulations.

• Create a global function call runMonte. Its input parameters should be a LoanPool, a StructuredSecurities object, tolerance, and NSIM. The tranches in the StructuredSecurities object should be initialized with rates of 5% and 8% for class A and class B respectively. The runMonte function should do the following:

o Kick off an infinite loop. The below steps belong inside this infinite loop. © 2016 All rights reserved

10

o Invoke the simulateWaterfall with the LoanPool and StructuredSecurities objects, as well as the NSIM. Save down the resulting average DIRR/WAL for each tranche.

o Now that you have the average DIRR and WAL for each tranche, the next step is to calculate the yield. Yield is determined from a yield curve. Constructing a proper yield curve is itself a major topic, which is beyond the scope of a Python course. Therefore, all you need to do is implement the below equation (which is one possible yield curve) into a calculateYield function. Call this function with the average DIRR/WAL for both tranches and save down the yields:

( 7 𝑎 +.019√(𝑎)(𝑑∗100))

12 𝒘𝒉𝒆𝒓𝒆 𝑎 𝑖𝑠 𝑡h𝑒 𝑊𝐴𝐿 𝑎𝑛𝑑 𝑑 𝑖𝑠 𝑡h𝑒 𝐷𝐼𝑅𝑅.

𝑦𝑖𝑒𝑙𝑑 =

1 + .08 ∗ 𝑒−.19(12)

100

o Calculate the new tranche rates using the previous tranche rates and the above yield for each tranche. We will use something call relaxation, which is a technique to speed up convergence. To achieve this, use the following formula for each tranche:

𝑛𝑒𝑤𝑇𝑟𝑎𝑛𝑐h𝑒𝑅𝑎𝑡𝑒 = 𝑜𝑙𝑑𝑇𝑟𝑎𝑛𝑐h𝑒𝑅𝑎𝑡𝑒 + 𝑐𝑜𝑒𝑓𝑓 ∗ (𝑦𝑖𝑒𝑙𝑑 − 𝑜𝑙𝑑𝑇𝑟𝑎𝑛𝑐h𝑒𝑅𝑎𝑡𝑒) 𝒘𝒉𝒆𝒓𝒆 𝑐𝑜𝑒𝑓𝑓 𝑖𝑠 1.2 𝑓𝑜𝑟 𝑇𝑟𝑎𝑛𝑐h𝑒 𝐴 𝑎𝑛𝑑 0.8 𝑓𝑜𝑟 𝑇𝑟𝑎𝑛𝑐h𝑒 𝐵

Don’t worry if you don’t understand why we are doing this – it’s the topic of an advanced numerical methods course. The focus here is solely on implementing this sort of equation into Python.

o Check if the new tranche rate differs from the previous tranche rate, for each tranche, by more than tolerance. Use the following formula to calculate this:

𝑑𝑖𝑓𝑓 =

(𝑛𝐴 ∗ |𝑙𝑎𝑠𝑡𝐴𝑅𝑎𝑡𝑒 − 𝑛𝑒𝑤𝐴𝑅𝑎𝑡𝑒| + 𝑛𝐵 ∗ |𝑙𝑎𝑠𝑡𝐵𝑅𝑎𝑡𝑒 − 𝑛𝑒𝑤𝐵𝑅𝑎𝑡𝑒|) 𝑙𝑎𝑠𝑡𝐴𝑅𝑎𝑡𝑒 𝑁 𝑙𝑎𝑠𝑡𝐵𝑅𝑎𝑡𝑒

𝒘𝒉𝒆𝒓𝒆:
𝑛𝐴 𝑖𝑠 𝑇𝑟𝑎𝑛𝑐h𝑒 𝐴 𝑛𝑜𝑡𝑖𝑜𝑛𝑎𝑙, 𝑛𝐵 𝑖𝑠 𝑇𝑟𝑎𝑛𝑐h𝑒 𝐵 𝑛𝑜𝑡𝑖𝑜𝑛𝑎𝑙,

𝑁 𝑖𝑠 𝑡h𝑒 𝑡𝑜𝑡𝑎𝑙 𝑛𝑜𝑡𝑖𝑜𝑛𝑎𝑙.

If diff is lower than tolerance, then break from the infinite loop – your Monte Carlo is finished! In this case, return the final average DIRR/WAL and yields for each tranche. If diff is greater than tolerance, then modify the tranche rates to reflect the yields and loop again. Your main code should create the LoanPool and StructuredSecurities object and invoke runMonte with those as arguments, in addition to a tolerance of 0.005 and NSIM of 2000. Once you receive the results, translate the DIRR to a letter rating and output the DIRR, Rating, WAL, and rate of each tranche.

Congratulations, you’ve implemented your first financial Monte Carlo simulation in Python! © 2016 All rights reserved

11

Note that this simulation can take a really long time to complete. Multiprocessing can be your savior here. It will be in your interest to modify the above steps to work with multiprocessing, as the simulation will take much, much quicker. The rough steps to do so are below:

  1. We cannot parallelize the outer loop (the runMonte function). This is because each loop is dependent on the previous. However, we can parallelize the runSimulation function, since each loop is independent from all the others. To do this, create a function called runSimulationParallel. Its input parameters should be a LoanPool, a StructuredSecurities object, NSIM and numProcesses. Modify the runMonte function to call runSimulationParallel instead of runSimulation. You should specify 20 for numProcesses, but you can experiment with more or less later.
  2. runSimulationParallel should start the processes. It should use two Queues, as demonstrated in the Concurrency section of this course. The process’ targets should be doWork (which monitors the input queue).

o Add numProcesses number of tuples to the input Queue. The NSIM argument for runSimulation should be NSIM divided by numProcesses. This makes sure that we evenly split the total simulations between processes.

o Thesub-processesmonitortheinputQueue.
o The main process monitors the output Queue. There is no need to write ‘Done’ or check for

‘Done’ in this case; the output Queue monitoring loop can simply exit as soon as the length of

the results list is the same as NSIM.
o Once the output Queue monitoring loop completes, aggregate and average the resulting

tranche metrics from each process and return these to runMonte.
o Before returning to runMonte, be sure to terminate the sub-processes by calling stop() on each

sub-process handle.

Your entire simulation should now run significantly quicker than before (maybe even 20x quicker!). Feel free to play around with different numbers of processes to get a sense of the optimal number.

© 2016 All rights reserved

12

Appendix A ABS Rating Table

The DIRR is quoted in basis points (BPS). One basis point is 1/100 of a percent. 10,000 basis points is 100% (which is rated Ca in the below table). You may need to convert your DIRR to basis points to match.

Note that the above table is one possible example of a ratings table; in practice, these numbers may differ.

© 2016 All rights reserved

13

Bibliography

Allman, Keith A. Modeling Structured Finance Cash Flows with Microsoft Excel: a Step-by-Step. John Wiley & Sons, 2007.

Rutledge, Ann, and Sylvain Raynes. Elements of Structured Finance. Oxford Univ. Press, 2010.

© 2016 All rights reserved

14