;extensions [profiler] extensions [palette] ;;; ;;; PwC Housing Market model ;;; Updated and heavily modified and commented by 深度碎片 EmbraceLife ;;; this updated model and notes can be downloaded from https://github.com/EmbraceLife/NetLogo-Modeling ;;; video tutorials on updating and understanding this model are available below ;;; Chinese version see Bilibili: https://www.bilibili.com/video/av31860025/ ;;; English version see Youtube: https://www.youtube.com/playlist?list=PLx08F1efFq_XPiMl74IHpppb8NGqITLn2 ;;; originally written by Nigel Gilbert, n.gilbert@surrey.ac.uk ;;; the original model can be downloaded from http://cress.soc.surrey.ac.uk/housingmarket/ukhm.html ;;; ;;; Disclaimer ;;; This model has been prepared for general guidance on matters of interest only, and ;;; does not constitute professional advice. The results are purely illustrative. You ;;; should not act upon any results from this model without obtaining specific professional ;;; advice. No representation or warranty (express or implied) is given as to the accuracy ;;; or completeness of the model, and, to the extent permitted by law, PricewaterhouseCoopers, ;;; its members, employees and agents accept no liability, and disclaim all responsibility, ;;; for the consequences of you or anyone else acting, or refraining to act, in reliance on ;;; the model or for any decision based on it. ;;; ;;; This Housing Market model was developed by Nigel Gilbert with the assistance of John Hawksworth ;;; and Paul Sweeney of PricewaterhouseCoopers and is licensed under a ;;; Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License: ;;; Creative Commons License
Housing Market model by Nigel Gilbert is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. ;;; ;;; To refer to this model in academic literature, cite: ;;; Gilbert, N, Hawksworth, J C, and Sweeney, P (2008) 'An Agent-based Model of the UK ;;; Housing Market'. University of Surrey http://cress.soc.surrey.ac.uk/housingmarket/ukhm.html ;;; ;;; version 0 NG 18 October 2007 ;;; version 0.1 NG 09 November 2007 ;;; version 0.2 NG 17 November 2007 ;;; version 0.3 NG 23 November 2007 (bug: new entrants with zero mortgage) ;;; version 0.4 NG 08 December 2007 (bug: movers not recorded as being in new house; ;;; house prices reduced after no sale; purchasers ;;; only have upper bound limiting offer; ;;; entrants exit after a period if they can't find ;;; a house; realtors add a percentage on to the ;;; average price of local houses in forming their ;;; valuation ;;; version 0.5 NG 02 January 2008 New processes for realtor valuations and for ;;; making offers ;;; version 0.6 NG 26 January 2008 Added affordability, interest rate, house ;;; construction, sliders and code ;;; version 0.61 NG 11 February 2008 Added demolish proc to allow houses to die ;;; version 0.72 NG 24 March 2008 Redid house valuation to allow for quality ;;; version 0.8 JH, NG 4 April 2008 Adjusted initial parameters for more realistic ;;; behaviour ;;; NG 5 April 2008 Added gamma distribution for income, and income ;;; plot ;;; version 0.9 NG 17 April 2008 Added gini coefficient plot, changed display icons ;;; version 0.91 NG 18 April 2008 Added mortgage interest/income plot ;;; version 9.2 NG 19 April 2008 Added time on market plot, v. cheap houses get demolished ;;; version 10.2 NG 26 May 2008 Added gains from investment, re-did paint houses to ;;; use quantiles, ;;; re-did clustering, made sure realtors did not ;;; over-value ;;; version 10.4 NG 22 Jun 2008 Added fake realtor records at setup. Added correct ;;; mortgage interest calculations, ;;; inflation, slider for ticks per year ;;; version 1.1 NG 22 Jun 2008 Up and down shocks now defined in terms of ;;; Affordability, rather than hardwired numbers ;;; adjusted initial valuations to value houses for ;;; sale at start better ;;; version 1.2 NG 17 Jul 2008 Dealt with -ve equity, repayments > income, and ;;; further corrections to handling of mortgages. ;;; General tidy up. This is the version used for the ;;; ESSA paper ;;; version 1.3 NG 5 Sept 2008 1st time buyers get fixed capital ;;; version 1.4 NG 6 Sept 2008 Added initial savings slider and disclaimer ;;; version 1.5 NG 20 Jun 2011 Upgraded to work with NetLogo 1.4.3 ;;; version 1.6 NG 21 Dec 2013 Upgraded to NetLogo 5.0.4 and open sourced under a Creative Commons licence ;;; version 1.61 NG 24 Jan 2013 Corrected bug introduced in upgrading to NL 5.0.4 ;;; version 1.7 深度碎片 2 Oct 2018 corrected bug introduced in upgrading to NL 6.0.4 with many tiny modifications and heavily commented. globals [ ; scenario ; to illustrate various step changes ;; these could become sliders initialVacancyRate ; proportion of empty houses at start nRealtors ; number of realtors min-price-fraction ; if a house price falls below this fraction of the median price, it is demolished ; globally accessible variables (mainly here as globals so that they can be plotted) moves ; number of households moving in this step interestPerTick ; interest rate, after cyclical variation has been applied nUpshocked ; number of owners putting their house for sale because their income has risen nDownshocked ; number of owners putting their house for sale because their income has dropped nDemolished ; number of houses demolished in this step medianPriceOfHousesForSale ; guess! nDiscouraged ;; number of owners who discouraged by homeless and leave the city nExit ;; number of owners who naturally leave the city or cease to exist nEntry ;; number of owners who naturally enter or born into the city nForceOut ;; number of owners whose repayment is greater than income and force to leave nOriginalOwners ;; original number of owners at beginning nOwnersOffered ;; number of owners who made an offer on a house (have enough money and have target to buy) meanIncomeForceOut ;; cal the mean income of all owners who are forced out due to low income to repay mortgage ] breed [houses house ] ; a house, may be occupied and may be for sale breed [owners owner ] ; a household, may be living in a house, or may be seeking one breed [realtors realtor ] ; an estate agent breed [records record ] ; a record of a sale, kept by realtors houses-own [ my-owner ; the owner who lives in this house local-realtors ; the local realtors quality ; index of quality of this house relative to its neighbours for-sale? ; whether this house is currently for sale sale-price ; the price of this house (either now, or when last sold) date-for-sale ; when the house was put on the market my-realtor ; if for sale, which realtor is selling it offered-to ; which owner has already made an offer for this house offer-date ; date of the offer (in ticks) end-of-life ; time step when this house will be demolished ] owners-own [ my-house ; the house which this owner owns income ; current income mortgage ; value of mortgage - reduces as it is paid off capital ; capital that I have accumulated from selling my house repayment ; my mortgage repayment amount, at each tick date-of-purchase ; when my-house was bought made-offer-on ; house that this owner wants to buy homeless ; count of the number of periods that this owner has been ; without a house ] realtors-own [ my-houses ; the houses in my territory sales ; the last few house sales that I have made average-price ; the average price of a house in my territory ] records-own [ ; object holding a realtor's record of a transaction the-house ; the house that was sold selling-price ; the selling price date ; the date of the transaction (in ticks) ] to setup clear-all reset-ticks ;; we can experiment on one of five scenarios (analysis) ;; the choise is given in go procedure ; if scenario = "ltv" [ set MaxLoanToValue 60 ] ; if scenario = "ratefall" [ set InterestRate 3 ] ; if scenario = "influx" [ set EntryRate 10 ] ; if scenario = "poorentrants" [ set MeanIncome 24000 ] ; if scenario = "clusters", continue for 400 steps ;; initialise globals (in code, but there are globals in interface to be initialized as well ) set initialVacancyRate 0.05 set nRealtors 6 ;; original is 6, I shrink the size of agents (all kinds) set maxHomelessPeriod 5 set interestPerTick InterestRate / ( TicksPerYear * 100 ) ;; meaning clarified in note set min-price-fraction 0.1 if scenario = "base-line" [ set Inflation 0 ;; inflation rate 0 or 2 set InterestRate 7 ;; 7 as 7% per year set TicksPerYear 4 ;; 4 ticks = a year set CycleStrength 0 ;; how much variation (0) is introduced to interest rate set Affordability 25 ;; 25% of income can be used to pay for mortgage set Savings 50 ;; 50% of income will be saved set ExitRate 2 ;; 2% of owners will exit city due to death or relocation of job each tick set EntryRate 5 ;; 5% of owners are new comers enter the city each tick set MeanIncome 30000 ;; mean income of whole population is 30000, used to calc each person's income using a gamma distribution set Shocked 20 ;; 20% of whole population will get an income shock (either up or down) set MaxHomelessPeriod 5 ;; maximum duration of homeless any one can stand before exit the city set BuyerSearchLength 10 ;; any buyer will only have patience to shop around maximum 10 houses set RealtorTerritory 8 ;; realtor's territory is a circle with radius equal to 8 units set Locality 3 ;; local neighbors to a house is all the houses within 3 units distance to it set RealtorMemory 10 ;; any record can only live for 10 ticks set PriceDropRate 3 ;; if not sold at current tick, then drop sale-price by 3% set RealtorOptimism 3 ;; when doing a valuation for a house, raise valuation by 3% due to realtor's optimism set Density 70 ;; 70% of land are filled with houses set HouseMeanLifetime 100 ;; the end of life of a house is determined by a exponential distribution using the mean lifetime of all houses (100 years) set MaxLoanToValue 100 ;; maximum mortgage / house sale-price = 100% = 1 set StampDuty? false ;; do not consider StampDuty set MortgageDuration 25 ;; mortgage taks 25 years to repay set HouseConstructionRate 0.33 ;; each tick build new houses equal to 0.33% of current total houses set Income-shock 20 ;; income shock is to rise or fall by 20% set InitialGeography "Random" ;; houses are located randomly, not by gradient nor cluster set price-difference 5000 ;; in cluster mode, consider houses whose price is more than 5000 differ from their neighbor houses, belong to different clusters set scenario "base-line" ;; automatically set all parameters to base line values set initialVacancyRate 0.05 ;; at the very beginning there are 5% of houses are empty set nRealtors 6 ;; there are 6 realtors in the city set min-price-fraction 0.1 ;; when the sale-price of a house drop to 10% of median price of all houses, make this house demolished. set interestPerTick InterestRate / ( TicksPerYear * 100 ) ;; convert interest rate per year to interest rate per tick set house-alpha 251 ;; no transparency set debug-setup "none" set debug-go "none" set exp-options "none" ] ; no-display ;; to make setup run faster, avoid display in process (given continous mode rather than tick mode) ;; 1. patches ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; make the world or land light gray from color swatches ask patches [ set pcolor gray + 3 ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "1 patches" [ inspect patch 1 1 user-message (word "1 patches : loop each patch, paint it muddy green. ") stop-inspecting patch 1 1 ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2 realtors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; create and distribute the realtors (estate agents) set-default-shape realtors "flag" ;; let direction random 360 create-realtors nRealtors [ ;; create one at a time, totally nRealtors set color yellow ; distribute realtors in a rough circle set heading direction jump (max-pxcor - min-pxcor) / 4 ;; jump outward by 1/4 of length of the world set direction direction + 120 + random 30 ; prepare direction of jump for the next realtor set size 1 ;; original 3, here only 1 is visually good ; draw a circle to indicate a realtor's territory draw-circle RealtorTerritory ;; RealtorTerritory is slider global variable ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; if debug? or debug-setup = "2 realtors" [ ; inspect min-one-of realtors [who] ; user-message (word "2 realtors : build realtors with flags, and draw circles as territory ") ; stop-inspecting min-one-of realtors [who] ; ] if exp-options = "realtor" [ ask realtor 0 [ inspect self type "this realtor is just created. " print "" user-message (word "") ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 3 houses;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; create and distribute the houses repeat (count patches * Density / 100) [ build-house ] ;; Density=70% is a slider global variable for houses, 70 houses on 100 patches, use this ratio to create enough houses for this world ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "3 houses" [ inspect max-one-of houses [who] user-message (word "3 houses : build a number of houses. Check which properties are initialized. " ) stop-inspecting max-one-of houses [who] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 4 owners: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; create the owners, one per house set-default-shape owners "dot" ;; all owners are dots let occupied-houses n-of ((1 - initialVacancyRate) * count houses) houses ;; randomly take (1 - initialVacancyRate) proportion of houses to be `occupied-houses` ask occupied-houses [ ;; define each home-owner's properties set for-sale? false ;; since owners living inside, it should not for-sale now hatch-owners 1 [ ;; create an owner inside this house ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; if debug? or debug-setup = "4 owners" [ ; ; inspect self ; inspect one-of houses-here ;; here refers to patch underneath ; ; user-message ( word " 4 owners : it is a bare owner " ) ; ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set color red ;; make owner red set size 0.7 ;; owner easy to see but not too big set my-house myself ;; owner claims its house ask my-house [set my-owner myself ] ;; ask the house to claim its owner assign-income ;; create income and capital for owner if InitialGeography = "Gradient" [ set income income * ( xcor + ycor + 50) / 50 ] ;; income increase from bottom-left to top-right set mortgage income * Affordability / ( interestPerTick * ticksPerYear * 100 ) ;; create mortgage let deposit mortgage * ( 100 / MaxLoanToValue - 1 ) ;; create deposit ask my-house [ set sale-price [mortgage] of myself + [deposit] of myself ] ;; create sale-price = mortgage + deposit for the house set repayment mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; if debug? or debug-setup = "4 owners" [ ; ; user-message (word "4 owners : build an owner, initialize properties to owner and its house. " ) ; ; stop-inspecting self ; stop-inspecting one-of houses-here ; ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] if exp-options = "house" and who = 0 [ type " the house is made occupied by created an owner to it : check for-sale, my-owner" print "" user-message (word "" ) ] ] set nOriginalOwners count owners paint-houses ;; since houses got prices, let's paint houses ;; 5 empty ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; For vacant houses, without owners, those houses have no sale-prices, my-owner properties let ln-min-price precision ln [sale-price] of min-one-of houses with [ sale-price != 0 ] [sale-price] 1 ;; copy ln-min-price from paint-houses let ln-max-price precision ln [sale-price] of max-one-of houses with [ sale-price != 0 ] [sale-price] 1 let median-price median [ sale-price ] of houses with [ sale-price > 0 ] ;; median sale-prices of all houses with owners ask houses with [ sale-price = 0 ] [ ;; loop each empty house if debug? or debug-setup = "5 empty" [ inspect self ;; check bare empty house user-message (word "5 empty : check a bare empty house, to initialize my-owner, sale-price, and color it up " ) ] set my-owner nobody ;; my-owner from 0 to nobody let local-houses houses with [distance myself < Locality and sale-price > 0] ;; find all local houses of the empty house = locality distance and has owner with sale-price ifelse any? local-houses ;; if there exist local houses, [ set sale-price median [ sale-price ] of local-houses ] ;; use local houses median price as the empty house sale-price [ set sale-price median-price ] ;; otherwise, use all occupied houses median price for the empty house sale-price set color palette:scale-scheme "Divergent" "Spectral" 5 (ln sale-price) ln-min-price ln-max-price ;; borrow it from paint-houses to color the empty house if debug? or debug-setup = "5 empty" [ user-message (word "5 empty : No more a bare house, check my-owner, sale-price, and new color. " ) stop-inspecting self ] ] if InitialGeography = "Clustered" [ cluster ] ;; move houses to the neighbors with similar prices ;; 7 quality ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set medianPriceOfHousesForSale median [sale-price] of houses ;; get median price for all houses ask houses [ set quality sale-price / medianPriceOfHousesForSale ;; quality is sale-price/median-price if quality > 3 [set quality 3] if quality < 0.3 [set quality 0.3] ;; quality is between 0.3 to 3 ; set color scale-color magenta quality 0 5 ;; quality by magenta scale ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "7 quality" [ inspect max-one-of houses [ who ] user-message (word "7 quality: initialize quality of house, based on sale-price " ) stop-inspecting max-one-of houses [ who ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 9 realtors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; initialize sales, my-houses, average-price ask realtors [ set sales [] ;; take sales as empty list set my-houses houses with [member? myself local-realtors ] ;; take all houses having the realtor as one of their local-realtors to be my-houses set average-price median [ sale-price ] of my-houses ;; take median price of my-houses to be average-price ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "9 realtors: my-houses, avg-price" [ inspect max-one-of realtors [ who ] user-message (word "9 realtors: initialize sales, my-houses, average-price for realtors ") stop-inspecting max-one-of realtors [ who ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 10 records;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; create records for each and every house ;; at the start, every house is assumed to be sold previously and has a record ;; the house's sale-price is the record's selling-price, ;; my-realtor is set randomly at the start, and this realtor will store the record into its sales list ask houses [ ;; loop each house let the-record nobody ;; `the-record` is nobody hatch-records 1 [ ;; hatch a record from a house if debug? or debug-setup = "10 records" [ inspect myself ;; inspect the current house inspect self ;; inspect the current record user-message (word "10 records : initialize the-house, selling-price for current record; initialize my-realtor for current house; update sales for my-realtor. ") ] hide-turtle ;; hide the current record set the-house myself ;; take the current house to be the-house of the current record set selling-price [ sale-price ] of myself ;; take the sale-price of the house to be selling-price of the current record set the-record self ;; use the-record to carry the current record outside the hatch function into the house context ] set my-realtor one-of local-realtors ;; randomly take one of the local-realtors to be my-realtor of the current house ask my-realtor [ file-record the-record ] ;; ask my-realtor to save the current record (the-record) into sales of my-realtor if debug? or debug-setup = "10 records" [ inspect my-realtor user-message (word "10 records : initialize the-house, selling-price for current record; initialize my-realtor for current house; update sales for my-realtor. ") stop-inspecting self stop-inspecting the-record stop-inspecting my-realtor ] ] ;; to experiment for verification experiments paint-houses display do-plots reset-ticks end ;; create random income and capital for an owner ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to assign-income ;; an owner's income is a random number from a particular gamma distribution ;; an owner's capital is a proportion of income ;; income distribution formula is based on the following paper ;; parameters taken from http://www2.physics.umd.edu/~yakovenk/papers/PhysicaA-370-54-2006.pdf let alpha 1.3 let lambda 1 / 20000 set income 0 ; avoid impossibly low incomes (i.e. less than half the desired mean income) while [ income < MeanIncome / 2 ] [ ;; as long as income is less than half of median income set income (MeanIncome * lambda / alpha ) * (random-gamma alpha lambda) * (1 + (Inflation / (TicksPerYear * 100)) ) ^ ticks ;; redefine income value with this equation (check the paper for details ) ] ; give them a proportion of a year's income as their savings set capital income * Savings / 100 ;; save up money or captial for buying houses every year end ;; 2.5 build-a-house ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; created houses, make sure one patch one house, one house has at least one realtor, house for sale at first, set demolish-time to build-house set-default-shape houses "my-house" ;; I changed the design of a house create-houses 1 [ ; hide-turtle ;; original code, but I don't like house to be hidden set color 35 ;; set house to be brown ;; How to make transparent color ? set color lput house-alpha extract-rgb color ; for speed, dump the house anywhere, check if there is already a house there, ; and if so, move to an empty spot move-to one-of patches if count houses-here > 1 [ ;; if more than 1 houses on the current patch ;; houses-here == turtles-here, check document ; user-message ( word "count houses-here > 1 is true, how many inside houses-here? " count houses-here ) let empty-sites patches with [ not any? houses-here ] ;; ask every patch to see whether it already has a house on it or not, if not consider it an empty-site ; user-message ( word "let empty-sites patches with [ not any? houses-here ], length empty-sites" count empty-sites) ;; debug for details if any? empty-sites [ move-to one-of empty-sites ] ;; if empty-sites exist, let current house move to any one of the empty-site ] ; assign to a realtor or realtors if in their territory set local-realtors realtors with [ distance myself < RealtorTerritory ] ;; if the realtor to the house distance < radius, make the realtor(s) for the house ; if no realtor assigned, then choose nearest if not any? local-realtors [ set local-realtors turtle-set min-one-of realtors [ distance myself ] ] ;; turtle-set to check put-on-market ; initially empty houses are for sale ; note how long this house will last before it falls down and is demolished set end-of-life ticks + int random-exponential ( HouseMeanLifetime * TicksPerYear ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "2.5 build-a-house" [ inspect self user-message ( word "2.5 build-a-house : create a single house, paint it brown, make it transparent, move it a random patch without house, find local-realtors, " word "or just a nearest realtor, put on market for sale, calc end-of-life with random-exponential" "." ) stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] end to put-on-market ;; house procedure ;; show that this house is for sale set for-sale? true set date-for-sale ticks end to draw-circle [radius] ;; the current realtor turtle will create a new turtle to draw a circle as territory ;; draw the circumference of a circle at the given radius hatch 1 [ ;; based on current turtle, let's create/hatch a new turtle which inherit its parent's properties set pen-size 1 set color yellow set heading -90 fd radius ;; set up pen size, color and radius for drawing a circle set heading 0 ;; set the heading to be tanget line direction pen-down while [heading < 359 ] [ rt 1 fd (radius * sin 1) ] ;; drawing a circle, see the debug proof below ; user-message (word "finished drawing circle ? ") ;; yes, this is debugging die ;; end the drawing turtle ] end ;; 11 paint-log-price ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; scale-paint houses according to log of sale-price to paint-houses let min-price precision [sale-price] of min-one-of houses with [ sale-price != 0 ] [sale-price] 1 let ln-min-price precision ln [sale-price] of min-one-of houses with [ sale-price != 0 ] [sale-price] 1 let max-price precision [sale-price] of max-one-of houses with [ sale-price != 0 ] [sale-price] 1 let ln-max-price precision ln [sale-price] of max-one-of houses with [ sale-price != 0 ] [sale-price] 1 ask houses with [ sale-price != 0 ] [ ;; maybe set empty house initial 0 price to "0" ? if debug? or debug-setup = "11 paint-log-price" [ follow-me user-message (word " 11 paint-log-price : loop each house , paint each house with divergent colors based on log sale-prices " ) ] set color palette:scale-scheme "Divergent" "Spectral" 5 (ln sale-price) ln-min-price ln-max-price ; scale-scheme "Divergent" "RdYlBu" 10 ; the number 10 control how many different colors in between, 5 may be the best ; good color options: "Spectral" "RdYlBu" "RdYlGn" ;; ok color options : PiYG PRGn PuOr RdBu RdGy ;; set color scale-color red ln sale-price ln-min-price ln-max-price set color lput house-alpha color ;; add transparency to color if debug? or debug-setup = "11 paint-log-price" [ user-message (word " 11 paint-log-price : loop each house , paint each house with divergent colors based on log sale-prices " ) ] ] end ;; 6 cluster ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to cluster ;; cluster houses together based on price similarity repeat 3 [ ;; cluster all all houses three times paint-houses ;; scale-paint houses based on log sale-price let houses-to-move sort-by [ [ house1 house2 ] -> price-diff house1 > price-diff house2 ] houses ;; new-version ;; reorder every house based on price-difference to its neighbor houses, largest first, smallest last foreach houses-to-move [ ;; loop each house x -> if price-diff x >= price-difference [ ;; if current house price is way too different from its surroundign houses let vacant-plot one-of patches with [ ;; get one of many empty patches, where not any? houses-here and ;; there is no house built abs (local-price - [ sale-price ] of x ) < 1000 ] ;; where the surrounding house prices is similar to the current house if vacant-plot != nobody [ ;; if those empty patches do exist ask x [ ;; ask this current house ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "6 cluster" [ pd set pen-size 2 ;; put pen down to draw a track if is-owner? my-owner [ ask my-owner [ follow-me ] ;; watch the owner ( can't use watch-me here) ] user-message (word "6 cluster : the house move with a track line, the owner is watched. " ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; move-to vacant-plot ;; to move to one of the empty patch if is-owner? my-owner [ ;; whether it got an owner, if so ask my-owner [ move-to myself ] ;; ask the owner move to where the house is ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-setup = "6 cluster" [ user-message (word "6 cluster : the house move with a track line, the owner is watched. " ) pen-up ;; pull pen up ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] ] ] ] ] end ;; find out median price for local houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to-report local-price let local-houses houses-on neighbors ;; based on the current patch, looking for its eight neighbor patches, put all the houses on those patches under `local-houses` ifelse any? local-houses ;; if `loca-houses` is not empty [ report median [sale-price] of local-houses ] ;; report median price of all neighbor houses' sale-prices to be `local-price` [ report 0 ] ;; if no neighbor houses, report 0 to be `local-price` end ;; find out the price difference between a house and its neighbors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to-report price-diff [ a-house ] report abs ([sale-price] of a-house - [local-price] of a-house) ;; Note the use [ local-price ] of a-house end ;; experiment for verification ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to experiments if exp-options = "track-owner-numbers" [ type "nOriginalOwners: " type nOriginalOwners type " owner without house: " type count owners with [not is-house? my-house ] type " nOwnersOffered: " type nOwnersOffered ;; each tick how many owners can afford a targeted house to buy type " owners now: " type (count owners) type " exit: " type nExit type " entry: " type nEntry type " nDiscouraged: " type nDiscouraged type " nForceOut: " type nForceOut print "" ] if exp-options = "track-houses-sales-numbers" [ let sum-sales 0 ask realtors [ set sum-sales sum-sales + length sales] show sum-sales let sum-houses 0 ask realtors [ set sum-houses sum-houses + count my-houses] show sum-houses type "total houses: " type count houses type ", total sales: " type sum-sales type ", total houses under 3 realtors (include duplicated) : " type sum-houses print "" ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to go set nDiscouraged 0 set nExit 0 set nEntry 0 set nForceOut 0 set nOwnersOffered 0 set meanIncomeForceOut 0 ;; get mean income of owners who are forced out if debug? or debug-go = "s0 go-structure" [ user-message (word "s0 go-structure : set simulation duration, half time bring in a scenario, one step per go, 3 conditions to stop simulation. Now let's run! ") ] ;; basic loop if ticks > 400 [ print "Finished: 400 ticks reached " stop ] if ticks = 200 [ if scenario = "ltv" [ set MaxLoanToValue 60 ] if scenario = "raterise 3" [ set InterestRate 3 ] if scenario = "raterise 7" [ set InterestRate 7 ] if scenario = "raterise 10" [ set InterestRate 10 ] if scenario = "influx" [ set EntryRate 10 ] if scenario = "influx-rev" [ set EntryRate 5 ] if scenario = "poorentrants" [ set MeanIncome 24000 ] type "We are at middle of simulation duration, ticks = " type ticks type ", a shock event coming in := " type scenario print ";" ] set nOwnersOffered 0 step ;; do one time step (a quarter of a year?) if not any? owners [ user-message(word "Finished: no remaining people" ) stop ] ;; stop if no owners or houses left if not any? houses [ user-message(word "Finished: no remaining houses" ) stop ] do-plots ;; update the plots ;; experiment for verification experiments tick ;; advance the clock end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to step ;; each time step... ;; count total number of owners ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let n-owners count owners ;; take a count of total owners at the moment ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s1 count-owners" [ user-message (word "s1 count-owners : to start, count total number of all owners = " n-owners) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; calc interest per tick ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; add an exogenous cyclical interest rate, if required: varies around mean of ; the rate set by slider with a fixed period of 10 years set interestPerTick InterestRate / ( TicksPerYear * 100 ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s2 interestPerTick" [ user-message ( word "s2 interestPerTick : from interest per year to interest per tick" ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; add cyclical variation to interest ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if CycleStrength > 0 [ set interestPerTick interestPerTick * (1 + (CycleStrength / 100 ) * sin ( 36 * ticks / TicksPerYear )) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s3 interest-Cycle" [ user-message (word "s3 interest-Cycle : add cyclical influence to interestPerTick. see the figure. " ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; inflation drive up income ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; add inflation to salary, at inflation rate / TicksPerYear if Inflation > 0 [ ask owners [ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s4 inflation-income" [ inspect self user-message ( word "4 inflation-income : inflation will drive up income accordingly. " precision income 1) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set income income * (1 + Inflation / ( TicksPerYear * 100 )) ;; every tick, income stay the same or varied by inflation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s4 inflation-income" [ user-message ( word "s4 inflation-income : inflation will drive up income accordingly. " precision income 1) stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] ] ;; get all the owners with houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let owner-occupiers owners with [ is-house? my-house ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s5 owner-occupiers" [ user-message ( word "s5 owner-occupiers : bring all owners with houses under variable `owner-occupiers`. the count = " count owner-occupiers ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; introduce income rise and fall shock to owners ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let shocked-owners n-of (Shocked / 100 * count owner-occupiers ) owner-occupiers ;; gather Shocked% of `owner-occupiers` under `shocked-owners` let upshocked n-of (count shocked-owners / 2) shocked-owners ;; gather half of `shocked-owners` under `upshocked` set nUpShocked 0 ;; initialize the number of upshocked owners under `nUpShocked` ask upshocked [ set income income * (1 + income-shock / 100) ] ;; ask each `upshocked` to increase income by 20% let downshocked shocked-owners with [ not member? self upshocked ] ;; gather the non-upshocked as down shocked owners under `downshocked` set nDownShocked 0 ;; initialize the number of upshocked owners under `nUpShocked` ask downshocked [ set income income * (1 - income-shock / 100 ) ] ;; ask each downshocked to drop income by 20% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s6 income-shock" [ user-message ( word "s6 income-shock : each tick, a Shocked% of home-owners got income shock = " Shocked word "; half income rise income-shock% the other drop income-shock% = " income-shock ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; income-shock intrigers some owners to sell houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; after income shock, which type of owners will sell houses due to income rise, and which type of owners sell houses due to income drop ask owner-occupiers with [ not [for-sale?] of my-house ][ ;; ask all home-owners whose house is not for sale (in setup, all home-owners don't sell houses) let ratio repayment * TicksPerYear / income ;; put yearly-repayment / income under `ratio` if ratio < Affordability / 200 [ ;; if ratio < half of Affordability %, meaning yearly-repayment is easy and owner is rich ask my-house [ put-on-market ] ;; ask owner's house to put on the market for sale set nUpShocked nUpShocked + 1 ;; add 1 to `nUpShocked`, meaning one more owner selling house due to income rise ] if ratio > Affordability / 50 [ ;; if ratio > 2 * Affordability % , meaning yearly-repayment is way to heavy for owners to bear, owner is poor ask my-house [ put-on-market ] ;; ask owner's house to put on the market for sale set nDownShocked nDownShocked + 1 ;; add 1 to `nDownShocked`, meaning one more owner selling house due to income drop ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s7 shock-sale" [ user-message ( word "s7 shock-sale : after income-shock, only owners whose repayment < half of affordability, will put house on sale due to income rise; " word " only owners whose repayment > twice of affordability, will put house on sale due to income drop " "." )] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; owners die or leave naturally ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; every tick, a proportion of owners put their houses on the market and leave town ask n-of (ExitRate * n-owners / 100) owners with [ is-house? my-house ] [ ;; ask randomly select (ExitRate% of all owners) number of home-owners to do ... ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s8 owners-gone" [ inspect self inspect my-house user-message ( word " s8 owners-gone : watch this owner to sell and leave. " word " it is one of = " round (ExitRate * n-owners / 100) )] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ask my-house [ put-on-market ;; put itself on market set my-owner nobody ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s8 owners-gone" [ user-message (word " watch the changes " ) stop-inspecting self stop-inspecting my-house ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set nExit nExit + 1 die ] ;; new comers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; a fixed number of new comers enter the city repeat EntryRate * n-owners / 100 [ ; create-owners EntryRate * n-owners / 100 [ ;; create a fixed proportion of new owners create-owners 1 [ set color gray ;; gray set size 1 ;; to make new comers differ from other owners ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s9 new-comers" [ inspect self ;; inspect one of new comer follow-me ;; watch it user-message (word "s9 new-comers : create a new comer and watch its properties " ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set size 0.7 ;; make them visible but not too big assign-income ;; initialize income and capital hide-turtle ;; new comers have no houses, so they are nowhere to be seen ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s9 new-comers" [ user-message (word "s9 new-comers, now it is hidden. " ) stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set nEntry nEntry + 1 ] ] ;; discouraged-leave ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; if an owner without home for too long, it will move out of city if MaxHomelessPeriod > 0 [ ; meaning if this value is set ask owners with [ not is-house? my-house ] [ ;; ask each owner without a house set homeless homeless + 1 ;; count the owner's homeless duration if homeless > maxHomelessPeriod [ ;; if homeless duration is beyond limit, this owner will move out of the city (agent die) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s10 discouraged-move-away" [ inspect self user-message ( word " this owner's homeless duration is " homeless ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set nDiscouraged nDiscouraged + 1 die ] ] ] ;; income < repayment, house taken, and owner force leave ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let total-drop-sale count owner-occupiers with [ [for-sale?] of my-house and repayment * TicksPerYear > income ] ;; get all home-owners whose houses are on-sale and whose yearly-repayment is larger than income, and count the number `total-drop-sale` let ForceOut owner-occupiers with [ [for-sale?] of my-house and ;; get all home-owners whose houses are on-sale and repayment * TicksPerYear > income ] ;; whose yearly-repayment is larger than income set nForceOut count ForceOut ;; count the number of owners have forced out of city ; meanIncomeForceOut ;; get their mean income ask ForceOut [ ;; ask each of the forced out people ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s11 drop-sale" [ user-message (word "s11 drop-sale : this owner's yearly repayment = " (repayment * 4 ) word ", the owner's income is only " income word ", this owner can't repay mortgage, forced out" ". " ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ask my-house [ set my-owner nobody ] ;; ask its house to set owner to be nobody set meanIncomeForceOut meanIncomeForceOut + income ;; to sum up all income of the owners who are forced out die ;; ask the owner to die ] ifelse nForceOut > 0 [ set meanIncomeForceOut meanIncomeForceOut / nForceOut ] [ set meanIncomeForceOut 0] ;; take the mean ; if meanIncomeForceOut > 0 [user-message( word " meanIncomeForceOut " meanIncomeForceOut ) ] ;; some new houses are built, and put up for sale ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; repeat count houses * HouseConstructionRate / 100 [ ;; build a fixed proportion of new houses if any? patches with [ not any? houses-here ] [ ;; patches with [ not any? houses-here ] = patches where there are no houses on them ;; any? patches with = do these patches exist or not ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s12 new-houses" [ user-message (word "s12 new-houses : as long as there is an empty land, build a house, until the number is met. " floor (count houses * HouseConstructionRate / 100) ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; build-house ;; this function will automatically find an empty land to build a house on ] ] ;; update 0-quality houses to [0.3, 3] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ask houses with [ quality = 0 ] [ ;; ask each house with quality = 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s13 remove-0-quality" [ inspect self user-message (word "s13 remove-0-quality : see the quality changes. In total 0-quality houses number = " count houses with [ quality = 0 ] )] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let houses-around-here other houses in-radius Locality ;; put ( the other houses which are within the radius circle where the current house is the center ) under `houses-around-here` set quality ifelse-value any? houses-around-here ;; if `houses-around-here` exist, then return first value to `quality` [ mean [ quality ] of houses-around-here ] [ 1 ] ;; if `houses-around-here` exist, then return second value to `quality` if quality > 3 [set quality 3] ;; quality has upper limit to be 3 if quality < 0.3 [set quality 0.3] ;; quality has lower limit to be 0.3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s13 remove-0-quality" [ user-message (word "s13 remove-0-quality : see the quality changes. ") stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] ;; value-houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; initially, house sale-price is added up by mortgage and deposit in setup ;; once a house put on sale, sale-price, my-realtor (house) , average-price (realtor), median price for all houses on sale, are to be updated. let houses-for-sale houses with [ for-sale? ] ;; find all the houses for sale if any? houses-for-sale [ ;; if these houses exist ask houses-for-sale with [ date-for-sale = ticks ] [ ;; ask each of those houses which are just on sale from now on ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s14 value-houses" [ inspect self user-message (word "s14 value-houses : valuation current house, compare changes of house and realtor properties. ")] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set my-realtor max-one-of local-realtors [ valuation myself ] ;; set the realtor gives the current house the highest valuation to be my-realtor set sale-price [ valuation myself ] of my-realtor ;; take the highest value valuation price as sale-price of the current house ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s14 value-houses" [ user-message (word "s14 value-houses : sale-price, my-realtor are updated. ") stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] ; update the average-price of each realtor ask realtors [ ;; ask each realtor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s15 realtor-average-price" [ inspect self user-message (word "s15 realtor-average-price : update realtor's average-price. " )] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let my-houses-for-sale houses-for-sale with [ member? myself local-realtors ];; get all houses under this realtor if any? my-houses-for-sale [ set average-price median [ sale-price ] of my-houses-for-sale ] ;; if these houses exist, take their median price as the realtor's average-price for its all houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s15 realtor-average-price" [ user-message (word "s15 realtor-average-price : average-price is updated. ") stop-inspecting self ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] set medianPriceOfHousesForSale median [sale-price] of houses-for-sale ;; update median price of all houses on sale ] paint-houses ;; update colors after prices are updated ;; make an offer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; owners without houses or whose houses are on-sale, can make offers to other houses on sale let buyers owners with [ not (is-house? my-house) or ([ for-sale? ] of my-house) ] ;; put all owners who don't have a house or whose houses on sale under `buyers` ask owners with [ not (is-house? my-house) ] [ ;; ask each owner who has no house to make an offer on `houses-for-sale` make-offer houses-for-sale ] ask owners with [ (is-house? my-house) and ([ for-sale? ] of my-house) ] [ ; and now those who do have a house to sell get a chance to make an offer on `houses-for-sale` make-offer houses-for-sale ] set nOwnersOffered count owners with [is-house? made-offer-on ] ;; count the number of owners who has an affordable house to buy ;; move into new houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; if a deal is made, then households will move in and out of houses set moves 0 ;; the number of households moving in this step ask buyers with [ not is-house? my-house and is-house? made-offer-on ] [ ;; ask buyers who have no houses and made offer on a house if follow-chain self [ ;; self is buyer, and check whether the buy-sell chain is intact or not move-house ;; if intact, deal is made, and households move out and into houses, count the number of moves ] ] ; if debug? or debug-go = "34 follow-chain" [ ; user-message (word "34 follow-chain, step 22 : check whether the buy-sell houses mechanism is intact or not. " ; word "1. if buyer's `made-offer-on` is not house (meaning buyer buy nothing, no deal), report false; " ; word "2. given the buyer offered on a real house, then set `my-owner` of the house being offered on to be `seller`; " ; word "3. if the `seller` is not an `owner` (meaning the house is vacant, deal right away ), report true; " ; word "4. given `sell` is an owner, if the input `buyer` = `seller`, then the flow is intact, This is confusing, but don't be. The following line solve the problem. " ; word "5. given the buyer is not the seller (no match), now let's focus on the seller, run follow-chain under seller context, meaning we are finding the owner of house which the seller made an offer on; " ; word "if the buyer and the seller of the house the older sell want to buy are the same owner, then both buyer and older seller match a deal." "so the flow is intact. " ; ) ;] ; if debug? or debug-go = "35 move-house" [ ; user-message (word "35 move-house, step 23 : move me to the house I am buying, then move the seller to their new house etc. " ; word "1. under context of buyer or owner, save `made-offer-on` into `new-house`; " ; word "2. if the `new-house` is not house, meaning buyer is not buying, then stop moving; " ; word "3. assign `my-owner` of `new-house` into `seller`; " ; word "4. if seller is an owner, calc the profit made by selling the house: " ; word "assign (sale-price - mortgage) to `profit`, and set seller's mortgage to 0; " ; word "If sell made a profit, then add profit into seller's capital. " ; word "5. since deal is made, change new-house owner to the buyer; " ; word "6. calc the duty payable with the new house sale-price; " ; word "7. if the owner can't pay for the house in cash, s/he has to have a mortgage, " ; word "borrow as much as possible, given owner's income and value of house, choose the smaller value of two calc formula; " ; word "8. after paying rest with capital, the remaining still kept inside capital. " ; word "9. calc repayment to pay back mortgage; " ; word "10. or if the buyer is a cash buyer, capital pays all, mortgage, repayment both are 0; the remaining still kept in capital " ; word "11. if buyer's capital is not enough for downpayment, set the negative remaining to 0; but this no enuogh capital for down-payment should not happen, why here? " ; word "12. new entrants are now made visible, and move buyer to its new house, set buyer's homeless period to 0; " ; word "13. set buyer's `my-house` to be the `new-house`, record the current ticks when the house is bought as `date-of-purchase`; " ; word "14. ask each new-house to put off market and make `offered-to` as nobody; " ; word "15. under buyer's context, buyer is not making any offer now; create a new record under the buyer context; " ; word "16. make record invisible, record current ticks to be the `date` of record, assign the current `new-house` to be `the-house` of record; " ; word "17. assign the `sale-price` of new-house to be `selling-price` of record; ask the new-house realtor to save record into its sales list; " ; word "18. count 1 more moving household into `moves`; if sell as owner exist, then ask seller to move-house too" "." ; ) ; ] ;; remove old record ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; after certain period, all old records should be removed, realtors will remove all their sales ask records [ if date < (ticks - RealtorMemory) [ die ] ] ;; for each record, after RealtorMemory duration, it has to be removed ask realtors [ set sales remove nobody sales ] ;; ask realtors to remove dead records from the sales list ;; remove offers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; remove the offer information upon a house ask houses with [ is-owner? offered-to ] [ ;; for each of the houses which have owners/buyer to make offer on ask offered-to [ set made-offer-on nobody ] ;; ask each buyer to set property `made-offer-on` as nobody set offered-to nobody ;; set the house's buyer property `offered-to` to be nobody set offer-date 0 ;; set house property `offer-date` to 0 ] ;; demolish houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;demolish old houses or houses with below minimum price set nDemolished 0 ;; record the number of demolished houses at each tick if any? records [ ;; if there are records left let minimum-price min-price-fraction * medianPriceOfHousesForSale ;; set minimum-price to be 10% of all sold-houses median price ask houses with [ (ticks > end-of-life) or ;; ask all houses, if its life is over its life limit or (for-sale? and sale-price < minimum-price )] ;; if the house is for sale and sale-price < minimum-price [ demolish ] ;; let's demolish the house ] ; if debug? or debug-go = "36 remove-records-offers-houses" [ ; user-message (word "36 remove-records-offers-houses, step 24 : after certain period, all old records should be removed, realtors will remove all their sales: " ; word "1. since the record is created, after RealtorMemory duration (update is needed now), ask all records to die; " ; word "2. ask realtors to remove dead records from the sales list. " ; word "Next, remove the offers to houses : 1. for each of the houses which have owners/buyer to make offer on, " ; word "ask each buyer to set property `made-offer-on` as nobody, set the house's buyer property `offered-to` to be nobody, " ; word "set house property `offer-date` to 0. Finally, demolish old houses or houses with below minimum price. " ; word "1. use this variable to record the number of houses demolished; if there are records left, set minimum-price to be 10% of all sold-houses median price; " ; word "2. ask all houses, if its life is over its life limit or if the house is for sale and sale-price < minimum-price, let's demolish the house" "." ; ) ; ] ;; reduce or update sale-prices of unsold houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; reduce sale-price is a house is not sold in each tick ask houses with [ for-sale? ] [ ;; ask all houses which still are for sale set sale-price sale-price * (1 - PriceDropRate / 100 );; to reduce its sale-price by certain amount ] ;; update owners' mortgage and repayment in each tick ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ask owners with [ is-house? my-house and mortgage > 0 ] [ ;; ask all owners who do have houses and mortgage to pay set mortgage mortgage - ( repayment - interestPerTick * mortgage );; mortgage will be reduced due to repayment if mortgage <= 0 [ ;; if mortgage is fully repaid, then set both mortgage and repayment to 0 set mortgage 0 set repayment 0 ] ] ; if debug? or debug-go = "37 update-house-owner" [ ; user-message( word "37 update-house-owner, step 25 : update houses sale-price 1. ask all houses which still are for sale, " ; word "to reduce its sale-price by certain amount. Now, update owners' mortgage and repayment : " ; word "1. ask all owners who do have houses and mortgage to pay, mortgage will be reduced due to repayment; " ; word "2. if mortgage is fully repaid, then set both mortgage and repayment to 0" "." ; ) ; ] ; if debug? or debug-go = "38 demolish" [ ; user-message (word "38 demolish, step 26 : let demolish the house and everything associate it. " ; word "1. under the context of the house, check the household is owner or not, if it is owner, set my-house nobody, " ; word "set mortgage and repayment to 0, set the owner invisible, meaning the owner is homeless; " ; word "2. delete any record that mentions the house inside the sales of a realtor, set the land to be muddy green, " ; word " add 1 upon nDemolished, make the house die" "." ; ) ;] end ;; valuation house price by realtor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to-report valuation [ property ] ;; realtor procedure let normalization 1 ;; create a local variable normalization let multiplier [ quality ] of property * ;; create a multiplier for final finish of valuation price (1 + RealtorOptimism / 100) * normalization ;; component of multiplier include quality, optimism, normalization ; let local-sales (turtle-set sales) with [ ( [distance property ] of the-house ) < Locality ] ;; old-version let local-sales (turtle-set sales) with [ the-house != nobody and ( [distance property ] of the-house ) < Locality ] ;; new-version ;; under realtor context, sales is a list of records, use `turtle-set` force list into an agentset to use with, each record has property of the-house ;; get all the sales (lists of records) whose houses are sold and those sold-houses are neighboring to the input house under `local-sales` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if any? local-sales and ( debug? or debug-go = "s18 valuation 1" ) [ ask property [ set size 2 ] ask local-sales [ ask the-house [ set pcolor pink ] ] user-message (word "s18 valuation 1 : identify neighboring and sold houses. Enlarge them. ") ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; let old-price [sale-price] of property ;; set the input house's sale-price as old price let new-price 0 ;; create a new price variable with 0 value ifelse any? local-sales ;; if the local-sales exist [ set new-price median [ selling-price ] of local-sales ] ;; assign the median price of all record houses to new-price [ let local-houses houses with [ distance myself <= Locality ];; if no local-sales exist, take neighboring houses around the current realtor under `local-houses` ifelse any? local-houses ;; if local-houses exist [set new-price median [sale-price] of local-houses ;; set the median price of all local-houses to be new-price ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s19 valuation 2" [ ask property [ set size 3 ] ask self [ set color red ] ask local-houses [ set pcolor pink ] user-message (word "s19 valuation 2 : identify neighboring houses to the realtor. Display them. ") ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] [set new-price average-price ] ;; otherwise set average-price of the realtor to be new-price (is realtor's average-price updated every tick?) ] if old-price < 5000 [ report multiplier * new-price ] ;; if current sale-price is too low, just accept multiplier * new-price as valuation price let ratio new-price / old-price ;; compare calc ratio between new-price and old-price let threshold 2 ;; a base line for ratio ifelse ratio > threshold ;; [ set new-price threshold * old-price ] ;; if new-price is more than twice old-price, make new-price twice of old-price. " [ if ratio < 1 / threshold [ set new-price old-price / threshold ] ] ;; if new-price is less than half of old-price, make new-price half of old-price. report multiplier * new-price ;; finally report multiplier * new-price" "." end ;; make offer on houses on sale ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to make-offer [ houses-for-sale ] let new-mortgage income * Affordability / ( interestPerTick * ticksPerYear * 100 );; use current income, Affordability, interestPerTick to calc new-mortgage let budget new-mortgage - stamp-duty-land-tax new-mortgage ;; actual budget for buying a house == new-mortgage - duty or tax we get back let deposit capital ;; buyer use capital to pay for new deposit if is-house? my-house [ set deposit deposit + ([ sale-price ] of my-house - mortgage) ] ;; under the context of owners, if it has a house, update new deposit with new deposit + sale-price of current house - current mortgage let upperbound budget + deposit ;; upperbound = the maximum amount afford to offer on a house = new mortgage - duty-back + new deposit if MaxLoanToValue < 100 [ ;; if mortgage is less than house value => (MaxLoanToValue/100 < 100/100 ) set upperbound min ( list (budget + deposit ) ( deposit / ( 1 - MaxLoanToValue / 100 ))) ;; update upperbound with the less between two similar values ] if upperbound < 0 [ ;; if upperbound is less than 0, meaning the owner has negative equity (how it is possible?) ask my-house [ set for-sale? false ] ;; pull the house back from market, and stay in the house stop ;; this owner stop performing the rest action below ] let lowerbound upperbound * 0.7 ;; set lowerbound to be 70% of upperbound let current-house my-house ;; get the current owner's my-house under `current-house` let interesting-houses houses-for-sale with [ ;; from all the houses on sale, get those not is-owner? offered-to and ;; without offer sale-price <= upperbound and ;; and sale-prices within upperbound sale-price > lowerbound and ;; and sale-prices greater than lowerbound self != current-house ] ;; and the house is not current house, ---> into `interesting-houses` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s20 make-offer part1" [ ask interesting-houses [ set size 2 ] user-message (word "s20 make-offer part1, identify the interesting houses buyers may make an offer. See the enlarged houses. " ) ask interesting-houses [ set size 1 ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if count interesting-houses > BuyerSearchLength [ ;; if number of interesting-houses > BuyerSearchLength (number of houses buyers willing to see) set interesting-houses n-of BuyerSearchLength interesting-houses ;; then select randomly BuyerSearchLength number of interesting-houses ] if any? interesting-houses [ ;; if interesting-houses exist let property max-one-of interesting-houses [ sale-price ] ;; find the house with the maximum sale-price of interesting-houses and assigned to `property` a local-var if is-house? property [ ;; if the `property` is a house ask property [ ;; ask this house set offered-to myself ;; assign the current owner as `offered-to` under the context of `property` set offer-date ticks ;; set `ticks` to be `offer-date` (house property) ] set made-offer-on property ;; assign `property` (a house ) to owner's property `made-offer-on` ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if debug? or debug-go = "s21 make-offer part2" [ ask property [ follow-me ] user-message (word "s21 make-offer part2 : choose from interesting houses and make an offer on the most expensive house, and update its `offered-to` and `offer-date`." ) ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ] end ;; set three duty return thresholds ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to-report stamp-duty-land-tax [ cost ] ;; stamp duty land tax ('stamp duty') is 1% for sales over $150K, 3% over $250K, 4% over $500K, (see http://www.hmrc.gov.uk/so/rates/index.htm ) if StampDuty? [ if cost > 500000 [ report 0.04 * cost ] if cost > 250000 [ report 0.02 * cost ] if cost > 150000 [ report 0.01 * cost ] ] report 0 end ;; whether buy-sell flow is intact or not ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to-report follow-chain [ first-link ] ;; first-link is an owner too ;; two ways to be intact : 1. a house on-sale without a seller (buy a total new house or house without owner) ;; 2. the buyer of house A is the owner of house B which is made an offer by seller (switch houses with the other person ) ; inspect self inspect first-link ; user-message (word " if not is-house? made-offer-on [ report false ], and condition is " not is-house? made-offer-on ) if not is-house? made-offer-on [ report false ] ;; if buyer's made-offer-on is not house (meaning buyer buy nothing, no deal), report false let seller [ my-owner ] of made-offer-on ;; given the buyer offered on a real house, then set `my-owner` of the house being offered on to be `seller` ; user-message ( word "if not (is-owner? seller ) [ report true ], can condition is " not is-owner? seller ) ; stop-inspecting self stop-inspecting first-link if not (is-owner? seller ) [ report true ] ;; if the `seller` is not an `owner` (meaning the house is vacant, deal right away ), report true ; inspect first-link inspect seller user-message (word " check first-link with id " [who] of first-link word "check seller with id " [who] of seller ) if first-link = seller [ report true ] ;; given `sell` is an owner, if `first-link` and `seller` are the same owner, then the flow is intact. ;; This is confusing, but don't be. The following line solve the problem. ; stop-inspecting first-link stop-inspecting seller report [follow-chain first-link ] of seller ;; given the buyer is not the seller (no match), now let's focus on the seller, run follow-chain under seller context, ;; meaning we are finding the owner of house which the seller made an offer on. ;; if the buyer and the seller of the house the older sell want to buy, are the same owner, then both buyer and older seller match a deal. flow is intact. end ;; buyers are moving into new houses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to move-house ;; move me to the house I am buying ;; then move the seller to their new house etc. let new-house made-offer-on ;; under context of buyer or owner, save `made-offer-on` into `new-house`; if not (is-house? new-house) [ stop ] ;;if the `new-house` is not house, meaning buyer is not buying, then stop moving; let seller [ my-owner ] of new-house ;; assign `my-owner` of `new-house` into `seller` if is-owner? seller [ ;; if seller is an owner, calc the profit made by selling the house ; seller gets selling price to pay off mortgage or add to capital let profit [ sale-price ] of new-house - [ mortgage ] of seller ;; assign (sale-price - mortgage) to `profit` ask seller [ set mortgage 0 ] ;; set seller's mortgage to 0 if profit > 0 [ ; If sell made a profit, then add profit into seller's capital. ask seller [ set capital capital + profit ] ] ] ask new-house [ set my-owner myself ] ;; since deal is made, change new-house owner to the buyer let duty stamp-duty-land-tax [ sale-price ] of new-house ;; calc the duty payable with the new house sale-price ; if duty > 0 [user-message(word "duty" duty)] ifelse [ sale-price ] of new-house > capital ;; if the owner can't pay for the house in cash, s/he has to have a mortgage [ ; borrow as much as possible, given owner's income and value of house, choose the smaller value of two calc formula set mortgage min (list (income * Affordability / ( interestPerTick * ticksPerYear * 100 )) ([ sale-price ] of new-house * MaxLoanToValue / 100 )) set capital capital - int ([ sale-price ] of new-house - mortgage) - duty ;; after paying rest with capital, the remaining still kept inside capital set repayment mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) ;; calc repayment to pay back mortgage ] ; or if the buyer is a cash buyer, capital pays all, mortgage, repayment both are 0, and remaining still kept in capital [ set mortgage 0 set repayment 0 set capital capital - [ sale-price ] of new-house - duty ] if capital < 0 [ set capital 0 ] ;; if buyer's capital is not enough for downpayment, set the negative remaining to 0. ;; but this no enuogh capital for down-payment should not happen, why here? show-turtle ; new entrants are not visible until now move-to new-house ;; move owner to where the new-house is set homeless 0 ;; set buyer's homeless period to 0 set my-house new-house ;; set buyer's `my-house` to be the `new-house` set date-of-purchase ticks ;; record the current ticks when the house is bought as `date-of-purchase` ask new-house [ ;; ask each new-house to put off market and make `offered-to` as nobody set for-sale? false set offered-to nobody ] set made-offer-on nobody ;; under buyer's context, buyer is not making any offer now ;; create a new record for the new deal, and save it into the house my-realtor sales list hatch-records 1 [ ;; create a new record under the buyer context hide-turtle ;; make record invisible set date ticks ;; record current ticks to be the `date` of record set the-house new-house ;; assign the current `new-house` to be `the-house` of record set selling-price [sale-price] of new-house ;; assign the `sale-price` of new-house to be `selling-price` of record ask [ my-realtor ] of new-house [ file-record myself ] ;; ask the new-house realtor to save record into its sales list ] set moves moves + 1 ;; count 1 more moving household into `moves` if is-owner? seller [ ask seller [ move-house ] ] ;; if sell as owner exist, then ask seller to move-house too end to file-record [ the-record ] ;; realtor procedure ; push this sales record onto the list of those I keep set sales fput the-record sales end to unfile-record [ a-house ] ;; realtor procedure ; delete any record that mentions the house ; set sales filter [ [the-house] of ? != a-house ] sales ;; old-version set sales filter [ s -> [the-house] of s != a-house ] sales ;; new-version ; foreach sales [ x -> if [the-house] of x = a-house [ inspect x user-message ( word " a matched house in sales " ) ; inspect a-house user-message (word "inspect a-house") ] ] ;; debugging end to demolish if is-owner? my-owner [ ;; under the context of the house, check the household is owner or not ask my-owner [ ;; if it is owner, set my-house nobody set my-house nobody set mortgage 0 ;; set mortgage and repayment to 0 set repayment 0 hide-turtle ; set the owner invisible, meaning the owner is homeless ] ] ask realtors [ unfile-record myself ] ;; delete any record that mentions the house inside the sales of a realtor ; set pcolor 57 ;; set the land to be muddy green set nDemolished nDemolished + 1 ;; add 1 upon nDemolished die ;; make the house die end to-report gini-index [ lst ] ;; reports the gini index of the values in the given list ;; Actually returns the gini coefficient (between 0 and 1) - the ;; gini index is a percentage let sorted sort lst let total sum sorted let items length lst let sum-so-far 0 let index 0 let gini 0 repeat items [ set sum-so-far sum-so-far + item index sorted set index index + 1 set gini gini + (index / items) - (sum-so-far / total) ] ; only accurate if items is large report 2 * (gini / items) end to do-plots ;; draw a range of plots ;; plot income mean and median ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot "income averages" set-current-plot-pen "mean" plot mean [income] of owners with [ any? owners ] / 10000 set-current-plot-pen "median" plot median [income] of owners with [any? owners ] / 10000 ;; plot the number all-houses, empty-houses, buyers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; count of total houses, empty houses, owners look for houses, houses with mortgage > sale-price set-current-plot "count houses owners" ;; "Homes" must be defined in the interface set-current-plot-pen "houses" ;; pen and its color must be defined inside interface plot count houses ;; count all houses set-current-plot-pen "population" ;; pen and its color must be defined inside interface plot count owners ;; count all houses set-current-plot-pen "homeowners" ;; pen and its color must be defined inside interface plot count owners with [ is-house? my-house ] ;; count all houses set-current-plot "People In-Out House Demolished" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot-pen "nExit" ;; fixed proportion of owners die or exit the city every tick plot nExit set-current-plot-pen "nEntry" ;; fixed proportion of newcomer enter the city every tick plot nEntry set-current-plot-pen "nDemolished" ;; the number of houses demolished due to too old or price too low plot nDemolished set-current-plot "People-discouraged-forced HousePrice-too-low" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot-pen "nDiscouraged" ;; the number of owners discouraged to leave after being homeless too long plot nDiscouraged set-current-plot-pen "nForceOut" ;; the number of owners can't afford repayment plot nForceOut set-current-plot-pen "nPrice 0 ] if any? houses-for-sale [ ;; if there are houses ready for sales set-current-plot "house for-sale distribution" ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 10000 ;; every time plot with 1000 units as distance set-plot-x-range 0 1000000 ;; set x range from 0 to 1000000 set-current-plot-pen "for-sale" ;; choose the pen named "For sale" histogram [ sale-price ] of houses-for-sale ;; do histogram on sale-prices of all houses for sale set-current-plot "all house price distribution" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 10000 ;; every time plot with 1000 units as distance set-plot-x-range 0 1000000 ;; set x range from 0 to 1000000 set-current-plot-pen "all" histogram [ sale-price ] of houses ;; histogram of all houses set-current-plot "new sale-price distribution" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 10000 ;; every time plot with 1000 units as distance set-plot-x-range 0 1000000 ;; set x range from 0 to 1000000 set-current-plot-pen "new-sales" histogram [ sale-price ] of houses-for-sale with [ date-for-sale = ticks ] ;; histogram of prices of houses currently enter markets ] if any? owners [ set-current-plot "Income distribution for all" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 30000 set-plot-x-range 1000 ifelse-value (max [income] of owners > 1E+5) [ 1E+6 ] [ 1E+5 ] set-current-plot-pen "all" histogram [ income ] of owners ;; histogram of all owerns income set-current-plot "Income distribution for discouraged" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 30000 set-plot-x-range 1000 ifelse-value (max [income] of owners > 1E+5) [ 1E+6 ] [ 1E+5 ] set-current-plot-pen "discouraged" histogram [ income ] of owners with [ homeless >= maxHomelessPeriod - 1 ] ; set-current-plot "Income distribution for forced-out" ; set-plot-pen-interval 30000 ; set-plot-x-range 1000 ifelse-value (max [income] of owners > 1E+5) [ 1E+6 ] [ 1E+5 ] ; set-current-plot-pen "forced-out" ; histogram [ income ] of owners with [ is-house? my-house and [for-sale?] of my-house and repayment * TicksPerYear > income ] set-current-plot "mean income of forced-out with 0-2 owners" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot-pen "forced-out" plot meanIncomeForceOut set-current-plot "Income distribution for house price < mortgage" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-plot-pen-interval 30000 set-plot-x-range 1000 ifelse-value (max [income] of owners > 1E+5) [ 1E+6 ] [ 1E+5 ] set-current-plot-pen "price 0 ] = 0 [ user-message (word "how many owners left ? " count owners )] ;; debug when owners number shrink down to 0 plot mean [ TicksPerYear * repayment / income ] of owners with [ repayment > 0 ] ] ;; plot median sold prices and median owner income ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if any? houses-sold and any? owners[ set-current-plot "Median house price / Median income" plot medianSellingPriceOfHouses / median [ income ] of owners ] ;; plot the median duration of all houses on-sale ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if any? houses-for-sale [ set-current-plot "Median time on market" plot median [ ticks - date-for-sale ] of houses-for-sale ] ;; plot each tick how many houses deals made or moved ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot "Transactions" plot moves ;; plot interest rate and inflation rate ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set-current-plot "Rates" set-current-plot-pen "Interest Rate" plot interestPerTick * TicksPerYear * 100 set-current-plot-pen "Inflation Rate" plot Inflation ;; plot capital distribution of all owners ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if any? owners [ set-current-plot "Capital distribution of all people" set-plot-pen-interval 5000 set-plot-x-range 0 100000 histogram [ capital ] of owners ] end ;; two procedures to enable large numbers of owners to be added to, or removed from the market ;; for experimentation with the model ;; ;; to use, type into the command centre (for example): make-owners 500 ;; to make-owners [ n ] ;; make some new owners arrive create-owners n [ set color gray ; set initial income and savings assign-income ; new owners are not located anywhere yet hide-turtle ] end to kill-owners [ n ] ;; make some owners put their houses on the market and leave town ask n-of n owners with [ is-house? my-house ] [ ask my-house [ put-on-market set my-owner 0 ] die ] end @#$#@#$#@ GRAPHICS-WINDOW 189 37 708 557 -1 -1 15.5 1 15 1 1 1 0 0 0 1 -16 16 -16 16 0 0 1 ticks 30.0 TEXTBOX 18 10 168 38 PwC Housing Market model\nversion 1.7 11 0.0 1 TEXTBOX 8 42 158 60 ---Macro-economy --- 9 0.0 1 SLIDER 3 56 175 89 Inflation Inflation 0 20 0.0 0.1 1 % pa HORIZONTAL SLIDER 3 91 175 124 InterestRate InterestRate 0 20 7.0 0.1 1 % pa HORIZONTAL SLIDER 3 125 175 158 TicksPerYear TicksPerYear 0 12 4.0 1 1 NIL HORIZONTAL SLIDER 3 159 175 192 CycleStrength CycleStrength 0 80 0.0 5 1 % HORIZONTAL TEXTBOX 7 206 157 224 --- Owners --- 10 0.0 1 SLIDER 5 222 177 255 Affordability Affordability 0 100 25.0 1 1 % HORIZONTAL SLIDER 5 256 177 289 Savings Savings 0 100 50.0 1 1 % HORIZONTAL SLIDER 5 290 177 323 ExitRate ExitRate 0 10 2.0 1 1 % HORIZONTAL SLIDER 5 324 177 357 EntryRate EntryRate 0 10 5.0 1 1 % HORIZONTAL SLIDER 5 358 177 391 MeanIncome MeanIncome 0 100000 30000.0 1000 1 pa HORIZONTAL SLIDER 6 393 178 426 Shocked Shocked 0 100 20.0 1 1 % HORIZONTAL SLIDER 6 427 178 460 MaxHomelessPeriod MaxHomelessPeriod 0 10 5.0 1 1 ticks HORIZONTAL TEXTBOX 9 461 159 479 0 means no limit 8 0.0 1 SLIDER 6 470 178 503 BuyerSearchLength BuyerSearchLength 0 100 10.0 1 1 NIL HORIZONTAL TEXTBOX 7 505 157 523 ---Realtors--- 10 0.0 1 TEXTBOX 6 194 156 212 10 year exogenous interest rate cycle 8 0.0 1 SLIDER 6 518 178 551 RealtorTerritory RealtorTerritory 0 50 8.0 1 1 NIL HORIZONTAL SLIDER 7 553 179 586 Locality Locality 0 10 3.0 1 1 NIL HORIZONTAL SLIDER 7 587 179 620 RealtorMemory RealtorMemory 0 10 10.0 1 1 ticks HORIZONTAL SLIDER 7 622 179 655 PriceDropRate PriceDropRate 0 10 3.0 1 1 % HORIZONTAL SLIDER 7 656 179 689 RealtorOptimism RealtorOptimism -10 10 3.0 1 1 % HORIZONTAL TEXTBOX 207 658 357 680 ---Houses--- 10 0.0 1 CHOOSER 712 451 883 496 InitialGeography InitialGeography "Random" "Gradient" "Clustered" 0 SLIDER 205 616 377 649 Density Density 0 100 70.0 1 1 % HORIZONTAL SLIDER 623 614 886 647 HouseConstructionRate HouseConstructionRate 0 1 0.33 0.01 1 % per tick HORIZONTAL SLIDER 377 575 544 608 HouseMeanLifetime HouseMeanLifetime 1 500 100.0 1 1 years HORIZONTAL SLIDER 379 616 547 649 MaxLoanToValue MaxLoanToValue 0 125 100.0 1 1 % HORIZONTAL SLIDER 718 578 885 611 MortgageDuration MortgageDuration 0 100 25.0 1 1 years HORIZONTAL SWITCH 591 578 720 611 StampDuty? StampDuty? 1 1 -1000 BUTTON 713 277 783 310 SETUP setup NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 713 311 782 344 Go go T 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 713 345 784 378 One Tick go NIL 1 T OBSERVER NIL NIL NIL NIL 1 PLOT 2066 310 2445 430 count houses owners time Number 0.0 0.0 750.0 0.0 true true "" "" PENS "houses" 1.0 0 -4079321 true "" "" "population" 1.0 0 -5298144 true "" "" "homeowners" 1.0 0 -13840069 true "" "" PLOT 1611 36 2037 188 all house price distribution Price Number 0.0 100.0 0.0 20.0 true false "" "" PENS "all" 1.0 1 -16777216 true "" "" PLOT 1589 497 2081 678 median sale vs sold price time NIL 0.0 10.0 60000.0 80000.0 true true "" "" PENS "For sale" 1.0 0 -5298144 true "" "" "Sold" 1.0 0 -13345367 true "" "" PLOT 1399 906 1651 1037 Mortgage repayment / income time NIL 0.0 10.0 0.0 1.0 true false "" "" PENS "default" 1.0 0 -16777216 true "" "" PLOT 1155 775 1397 906 Median time on market time ticks 0.0 10.0 0.0 10.0 true false "" "" PENS "default" 1.0 0 -14454117 true "" "" PLOT 1666 915 2068 1035 Rates time % 0.0 10.0 0.0 10.0 true true "" "" PENS "Inflation Rate" 1.0 0 -13345367 true "" "" "Interest Rate" 1.0 0 -14439633 true "" "" PLOT 1157 654 1586 774 Capital distribution of all people NIL Number 0.0 100000.0 0.0 10.0 true false "" "" PENS "default" 1.0 1 -955883 true "" "" PLOT 1155 905 1397 1037 Transactions time Number 0.0 10.0 0.0 10.0 true false "" "" PENS "default" 1.0 0 -16777216 true "" "" PLOT 1397 774 1651 907 Median house price / Median income time NIL 0.0 10.0 0.0 4.0 true false "" "" PENS "p/e" 1.0 0 -5825686 true "" "" PLOT 1666 793 2042 914 Gini index time NIL 0.0 10.0 0.0 1.0 true true "" "" PENS "Incomes" 1.0 0 -16777216 true "" "" "Prices" 1.0 0 -2674135 true "" "" PLOT 2068 584 2411 712 trade house up or down NIL NIL 0.0 0.0 0.0 0.0 true true "" "" PENS "up" 1.0 0 -5298144 true "" "" "down" 1.0 0 -14070903 true "" "" SWITCH 713 381 816 414 debug? debug? 1 1 -1000 CHOOSER 713 38 884 83 debug-setup debug-setup "none" "1 patches" "2 realtors" "2.5 build-a-house" "3 houses" "4 owners" "5 empty" "6 cluster" "7 quality" "9 realtors: my-houses, avg-price" "10 records" "11 paint-log-price" 0 SLIDER 713 417 885 450 price-difference price-difference 1000 10000 5000.0 1000 1 NIL HORIZONTAL CHOOSER 714 87 884 132 debug-go debug-go "none" "s0 go-structure" "s1 count-owners" "s2 interestPerTick" "s3 interest-Cycle" "s4 inflation-income" "s5 owner-occupiers" "s6 income-shock" "s7 shock-sale" "s8 owners-gone" "s9 new-comers" "s10 discouraged-move-away" "s11 drop-sale" "s12 new-houses" "s13 remove-0-quality" "s14 value-houses" "s15 realtor-average-price" "s16 paint-house" "s18 valuation 1" "s19 valuation 2" "s20 make-offer part1" "s21 make-offer part2" "33 deal-move" "34 follow-chain" "35 move-house" "36 remove-records-offers-houses" "37 update-house-owner" "38 demolish" 0 TEXTBOX 197 14 487 42 red dot = existing owners, gray dot = new comers 11 0.0 1 SLIDER 714 135 886 168 house-alpha house-alpha 1 255 251.0 10 1 NIL HORIZONTAL MONITOR 2067 963 2157 1008 tick interest % interestPerTick * 100 2 1 11 MONITOR 2068 918 2155 963 NIL InterestRate 17 1 11 SLIDER 712 499 884 532 income-shock income-shock 0 50 20.0 1 1 % HORIZONTAL CHOOSER 714 169 884 214 scenario scenario "base-line" "raterise 3" "raterise 7" "raterise 10" "influx" "influx-rev" "poorentrants" "ltv" 0 PLOT 1666 671 2032 791 income averages ticks w 0.0 0.0 0.0 0.0 true true "" "" PENS "mean" 1.0 0 -5825686 true "" "" "median" 1.0 0 -13791810 true "" "" CHOOSER 713 216 863 261 exp-options exp-options "none" "track-owner-numbers" "track-houses-sales-numbers" "house" "realtor" 0 PLOT 2066 35 2452 155 People In-Out House Demolished NIL NIL 0.0 10.0 0.0 10.0 true true "" "" PENS "nExit" 1.0 0 -5298144 true "" "" "nEntry" 1.0 0 -13345367 true "" "" "nDemolished" 1.0 0 -11053225 true "" "" PLOT 2066 156 2470 306 People-discouraged-forced HousePrice-too-low NIL NIL 0.0 10.0 0.0 10.0 true true "" "" PENS "nDiscouraged" 1.0 0 -16777216 true "" "" "nForceOut" 1.0 0 -5298144 true "" "" "nPrice