Post on 23-Sep-2020
Modeling the Mortgage Bubble and the 2008 Financial Crisis
Julian Aronowitz Beginning in 2007, the global economy faced the largest financial crisis since
the Great Depression. The so-‐called ‘Great Recession’ that followed started in the
United States mortgage market and spread through the financial sector onto the
larger macro economy. The devastating consequences of this meltdown are still
being felt today. As of summer 2012, the United States seasonally adjusted
unemployment rate remains around 8.2%, which characterizes this downturn as
having one of the slowest ‘jobless recoveries’ since World War II (U.S. Bureau of
Labor Statistics). In most developed economies, GDP declined 6% from peak to
trough (Davies 2010).
The long-‐term qualitative effects of the crisis are equally if not more
significant than the quantitative data that characterizes the short-‐term visible
effects. The Arab Spring uprisings occurred largely due to high food prices and
unemployment that trace their origins back to the financial crisis (Spencer 2011).
The current European Sovereign Debt Crisis was exacerbated by government
bailouts of European banks that had placed bad bets in the US housing market
(Louis 2011). Furthermore, the incentive structure that came about as a result of
the governmental response to the crisis has the potential to adversely affect the U.S.
economy for decades to come. The Fed/Treasury bailouts of virtually all major
financial institutions in 2008 and 2009 acted as a powerful market signal that our
banks are indeed ‘too big to fail’. The moral hazard created by this signal
emphasizes the exact same incentives that contributed so heavily to causing the
crisis in the first place.
The fact that the financial crisis has had an incalculable effect on the global
economy and on the nature of our global society is indisputable. What is still of
some debate are the significant causes of the crisis and what policies should be
enacted to prevent a financial meltdown in the future. Blame for the crisis has been
laid upon too much government intervention, such as mandates for government-‐
supported entities (GSEs) to expand the subprime mortgage market1, as well as too
little government intervention, in the form of lax regulations on over-‐the-‐counter
derivative trading2 and predatory lending3.
To say these two perspectives, as some have suggested, are simply
contradictory is of course misleading. There’s no reason to believe that too little
government in one area and too much government in another cannot
simultaneously have negative, unforeseen consequences. Even so, the general
attitude toward these things tends to simplify the debate down to ideological
stances. Therefore, the goal of this paper is to present a balanced dissection of many
of the most popular arguments for the cause of the 2007-‐2012 financial crisis.
Section 1 of this paper contains general explanations for each of the most
prevalent arguments for the financial collapse. Section 2 discusses the
implementation of the financial model that was constructed in order to mimic the
growth and collapse of the mortgage and financial markets. Finally, section 3
1 Davies 2010, Chapter 6: ‘The Subprime Collapse: A Failure of Government?’ 2 Davies, Chapter 13: ‘Financial Weapons of Mass Destruction: Derivatives’ 3 Johnson and Kwak 2010, pg 141-‐2
assesses the conclusions that can be drawn from the model and the lessons that can
be learned from this crisis.
Section 1: The Path Toward the Meltdown
A: Macroeconomic Factors
The problems that led to the financial crisis were arguably embedded within
the very structure of our global economy. These first arguments focus on various
macroeconomic factors that contributed to the financial collapse. The general
emphasis is on cheap lending and lowered interest rates within the financial and
housing sector.
Starting in the 1990s, the developing Chinese economy started to grow at an
astronomical rate. With this growth came a large current account surplus that was
driven partially by increased governmental savings but largely by enterprise and
household savings. By 2007, gross domestic savings in China had risen to over 50%
of GDP while annual GDP growth had climbed to 14% (data.worldbank.org). From
2000 to 2006, global fixed income securities doubled from $36 trillion to $70 trillion
(Davidson and Blumberg 2008). This ‘savings glut’ was largely invested into safe
U.S. treasuries which in turn drove down the interest rates on long-‐term US
government securities. Due to the falling returns on treasury bonds, investors
started to look elsewhere for AAA rated investments to place their money.
The increase of demand for new safe investment opportunities had two main
effects on U.S. banks. First, they could cheaply finance their own balance sheets
through the commercial paper market (this led to a dramatic increase in leverage
and thus instability within the banks themselves). Second, they met the new
demand by manufacturing securitized debt instruments such as mortgage-‐backed
securities (MBS) (Davidson and Blumberg 2008). Hence the savings glut did not
directly create the crisis. Instead it pushed excess capital toward unsafe
investments in the financial sector. In 2009 at the Conference at the Council on
Foreign Relations, Ben Bernanke stated “it is impossible to understand the crisis
without reference to the global imbalances in trade and capital flows that began in
the latter half of the 1990s.”
A complementary view of the financial crisis centers on the Federal Reserve’s
handling of the federal funds rate. From 2001 to 2005 the Federal Reserve pushed
interest rates to historical lows. This caused effects that acted in conjunction with
those caused by the savings glut. Cheap money made it easier for people to buy
larger homes financed with larger mortgages, driving up housing prices. If the Fed
had raised the rate earlier in the decade, it’s possible that they could have deflated
the housing bubble before it popped.
Alan Greenspan has argued against this line of reasoning. He maintained that
it was long-‐term interest rates that drove housing prices in the lead up to the crisis.
During that time, the federal funds rate seemed to have temporarily stopped guiding
long-‐term interest rates. Therefore the Fed’s actions did not exacerbate the bubble.
Furthermore, actively trying to defuse the bubble by raising interest rates could
have been extremely damaging to the mortgage market in its own right (Greenspan
2010).
Of course Greenspan’s defense should be taken with a grain of salt. No one
has a larger incentive to transfer blame away from the 2001-‐2006 Federal Reserve
than Alan Greenspan. In addition, it seems unlikely that a Fed led deflation of the
subprime market could have had as devastating an effect as letting the bubble pop
and cleaning up afterwards.
B: Subprime Mortgage Market
Without a doubt, the most crucial aspect of the financial crisis was the bubble
in the subprime mortgage market. Throughout the late 90s and early 2000s, newly
created financial instruments allowed banks and investors to become increasingly
interconnected with the mortgage market in completely novel ways. For example,
the mortgage-‐backed security is a product that combines a bulk of mortgages
together into a single product that has portions sold to investors. Each slice is of a
specific type or tranche. For each payment period, senior tranches get paid off first
while junior tranches get paid later. In this way if any defaults happen in the MBS
(or collateralized debt obligation), then all the junior tranche holders experience
losses before any of the senior tranche holders.
Mortgage-‐backed securities had a profound effect on the financial sector and
the housing sector. First off, more money funneled into the housing market since
investors of all types could now finance mortgages. Second, mortgages could be
traded in larger bulk. Before securitization mortgages had to be sold individually,
and since each mortgage is unique, the mortgage trading was generally small in
volume and isolated to the governmentally subsidized enterprises (GSEs) Fannie
Mae and Freddie Mac. With the advent of MBSs, mortgages could be sold ‘wholesale’
where the safe mortgages could mask the risks of the unsafe mortgages. Third, it
created the “originate to distribute” model. This technique allows lenders to make
mortgages without having to hold on to them. Lenders immediately sell the loans
to banks that repackage them into MBSs. These MBSs are then sold to investors
around the world. In this process lenders have little incentive to police the quality
of the loans they are creating, and therefore can increase the amount of subprime
loans being made without suffering repercussions. Banks can increase the
complexity of the investments in order to manufacture AAA ratings to attract
investors. Investors who buy slices of CDOs have the incentive to keep tabs on the
quality of the loans, but have little reason to do so because of the outstanding
ratings of the investment. The complexity of the system dilutes information about
the mortgages to the point where investors have no idea what they are buying. A
bank in Germany or a pension fund in Florida is unlikely to check on the credit
worthiness of individual homebuyers in Nevada. Mortgage-‐backed securities and
CDOs encouraged the growth of the mortgage market and spread the exposure of
these assets all around the globe. The quantity of MBS grew from $200 billion in
1994 to almost $3 trillion in 2007 (Johnson pg. 76).
Another financial instrument new to the scene was the credit default swap.
Credit default swaps can be understood as an agreement between two parties
where one person provides insurance against the default of an asset to another
person. The difference between this and regular insurance is that the person being
insured does not have to own the asset the insurance is based on. It’s as if a person
has an insurance claim on a house he doesn’t own.
Using credit default swaps, banks were able to manufacture a type of product
known as a ‘synthetic CDO’. In order to create a synthetic CDO, a bank would first
create an off balance sheet special-‐purpose vehicle (SPV). The SPV gathered
financing from investors in order to sell a credit default swap back to the bank. The
credit default swap would insure against the default of some preexisting group of
mortgages. If the mortgages did not default, the bank would pay out insurance
premiums to the synthetic CDO, and the investors would receive a fixed income. If
the borrowers did not pay their loans, the synthetic CDO would pay the full
insurance to the bank and the investors would lose their money. In effect, this
works exactly the same as a regular CDO only it is not based on any underlying
assets that any party owns. This is particularly dangerous because if a borrower
defaults on his loans, not only is the lender losing money, but also all other
secondary parties that took out a credit default swap lose money. The losses on a
defaulted loan can become much larger than the size of the loan itself.
A general theme among these financial innovations is that they all increase
systemic complexity and they all propagate systemic interdependence. In one sense
this means that risk is spread among a larger group of individuals, watering down
the risks for everyone. More crucially though, this magnifies the damage from large
systemic shocks and increases general uncertainty about the stability of the system.
Nassim Taleb has written extensively about these types of institutional dangers.
When the entire financial network becomes increasingly interconnected and
homogenizes risks, unforeseen crises hit longer and harder. In addition, when the
network increases its complexity, individuals lose access to crucial information that
should affect their decision-‐making.
C: Risk Mismanagement
One of the key ingredients in causing the crisis was the general increase in
leverage within the financial sector. Leverage describes the combination of capital
and debt that is used to finance a firm’s balance sheet. If you invest $10 of your own
money and $90 of borrowed money into buying a $100 asset, then your capital-‐to-‐
asset ratio is 10 percent and your leverage (debt to equity) is 9-‐to-‐1. Controlling a
firm’s capital ratio is vital because it dictates an important trade off between risk
and profits. If you invest $10 of your own money into an asset that generates 10
percent returns, then you produce $1 in profits. If you instead invest $10 of your
own money and $90 of borrowed money into that asset, you produce $10 in profit.
Therefore when making profitable investments, a low capital-‐to-‐asset ratio can
easily magnify returns on equity. On the other hand, low capital-‐to-‐asset ratios
dramatically increase risks of insolvency. An 11 percent loss on $10 of your own
money leaves you with $8.90. An 11 percent loss on $10 of your own money and
$90 of borrowed money wipes you out and leaves you insolvent. Therefore a high
degree of leverage is characteristic of a very profitable and very risky firm.
Non-‐financial firms have, on average, capital-‐to-‐asset ratios of 30 to 40
percent. Before the financial crisis, the world’s largest 50 banking firms held, on
average, a 4 percent capital to asset ratio (Hildebrand 2008). At its height, Bear
Stearns’s leverage ratio reached thirty-‐three to one. This meant that if the value of
their assets fell by only 3 percent the bank would be insolvent.
Regulators use the Basel Accords, issued by the Basel Committee on Banking
Supervision, as a guideline for setting capital requirements. In the first half of the
decade, United States regulators were using Basel I guidelines for capital
requirements. These regulations require banks to maintain around 4 to 8 percent
minimum capital-‐to-‐asset ratios. The exact capital requirement is determined by
the risk of assets being financed. The general idea is that less risky investments can
be financed by more debt while riskier investments require more capital.
There are three major problems with this system. First, the capital
requirements in general are arguably set way too low. Immediately before its
bankruptcy, Lehman Brothers had a capital ratio of 11 percent, well above any
federal or international guidelines. Anat Admati of Stanford University has
frequently called for capital requirements of up to 50 percent arguing that if the
banks are indeed treated as ‘too big to fail’ they need to have a capital cushion that
sufficiently protects the need for taxpayer bailouts.
Second, the idea of risk weighting assets for the purpose of regulation is
inherently procyclical. This means that the regulation is strongest when it is not
needed and weakest when it is needed the most. By and large, the majority of risk
models used by the financial industry are value at risk (VaR) models. These models
use historical data to estimate the maximum amount that can be lost on a specific
portfolio on a given day 99 percent of the time. This risk measurement system
works reasonably well on an average day, but it performs terribly when dealing
with rare events. As one commentator put it, “this is like an air bag that works all
the time, except when you have a car accident” (Einhorn 2008). At the peak of a
bubble, the historical data shows the asset to be the most safest it has ever been.
Therefore the capital requirements on the asset will be made to be exceedingly low.
Lastly, the process of weighing the risks of assets was conducted under the
banks’ supervision. The Securities and Exchange Commission (SEC) allowed
financial institutions to use their own internal risk models to determine the risks of
the assets that the regulations were based on. In terms of capital requirements,
oversight was essentially left to the banks themselves.
In a normal market, there are sufficient natural inhibitors that prohibit a firm
from becoming over leveraged. As a firm becomes more and more financed by debt,
the cost of acquiring additional debt increases and share prices fall to reflect the
additional risk. When it comes to banking, deposit insurance removes all the costs
of financing with deposit debt. As for uninsured debt, implicit governmental
guarantees act as a market signal to creditors that overleveraging is not an indicator
of an unsafe investment. On top of this, corporate debt interest payments are tax
deductible. Hence bank debt funding is essentially governmentally subsidized.
Section 2: Building and Running the Model
The model that was built for this paper was written in the Java programing
language and uses the database software Neo4j. Neo4j organizes information into a
graph structure. This means that everything stored in the database is a node (a
distinct object), a relationship between nodes, or a property of a node or
relationship. Figure 1 is an illustration of a simple graph that can be created with
Neo4j.
Figure 1: A simple graph that shows a bank providing a mortgage to an individual.
The model generates a graph with over 3000 nodes, over 19000 properties,
and over 19000 relationships. After the initial graph is created in one program, a
second program ‘runs’ the graph so that individual nodes are made to interact with
one another in various ways. New relationships are formed if the right conditions
are met, and properties change based on these adjustments. These interactions
repeat a set number of times before the program terminates. For each iteration,
individual ‘actors’ (nodes) roughly take into account the actions of the past
iterations. For example, bank nodes keep a running tally of the number of
successive increases in housing prices. They use this information when buying
mortgages from mortgage lenders. The more time the asset price has been
increasing, the more willing they will be to buy mortgages (this simulate the effects
of value-‐at-‐risk modeling on the banks’ decision making).
In the model there are eight types of nodes and eleven different types of
relationships. The types of nodes are mortgage lenders, persons, banks, firms,
shareholders, investors, CDOs, and houses. A map of this simplified graph can be
seen in Figure 2. Mortgage lenders search through the system for people who are
currently employed and attempt to give them mortgages. Once a suitable fit is
made, a mortgage relationship is created between the lender and the person and a
house node is connected to the person. The size of the mortgage compared to the
value of the house (loan to value ratio) is initially an input variable. As more loans
are created and the market for houses dries up, lenders start to make subprime
loans, or loans with dangerously high loan to value ratios.
Once lenders have made mortgage relationships, they try and sell the loans
to a bank. Banks are financed by a mixture of shareholders and investors. The exact
leverage ratio of each of the banks is determined as an input variable. Banks buy
mortgages (the mortgage relationship between the lender and the person is broken
and a new one is created between the bank and the person) and group them
together into packages of thirty. These thirty mortgages are then attached to a
newly created CDO. The CDO makes connections to investors who pay the bank for
a share in the fixed income of the mortgages. The mortgages pay into the CDO and
the CDO pays out first to senior tranche holders then to junior tranche holders
Figure 2: map of the model
In each iteration, the percent change of home values is determined by a
combination of the amount of new loans and the amount of defaults. When new
loans are created, it indicates that the housing market is healthy and expanding, this
signals that the value of houses is generally increasing. Mortgage defaults increase
the supply of new houses and lower the value of nearby houses. This pushes the
value of houses downward. At the start, only good loans are being made so the asset
price is increasing. Eventually, the loan to value ratios of newly created loans go so
high that new home owners are underwater on their mortgage before their first
payment4. Around this time, individuals start strategically defaulting on their loans.
This causes a downward push on asset prices that triggers even more defaults. The 4 See Knox 2006 for more details on “no money down” loans.
result is a popping of the housing bubble where borrowers leave their homes and
lenders are left holding assets severely depreciated from their original cost. Due to
fair value accounting (where the holder of an asset essentially has to value the asset
at the price they could sell it for) the banks’ balance sheets are affected by the
fluctuating value of the ‘toxic’ houses the banks now own. Since these losses are
recognized immediately, banks and lenders become insolvent soon after enough
homeowners default.
Within the context of this simple model, multiple causal relationships can be
tested. One could measure the effect of the rate at which mortgages are sold to
banks on bank solvency. One could also examine the role of leverage on bank losses.
Conversely, due to the multitude of variables that need to work together to run this
model, in order to test anything, most of the variables have to be predetermined (or
have to be governed by an extremely limited set of rules). This fact alone means this
model, and arguably all models of this sort, are exceedingly unrealistic. In a real
market setting, an important factor in an individual’s decision-‐making process may
not stay important for very long. When programing models, the changeability of the
decision-‐making algorithm is inescapably limited. Another constraint is that certain
real world processes may not be understood (or understandable), but they could
still be vital to the model’s workings. For example, this model only works given it
has an algorithm for determining the change in value for any given house from one
three month period to the next. A real world deterministic algorithm for this does
not exist, and arguably cannot exist. The best one can do is make up an algorithm
and test it against historical evidence, but as we’ve seen from section 1c, historical
evidence alone can be dangerously misleading, not to mention scientifically
insufficient. Therefore, models like this do not work as predictive tools. Models of
this type are practical in that they can help illustrate the qualitative nature of a set of
interactions ex post. From this analysis, certain conclusions that can be drawn from
running this model are inescapable, not because of the particulars of the model’s
outputs, but because of the logical necessity of their workings.
First off, if you have more invested into a single type of asset than you have
equity to finance it, and if the value of that asset uncontrollably plummets, it’s just a
matter of time before you become insolvent. You can adjust starting variable as
much as you want, but this result will remain true because this result is a
mathematical necessity. The more the exposure and the higher the leverage, the
sooner the default occurs, but its occurrence is a matter of course. Second, abusing
the ‘originate to distribute’ model by making bad loans is a lot harder to pull off than
it might seem. Every time this model is run, lenders are the first ones to be declared
insolvent. The trick lenders are trying to pull off is to not be holding subprime loans
at the time when they all start losing their value. The problem is, if your entire
business model is based on making and selling subprime loans, you will always have
loans on your books. In addition, the moment you realize the crash is coming is the
same time everyone else realizes it. Therefore it becomes impossible to unload the
toxic assets since no one will buy them. Like many of the other business strategies
that lead to the financial crisis, the ‘originate to distribute’ model only produces
short term profits and is clearly unsustainable in the long run.
Section 3: Conclusions
Out of all that has been said about the financial crisis, one aspect is more
important than all the rest: what lessons have been learned and who learned them.
The causes of the crisis and how the crisis played out can only tell us so much about
our evolving financial system and its weaknesses. Yes it would be a bad idea to
continually create synthetic CDOs out of credit default swaps or have financial firms
with absurdly high leverage. Of course risk managers should reevaluate their
dependence on value at risk models that sanction a firm’s appetite for increased
risk. Each of these conclusions is true, but to simply address these problems will do
nothing to prevent the next, assuredly different, financial crisis.5 The real lesson to
understand is who learned what from the financial crisis.
When the U.S. Treasury Department let Lehman Brothers fail, the ensuing
market crashes were interpreted to mean that federal regulators mishandled the
situation. The regulators themselves were responsible for allowing the chaos to
happen. Therefore regulators learned that the government must step in to protect
the collapse of ‘systematically important’ institutions. Bankers learned this lesson
as well, but with slightly more sinister implications. If the United States government
won’t allow systematically important institutions to fail, then the most prudent
business move available is to become systematically crucial in the eyes of the U.S.
government. This can be achieved two ways. One is to grow your firm to enormous
proportions; the other is to gain influence within the government. Banks with the 5 This is a tautology. If the next crisis is caused by these same problems, then addressing these problems will prevent the next financial crisis. Since it is prevented it wont be the next financial crisis and so the actual next financial crisis necessarily will be caused by different problems.
resources to implement these strategies have adopted both of them. The net
outcome is a financial system that is protected from its downside by an implicit
government guarantee to socialize their losses. In general, when risks are mitigated,
one acts recklessly. This is the lesson to learn from the crisis; that banks have been
given the right to act imprudently. Be it in the form of overleveraging or some other
bad idea we don’t yet know is bad, banks have less incentive than ever to align their
interests with society.
Bibliography
Bondy, J. A., and U. S. R. Murty. Graph Theory. New York: Springer, 2008. Print. Davies, H. The Financial Crisis: Who Is to Blame? Cambridge, UK: Polity, 2010. Print. Davidson, Adam, and Blumberg, Alex. "The Giant Pool of Money." Audio blog post. This American Life. N.p., 9 May 2008. Web. The Economist Magazine Einhorn, David. “Private Profits and Socialized Risk.” Global Association of Risk Professionals Review June/July 2008: n. pag. Print. Goodhart, C. A. E., and Gerhard Illing. Financial Crises, Contagion, and the Lender of Last Resort: A Reader. Oxford: Oxford UP, 2002. Print. Greenspan, Alan. “The Crisis.” Brookings Paper on Economic Activity. Spring 2010. www.brookings.edu. Hildebrand, Philip. “Is Basel II Enough? The Benefits of a Leverage Ratio” Speech at the London School of Economics. London. 15 December 2008. Johnson, Simon, and Kwak, James. 13 Bankers: The Wall Street Takeover and the next Financial Meltdown. New York: Pantheon, 2010. Print. Knox, Noelle. “43% of first-‐time home buyers put no money down.” USA Today 18 Oct 2006: n. pag. Print. Lewis, Michael. Boomerang: Travels in the New Third World. New York: W.W. Norton &, 2011. Print. Libby, Robert, Patricia A. Libby, and Daniel G. Short. Financial Accounting. Boston: McGraw-‐Hill Irwin, 2009. Print. Nocera, Joe. "Risk Mismanagement." New York Times 2 Jan. 2009: n. pag. Print. NPR: Planet Money Podcast
Roberts, Russ, and Anat Admati. "Admati on Financial Regulation." Audio blog post. EconTalk. Russ Roberts, 1 Aug. 2011. Web. Roberts, Russ, and Charles Calomiris. "Calomiris on Capital Requirements, Leverage, and Financial Regulation." Audio blog post. EconTalk. Russ Roberts, 5 Mar. 2012. Web.
Roberts, Russ, and Simon Johnson. "Simon Johnson on the Financial Crisis." Audio blog post. EconTalk. Russ Roberts, 28 Nov. 2011. Web. Sorkin, Andrew Ross. Too Big to Fail: The inside Story of How Wall Street and Washington Fought to save the Financial System from Crisis-‐-‐and Themselves. New York: Viking, 2009. Print. Spencer, Richard. “Tunisia riots: Reform or be overthrown, US tells Arab states amid fresh riots”. Telegraph 13 January 2011. Web. Taleb, Nassim. The Black Swan: The Impact of the Highly Improbable. New York: Random House, 2007. Print.
Appendix A: Model Code
package org.financialModel; import org.neo4j.cypher.javacompat.ExecutionEngine; import org.neo4j.cypher.javacompat.ExecutionResult; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import org.neo4j.helpers.collection.IteratorUtil; import java.io.File; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; public class Model02 { private static final String DB_PATH = "target/neo4j-model02-db"; //Start: Changeable vars //private static final int NUM_PersonS = 100; private static final double AVG_CASH_OVER_ASSETS = .2; private static final double CASHOA_RANGE = .2; private static final double AVG_CAPTIAL_OVER_ASSETS = .075; private static final double CAPOA_RANGE = .07; private static final double FIRM_FINANCE_PERCENT = .3; //End: Changable vars //types private static final String TYPE_KEY = "node_type"; private static final String MORTGAGE_LENDER = "mortgage_lender"; private static final String PERSON = "person"; private static final String FIRM = "firm"; private static final String BANK = "bank"; private static final String SHARE_HOLDER = "share_holder"; private static final String INVESTOR = "investor"; //Person keys private static final String INCOME_KEY = "income"; private static final String MIN_EQUITY_KEY = "min_equity"; private static final String DEFAULT_KEY = "in_default"; //bank keys private static final String SOLVENT_KEY = "is_solvent"; //assets private static final String CASH_KEY = "cash"; private static final String TARGET_CASH_KEY = "target_cash"; //liabilities private static final String DEBT_KEY = "debt"; private static final String CAPITAL_KEY = "equity"; private static GraphDatabaseService graphDb;
private static Random generator = new Random(); private static ExecutionEngine engine; public static enum RelTypes implements RelationshipType { BANK_REFERENCE, //from reference node to all banks PROVIDES_MORTGAGE, //from person nodes to mortgage_lenders once lenders create loans FINANCES, //from banks to firms EMPLOYS, //from firms to persons BUYS_MORTGAGES, //from banks to mortgage_lenders OWNS, //from person to house or from mortgage_lender to house or from bank to house. PROVIDES_CAPITAL,//from share_holders to banks PROVIDES_DEBT, //from investors to banks (repo loans/ commercial paper) BUYS_CDO, //from investors to banks CREATES_CDO, //(investment vehicle) from bank to CDO CDO_BOND //from investors to CDO // DEPOSITS? //from banks to banks and from creditors to banks } private static Node createShareHolder() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, SHARE_HOLDER); node.setProperty("profit", 0.0); return node; } private static Node createInvestor() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, INVESTOR); node.setProperty("profit", 0.0); node.setProperty(CASH_KEY, 2000000.0 + (.5-generator.nextDouble())*1000000); return node; } private static Node createFirm() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, FIRM); node.setProperty("is_financed", true); node.setProperty(CASH_KEY, 0.0); return node; } private static Node createBank() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, BANK); //Start: empty properties (might delete) node.setProperty(CASH_KEY, 0);
node.setProperty(DEBT_KEY, 0); node.setProperty(CAPITAL_KEY, 0); //End: empty properties //Whether or not in default. node.setProperty(SOLVENT_KEY, true); return node; } private static Node createPerson() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, PERSON); node.setProperty("is_employed", true); node.setProperty("home_owner", false); //sets max monthly outflow of cash to mortgage node.setProperty(INCOME_KEY, (1000 + 1000*(.5-generator.nextDouble())) ); //sets min equity ratio. Less than this defaults. node.setProperty(MIN_EQUITY_KEY, -generator.nextDouble()/5); //Whether or not in default. node.setProperty(DEFAULT_KEY, false); return node; } private static Node createLender() { Node node = graphDb.createNode(); node.setProperty(TYPE_KEY, MORTGAGE_LENDER); //Start: balance sheet properties node.setProperty(DEBT_KEY, 50000.0/(AVG_CAPTIAL_OVER_ASSETS+(.5-generator.nextDouble())*CAPOA_RANGE) - 50000); node.setProperty(CAPITAL_KEY, 50000.0); node.setProperty(TARGET_CASH_KEY, ((Double)node.getProperty(DEBT_KEY)+ (Double)node.getProperty(CAPITAL_KEY))* (AVG_CASH_OVER_ASSETS+(.5-generator.nextDouble())*CASHOA_RANGE)); node.setProperty(CASH_KEY, (Double)node.getProperty(DEBT_KEY) + (Double)node.getProperty(CAPITAL_KEY)); //End: balance sheet properties //Whether or not in default. node.setProperty(SOLVENT_KEY, true); return node; } private static void transferCash(final Relationship rel, double quantity) { Map<String, Object> params = new HashMap<String, Object>(); params.put( "rel", rel ); params.put("quant", quantity); engine.execute("start rel = relationship({rel}) match a-[rel]->b " + "set a.cash=a.cash-{quant} set b.cash=b.cash+{quant} set rel.quantity=rel.quantity+{quant}", params); }
public static void setup() { deleteFileOrDirectory( new File( DB_PATH ) ); graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH); registerShutdownHook(graphDb); engine = new ExecutionEngine( graphDb ); } public static void main(String[] args) { setup(); //start: creates banks Transaction tx = graphDb.beginTx(); try { //set reference type Node reference = graphDb.getReferenceNode(); reference.setProperty("node_type", "reference"); //create banks for (int i=0; i<7; i++) { Node bank = createBank(); reference.createRelationshipTo(bank, RelTypes.BANK_REFERENCE); } tx.success(); } finally { tx.finish(); } //end: create banks //start: create lenders, firms, share_holders, and investors Transaction tx1 = graphDb.beginTx(); try { //create lenders and link them to all banks for (int i=0; i<100; i++) { Node node = createLender(); ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b return b"); Iterator<Node> b_column = result.columnAs( "b" ); for ( Node bank : IteratorUtil.asIterable( b_column ) ) bank.createRelationshipTo(node, RelTypes.BUYS_MORTGAGES); } //create firms and link them to random banks for (int i=0; i<100; i++) { Node node = createFirm(); int randomIndex = generator.nextInt( 7 ); ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b return b"); Iterator<Node> b_column = result.columnAs( "b" ); Relationship r = IteratorUtil.fromEnd(b_column, randomIndex).createRelationshipTo(node, RelTypes.FINANCES); r.setProperty("quantity", 0.0); }
//create share_holders for (int i=0; i<200; i++) { Node node = createShareHolder(); int randomIndex = generator.nextInt( 7 ); ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b return b"); Iterator<Node> b_column = result.columnAs( "b" ); Relationship r = node.createRelationshipTo(IteratorUtil.fromEnd(b_column, randomIndex), RelTypes.PROVIDES_CAPITAL); r.setProperty("quantity", generator.nextDouble()*50000); } //create investors for (int i=0; i<1000; i++) { Node node = createInvestor(); ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b return b"); Iterator<Node> b_column = result.columnAs( "b" ); for ( Node bank : IteratorUtil.asIterable( b_column ) ) { node.createRelationshipTo(bank, RelTypes.BUYS_CDO); Relationship r = node.createRelationshipTo(bank, RelTypes.PROVIDES_DEBT); r.setProperty("quantity", 0.0); } } tx1.success(); } finally { tx1.finish(); } Transaction tx2 = graphDb.beginTx(); try { //create persons and link them to random firms for (int i=0; i<1000; i++) { Node node = createPerson(); int randomIndex = generator.nextInt( 100 ); ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b-[:FINANCES]->c return c"); Iterator<Node> c_column = result.columnAs( "c" ); IteratorUtil.fromEnd(c_column, randomIndex).createRelationshipTo(node, RelTypes.EMPLOYS); } //set up bank balance sheet ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->b return b"); Iterator<Node> b_column = result.columnAs( "b" ); for ( Node bank : IteratorUtil.asIterable( b_column ) ) { //find total equity
double totalCapital = 0.0; for (Relationship r : bank.getRelationships(Direction.INCOMING, RelTypes.PROVIDES_CAPITAL)) { totalCapital += (Double)r.getProperty("quantity"); } //bank debt and cash double debt = totalCapital/(AVG_CAPTIAL_OVER_ASSETS+ (.5-generator.nextDouble())*CAPOA_RANGE)-totalCapital; double cash = totalCapital+debt; //set up bank properties bank.setProperty(CAPITAL_KEY, totalCapital); bank.setProperty(DEBT_KEY, debt); bank.setProperty(CASH_KEY, totalCapital); bank.setProperty(TARGET_CASH_KEY, (cash)*(AVG_CASH_OVER_ASSETS+(.5-generator.nextDouble())*CASHOA_RANGE)); //finance bank debt from investors while (debt != 0) { for (Relationship rel : bank.getRelationships(Direction.INCOMING, RelTypes.PROVIDES_DEBT)) { if (generator.nextBoolean()) { Node investor = rel.getStartNode(); int amount = generator.nextInt(7)*10000+ 10000; if(debt >= amount && (Double)investor.getProperty(CASH_KEY) >= amount) { transferCash(rel, amount); debt -= amount; } else if(debt < amount && (Double)investor.getProperty(CASH_KEY) >= amount) { transferCash(rel, debt); debt = 0; } } } } //total cash allocated to firms double firmFinance = cash*FIRM_FINANCE_PERCENT; bank.setProperty("firm_finance", firmFinance); //gets amount of firms Map<String, Object> params = new HashMap<String, Object>(); params.put( "bank", bank ); ExecutionResult result1 = engine.execute("start b = node({bank}) match b-[rel:FINANCES]->f return count(f)", params); Long firmNum = (Long) result1.columnAs( "count(f)" ).next(); assert (firmNum > 0); //transfers equal cash to each firm out of the alocated cash from bank for(Relationship rel: bank.getRelationships(Direction.OUTGOING, RelTypes.FINANCES)) transferCash(rel, firmFinance/firmNum); }
tx2.success(); } finally { tx2.finish(); } //tests ExecutionResult result = engine.execute( "start a=node(0) match a-[:BANK_REFERENCE]->b-->firm-->person return count(person)" ); System.out.println(result); System.out.println("Shutting down database..."); graphDb.shutdown(); } private static void deleteFileOrDirectory( final File file ) {//deletes graph if it exists if ( !file.exists() ) { return; } if ( file.isDirectory() ) { for ( File child : file.listFiles() ) { deleteFileOrDirectory( child ); } } else { file.delete(); } } private static void registerShutdownHook( final GraphDatabaseService graphDb ) { // Registers a shutdown hook for the Neo4j instance so that it // shuts down nicely when the VM exits (even if you "Ctrl-C" the // running example before it's completed) Runtime.getRuntime().addShutdownHook( new Thread() { @Override public void run() { graphDb.shutdown(); } } ); } }
Appendix B: RunModel Code
package org.financialModel; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; import org.financialModel.Model02.RelTypes; import org.neo4j.cypher.javacompat.ExecutionEngine; import org.neo4j.cypher.javacompat.ExecutionResult; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import org.neo4j.helpers.collection.IteratorUtil; /** * @author Julian Aronowitz * */ public class RunModel02 { private static final String DB_PATH = "target/neo4j-model02-db"; private static double totalProfits = 0; private static double AVG_LTV = .9; //between 0 and 1 private static double LTV_RANGE = .2; //LTV - |.5*LTV_RANGE| <= 1 private static double SENIOR_TRANCHE = .3; private static double BANK_OWNED_TRANCHE = .2; //less than senior tranche private static long numPersons; private static long numBanks; private static int consecutivePriceIncreases; private static GraphDatabaseService graphDb; private static Random generator = new Random(); private static ExecutionEngine engine; //COMPLETE TESTED (only person owned houses) public static void changeHouseVal(double percentChange) { Map<String, Object> params = new HashMap<String, Object>(); params.put( "percentChange", percentChange ); //change bank owned houses engine.execute("start a=node(0) " + "match a-[:BANK_REFERENCE]->b-[:OWNS]->h set h.home_value = h.home_value*(1+{percentChange})", params); //change lender owned houses engine.execute("start b=node(1) " + "match b-[:BUYS_MORTGAGES]->l-[:OWNS]->h set h.home_value = h.home_value*(1+{percentChange})", params); //change person owned houses engine.execute("start a=node(0) " +
"match a-[:BANK_REFERENCE]->b-[:FINANCES]->firm-[:EMPLOYS]->p-[:OWNS]->h " + "set h.home_value = h.home_value*(1+{percentChange})", params); } //COMPLETE TESTED public static double percentOfDebtCurrRepayable(Node bank) { //cash and firm finance double assets = (Double) bank.getProperty("cash"); if (bank.hasProperty("firm_finance")) { assets += (Double) bank.getProperty("firm_finance"); } Map<String, Object> params0 = new HashMap<String, Object>(); params0.put( "bank", bank ); //toxic assets if (bank.hasRelationship(Direction.OUTGOING, RelTypes.OWNS)) { ExecutionResult result0 = engine.execute("start b=node({bank})" + " match b-[:OWNS]->h return sum(h.home_value)", params0); assets += (Double) result0.columnAs("sum(h.home_value)").next(); } //cdos for(Relationship bond : bank.getRelationships(RelTypes.CDO_BOND)) { Node cdo = bond.getEndNode(); double defaultPercent = (Double) cdo.getProperty("percent_in_default"); if (defaultPercent < .999) { double share = (Double) bond.getProperty("percent_of_cdo"); //double initialVal = (Double) cdo.getProperty("initial_val"); double value = cdoCurValue(cdo); if ( (1 - defaultPercent) < SENIOR_TRANCHE) assets += (share/SENIOR_TRANCHE) * value; else assets += value * share; } } //loans if (bank.hasRelationship(Direction.OUTGOING, RelTypes.PROVIDES_MORTGAGE)) { ExecutionResult result1 = engine.execute("start b=node({bank}) " + " match b-[relA:PROVIDES_MORTGAGE]->c return sum(relA.quantity)", params0); assets += (Double) result1.columnAs("sum(relA.quantity)").next(); }
return assets/((Double) bank.getProperty("debt")); } //COMPLETE TESTED public static double cdoCurValue( Node cdo) { Map<String, Object> params1 = new HashMap<String, Object>(); params1.put( "cdo", cdo ); ExecutionResult result0 = engine.execute("start a = node({cdo}) " + "match a-[rel:PROVIDES_MORTGAGE]->person return sum(rel.quantity)", params1); return (Double) result0.columnAs("sum(rel.quantity)").next(); } //COMPLETE TESTED public static void defaulting(Node person) { //takes person and gives their house to their debtor and sets them to in default. //gives house to lender Relationship r0 = person.getSingleRelationship(RelTypes.OWNS, Direction.OUTGOING); Relationship r1 = person.getSingleRelationship(RelTypes.PROVIDES_MORTGAGE, Direction.INCOMING); Node house = r0.getEndNode(); Node lender = r1.getStartNode(); r0.delete(); r1.delete(); //NOT TESTED //CDO if (lender.hasProperty("percent_in_default")) { lender.getSingleRelationship(RelTypes.CREATES_CDO, Direction.INCOMING).getStartNode().createRelationshipTo(house, RelTypes.OWNS); } else { lender.createRelationshipTo(house, RelTypes.OWNS); } //sets default person.setProperty("in_default", true); } public static double changeAssetPercent(int houseDefaultCount, int houseCreationCount) { double defaultEffect = houseDefaultCount * -1.0/numPersons; double boomEffect = houseCreationCount * 1.0/numPersons; return 2*defaultEffect + boomEffect; } public static void changeLTV(int houseCreationCount) { AVG_LTV *= 1 + houseCreationCount* .5/numPersons;
} //COMPLETE TESTED public static Node createHouse() { Node node = graphDb.createNode(); node.setProperty("node_type", "house"); //sets home value at 100k node.setProperty("home_value", 100000.0); return node; } //COMPLETE TESTED public static Node createCDO() { Node node = graphDb.createNode(); node.setProperty("node_type", "cdo"); node.setProperty("cash", 0.0); node.setProperty("percent_in_default", 0.0); node.setProperty("initial_val", 0.0); node.setProperty("initial_payments", 0.0); node.setProperty("principle", 0.0); return node; } //COMPLETE TESTED public static void createNewLoan(Node start, Node end) { //add in changing LTV, add in changing monthly payments double quantity = 100000*(AVG_LTV+(.5-generator.nextDouble())*LTV_RANGE); double principle = quantity/1.1; Relationship r = start.createRelationshipTo(end, RelTypes.PROVIDES_MORTGAGE); r.setProperty("quantity", quantity); r.setProperty("principle", principle); r.setProperty("monthly_payment", 200.0); start.setProperty("cash", (Double) start.getProperty("cash")-principle); } //COMPLETE TESTED public static void payMortgages() { engine.execute("start a = node(*) match a-[rel:PROVIDES_MORTGAGE]->b " + "set a.cash = a.cash + rel.monthly_payment, rel.quantity = rel.quantity - rel.monthly_payment"); //CAN NOT PAY OFF MORTGAGE COMPLETELY (doesn't check for quantity 0) } //COMPLETE TESTED public static void transferMortgage(Node buyer, Relationship mortgage) { Node homeOwner = mortgage.getEndNode(); //Node seller = mortgage.getStartNode(); double principle = (Double) mortgage.getProperty("principle"); Relationship newMortgage = buyer.createRelationshipTo(homeOwner, RelTypes.PROVIDES_MORTGAGE);
newMortgage.setProperty("monthly_payment", mortgage.getProperty("monthly_payment")); newMortgage.setProperty("quantity", mortgage.getProperty("quantity")); newMortgage.setProperty("principle", principle); mortgage.delete(); } public static void cdoPayments() { ExecutionResult result0 = engine.execute("start a = node(0) " + "match a-[:BANK_REFERENCE]->bank-[:CREATES_CDO]->cdo where cdo.percent_in_default < .999 return cdo"); Iterator<Node> cdo_column = result0.columnAs( "cdo" ); for ( Node cdo : IteratorUtil.asIterable( cdo_column ) ) { Map<String, Object> params = new HashMap<String, Object>(); params.put( "cdo", cdo ); ExecutionResult result1 = engine.execute("start cdo = node({cdo}) " + "match cdo<-[rel:CDO_BOND]-investor where rel.tranche = 'senior' return rel", params); Iterator<Relationship> senior_column = result1.columnAs( "rel" ); double defaultPercent = (Double) cdo.getProperty("percent_in_default"); if ( (1 - defaultPercent) < SENIOR_TRANCHE) { double remainingCash = (Double) cdo.getProperty("cash"); for ( Relationship sBond : IteratorUtil.asIterable( senior_column )) { payment(cdo, sBond.getStartNode(), (Double) remainingCash * (Double) sBond.getProperty("percent_of_cdo")/SENIOR_TRANCHE); } } else { for ( Relationship sBond : IteratorUtil.asIterable( senior_column )) { payment(cdo, sBond.getStartNode(), (Double) cdo.getProperty("initial_payments") * (Double) sBond.getProperty("percent_of_cdo")); } double remainingCash = (Double) cdo.getProperty("cash"); ExecutionResult result2 = engine.execute("start cdo = node({cdo}) " + "match cdo<-[rel:CDO_BOND]-investor where rel.tranche = 'junior' return rel", params); Iterator<Relationship> junior_column = result2.columnAs( "rel" );
for ( Relationship jBond : IteratorUtil.asIterable( junior_column )) { payment(cdo, jBond.getStartNode(), remainingCash * (Double) jBond.getProperty("percent_of_cdo")/(1-SENIOR_TRANCHE)); } } } } //COMPLETE TESTED public static void payment(Node from, Node to, double amount) { from.setProperty("cash", (Double) from.getProperty("cash")-amount); to.setProperty("cash", (Double) to.getProperty("cash")+amount); } public static void lenderDefault(Node lender) { lender.setProperty("is_solvent", false); } public static void bankDefault(Node bank) { bank.setProperty("is_solvent", false); } //COMPLETE TESTED public static void changeCdoDefault(Node person) { Relationship mortgage = person.getSingleRelationship(RelTypes.PROVIDES_MORTGAGE, Direction.INCOMING); Node cdo = mortgage.getStartNode(); double percentIncrease = (Double) mortgage.getProperty("principle") / (Double) cdo.getProperty("principle"); cdo.setProperty("percent_in_default", (Double) cdo.getProperty("percent_in_default") + percentIncrease); } //COMPLETE TESTED public static int evalDefaults() { int count = 0; //returns people who will strategicly default ExecutionResult result0 = engine.execute("start a=node(0) " + "match a-[:BANK_REFERENCE]->bank-[:FINANCES]->firm-[:EMPLOYS]->person-[:OWNS]->house, " + "person<-[loan:PROVIDES_MORTGAGE]-lender " + "where (person.in_default = false) and " + "( (house.home_value - loan.quantity)/house.home_value < person.min_equity ) return person"); Iterator<Node> s_column = result0.columnAs( "person" ); for ( Node person : IteratorUtil.asIterable( s_column ) ) { Node lender = person.getSingleRelationship(RelTypes.PROVIDES_MORTGAGE, Direction.INCOMING).getStartNode(); //IF CDO
if (lender.hasProperty("percent_in_default")) { changeCdoDefault(person); } defaulting(person); count += 1; } //defaults people who are unemployed ExecutionResult result1 = engine.execute("start a=node(0) " + "match a-[:UNEMPLOYED]->person where (person.in_default = false) return person"); Iterator<Node> u_column = result1.columnAs( "person" ); for ( Node person : IteratorUtil.asIterable( u_column ) ) { defaulting(person); count += 1; } return count; } //COMPLETED TESTED public static int evalLenderSolvency() { int count = 0; ExecutionResult result = engine.execute("start a = node(1) match a-[:BUYS_MORTGAGES]->lender " + "where lender.is_solvent = true return lender"); Iterator<Node> l_column = result.columnAs( "lender" ); for ( Node lender : IteratorUtil.asIterable( l_column ) ) { if (percentOfDebtCurrRepayable(lender) < 1.0) { lenderDefault(lender); count++; } } return count; } public static int evalBankSolvency() { int count = 0; ExecutionResult result = engine.execute("start a = node(0) match a-[:BANK_REFERENCE]->bank " + "where bank.is_solvent = true return bank"); Iterator<Node> b_column = result.columnAs( "bank" ); for ( Node bank : IteratorUtil.asIterable( b_column ) ) { if (percentOfDebtCurrRepayable(bank) < 1.0) { lenderDefault(bank); count++; } } return count; }
public static int evalMortgageTransfers() { int totalTransfers = 0; ExecutionResult result1 = engine.execute("start a = node(0) " + "match a-[:BANK_REFERENCE]->bank where bank.cash > bank.target_cash return bank"); Iterator<Node> b_column = result1.columnAs( "bank" ); for (Node bank : IteratorUtil.asIterable( b_column ) ) { for ( Relationship buys : bank.getRelationships(RelTypes.BUYS_MORTGAGES)) { Node lender = buys.getEndNode(); int count = 0; for ( Relationship mortgage : lender.getRelationships(RelTypes.PROVIDES_MORTGAGE)) { if (count > 0 || (Double)bank.getProperty("cash") < (Double)bank.getProperty("target_cash")) break; if (.1 - generator.nextDouble() + consecutivePriceIncreases/5 > 0) { payment(bank, lender, (Double)mortgage.getProperty("principle")*1.02); transferMortgage(bank, mortgage); totalTransfers++; } count++; } } } return totalTransfers; } public static int evalCDOs() { int cdos = 0; //banks ExecutionResult result0 = engine.execute("start a = node(0) " + "match a-[:BANK_REFERENCE]->bank where bank.is_solvent = true return bank"); Iterator<Node> b_column = result0.columnAs( "bank" ); //investors ExecutionResult result1 = engine.execute("start a = node(1) match a<-[:BUYS_CDO]-i where i.cash > 500 return i"); Iterator<Node> i_column = result1.columnAs("i"); //for banks for ( Node bank : IteratorUtil.asIterable( b_column ) ) { Map<String, Object> params = new HashMap<String, Object>(); params.put( "bank", bank);
//if less than 30 mortgages, next bank ExecutionResult result2 = engine.execute("start a = node({bank}) " + "match a-[rel:PROVIDES_MORTGAGE]->p return count(rel)", params); if (result2.columnAs("count(rel").hasNext() && (Long) result2.columnAs("count(rel)").next() >= 30) { double principle = 0.0; double initial_val = 0.0; double initial_payments = 0; //create CDO Node cdo = createCDO(); cdos++; bank.createRelationshipTo(cdo, RelTypes.CREATES_CDO); params.put( "cdo", cdo); //finds all mortgages ExecutionResult result3 = engine.execute("start a = node({bank}) " + "match a-[rel:PROVIDES_MORTGAGE]->p return rel", params); Iterator<Relationship> m_column = result3.columnAs( "rel" ); //transfer mortgages to CDO int count = 0; for ( Relationship mortgage : IteratorUtil.asIterable( m_column ) ) { if (count >= 30) break; principle += (Double) mortgage.getProperty("principle"); initial_val += (Double) mortgage.getProperty("quantity"); initial_payments += (Double) mortgage.getProperty("monthly_payment"); transferMortgage(cdo, mortgage); count++; } //add in CDO properties cdo.setProperty("principle", principle); cdo.setProperty("initial_val", initial_val); cdo.setProperty("initial_payments", initial_payments); //bank keeps % of slices of CDOs (all senior) Relationship primary = bank.createRelationshipTo(cdo, RelTypes.CDO_BOND); primary.setProperty("tranche", "senior"); primary.setProperty("percent_of_cdo", BANK_OWNED_TRANCHE); count = 0; for (Node investor : IteratorUtil.asIterable( i_column )) { if (count >= 100 - (BANK_OWNED_TRANCHE * 100)) break;
Relationship bond = investor.createRelationshipTo(cdo, RelTypes.CDO_BOND); if (count < (SENIOR_TRANCHE - BANK_OWNED_TRANCHE)*100) { bond.setProperty("tranche", "senior"); bond.setProperty("percent_of_cdo", .01); payment(investor, bank, principle * .0107); count++; } else { bond.setProperty("tranche", "junior"); bond.setProperty("percent_of_cdo", .01); payment(investor, bank, principle * .0105); count++; } } } } return cdos; } //COMPLETE TESTED public static int evalNewLoans() { //add in change based on buy amount and asset price int numLoans = 0; ExecutionResult result0 = engine.execute("start a = node(1) " + "match a-[:BUYS_MORTGAGES]->lenders " + "where (lenders.target_cash < lenders.cash) and (lenders.is_solvent = true) return lenders"); ExecutionResult result1 = engine.execute("start a = node(0) " + "match a-[:BANK_REFERENCE]->b-[:FINANCES]->firm-[:EMPLOYS]->people " + "where people.home_owner = false return people"); Iterator<Node> lenders = result0.columnAs( "lenders" ); Iterator<Node> people = result1.columnAs( "people" ); int houses = 0; for ( Node lender : IteratorUtil.asIterable( lenders ) ) { for ( Node person : IteratorUtil.asIterable( people ) ) { if (houses > 3 || (Double) lender.getProperty("cash") < (Double) lender.getProperty("target_cash")) break; if (.6 - generator.nextDouble() + consecutivePriceIncreases/5 > 0) { Node aHouse = createHouse(); person.createRelationshipTo(aHouse, RelTypes.OWNS);
person.setProperty("home_owner", true); createNewLoan(lender, person); numLoans++; } houses++; } houses = 0; } return numLoans; } //COMPLETE TESTED public static void setup() { graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH); registerShutdownHook(graphDb); engine = new ExecutionEngine( graphDb ); //set numPersons ExecutionResult result = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->bank-[:FINANCES]->firm-[:EMPLOYS]->person return count(person)"); numPersons = (Long) result.columnAs("count(person)").next(); ExecutionResult result0 = engine.execute("start a=node(0) match a-[:BANK_REFERENCE]->bank return count(bank)"); numBanks = (Long) result0.columnAs("count(bank)").next(); } public static void main(String[] args) { setup(); Transaction tx = graphDb.beginTx(); try { System.out.println("number of individuals: " + numPersons); System.out.println("number of banks: " + numBanks); System.out.println(); consecutivePriceIncreases = 1; double assetChange = 0.0; for (int i = 0; i < 15; i++) { int mortgageDefaults = evalDefaults(); payMortgages(); cdoPayments(); int cdos = evalCDOs(); int transfers = evalMortgageTransfers(); System.out.println( "transfers: " + transfers + ", new cdos: " + cdos); int newLoans = evalNewLoans(); System.out.println( "defauls: " + mortgageDefaults + ", new loans: " + newLoans); //PRICE CHANGE STUFF assetChange = changeAssetPercent(mortgageDefaults, newLoans); changeLTV(newLoans); changeHouseVal(assetChange); System.out.println("assetChange: " + assetChange);
System.out.println("Loan-to-Value: " + AVG_LTV); System.out.println("consecutive price increases: " + consecutivePriceIncreases); if (consecutivePriceIncreases > 0 && assetChange >= 0) consecutivePriceIncreases++; else if (consecutivePriceIncreases > 0 && assetChange < 0) consecutivePriceIncreases = -1; else if (consecutivePriceIncreases < 0 && assetChange < 0) consecutivePriceIncreases--; else consecutivePriceIncreases = 1; //PRICE CHANGE STUFF int lenderDefaults = evalLenderSolvency(); int bankDefaults = evalBankSolvency(); System.out.println( "lender defauls: " + lenderDefaults + ", bank defaults: " + bankDefaults); System.out.println("total profits: " + totalProfits); System.out.println(); } tx.success(); } finally { tx.finish(); } System.out.println("Shutting down database..."); graphDb.shutdown(); } private static void registerShutdownHook( final GraphDatabaseService graphDb ) { // Registers a shutdown hook for the Neo4j instance so that it // shuts down nicely when the VM exits (even if you "Ctrl-C" the // running example before it's completed) Runtime.getRuntime().addShutdownHook( new Thread() { @Override public void run() { graphDb.shutdown(); } } ); } }