UK Housing ABM Simple UI

UK Housing ABM Simple UI preview image

1 collaborator

Default-person Yahya Gamal (Author)

Tags

finances, economics 

Tagged by Yahya Gamal 4 days ago

housing market 

Tagged by Yahya Gamal 4 days ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.4.0 • Viewed 17 times • Downloaded 1 time • Run 0 times
Download the 'UK Housing ABM Simple UI' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

extensions [palette import-a fetch]
globals[
  setup?              ; at setup phase or not

  interestPerTick     ; interest rate, after cyclical variation has been applied; depends on interest rate and ticks per year
  medianPriceOfHousesForSale ;; median Price Of Houses For Sale
  medianPriceOfHousesForRent ;; median Price Of Houses For Rent

  nupShocked
  ndownShocked
  nUpshockedSell          ; number of owners putting their house for sale because their income has risen
  nDownshockedSell        ; number of owners putting their house for sale because their income has dropped
  nUpshockedRent          ; number of owners putting their house for rent because their income has risen
  nDownshockedRent        ; number of owners putting their house for rent because their income has dropped

  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
  moves               ; number of households moving in this step
  nDemolished

  nForceOutSell           ;; number of owners whose repayment is greater than income and force to leave
  nOwnersOffered      ;; number of owners who made an offer on a house (have enough money and have target to buy)
  meanIncomeForceOutSell  ;; cal the mean income of all owners who are forced out due to low income to repay mortgage
  nForceOutRent           ;; number of owners whose repayment is greater than income and force to leave
  meanIncomeForceOutRent  ;; cal the mean income of all owners who are forced out due to low income to repay mortgage
  nForceInSell
  meanIncomeForceInSell


  nEvictedMortgage           ;; number of evicted owners of type mortgage
  nEvictedRent               ;; number of evicted owners of type rent
  nEnterMarketMortgage       ;; number of owners entering the mortgage market
  nEnterMarketRent           ;; number of owners entering the rent market
  nEnterMarketBuyToLet       ;; number of owners entering the buy-to-let market
  nForceSell                 ;; number of owners forced to put one of their houses on the buy-to-let market
  meanIncomeEvictedMortgage  ;; mean income of evicted owners of type mortgage
  meanIncomeEvictedRent      ;; mean income of evicted owners of type rent

  nEvictedMortgageOneHouse
  nEvictedMortgageMoreHouses

  nHomeless                  ;; number of owners evicted from their houses (does not include owners coming into the system as immigrants)

  visualiseModeCurrent       ;; current used visualisation mode used (prices or types)

  ;; globals added for simplified UI
  medianSalePriceHouses
  medianRentPriceRentHouses
  setup-a
  setup-b

  ;; added for the simplified UI ABM
  ActWhenShocked
  Affordability
  BuyerSearchLength
  calculate-wealth?
  CapitalMortgage
  CapitalRent
  clusteringRepeat
  cooldownPeriodBTL
  cooldownPeriodMortgage
  CycleStrength
  Density
  EntryRate
  eviction-threshold-mortgage
  eviction-threshold-rent
  ExitRate
  FullyPaidMortgageOwners
  HouseConstructionRate
  HouseMeanLifetime
  income-shock
  InitialGeography
  Initialisation
  initialOccupancy
  investors


  Locality
  MaxForRentPeriodPoorLandlord
  MaxHomelessPeriod

  MaxRateDurationBTL
  MaxRateDurationM

  min-price-fraction
  MinRateDurationBTL
  MinRateDurationM



  new-owner-type
  nRealtors

  onMarketPeriodBTL
  onMarketPeriodMortgage
  Override-Income-Capital
  Owned-Rent-Percentage

  price-difference
  PriceDropRate

  RealtorMemory
  RealtorOptimism
  RealtorTerritory
  rent-difference
  RentDropRate
  Savings
  SavingsRent
  savings-to-rent-threshold
  scenario
  Shocked
  shock-frequency

  TicksPerYear
  upgrade-tenancy


]

breed [houses house ]      ; a house, may be occupied or not, and may be for sale/mortgage or for rent
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[
  myType              ; type of house; owned or rented; can be others as well
  local-realtors      ; the local realtors of the house
  local-sales         ; the records for the sale transactions of houses in the intersection of the locality of self and realtor
  local-rents         ; the records for the rent transactions of houses in the intersection of the locality of self and realtor
  locality-houses     ; the houses in my own locality (an agentset)
end -of-life         ; time step when this house will be demolished
  for-sale?           ; whether this house is currently for sale or rent
  for-rent?           ; whether this house is currently for rent
  on-market-period    ; time the house has been on the market
  date-for-sale       ; when the house was put on the market for sale
  date-for-rent       ; when the house was put on the market for rent
  my-owner            ; the owner of this house; owner may not be living in the house if it is rented
  sale-price          ; the price of this house (either now, or when last sold); price sold and rented
  rent-price          ; the rent price of this house
  quality             ; index of quality of this house relative to its neighbours
  my-realtor          ; if for sale/rent, 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)
  rented-to           ; which renter has already made an offer for this house
  rent-date           ; date of the rent offer (in ticks)
  my-occupier         ; the individual that lives here; can be the owner or the renter
  diversity           ; the diversity index of the house (only used for visualisation)
  G                   ; Getis-Ord z-score for the hotspot analysis
]

owners-own[
  my-house            ; the house which this owner owns/rents
  income              ; current income from work per year (this is the ONLY yearly measure)
  income-rent         ; income from rent per tick
  income-surplus      ; residual income after spending on housing commodities
  surplus-rent        ; residual rent for each house after deducing its repayment
  mortgage            ; value of mortgage - reduces as it is paid off
  mortgage-initial    ; value of initial mortgage (does not decrease every tick)
  mortgage-duration   ; the remaining time on the mortgage
  rate                ; the yearly interest rate of the currently aggreed mortgage
  rate-duration       ; the remaining years on the current rate (at the end updates)
  capital             ; capital that I have accumulated from selling my house
  wealth              ; capital + sale-prices of houses - mortgages
  repayment           ; my mortgage repayment amount, at each tick
  my-rent             ; rent at each tick
  homeless            ; count of the number of periods that this owner has been without a house
  myType              ; type of owner, 1 for owned and 0 for rented
  made-offer-on       ; house that this owner wants to buy/rent
  date-of-acquire     ; when my-house was bought/rented
  my-ownership        ; houses I own
  on-market?          ; currently on the market or not (myType depicts the type of the market I use)
  on-market-type      ; type of market a buyer is on now
  time-on-market      ; number of ticks a buyer has been on the market
  on-cooldown?        ; whether the owner is in the cooldown period or not (cooldown occurs after an owner gets discouraged from the BTL market)
  on-cooldown-type    ; type of market from which the owner is on cooldown ("mortgage" or "buy-to-let")
  time-on-cooldown    ; the number of ticks the owner has been on cooldown
  propensity          ; the probability I will invest in housing
]

realtors-own[
  my-houses-rent           ; the houses in my territory for rent
  sales-rent               ; the last few house for rent that I have made
  my-houses-sold           ; the houses in my territory for sale
  sales-sold               ; the last few house sales that I have made
  average-price       ; the average price (sale) of a house in my territory
  average-rent        ; the average rent of a house in my territory
]

records-own[
  the-house           ; the house that was sold or rented
  selling-price       ; the selling price
  ;;YG
  renting-price       ; the renting price
  date                ; the date of the transaction (in ticks)
  filed-at-houses     ; houses that filed the record
]

to reset
   ; baseline


  set ActWhenShocked false
  set Affordability 33
  set BuyerSearchLength 5
  set calculate-wealth? true
  set CapitalMortgage 100
  set CapitalRent 50
  set clusteringRepeat 3
  set cooldownPeriodBTL 6
  set cooldownPeriodMortgage 6
  set CycleStrength 0
  set Density 70
  set EntryRate 4
  set eviction-threshold-mortgage 2
  set eviction-threshold-rent 1
  set ExitRate 2
  set FullyPaidMortgageOwners 0
  set HouseConstructionRate 0.36
  set HouseMeanLifetime 100
  set income-shock 20
  set InitialGeography "Random"
  set Initialisation "repayment--> mortgage--> price"
  set initialOccupancy 0.95
  set InterestRate 3.7
  set investorspercentage 20
  set Locality 3
  set MaxForRentPeriodPoorLandlord 4
  set MaxHomelessPeriod 7
  set MaxLoanToValue 90
  set MaxRateDurationBTL 5
  set MaxRateDurationM 5
  set MeanIncome 30000
  set min-price-fraction 0.2
  set MinRateDurationBTL 2
  set MinRateDurationM 2
  set mInterest 8
  set MortgageDuration 25
  set mYear 100
  set new-owner-type "random"
  set nRealtors 6
  set nYears 300
  set onMarketPeriodBTL 1
  set onMarketPeriodMortgage 1
  set Override-Income-Capital false
  set Owned-Rent-Percentage 50
  set pLTV 90
  set price-difference 5000
  set PriceDropRate 3
  set RealtorMemory 10
  set RealtorOptimism 3
  set RealtorTerritory 16
  set rent-difference 500
  set RentDropRate 3
  set Savings 20
  set SavingsRent 5
  set savings-to-rent-threshold 5
  set scenario "base-line"
  set Shocked 20
  set shock-frequency 0
  set StampDuty? false
  set TicksPerYear 4
  set upgrade-tenancy 0
  set VisualiseMode "Prices"
  set WageRise 0
end 

to setup
  clear-all
  reset-ticks
  reset

  ; identify the current state of the model is initialisation
  set setup? true

  ; yearly interest rate is converted to interest per tick to be used to calculate finances of the owners at the setup
  set interestPerTick InterestRate / ( TicksPerYear * 100 )
  set investors investorsPercentage / 100
  ;no-display ; if do not want to visualize

  ; create realtors
  build-realtors

  ; create houses
  let total count patches * Density / 100 ; houses density
  ; how many of the total for ownership and how many for rent
  let owned ceiling Owned-Rent-Percentage * total / 100
  let rented total - owned
  repeat (owned) [ build-house "mortgage"] ; create ownership houses
  repeat (rented) [ build-house "rent"] ; create rent houses

  ; create owners
  build-owners
  ask owners [update-surplus-income]

  ; empty houses are for sale/rent; setting sale price (not related to owner)
  reset-empty-houses
  if InitialGeography = "Clustered" [ cluster ]   ;; move houses to the neighbors with similar prices

  reset-houses-quality ; assign quality to houses based on prices in the neighborhood
  reset-realtors ;; initialize sales, my-houses, average-price
  build-records

  ;; calculate the wealth of each household
  if calculate-wealth? = true [ask owners [update-wealth]]

  set VisualiseModeCurrent VisualiseMode
  update-visualisation

  ; identify the current state of the model is running
  set setup? false
end 

to simplified-setup-step-1
  clear-all
  reset-ticks
  type "Applied Setup step 1\n"
  fetch:url-async "https://raw.githubusercontent.com/YahyaGamal/Housing_ABM_Simple_UI/refs/heads/main/Worlds/S18.4.2_01_clean.csv" import-a:world
end 

to simplified-setup-step-2
  reset-ticks
  ask realtors [draw-circle RealtorTerritory]
  set visualiseMode "Prices"
  update-visualisation
  set setup-a 1
  set setup-b 1
  random-seed new-seed
  type "Applied Setup step 2\n"
end 

to build-realtors
  set-default-shape realtors "flag"  ;;
  let direction random 360
  create-realtors nRealtors [  ;; create one at a time, totally nRealtors
    set color red
    ; 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
  ]
end 

to draw-circle [radius]
;; 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 white 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
    die  ;; end the drawing turtle
   ]
end 

; now we only builds mortgage houses during the run (no input is used with type "rent" in go, but we initially build rent houses at setup)

to build-house [mtype]
  set-default-shape houses "house"
  create-houses 1 [
    ; assign type
    set myType mtype
    if myType = "mortgage" [set color 45]
    if myType = "rent" [set color 95]
   ; 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
      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
      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
      ]

    ifelse calculate-wealth? = true [
      ; find a list of the local-realtors (list type is required for wealth calculation)
      set local-realtors [self] of realtors with [ distance myself < RealtorTerritory ]
      let temp-locals-list (list)
      repeat length local-realtors [set temp-locals-list lput (list) temp-locals-list]
      set local-sales temp-locals-list
      set local-rents temp-locals-list
      set locality-houses [self] of houses with [distance myself <= locality]
      ask turtle-set locality-houses [set locality-houses lput  myself locality-houses]
      ; if no realtor assigned, then choose nearest
      if not any? turtle-set local-realtors [
        set local-realtors (list min-one-of realtors [ distance myself ])
        set local-sales (list (list))
        set local-rents (list (list))
      ]
    ]
    ; if calculate-wealth? = false
    [
      ; 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, exluded when owners are build in the setup; all houses created later are put on market
    set my-owner nobody
    set my-occupier nobody
    set rented-to nobody
    set offered-to nobody
    ; note how long this house will last before it falls down and is demolished
    set end-of-life ticks + int random-exponential ( HouseMeanLifetime * TicksPerYear )
  ]
end 


;; Considers the presence of a rent market

to put-on-market
  ;; reset market period counter
  set on-market-period 0
  ;; add the house to the mortgage or rent market
  if myType = "mortgage" [put-on-sale-market]
  if myType = "rent" [put-on-rent-market]
end 

;; adds the house to the sale market

to put-on-sale-market
  set for-sale? true
  set for-rent? false
  set offered-to nobody
  set date-for-sale ticks
  colour-house
end 

;; adds the house to the renting market

to put-on-rent-market
  set for-sale? false
  set for-rent? true
  set offered-to nobody
  set date-for-rent ticks
  colour-house
end 

;; create owners

to build-owners
  set-default-shape owners "dot"  ;; all owners are dots
  ; in the setup, how many houses are occupied
  let n floor (initialOccupancy * count houses) ; total occupancy
  let o floor (Owned-Rent-Percentage / 100 * n) ; owned occupancy
  let r n - o                                   ; rented occupancy
  let available-owned nobody
  let available-rented nobody
  let count-notavailable-owned 0
  let count-notavailable-rented 0
  ; setting availabilities
  if (o > count houses with [myType = "mortgage"]) [
    set available-owned houses with [myType = "mortgage"]
    set count-notavailable-owned o - count houses with [myType = "mortgage"]
  ]
  if (o <= count houses with [myType = "mortgage"]) [
    set available-owned n-of o houses with [myType = "mortgage"]
  ]
  if (r > count houses with [myType = "rent"]) [
    set available-rented houses with [myType = "rent"]
    set count-notavailable-rented r - count houses with [myType = "rent"]
  ]
  if (r <= count houses with [myType = "rent"]) [
    set available-rented n-of r houses with [myType = "rent"]
  ]

  ask available-owned [  ;; define each home-owner's properties
    ;; since owners living inside, it should not for-sale or for rent now
    set for-sale? false
    set for-rent? false
    hatch-owners 1 [  ;; create an owner inside this house
      set color black  ;; make owner red
      set size 0.7   ;; owner easy to see but not too big
      set propensity random-float 1.0
      set my-house myself  ;; owner claims its house
      ;; added occupier and rented-to
      set my-ownership (list myself)
      ask my-house [set my-owner myself set my-occupier myself set rented-to nobody] ;; ask the house to claim its owner and occupier

      set mytype "mortgage" ; owner
      assign-income ;; create income and capital for owner#
      ;; address rent from house (owner lives in the house, and accordingly income-rent = 0
      set income-rent (list 0)
      set surplus-rent (list 0)
      ;; address mortgage rate duration (can be assigned regardless of actual mortgage)
      set rate (list interestPerTick)
      set rate-duration (list ((MinRateDurationM + random (MaxRateDurationM - MinRateDurationM)) * ticksPerYear) )
      set mortgage-duration (list (MortgageDuration * ticksPerYear))

      let deposit 0

      if initialisation = "repayment--> mortgage--> price" [
        ; maximum repayment
        let max-repayment (income * Affordability / (ticksPerYear * 100))
        let max-mortgage min list ( (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) * max-repayment / interestPerTick )
        ( (capital * (MaxLoanToValue / 100)) / (1 - (MaxLoanToValue / 100)) )

        set mortgage (list max-mortgage)
        set mortgage-initial (list item 0 mortgage)
        set repayment (list( item 0 mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) ))
        set deposit ( item 0 mortgage * ( 100 /  MaxLoanToValue - 1 ) )  ;; create deposit

        ;set repayment (list (income * Affordability / (ticksPerYear * 100)) )
        ;set mortgage (list ( (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) * item 0 repayment / interestPerTick ))
        ;set mortgage-initial (list item 0 mortgage)
        ;set deposit ( item 0 mortgage * ( 100 /  MaxLoanToValue - 1 ) )  ;; create deposit
      ]

      if initialisation = "mortgage--> price" [
        ;; address mortgage, repayment and deposit
        set mortgage (list( income * Affordability / ( interestPerTick * ticksPerYear * 100 ) )) ;; create mortgage as a list
        set mortgage-initial (list item 0 mortgage)
        set deposit ( item 0 mortgage * ( 100 /  MaxLoanToValue - 1 ) )  ;; create deposit
                                                                         ;; create repayment as a list
        set repayment (list( item 0 mortgage * interestPerTick /
          (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) ))
      ]

      ;; create sale-price = mortgage + deposit for the house
      ask my-house [
        set sale-price [item 0 mortgage] of myself + deposit
        set rent-price 0
      ]
    ]
  ]

  ;; assign tenants and landlords to the houses rented
  ask available-rented [
    ;; since owners living inside, it should not be for-sale or for rent
    set for-sale? false
    set for-rent? false
    hatch-owners 1 [  ;; create an owner inside this house
      set color white  ;; make owner red
      set size 0.7   ;; owner easy to see but not too big
      set propensity random-float 1.0
      set my-house myself  ;; owner claims its house
      ;; manage ownership of house and owner agent
      set my-ownership (list)
      let owner-temp one-of owners with [mytype = "mortgage"]
      let house-temp myself
      set mytype "rent" ; renter/tenant (i.e., someone living now in a rented house)
      assign-income ;; create income and capital for owner (i.e. renter)
      ;; renters do not pay mortgage and have no repayments, but they pay rent
      let rent income * Affordability / (ticksPerYear * 100 ) ;; create rent
      ;; address mortgage rate duration (can be assigned regardless of actual mortgage)
      set rate (list)
      set rate-duration (list)
      set mortgage-duration (list)

      let price 0
      let repayment-temp 0

      if initialisation = "repayment--> mortgage--> price" [
        set repayment-temp income * Affordability / (ticksPerYear * 100 )
        set price (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) * repayment-temp / interestPerTick
      ]

      if initialisation = "mortgage--> price" [
        set price income * Affordability / ( interestPerTick * ticksPerYear * 100 )
        set repayment-temp price * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear ))
      ]


      ;; safegaurd that landlords at least recover their repayments from the rent (this leads to much higher rents with higher interest rates)
      if repayment-temp > rent [set rent repayment-temp]
      ;; add an owner to the rented house (required for adding the rent value to that person)
      ask my-house [
        set my-owner owner-temp
        set my-occupier myself
        set rented-to myself
        ;; set sale price of the rented house the same as the sale-price of my-house of the main owner
        ;set sale-price [sale-price] of ([my-house] of owner-temp)
        set sale-price price
        set rent-price rent
      ]
      ;; manage ownership, mortgage, repayment and rent of the landlord of the house
      ask owner-temp [
        set my-ownership lput (house-temp) (my-ownership)
        ;set mortgage lput (item 0 mortgage) (mortgage)
        set mortgage lput (price) (mortgage)
        set mortgage-initial lput (price) (mortgage-initial)
        ;set repayment lput (item 0 repayment) (repayment)
        set repayment lput (repayment-temp) (repayment)
        set income-rent lput rent income-rent
        set surplus-rent lput (rent - repayment-temp) surplus-rent
        ;; address mortgage rate duration (can be assigned regardless of actual mortgage)
        set rate lput (interestPerTick) (rate)
        set rate-duration lput ((MinRateDurationBTL + random (MaxRateDurationBTL - MinRateDurationBTL)) * ticksPerYear) (rate-duration)
        set mortgage-duration lput (MortgageDuration * ticksPerYear) mortgage-duration
      ]
      set my-rent rent
      ;; intialise mrotgage, repayment and income-rent as empty lists
      set mortgage (list)
      set mortgage-initial (list)
      set repayment (list)
      set income-rent (list)
      set surplus-rent (list)
      ask my-house [ set sale-price price set rent-price rent ] ;; create rent-price = rent
    ]
  ]

  ;; assign owners (i.e., landlords) to houses available on the rent market (i.e., not occupied)
  ask houses with [myType = "rent" and for-rent? = true] [
    let owner-temp one-of owners with [mytype = "mortgage"]
    let house-temp self
    ask owner-temp [
      set my-ownership lput (house-temp) (my-ownership)
      ;; repeat the mortgage (we assume sale-prices are based on income, this makes the sale-price of all houses owned by one owner the same at initialisation)
      set mortgage lput (item 0 mortgage) (mortgage)
      set mortgage-initial lput (item 0 mortgage-initial) (mortgage-initial)
      set repayment lput (item 0 repayment) (repayment)
      set income-rent lput 0 (income-rent)
      set surplus-rent lput (0 - item 0 repayment) surplus-rent
      ;; address mortgage rate duration (can be assigned regardless of actual mortgage)
      set rate lput (interestPerTick) (rate)
      set rate-duration lput ((MinRateDurationBTL + random (MaxRateDurationBTL - MinRateDurationBTL)) * ticksPerYear) (rate-duration)
      set mortgage-duration lput (MortgageDuration * ticksPerYear) mortgage-duration
    ]
    ask house-temp [
      set my-owner owner-temp
      set my-occupier nobody
      set rented-to nobody
      ;; set sale price of the rented house the same as the sale-price of my-house of the main owner (this is an assumption at set-up)
      set sale-price [sale-price] of ([my-house] of owner-temp)
      set rent-price median [rent-price] of houses with [myType = "rent" and for-rent? = false]
    ]
  ]

  ; houses not assigned
  if count-notavailable-owned > 0 [
    create-owners count-notavailable-owned [
      set color black  ;; make owner red
      set size 0.7   ;; owner easy to see but not too big
      ;; was nobody in 17.6
      ;; returned to nobody in 18.0
      ;set my-house one-of houses with [myType = "rent" and my-occupier = nobody]  ;; owner claims its house
      set my-house nobody
      set my-ownership (list)
      set mytype "mortgage" ; mortgage owner
      assign-income ;; create income and capital for owner
      ;let rent income * Affordability / (ticksPerYear * 100 ) ;; create rent
      set my-rent 0
      set mortgage (list)
      set mortgage-initial (list)
      set repayment (list)
      set income-rent (list)
      set surplus-rent (list)
      set rate (list)
      set rate-duration (list)
      set mortgage-duration (list)

      enter-market self myType
    ]
  ]

  ; tenants without houses at initialisation assigned
  if count-notavailable-rented > 0 [
    create-owners count-notavailable-rented [  ;; create an owner inside this house
      ;set hidden? true
      ;move-to one-of patches
      set color white  ;; make owner red
      set size 0.7   ;; owner easy to see but not too big
      ;; was nobody in 17.6
      ;; returned to nobody in 18.0
      ;set my-house one-of houses with [myType = "rent" and my-occupier = nobody]  ;; owner claims its house
      set my-house nobody
      set my-ownership (list)
      set mytype "rent" ; renter
      assign-income ;; create income and capital for owner
      ;let rent income * Affordability / (ticksPerYear * 100 ) ;; create rent
      set my-rent 0
      set mortgage (list)
      set mortgage-initial (list)
      set repayment (list)
      set income-rent (list)
      set surplus-rent (list)
      set rate (list)
      set rate-duration (list)
      set mortgage-duration (list)

      enter-market self myType
    ]
  ]

  ;; pay the mortgage of a portion of the owners (this cannot be applied when calculating the mortgages as the mortgage values are necessary to set prices)
  if FullyPaidMortgageOwners > 0 [

    ask owners with [myType = "mortgage"] [
      if FullyPaidMortgageOwners >= random 100 [
        let i 0
        let l length my-ownership
        ;; loop through all the ownership houses
        while [i < l] [
          set mortgage replace-item i mortgage 0
          set mortgage-initial replace-item i mortgage-initial 0
          set mortgage-duration replace-item i mortgage-duration nobody
          set repayment replace-item i repayment 0
          set surplus-rent replace-item i surplus-rent (item i income-rent)
          set rate replace-item i rate 0
          set rate-duration replace-item i rate-duration nobody
          set i i + 1
        ]
      ]
    ]
  ]
end 

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 MeanIncome-temp MeanIncome
  ;; override mean income if it does not cover the mean repayments
  let mean-deposit 0
  let min-deposit 0
  if (Override-Income-Capital = true and setup? = false) [
    let mean-price 0
    let min-price 0
    if any? houses with [myType = "mortgage" and sale-price > 0 and for-sale? = true] [
      set mean-price max list (mean [sale-price] of houses with [myType = "mortgage" and sale-price > 0 and for-sale? = true]) (medianPriceOfHousesForSale)
      set min-price max list (min [sale-price] of houses with [myType = "mortgage" and sale-price > 0 and for-sale? = true]) (min [sale-price] of houses with [myType = "mortgage" and sale-price > 0])
    ]
    set mean-deposit mean-price * ( 1 - (MaxLoanToValue / 100) )
    set min-deposit min-price * ( 1 - (MaxLoanToValue / 100) )
    let mean-mortgage mean-price * (MaxLoanToValue / 100)
    let mean-repayment mean-mortgage * interestPerTick / ( 1 - (1 + interestPerTick) ^ (- MortgageDuration * TicksPerYear) )
    set MeanIncome-temp max list (mean-repayment * TicksPerYear) (MeanIncome)
  ]

  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-temp / 2 ] [  ;; as long as income is less than half of median income
    set income (MeanIncome-temp * lambda / alpha ) * (random-gamma alpha lambda) *
    (1 + (WageRise / (TicksPerYear * 100)) ) ^ ticks  ;; redefine income value with this equation (check the paper for details )
  ]
  ;; assign the income-surplus initially as the income per tick (deductions will be made later from the income surplus)
  set income-surplus income / ticksPerYear

  ; if override capital is on, assure the mortgage owners have enough capital to at least buy the cheapest house on the market
  ifelse (Override-Income-Capital = true and setup? = false) [
    if myType = "mortgage" [set capital max list (income * CapitalMortgage / 100) ( (min-deposit + mean-deposit) / 2)]
  ]
  ; if not, give them a proportion of a year's income as their savings
  [
    if myType = "mortgage" [set capital income * CapitalMortgage / 100]
  ]
  if myType = "rent" [set capital income * CapitalRent / 100]
end 

to update-surplus-income
  set income-surplus (income / ticksPerYear) + sum(income-rent) - sum(repayment) - my-rent
end 

to update-cooldown
  ;; if the household is on BTL cooldown and have not reached the end of its cooldown period
  if on-cooldown? = true and on-cooldown-type = "buy-to-let" [
    if time-on-cooldown < cooldownPeriodBTL [set time-on-cooldown time-on-cooldown + 1]
    ;; if the household reached the end of its cooldown period
    if time-on-cooldown >= cooldownPeriodBTL [
      ;;type self type " | time-on-cooldown = " type time-on-cooldown type "\n"
      set on-cooldown? false
      set time-on-cooldown 0
      set on-cooldown-type nobody
    ]
  ]

  ;; if the household is on mortgage market cooldown and have not reached the end of its cooldown period
  if on-cooldown? = true and on-cooldown-type = "mortgage" [
    if time-on-cooldown < cooldownPeriodMortgage [set time-on-cooldown time-on-cooldown + 1]
    ;; if the household reached the end of its cooldown period
    if time-on-cooldown >= cooldownPeriodMortgage [
      ;;type self type " Mortgage | time-on-cooldown = " type time-on-cooldown type "\n"
      set on-cooldown? false
      set time-on-cooldown 0
      set on-cooldown-type nobody
    ]
  ]
end 

to update-wealth
  if calculate-wealth? = True [
    let i 0
    set wealth capital
    while [i < length my-ownership] [
      let mortgage-temp item i mortgage
      let my-ownership-temp item i my-ownership
      let myType-temp [myType] of item i my-ownership
      let sale-price-temp 0
      ask my-ownership-temp [
        set my-realtor max-one-of turtle-set local-realtors [ valuation myself ]               ;; set the realtor that gives the current house the highest valuation to be my-realtor
        set myType "mortgage"
        ask my-realtor [set sale-price-temp valuation my-ownership-temp]
        set myType myType-temp
      ]
      set wealth wealth + (sale-price-temp - mortgage-temp)
      set i i + 1
    ]
  ]
end 

to reset-empty-houses
  ;; For vacant houses, without owners, those houses have no sale-prices, my-owner properties

  let median-price 0
  let median-rent 0

  ; initial random assignments
  set median-price median [ sale-price ] of houses with [ sale-price > 0 and myType = "mortgage"] ;; median sale-prices of all houses with owners
  ;; consider rent-price for rented houses
  set median-rent median [ rent-price ] of houses with [ rent-price > 0 and myType = "rent"] ;; median sale-prices of all houses with owners
  ;; check my-occupier for empty houses
  ask houses with [ not (is-owner? my-occupier) and myType = "mortgage"] [  ;; loop each empty house owned?
    let local-houses-sale houses with [distance myself < Locality and sale-price > 0 and myType = "mortgage"]
    let local-houses-rent houses with [distance myself < Locality and rent-price > 0 and myType = "rent"]

    ;; assign sale
    ;; find all local houses of the empty house = locality distance and has owner with sale-price
    ifelse any? local-houses-sale ;; if there exist local houses,
        [ set sale-price  median [ sale-price ] of local-houses-sale
    ]  ;; 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

    ;; assign rent
    ;; find all local houses of the empty house
    ifelse any? local-houses-rent
        [ set rent-price  median [ rent-price ] of local-houses-rent ]  ;; use local houses median price as the empty house sale-price
    [ set rent-price  median-rent ]  ;; otherwise, use all occupied houses median price for the empty house sale-price

  ]
  ;; consider rent-price of local houses
  ask houses with [ not (is-owner? my-occupier) and myType = "rent"] [  ;; loop each empty house NOT owned?
  let local-houses houses with [distance myself < Locality and rent-price > 0 and myType = "rent"]
  ;; find all local houses of the empty house
  ifelse any? local-houses
      [ set rent-price  median [ rent-price ] of local-houses ]  ;; use local houses median price as the empty house sale-price
  [ set rent-price  median-rent ]  ;; otherwise, use all occupied houses median price for the empty house sale-price
  ]
end 

to cluster
  ;; cluster houses together based on price similarity
  let owned-houses houses with [myType = "mortgage"]
  let rented-houses houses with [myType = "rent"]
  cluster-type owned-houses price-difference
  cluster-type rented-houses rent-difference
end 

to cluster-type [all-houses diff]
  repeat clusteringRepeat [  ;;  cluster all all houses x times
    let houses-to-move sort-by [ [ house1 house2 ] ->  price-diff house1 > price-diff house2 ] all-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 >= diff [  ;; 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 ) < (diff / 5) ]  ;; 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
            move-to vacant-plot  ;; to move to one of the empty patch
            if is-owner? my-occupier [  ;; whether it got an owner, if so
              ask my-occupier [ move-to myself ] ;; ask the owner move to where the house is
            ]
          ]
        ]
      ]
    ]
  ]
end 

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 

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`
  ;; report prices of mortgaged houses only (do not report prices of rented houses)
  ifelse any? local-houses with [mytype = "mortgage"]  ;; if `loca-houses` is not empty
    [ report median [sale-price] of local-houses with [mytype = "mortgage"] ]  ;; 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 

to reset-houses-quality

  set medianPriceOfHousesForSale median [sale-price] of houses with [myType = "mortgage"]  ;; get median price for all houses owned
  set medianPriceOfHousesForRent median [rent-price] of houses with [myType = "rent"]  ;; get median price for all houses not owned

  ask houses with [myType = "mortgage"] [
    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 color quality 5 0  ;; quality by magenta scale
  ]

  ;; address rented houses
  ask houses with [myType = "rent"] [
    set quality rent-price / medianPriceOfHousesForRent  ;; 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 color quality 5 0  ;; quality by magenta scale
  ]
end 

to reset-realtors

  ask realtors [
    set sales-sold [] ;; take sales as empty list
    set sales-rent [] ;; take sales as empty list

    set my-houses-sold houses with [member? myself local-realtors and myType = "mortgage"]
    set my-houses-rent houses with [member? myself local-realtors and myType = "rent"]

    set average-price median [ sale-price ] of my-houses-sold
    ;; consider average rent
    set average-rent median [ rent-price ] of my-houses-rent
  ]
end 

to build-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

  set-default-shape records "square"
  ask houses [ ;; loop each house

    let the-record nobody ;; `the-record` is nobody
    hatch-records 1 [  ;; hatch a record from a house
      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
      ;; consider renting prices
      set renting-price [ rent-price] of myself

      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

    file-record my-realtor the-record  ;; ask my-realtor to save the current record (the-record) into sales of my-realtor

  ]
end 

to file-record [ input-realtor the-record ]         ;; realtor procedure
  ; push this sales record onto the list of those I keep
  let A [the-house] of the-record

  ask input-realtor [
    ; consider both rent and mortgage
    if [myType] of A = "mortgage" [set sales-sold fput the-record sales-sold]
    if [myType] of A = "rent" [set sales-rent fput the-record sales-rent]
  ]

  if calculate-wealth? = true [
    ; find local houses and store which houses filed the-record
    ;let A-local-houses houses with [distance A <= locality and member? input-realtor local-realtors]
    let A-local-houses (turtle-set [locality-houses] of A) with [member? input-realtor local-realtors]
    ; create a list of the houses that will file the record
    ask the-record [set filed-at-houses [self] of A-local-houses]
    if any? A-local-houses [
      ask A-local-houses [
        let i position input-realtor local-realtors
        if [myType] of A = "mortgage" [
          let relevant-records item i local-sales
          set relevant-records remove nobody relevant-records
          set relevant-records fput the-record relevant-records
          set local-sales replace-item i local-sales relevant-records
        ]
        if [myType] of A = "rent" [
          let relevant-records item i local-rents
          set relevant-records remove nobody relevant-records
          set relevant-records fput the-record relevant-records
          set local-rents replace-item i local-rents relevant-records
        ]
      ]
    ]
  ]
end 

to go
  if setup-a = 0 or setup-b = 0 [
    type "Error: Please make sure you press 'Setup step 1' then 'Setup step 2' before running the model\n"
    stop
  ]
  set nDiscouraged 0
  set nExit 0
  set nEntry 0
  set nForceOutRent 0
  set nForceOutSell 0
  set nForceInSell 0
  set nOwnersOffered 0
  set meanIncomeForceOutRent 0 ;; get mean income of owners who are forced out
  set meanIncomeForceOutSell 0 ;; get mean income of owners who are forced out
  set meanIncomeForceInSell 0

   if ticks = 200 [
    ; Sale market
     if scenario = "ltv"  [ set MaxLoanToValue 60 ]
     if scenario = "raterise 3" [ set InterestRate 3 ]
     if scenario = "raterise 10" [ set InterestRate 10 ]
    ; both
     if scenario = "influx" [ set EntryRate 10 ]
     if scenario = "influx-rev" [ set EXitRate 5 ]
     if scenario = "poorentrants" [ set MeanIncome 24000 ]
    ; rent market?


    if scenario != "base-line" [type "We are at middle of simulation duration, ticks = " type ticks type ", a shock event coming in := " type scenario  print ";"]
  ]
  if TicksPerYear > 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 ]
  ;paint-houses
  ;do-plots
  tick
end 

to step

  ; reset the count of upshocked and downshocked agents
  reset-globals

  update-visualisation

  let n-owners count owners  ;; take a count of total owners at the moment

  calculate-globals ; update interest rate and income
  ; owners living in houses
  let owner-occupiers owners with [ is-house? my-house ] ; all owners who are living
  ;type "calculate-globals | " type count owners with [length my-ownership > length repayment] type "\n"

  ; change in income due to income shock (all owners)
  ; shock related (possible) effort to change of house of owner occupiers
  shock-management owner-occupiers
  set n-owners count owners  ;; take a count of total owners at the moment
  set owner-occupiers owners with [ is-house? my-house ] ; all owners who are living
  ;type "shock-management | " type count owners with [length my-ownership > length repayment] type "\n"

  ; owners leaving naturally
  owners-leave n-owners
  set n-owners count owners  ;; take a count of total owners at the moment
  set owner-occupiers owners with [ is-house? my-house ] ; all owners who are living
  ;type "owners-leave | " type count owners with [length my-ownership > length repayment] type "\n"

  ; owners entering naturally
  new-owners n-owners
  set n-owners count owners  ;; take a count of total owners at the moment
  set owner-occupiers owners with [ is-house? my-house ] ; all owners who are living
  ;type "new-owners | " type count owners with [length my-ownership > length repayment] type "\n"

  ; owners leaving due to discouragement
  manage-discouraged
  set n-owners count owners  ;; take a count of total owners at the moment
  set owner-occupiers owners with [ is-house? my-house ] ; all owners who are living
  ;type "manage-discouraged | " type count owners with [length my-ownership > length repayment] type "\n"

  ; manage which market the agents enter to on the basis of their current occupation and budgets
  manage-market-participation owner-occupiers
  ;type "manage-market-participation | " type count owners with [length my-ownership > length repayment] type "\n"

  ; introduce new houses
  new-houses
  ;type "new-houses | " type count owners with [length my-ownership > length repayment] type "\n"

  ; trading and moving into houses
  trade-houses
  ;type "trade-houses | " type count owners with [length my-ownership > length repayment] type "\n"

  ;remove extras (this removes all the offers, but still keeps the houses on the market)
  remove-outdates
  ;type "remove-outdates | " type count owners with [length my-ownership > length repayment] type "\n"

  ; demolish old houses
  demolish-houses
  ;type "demolish-houses | " type count owners with [length my-ownership > length repayment] type "\n"
  ; decay the prices of houses
  update-prices
  ;type "update-prices | " type count owners with [length my-ownership > length repayment] type "\n"
  ; update the homeless owners and discourage those who exceed the maxhomelesslimit
  update-owners
  ;type "update-owners | " type count owners with [length my-ownership > length repayment] type "\n"
  update-globals
end 

to calculate-globals
  ;;; Calculate Globals

  ;; 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 )
  ;; add cyclical variation to interest ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if CycleStrength > 0 [
    set interestPerTick interestPerTick * (1 + (CycleStrength / 100 ) * sin ( 36 * ticks / TicksPerYear )) ]

  ;; inflation drive up income ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ; add inflation to salary, at inflation rate / TicksPerYear
  if WageRise > 0 [
    ask owners [
      set income income * (1 + (WageRise / ( TicksPerYear * 100 ))) ;; every tick, income stay the same or varied by inflation, income per year
    ]
  ]
end 

to shock-management [oo]
  set nupShocked 0
  set ndownShocked 0
  ; shock frequency is used to produce a random stock not every tick  but with a random frequency
  if random-float 1 < shock-frequency
  [
    ;; change in the income due to shock
    ;; introduce income rise and fall shock to owners ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    let shocked-owners n-of (Shocked / 100 * count owners ) owners ;; 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`
    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`
    ask downshocked [ set income income * (1 - income-shock / 100 ) ]  ;; ask each downshocked to drop income by 20%

    ;; only make those calculations if the switch is off (to save computation time)
    if ActWhenShocked = false [
      set nupShocked mean [income] of upShocked
      set ndownShocked mean [income] of downshocked
      set nUpShockedSell count upshocked with [myType = "mortgage"]
      set nDownShockedSell count downshocked with [myType = "mortgage"]
      set nUpShockedRent count upshocked with [myType = "rent"]
      set nDownShockedRent count downshocked with [myType = "rent"]
    ]

    ;; income-shock intriges some owners to sell / rent 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

    ;; only triggered if the "ActWhenShocked" is on, meaning the decision tree at shock is triggered
    if ActWhenShocked = true [
      set nupShocked mean [income] of upShocked
      set ndownShocked mean [income] of downshocked
      set nUpShockedSell 0  ;; initialize the number of upshocked owners sell
      set nDownShockedSell 0 ;; initialize the number of downshocked owners sell
      set nUpShockedRent 0   ;; rent
      set nDownShockedRent 0 ;; rent


      let owner-occupiers-owned oo with [myType = "mortgage" and is-house? my-house]
      if any? owner-occupiers-owned [
        ;; ask all home-owners whose house is not for sale (in setup, all home-owners don't sell houses)
        ask owner-occupiers-owned with [ [for-sale?] of my-house = false ][
          ;; put yearly-repayment / income  under `ratio`
          let ratio (sum repayment) * TicksPerYear / income
          ;; if ratio < half of Affordability %, meaning yearly-repayment is easy and owner is rich
          ; upshocked now go to buy-to-let market rather than upgrade their house
          ifelse  ratio <= Affordability / 200 [
            enter-market self "buy-to-let"
            set nUpShockedSell nUpShockedSell + 1   ;; add 1 to `nUpShocked`, meaning one more owner selling house due to income rise (not true now after adding buy-to-let, owners do not have to sell)
          ]
          [
            if ratio > Affordability / 50 [   ;; if ratio > 2 * Affordability % , meaning yearly-repayment is way to heavy for owners to bear, owner is poor
                                              ;; create a list of ownerships that are not my-house
              let my-ownership-temp my-ownership
              ask my-house [set my-ownership-temp other turtle-set my-ownership-temp]
              ;let my-ownership-temp remove my-house (list my-ownership)
              ;; if I have more than one house, evict the tenant and put the house on the mortgage market
              ifelse count turtle-set my-ownership > 1 [
                ;; find one of my ownerships that is not my-house (i.e., not where I live) and is not on the market for-sale
                ifelse any? my-ownership-temp with [for-sale? = false] [
                  ask one-of my-ownership-temp with [for-sale? = false] [
                    ; if there is an occupier, evict them
                    if is-owner? my-occupier [
                      let my-occupier-temp my-occupier
                      evict my-occupier-temp
                      enter-market my-occupier-temp "rent"
                    ]
                    ; put the house on the mortgage market
                    set myType "mortgage"
                    put-on-market
                  ]
                ]
                ;; if all my-ownership are on sale, then evict myself and join the rent market
                [
                  evict self
                  enter-market self "rent"
                ]
              ]
              ;; if I have only one house, I enter the rent market after the downshock
              [
                ; manage the ownership of my-house and put it on the market
                ask my-house [
                  set my-owner nobody
                  set my-occupier nobody
                  set rented-to nobody
                  set offered-to nobody
                  set myType "mortgage"
                  put-on-market
                ]  ;; ask owner's house to put on the market for sale
                   ; evict myself and enter the rent market
                evict self
                enter-market self "rent"
              ]
              set nDownShockedSell nDownShockedSell + 1  ;; add 1 to `nDownShocked`, meaning one more owner selling house due to income drop
                                                         ;set looking-for-transition true
            ]
          ]
        ]
      ]
      ;; find all tenants with a house
      let owner-occupiers-rented oo with [myType =  "rent" and is-house? my-house]
      if any? owner-occupiers-rented [
        ;; ask all the tenants to
        ask owner-occupiers-rented with [ [for-rent?] of my-house = false][ ;; ask all home-owners whose house is not for sale (in setup, all home-owners don't sell houses)
          let ratio my-rent / income ;; put yearly-repayment / income  under `ratio`
          ifelse  ratio <= Affordability / 200 [  ;; if ratio < half of Affordability %, meaning yearly-rent is easy and owner is rich
            ask my-house [
              set myType "rent"
              put-on-market
            ]
            ;; enter the mortgage market to buy a house
            ;; modified to mortgage REVISE AS THIS MAY CAUSE ERRORS
            enter-market self "mortgage"
            ;; The house will be put on the market later as soon as the tenant finds a house to buy
            ;ask my-house [ put-on-market ]  ;; ask owner's house to put on the market for rent
            set nUpShockedRent nUpShockedRent + 1   ;; add 1 to `nUpShocked`, meaning one more owner selling house due to income rise
                                                    ;set looking-for-transition true
          ]
          ;;  ;; if ratio > half of Affordability %
          [
            ;; if ratio > 2 * Affordability % , meaning yearly-rent is way to heavy for owners to bear, owner is poor
            if ratio > Affordability / 50 [
              ask my-house [
                set my-occupier nobody
                set rented-to nobody
                put-on-market
              ]  ;; ask owner's house to put on the market for rent
                 ;; evict myself and enter the rent market
              evict self
              enter-market self "rent"
              set nDownShockedRent nDownShockedRent + 1  ;; add 1 to `nDownShocked`, meaning one more owner selling house due to income drop
                                                         ;set looking-for-transition true
            ]
          ]
        ]
      ]
    ]
  ]
end 

to owners-leave [n-owners]
  ;; owners die or leave naturally ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; every tick, a proportion of owners put their houses on the market and leave town
  let owners-rent owners with [ is-house? my-house and myType = "rent" ]
  let n min (list count owners-rent (ExitRate * n-owners / 200))
  ask n-of n owners-rent [
    ;; amange the tenancy of my-house
    ask my-house [
      set rented-to nobody
      set my-occupier nobody
      set offered-to nobody
      put-on-market
    ]
    set nExit nExit + 1
    die
  ]


  let owners-mortgage owners with [ is-house? my-house and myType = "mortgage" ]
  ask n-of (ExitRate * n-owners / 200) owners-mortgage [  ;; ask randomly select (ExitRate% of all owners) number of home-owners to do ...
    ;; Modified to consider cases where a landlord leaves, leading to the eviction of all the tenant
    ; find my-ownership excluding my-house
    let my-ownership-temp turtle-set my-ownership
    ask my-house [set my-ownership-temp other turtle-set my-ownership-temp]

    ask my-ownership-temp [
      ;; If someone is occupying one of my owned houses, evict them
      if is-owner? my-occupier [
        let my-occupier-temp my-occupier
        evict my-occupier-temp
        enter-market my-occupier-temp "rent"
      ]
      ;; manage the ownership of the house
      set my-owner nobody
      set my-occupier nobody
      set rented-to nobody
      set offered-to nobody
      ;; put the house on the morgage market (now without an owner as the owner left)
      set myType "mortgage"
      put-on-market
    ]
    ;; manage the ownership of my-house (i.e, the one I live in)
    ask my-house [
      set my-owner nobody
      set my-occupier nobody
      set rented-to nobody
      set offered-to nobody
      ;; put the house on the morgage market (now without an owner as the owner left)
      set myType "mortgage"
      put-on-market
    ]

    set nExit nExit + 1
    die
  ]
end 

to new-owners [n-owners]

  ;; 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 [
      ;; assign type before assigning income
      if new-owner-type = "random" [
        let t random 2
        ifelse t = 0 [set myType "mortgage"] [set myType "rent"]
      ]
      if new-owner-type = "all-rent" [set myType "rent"]
      if new-owner-type = "all-owned" [set myType "mortgage"]
      if new-owner-type = "contextualized" [
        ;; Modified to my-occupier instead of my-owner for representing whether the house is vacant or not
        let x count houses with [myType = "mortgage" and my-occupier = nobody] ; count empty owned houses
        let xx count owners with [mytype = "mortgage" and my-house = nobody] ; owned owners no house
        let y count houses with [myType = "rent" and my-occupier = nobody] ; count empty rent houses
        let yy count owners with [mytype = "rent" and my-house = nobody] ; rent owners no house


        let diff1 x - xx ; if x = 3 and xx = 2, then diff is +ve, meaning owned houses are more than demand and vice versa
        let diff2 y - yy ; if y = 3 and yy = 2, then diff is +ve, meaning rent houses are more than demand and vice versa
        if diff1 <= 0 and diff2 >= 0 [set mytype "rent"] ; owned hosues are less and rent hosues are more/equal than demand, set type rent
        if diff1 <= 0 and diff2 <= 0 [
          let t random 2
          ifelse t = 0 [set myType "mortgage"] [set myType "rent"]
        ] ; owned houses are less and rent hosues are also less, random
        if diff1 >= 0 and diff2 >= 0 [
          let t random 2
          ifelse t = 0 [set myType "mortgage"] [set myType "rent"]
        ] ; both owned and rent houses are more than demand, random
        if diff1 >= 0 and diff2 <= 0 [set myType "mortgage"] ; owned houses are more/equal than demand and rent houses are less, set type owned
      ]

      set color gray  ;; gray
      set size 0.7  ;; make them visible but not too big
      assign-income  ;; initialize income and capital
      ;let rent income * Affordability / (ticksPerYear * 100 ) ;; create rent
      ;set my-rent rent
      ;set mortgage income * Affordability / ( interestPerTick * ticksPerYear * 100 ) ;; create mortgage
      ;let deposit mortgage * ( 100 /  MaxLoanToValue - 1 )  ;; create deposit
      ;set repayment mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear ))
      set mortgage (list)
      set mortgage-initial (list)
      set repayment (list)
      set income-rent (list)
      set surplus-rent (list)
      set rate (list)
      set rate-duration (list)
      set mortgage-duration (list)

      ;; assign the ownership and my-house of the new comer
      set my-ownership (list)
      set propensity random-float 1.0
      set my-house nobody
      set made-offer-on nobody


      ;; Enter the market on the absis of myType (i.e., either "mortgage" or "rent")
      enter-market self myType
      hide-turtle  ;; new comers have no houses, so they are nowhere to be seen
      set nEntry nEntry + 1

    ]
  ]
end 

to manage-discouraged
  ;; 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)
        set nDiscouraged nDiscouraged + 1
        die
      ]
    ]
  ]

  ;; if an `owner` is trying to invest on the BTL market for too long, it gets discouraged
  ;; if maximumPeriodBTL is higher than 0 - meaning the variable is set
  if onMarketPeriodBTL > 0 [
    ask owners with [on-market-type = "buy-to-let"] [
      if time-on-market >= onMarketPeriodBTL [
        ;;type self type " | time-on-maket = " type time-on-market type "\n"
        set on-market? false
        set on-market-type nobody
        set time-on-market 0
        set on-cooldown? true
        set on-cooldown-type "buy-to-let"
        set time-on-cooldown 0
      ]
    ]
  ]

  ;; if maximumPeriodMortgage is higher than 0 - meaning the variable is set
  if onMarketPeriodMortgage > 0 [
    ask owners with [on-market-type = "mortgage"] [
      if time-on-market >= onMarketPeriodMortgage [
        ;;type self type " Mortgage | time-on-maket = " type time-on-market type "\n"
        set on-market? false
        set on-market-type nobody
        set time-on-market 0
        set on-cooldown? true
        set on-cooldown-type "mortgage"
        set time-on-cooldown 0
      ]
    ]
  ]
end 

;; manage well-off and not well-off turtles of type 'owners'

to manage-market-participation [occupiers]
  ;;; manage not-well-off owners (i.e., those not being able to pay repayments or rent)
  ;; evict mortgage and rent
  ; poorer owners with myType = mortgage
  let not-well-off-mortgage occupiers with [on-market? = false and is-house? my-house and myType = "mortgage" and (sum (repayment) * TicksPerYear) > (eviction-threshold-mortgage * (income + (sum (income-rent) * TicksPerYear)) * Affordability / 100)]
  ; poorer owners with myType = mortgage and only one house (these will be evicted)
  let not-well-off-mortgage-evict not-well-off-mortgage with [count turtle-set my-ownership <= 1]
  ; poorer owners with myType = rent (these will always be evicted)
  let not-well-off-rent occupiers with [on-market? = false and is-house? my-house and myType = "rent" and (my-rent * TicksPerYear) > (eviction-threshold-rent * income * Affordability / 100)]
  ; create a set of all the owners that will be evicted
  let not-well-off-evict (turtle-set not-well-off-mortgage-evict not-well-off-rent)
  ; evict and enter rent market
  if any? not-well-off-evict [
    evict not-well-off-evict
    enter-market not-well-off-evict "rent"
  ]

  ;; force mortgage with more than one ownership to sell one of his ownership
  ; poorer owners with myType = mortgage and mare than one house (these will stay and will only sell one of their houses) and without any house already on sale (if a house is on sale, then this owner is waiting for the sale to happen to make profit and stop being not-well-off
  let not-well-off-mortgage-stay not-well-off-mortgage with [count turtle-set my-ownership > 1 and count ( (turtle-set my-ownership) with [for-sale? = true] ) = 0 and count ( (turtle-set my-ownership) with [for-rent? = true] ) = 0]
  ; force-sell, but do not go into any market (the seller is not trying to buy any house)
  if any? not-well-off-mortgage-stay [
    force-sell-rent not-well-off-mortgage-stay
  ]

  ;; well off mortgage and rent
  let well-off-mortgage occupiers with [
    on-market? = false and
    is-house? my-house and
    myType = "mortgage" and (capital >= (median (mortgage)) * ( 1 - (MaxLoanToValue / 100) )) and
    ( ((income + (sum(income-rent) * TicksPerYear) * Affordability / 100) - (sum repayment) * TicksPerYear) > (median(repayment) * TicksPerYear) )
  ]
  ;; sale price * MaxLTV / 100 --> the expected mortgage value
  ;; sale price * (1 - (MaxLTV / 100)) --> the expected deposit
  let well-off-rent occupiers with [
    on-market? = false and
    is-house? my-house and
    myType = "rent" and
    capital >= (savings-to-rent-threshold * [sale-price] of my-house * (1 - (MaxLoanToValue / 100)) ) and
    ( (income * Affordability / 100) > [sale-price] of my-house * (MaxLoanToValue / 100) * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear)) )
  ]
  ; assure no agent is counted twice as well-off and not-well-off
  ask not-well-off-mortgage [set well-off-mortgage other well-off-mortgage]
  ask not-well-off-rent [set well-off-rent other well-off-rent]
  if any? well-off-mortgage [
    ;; assure the ones joining the BTL market: (1) have the propensity to become investors; and (2) are not on-cooldown
    ask well-off-mortgage [
      if propensity > (1 - investors) and on-cooldown? = false [enter-market self "buy-to-let"]
    ]
  ]
  if any? well-off-rent [
    ask well-off-rent [
      if propensity > (1 - upgrade-tenancy) [enter-market self "rent"]
      if propensity <= (1 - upgrade-tenancy) and on-cooldown? = false [enter-market self "mortgage"]
    ]

  ]

  ;; manage globals
  ifelse any? not-well-off-mortgage [
    ;set nEvictedMortgageOneHouse count not-well-off-mortgage with [count my-ownership = 1]
    ;set nEvictedMortgageMoreHouses count not-well-off-mortgage with [count my-ownership > 1]
  ]
  [
    set nEvictedMortgageOneHouse 0
    set nEvictedMortgageMoreHouses 0
  ]
  ifelse any? not-well-off-mortgage-evict [set nEvictedMortgage count not-well-off-mortgage-evict] [set nEvictedMortgage 0]
  ifelse any? not-well-off-evict          [set nEnterMarketRent count not-well-off-evict    set nHomeless count not-well-off-evict] [set nEnterMarketRent 0     set nHomeless 0]
  ifelse any? well-off-rent               [set nEnterMarketMortgage count well-off-rent] [set nEnterMarketMortgage 0]
  ifelse any? well-off-mortgage           [set nEnterMarketBuyToLet count well-off-mortgage] [set nEnterMarketBuyToLet 0]
  ifelse any? not-well-off-mortgage-stay  [set nForceSell count not-well-off-mortgage-stay] [set nForceSell 0]
  ifelse any? not-well-off-mortgage-evict  [set meanIncomeEvictedMortgage mean [income] of not-well-off-mortgage-evict] [set meanIncomeEvictedMortgage 0]
  ifelse any? not-well-off-rent [
    set nEvictedRent count not-well-off-rent
    set meanIncomeEvictedRent mean [income] of not-well-off-rent
  ]
  [
    set nEvictedRent 0
    set meanIncomeEvictedRent 0
  ]
end 

;; evict occupiers from their houses (rented or mortgaged)

to evict [occupiers]
  ask occupiers [
    ;; if I am occupying a "mortgage" house (i.e., I own my house and live in it)
    if [myType] of my-house = "mortgage" [
      ;; manage my-house ownership parameters
      ask my-house [
        set my-occupier nobody
        set my-owner nobody
        set rented-to nobody
        ;; put the house in the "mortgage" market, now without an owner as the owner is being evicted
        put-on-market
      ]
      ;; find all my-ownership without including my-house
      let my-ownership-temp turtle-set my-ownership
      ask my-house [set my-ownership-temp other turtle-set my-ownership-temp]
      ;; address my-ownership without addressing my-house
      ask turtle-set my-ownership-temp [
        ;; If the ownership is a rented property
        if myType = "rent" [
          ;; and the ownership has an occupier
          if is-owner? my-occupier [
            ;; evict the occupier
            let my-occupier-temp my-occupier
            evict my-occupier-temp
            enter-market my-occupier-temp "rent"
          ]
          ;; manage ownership parameters and put the house on the mortgage market (with no owner)
          set myType "mortgage"
          set my-occupier nobody
          set my-owner nobody
          set rented-to nobody
          put-on-market
        ]
        ;; if my-ownership is a mortgage house (meaning it is on-sale? on the mortgage market)
        if myType = "mortgage" [
          ;; address the ownership parameters
          set my-occupier nobody
          set my-owner nobody
          set rented-to nobody
          set offered-to nobody
          ;; put the ownership back on the market, but now without an owner
          put-on-market
        ]
      ]
      ;; assure the owner being evicted now has no house and no ownership
      set my-house nobody
      set my-ownership (list)
      set mortgage (list)
      set repayment (list)
      set income-rent (list)
      set surplus-rent (list)
      ;; assure the homeless count is set back to 0
      set homeless 0
      stop
    ]

    ;; if I am living in a rented house
    if [myType] of my-house = "rent" [
      ;; put my house back on the rented market without an occupier
      ask my-house [
        set my-occupier nobody
        set rented-to nobody
        put-on-market
      ]
      ;; assure the landlord decreases their income-rent due to the eviction of a tenant
      let landlord [my-owner] of my-house
      if is-owner? landlord [
        let index-temp position my-house [my-ownership] of landlord
        ask landlord [
          set income-rent replace-item index-temp income-rent 0
          set surplus-rent replace-item index-temp surplus-rent (0 - item index-temp repayment)
        ]
      ]
      ;; assure I now have no house and set homeless to 0
      set my-house nobody
      set homeless 0
    ]
    hide-turtle
  ]
end 

to force-sell-rent [sellers]
  ask sellers [
    ;; find all the ownership that is not the house I live in (this is to avoid selling the house I occupy and becoming homeless)
    let my-ownership-temp turtle-set my-ownership
    let surplus-rent-temp remove-item 0 surplus-rent
    let house-to-sell nobody
    let house-to-rent nobody
    ask my-house [set my-ownership-temp other turtle-set my-ownership-temp]
    (ifelse
      any? my-ownership-temp with [for-rent? = true and on-market-period >= maxForRentPeriodPoorLandlord] [
        set house-to-sell one-of my-ownership-temp with [for-rent? = true and on-market-period >= maxForRentPeriodPoorLandlord]
      ]
      ;; if no houses are offered for rent (all occupied), offer the house with the lowest rent profit on the rent market again
      not any? my-ownership-temp with [for-rent? = true] [
        ;type self type " | surplus-rent = " type surplus-rent type " | my-ownership = " type my-ownership type "\n"
        let index-temp position (min surplus-rent-temp) surplus-rent
        set house-to-rent item index-temp my-ownership
      ]

    )

    if any? turtle-set house-to-sell [
      ;; manage house to sell
      ask house-to-sell [
        if is-owner? my-occupier [
          let my-occupier-temp my-occupier
          evict my-occupier-temp
          enter-market my-occupier-temp "rent"
        ]
        set myType "mortgage"
        put-on-market
      ]
    ]

    if any? turtle-set house-to-rent [
      ;; manage house to rent
      ask house-to-rent [
        if is-owner? my-occupier [
          let my-occupier-temp my-occupier
          evict my-occupier-temp
          enter-market my-occupier-temp "rent"
        ]
        set myType "rent"
        put-on-market
      ]
    ]
  ]
end 


;; force seller to put one of their ownership on the amrket (only triggered when a landlord is not well-off and needs to sell)

to force-sell [sellers]
  ask sellers [
    ;; find all the ownership that is not the house I live in (this is to avoid selling the house I occupy and becoming homeless)
    let my-ownership-temp turtle-set my-ownership
    let house-to-sell nobody
    ask my-house [set my-ownership-temp other turtle-set my-ownership-temp]
    ;; if there is a house that is not for sale and is not rented, sell that house
    ifelse any? my-ownership-temp with [for-sale? = false and rented-to = nobody] [
      set house-to-sell one-of my-ownership-temp with [for-sale? = false and rented-to = nobody]
    ]
    ;; if all the houses are rented, check the one that will yield the highest capital and sell it
    [
      ;; start from index 1 as the first item in the list is always my-house
      let i 1
      ;; set a list with one element 0 (reflecting no benefit from selling own house)
      let surplus (list 0)
      ;; loop into the ownership to create a list of surplus values
      while [i < length my-ownership] [
        let mortgage-temp item i mortgage
        let price-temp [sale-price] of item i my-ownership
        set surplus lput (price-temp - mortgage-temp) surplus
        set i i + 1
      ]
      ;; select the ownership leading to the highest surplus
      let index-temp position max(surplus) surplus
      set house-to-sell item index-temp my-ownership
    ]

    if any? turtle-set house-to-sell [
      ;; amange
      ask house-to-sell [
        if is-owner? my-occupier [
          let my-occupier-temp my-occupier
          evict my-occupier-temp
          enter-market my-occupier-temp "rent"
        ]
        set myType "mortgage"
        put-on-market
      ]
    ]
  ]
end 

;; enter the market for mortgage or rent

to enter-market [candidates market-type]
  ask candidates [
    set on-cooldown? false
    set time-on-cooldown 0
    set time-on-market 0
    set on-market? true
    set on-market-type market-type
  ]
end 

to new-houses
   ;; 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 ]  [build-house "mortgage"]
  ]
  reset-empty-houses ; set sale and rent price

  ask houses with [ quality = 0 ] [ ;; ask each house 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
  ]
end 

to trade-houses
  let houses-for-sale houses with [ for-sale? = true]                                  ;; find all the houses for sale
  ;; Consider for-rent?
  let houses-for-rent houses with [ for-rent? = true]
  value-hosues houses-for-sale houses-for-rent

  ;; we check here whether houses are on-market or not (as this is a decision that should have been premade by the owner)
  let buyers owners with [ on-market? = true ]  ;; put all owners who don't have a house or whose houses on sale under `buyers`


  make-offers buyers houses-for-sale houses-for-rent
  ;; 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

  ;; Removed the condition --> not is-house? my-house (as in this version, traders are any buyers on the market that made an offer regardless of my-house)
  ask buyers with [ is-house? made-offer-on and on-market? = true] [           ;; ask buyers who have no houses and made offer on a house
                                                                               ;; self is buyer, and check whether the buy-sell chain is intact or not
    if follow-chain self self [
      ;move-house                                                          ;; if intact, deal is made, and households move out and into houses, count the number of moves
      move-house self
    ]
  ]
end 

to value-hosues [houses-for-sale houses-for-rent]
  ;; 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.
  ;; because sellers will ask all local-realtors to value the house again and the seller will choose my-realtor again to update the sale-price

  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
      set my-realtor max-one-of turtle-set 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
    ]                                                                                   ;; update the average-price of each realtor
    ask realtors [                                                                 ;; ask each realtor
      let my-houses-for-sale houses-for-sale with [ member? myself local-realtors and myType = "mortgage"] ;; 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
    ]
    set medianPriceOfHousesForSale median [sale-price] of houses-for-sale
  ]

  if any? houses-for-rent [                                                      ;; if these houses exist
    ask houses-for-rent with [ date-for-rent = ticks ] [                         ;; ask each of those houses which are just on sale from now on
      set my-realtor max-one-of turtle-set local-realtors [ valuation myself ]               ;; set the realtor gives the current house the highest valuation to be my-realtor
      ;; Modified to rent-price
      set rent-price [ valuation myself ] of my-realtor                           ;; take the highest value valuation price as sale-price of the current house
    ]                                                                                  ;; update the average-price of each realtor
    ask realtors [                                                                 ;; ask each realtor
      let my-houses-for-rent houses-for-rent with [ member? myself local-realtors and myType = "rent"] ;; get all houses under this realtor
      ;; Modified to median of rent-price
      if any? my-houses-for-rent [ set average-rent median [ rent-price ] of my-houses-for-rent ] ;; if these houses exist, take their median price as the realtor's average-price for its all houses
    ]
    ;; Modified to rent-price
    set medianPriceOfHousesForRent median [rent-price] of houses-for-rent           ;; update median price of all houses on sale
  ]
end 

to-report valuation [ property ]    ;; realtor procedure
  ;; valuation house price by realtor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  let normalization 1  ;; create a local variable normalization
  let multiplier [ quality ] of property * (1 + RealtorOptimism / 100) * normalization         ;; create a multiplier for final finish of valuation price ;; component of multiplier include quality, optimism, normalization

  let old-price [sale-price] of property  ;; set the input house's sale-price as old price
  let old-rent [rent-price] of property
  let new-price 0  ;; create a new price variable with 0 value
  let new-rent 0
  let ptype [myType] of property

  ; if calculate-wealth? is true, use the saved lists of houses and records in houses (saves run time)
  ifelse calculate-wealth? = true [
    let i position self [local-realtors] of property
    let local-sales-sold item i [local-sales] of property
    let local-sales-rent item i [local-rents] of property
    let plocality [locality-houses] of property

    if ptype = "mortgage" [ ; owned
      ifelse any? turtle-set local-sales-sold  ;; if the local-sales exist
      [ set new-price median [ selling-price ] of turtle-set local-sales-sold ] ;; assign the median price of all record houses to new-price
      [ let local-houses turtle-set filter [h -> [myType] of h = "mortgage"] plocality ;; 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
        ]
        [set new-price average-price ] ;; otherwise set average-price of the realtor to be new-price (is realtor's average-price updated every tick?)
      ]
    ]

    ; not owned
    if ptype = "rent"[
      ifelse any? turtle-set local-sales-rent  ;; if the local-sales exist
                                               ;; modified to new-rent and rent-price
      [ set new-rent median [ renting-price ] of turtle-set local-sales-rent ] ;; assign the median price of all record houses to new-price
      [ let local-houses turtle-set filter [h -> [myType] of h = "rent"] plocality;; 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-rent median [rent-price] of local-houses  ;; set the median price of all local-houses to be new-price
        ]
        [set new-rent average-rent ] ;; otherwise set average-price of the realtor to be new-price (is realtor's average-price updated every tick?)
      ]
    ]
  ]

  ; if calculate-wealth? = false, find the locality houses and the records while evaluating
  [
    let local-sales-sold (turtle-set sales-sold) with [ the-house != nobody and ( [distance property ] of the-house ) < Locality and selling-price > 0]  ;; 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`
    let local-sales-rent (turtle-set sales-rent) with [ the-house != nobody and ( [distance property ] of the-house ) < Locality and renting-price > 0]  ;; new-version

    if ptype = "mortgage" [ ; owned
      ifelse any? local-sales-sold  ;; if the local-sales exist
      [ set new-price median [ selling-price ] of local-sales-sold ] ;; assign the median price of all record houses to new-price
      [ let local-houses houses with [ distance myself <= Locality and myType = "mortagage" ];; 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
        ]
        [set new-price average-price ] ;; otherwise set average-price of the realtor to be new-price (is realtor's average-price updated every tick?)
      ]
    ]

    ; not owned
    if ptype = "rent"[
      ifelse any? local-sales-rent  ;; if the local-sales exist
                                    ;; modified to new-rent and rent-price
      [ set new-rent median [ renting-price ] of local-sales-rent ] ;; assign the median price of all record houses to new-price
      [ let local-houses houses with [ distance myself <= Locality and myType = "rent" ];; 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-rent median [rent-price] of local-houses  ;; set the median price of all local-houses to be new-price
        ]
        [set new-rent average-rent ] ;; otherwise set average-price of the realtor to be new-price (is realtor's average-price updated every tick?)
      ]
    ]
  ]

  let ratio 0
  let threshold 2 ;; a base line for ratio
  if pType = "mortgage" [
    if old-price < 5000 [ report multiplier * new-price ]  ;; if current sale-price is too low, just accept multiplier * new-price  as valuation price
    set ratio new-price / old-price
    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" "."
  ]
  if pType = "rent" [
    if old-rent < 500 [ report multiplier * new-rent ]  ;; if current sale-price is too low, just accept multiplier * new-price  as valuation price
    set ratio new-rent / old-rent
    ifelse ratio > threshold  ;;
    [ set new-rent threshold * old-rent ] ;; if new-rent is more than twice old-rent,  make new-rent twice of old-rent. "
    [ if ratio < 1 / threshold [  set new-rent old-rent / threshold ] ]  ;;  if new-rent is less than half of old-rent, make new-rent half of old-rent.
    report  multiplier * new-rent  ;; finally report multiplier * new-rent" "."
  ]
end 

to make-offers [buyers houses-for-sale houses-for-rent]
  ;; make an offer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Owners make an offer based on the market type they are in
  ; start with "mortgage" | these "owners" want to buy a house to reside in
  ask buyers with [ on-market? = true and on-market-type = "mortgage" ] [
    make-offer-mortgage houses-for-sale
  ]
  ; second, address "buy-to-let" | these buyers already have a house and they are well-off enough to buy another one
  ask buyers with [ on-market? = true and on-market-type = "buy-to-let" ] [
    make-offer-mortgage houses-for-sale
  ]
  ; third, address "rent" | these buyers do not own a house and want to become a tenant
  ask buyers with [ on-market? = true  and on-market-type = "rent" ] [
    make-offer-rent houses-for-rent
  ]
  set nOwnersOffered count owners with [is-house? made-offer-on ]
end 

to make-offer-mortgage [ houses-for-sale ]
  ;; increment the time on market counter by 1 (applied for all market types)
  set time-on-market time-on-market + 1

  if on-market-type = "mortgage" [
    ;; use current income, Affordability, interestPerTick to calc new-mortgage
    let new-repayment (income * Affordability / (ticksPerYear * 100))
    let new-mortgage (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) * new-repayment / interestPerTick
    ;set deposit ( new-mortgage * ( 100 /  MaxLoanToValue - 1 ) )  ;; create deposit

    ;; use current income, Affordability, interestPerTick to calc new-mortgage
    ;let new-mortgage income * Affordability / ( interestPerTick * ticksPerYear * 100 )
    ;; actual budget for buying a house == new-mortgage - duty or tax we get back
    let budget new-mortgage - stamp-duty-land-tax new-mortgage
    ;; buyer use capital to pay for new deposit
    let deposit capital
    ;; under the context of owners, if it has a house, update new deposit with new deposit + sale-price of current house - current mortgage of my-house
    if is-house? my-house [
      let index-temp position my-house my-ownership
      if [for-sale?] of my-house = true [set deposit deposit + ([ sale-price ] of my-house - item index-temp mortgage) ]
    ]
    ;; upperbound = the maximum amount afford to offer on a house = new mortgage - duty-back + new deposit
    let upperbound budget + deposit
    ;; if mortgage is less than house value => (MaxLoanToValue/100 < 100/100 ) ;; update upperbound with the less between two similar values
    if MaxLoanToValue < 100 [set upperbound min ( list (budget + deposit) (deposit / ( 1 - MaxLoanToValue / 100 )) ) ]

    ;; if I cannot purchase, but I have a house, get out of the market for this round and assure any offers made to my house are removed
    if upperbound < 0 and is-house? my-house[
      set on-market? false
      set on-market-type nobody
      ask my-house [
        set for-sale? false
        set for-rent? false
        if is-owner? offered-to [ask offered-to [set made-offer-on nobody]]
        set offered-to nobody
        set rented-to nobody
      ]
      stop
    ]
    ;; if I cannot purchase and I do not have a house, stay on the market (i.e., do nothing)
    if upperbound < 0 and not is-house? my-house [stop]

    ;; set lowerbound to be 70% of upperbound
    let lowerbound upperbound * 0.7
    ;; get the current owner's my-house under `current-house`
    let current-house my-house
    let current-ownership turtle-set my-ownership
    ;; from all the houses on sale, get those
    ;; without offer
    ;; and sale-prices within upperbound
    ;; and sale-prices greater than lowerbound
    ;; and the house is not current house, assinged  into `interesting-houses`
    let interesting-houses houses-for-sale with [
      not is-owner? offered-to and
      sale-price <= upperbound and
      sale-price > lowerbound and
      self != current-house ]
    ;; assure buyers on mortgage market do not make offers on their own houses
    if any? current-ownership [ask current-ownership [set interesting-houses other interesting-houses]]
    ;; if number of interesting-houses > BuyerSearchLength (number of houses buyers willing to see)
    ;; then select randomly BuyerSearchLength number of interesting-houses
    if count interesting-houses > BuyerSearchLength [set interesting-houses n-of BuyerSearchLength interesting-houses with [sale-price < (budget + deposit)]]
    ;; if interesting-houses exist
    if any? interesting-houses [
      ;; find the house with the maximum sale-price of interesting-houses and assigned to `property` a local-var
      let property max-one-of interesting-houses [ sale-price ]
      ;; if the `property` is a house
      if is-house? property [
        ;; assign the current owner as `offered-to` under the context of `property`
        ;; set `ticks` to be `offer-date` (house property)
        ask property [
          set offered-to myself
          set offer-date ticks
        ]
        ;; assign `property` (a house ) to owner's property `made-offer-on`
        set made-offer-on property
      ]
    ]
  ]

  if on-market-type = "buy-to-let" [
    ;; use current income, Affordability, interestPerTick to calc new-mortgage
    let new-repayment (income * Affordability / (ticksPerYear * 100))
    let new-mortgage (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear )) * new-repayment / interestPerTick
    ;let new-mortgage income * Affordability / ( interestPerTick * ticksPerYear * 100 )
    ;; actual budget for buying a house == new-mortgage - duty or tax we get back
    let budget new-mortgage - stamp-duty-land-tax new-mortgage
    ;; buyer use capital to pay for new deposit
    let deposit capital
    ;; upperbound = the maximum amount afford to offer on a house = new mortgage - duty-back + new deposit
    let upperbound budget + deposit
    ;; if mortgage is less than house value => (MaxLoanToValue/100 < 100/100 ) ;; update upperbound with the less between two similar values
    if MaxLoanToValue < 100 [set upperbound min ( list (budget + deposit ) ( deposit / ( 1 - MaxLoanToValue / 100 ))) ]
    ;; under the context of owners, if it has a house, update new deposit with new deposit + sale-price of current house - current mortgage
    if upperbound < 0 [
      set on-market? false
      set on-market-type nobody
      stop
    ]
    ;; set lowerbound to be 70% of upperbound
    let lowerbound upperbound * 0.7
    ;; get the current owner's my-house under `current-house`
    let current-house my-house
    ;; get the current owner's my-ownership under 'current-ownership'
    let current-ownership turtle-set my-ownership
    ;; from all the houses on sale, get those
    ;; without offer
    ;; and sale-prices within upperbound
    ;; and sale-prices greater than lowerbound
    ;; and the house is not current house, assinged  into `interesting-houses`
    let interesting-houses houses-for-sale with [
      not is-owner? offered-to and
      sale-price <= upperbound and
      sale-price > lowerbound and
      self != current-house ]
    ;; assure buyers on buy-to let market do not make offers on their own houses
    if any? current-ownership [ask current-ownership [set interesting-houses other interesting-houses]]
    ;; if number of interesting-houses > BuyerSearchLength (number of houses buyers willing to see)
    ;; then select randomly BuyerSearchLength number of interesting-houses
    if count interesting-houses > BuyerSearchLength [set interesting-houses n-of BuyerSearchLength interesting-houses with [sale-price < (budget + deposit)]]
    ;; if interesting-houses exist
    if any? interesting-houses [
      ;; find the house with the maximum sale-price of interesting-houses and assigned to `property` a local-var
      let property max-one-of interesting-houses [ sale-price ]
      ;; if the `property` is a house
      if is-house? property [
        ;; assign the current owner as `offered-to` under the context of `property`
        ;; set `ticks` to be `offer-date` (house property)
        ask property [
          set offered-to myself
          set offer-date ticks
        ]
        ;; assign `property` (a house ) to owner's property `made-offer-on`
        set made-offer-on property
      ]
    ]
  ]
end 

to make-offer-rent [ houses-for-rent ]
  ;; increment the time on market counter by 1
  set time-on-market time-on-market + 1

  let new-rent income * Affordability / ( ticksPerYear * 100 );; use current income, Affordability, interestPerTick to calc new-mortgage
  let budget new-rent
  let upperbound budget                                                    ;; upperbound = the maximum amount afford to offer on a house = new mortgage - duty-back + new deposit
;  if upperbound < 0 [                                                               ;; if upperbound is less than 0, meaning the owner has negative equity (how it is possible?)
;    ;; modified to for-rent
;    ask my-house [ set for-rent? 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-rent with [                                     ;; from all the houses on sale, get those
                            not is-owner? offered-to and                            ;; without offer
                            rent-price <= upperbound and                            ;; and sale-prices within upperbound
                            rent-price > lowerbound and                             ;; and sale-prices greater than lowerbound
                            self != current-house ]                                 ;; and the house is not current house,            assinged  into `interesting-houses`


  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 [ rent-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`
    ]
  ]
end 

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 

;; function can now be called anywhere (not owner specific)

to-report follow-chain [buyer-tenant first-link]

  ;; If the buyer-tenant did not make any offer or is not on the market in the first place, report a false chain
  if not is-house? [made-offer-on] of buyer-tenant [report false]
  if [on-market?] of buyer-tenant = false [report false]
  ;; If the buyer is on the mortgage market
  if [on-market-type] of buyer-tenant = "mortgage" or [on-market-type] of buyer-tenant = "buy-to-let" [
    let buyer buyer-tenant
    let seller [my-owner] of made-offer-on
    ;; If there is no seller (i.e., house not owned), report a true chain
    if not is-owner? seller [report true]
    ;; If the seller has more than one house (i.e., seller does not need to find another house to buy before the transaction), report a true chain
    if count turtle-set [my-ownership] of seller > 1 [report true]
    if buyer = seller [report true]
    if seller = first-link [report true]
    ;; Else, meaning, if the seller has one house, check if the seller has a confirmed house to buy before making the transaction
    report follow-chain seller first-link
  ]

  if [on-market-type] of buyer-tenant = "rent" [
    let tenant buyer-tenant
    let house-made-offer-on [made-offer-on] of tenant
    let landlord [my-owner] of house-made-offer-on
    ;; If there is no occupier (i.e., the house is vacant and can be directly rented), report true chain
    if not is-owner? [my-occupier] of house-made-offer-on [report true]
    if first-link = [my-occupier] of house-made-offer-on [report true]
    ;; Else, meaning, if there is an occupier, check if that occupier found anouther house to rent or not before making the transaction
    report follow-chain [my-occupier] of house-made-offer-on first-link
  ]
end 

to move-house [buyer-tenant]
  let new-house [made-offer-on] of buyer-tenant
  if not (is-house? new-house) [stop]

  if on-market-type = "mortgage" or on-market-type = "buy-to-let" [
    ;; define buyer and seller
    let buyer buyer-tenant
    let seller [my-owner] of new-house
    ;; address the surplus of the seller if they exist
    if is-owner? seller [manage-surplus-seller seller new-house]
    ;; address the surplus of the buyer (includes managing capital, mortgage and repayments
    ;; manage the budget/capital of buyer
    manage-surplus-buyer buyer
    ;; manage the ownership parameters of the buyer
    manage-ownership-buyer buyer
    ;; if there is a seller, manage their ownership parameters
    if is-owner? seller [
      manage-ownership-seller seller new-house
    ]

  ]

  if on-market-type = "rent"[
    ;; define tenant and landlord
    let tenant buyer-tenant
    let landlord [my-owner] of new-house
    ; manage the budget/income of the landlord
    manage-surplus-landlord landlord new-house
    ; manage the budget of the tenant
    manage-surplus-tenant tenant
    ; manage the ownership parameters of the tenant
    manage-ownership-tenant tenant
  ]
end 

to manage-ownership-tenant [tenant]
  let new-house [made-offer-on] of tenant
  let house-temp my-house
  ask tenant [
    ;; if seller is an owner, calc the rent and assign.
    ;; record the rent transaction
    hatch-records 1 [
      hide-turtle
      move-to new-house
      set date ticks
      set date ticks
      set the-house new-house
      set selling-price 0
      set renting-price [rent-price] of new-house
      ;ask [ my-realtor ] of new-house [ file-record myself ]
      file-record ([my-realtor] of new-house) (self)
    ]
    ;; manage the parameters of the renter
    show-turtle
    move-to new-house
    set homeless 0
    set time-on-market 0
    set on-cooldown? false
    set time-on-cooldown 0
    set myType "rent"
    set my-house new-house
    set my-rent [ rent-price ] of new-house
    set my-ownership (list)
    set made-offer-on nobody
    set on-market? false
    set on-market-type nobody
    ; manage the parameters of the new-house
    ask new-house [
      ;; make sure the occupier unregisters the house from their my-house parameter
      ;; the occupier will later rent another house (this is checked within the follow-chain function)
      if is-owner? my-occupier [ask my-occupier [set my-house nobody]]
      set my-occupier myself
      set rented-to myself
      set for-sale? false
      set for-rent? false
    ]
    ; manage the parameters of the old house
    if is-house? house-temp [
      ask house-temp [
        set my-occupier nobody
        set rented-to nobody
        set for-sale? false
        set for-rent? true
      ]
    ]
  ]
end 

to manage-ownership-buyer [buyer]
  let new-house [made-offer-on] of buyer
  ask buyer [
    let house-temp my-house
    if on-market-type = "mortgage" [
      ;; record the sale transaction
      hatch-records 1 [
        hide-turtle
        move-to new-house
        set date ticks
        set the-house new-house
        set selling-price [sale-price] of new-house
        set renting-price [rent-price] of new-house
        ;ask [ my-realtor ] of new-house [ file-record myself ]
        file-record ([my-realtor] of new-house) self
      ]

      ;; manage the situation when a renter is buying and moving from their current my-house
      if is-house? my-house [
        if [myType] of my-house = "rent" [
          ask my-house [
            set my-occupier nobody
            set rented-to nobody
            put-on-market
          ]
        ]
      ]

      ;; move to the new house
      show-turtle
      move-to new-house
      set homeless 0
      set time-on-market 0
      set on-cooldown? false
      set time-on-cooldown 0
      set myType "mortgage"
      set my-house new-house
      set date-of-acquire ticks
      ;; address the parameters of the new house, and take it off the market
      ask new-house [
        set myType "mortgage"
        set my-owner myself
        set my-occupier myself
        set rented-to nobody
        set offered-to nobody
        set for-sale? false
        set for-rent? false
      ]

      ;; manage the parameters of the buyer
      set my-ownership (list new-house)
      set made-offer-on nobody
      set on-market? false
      set on-market-type nobody
    ]


    if on-market-type = "buy-to-let" [
      ;; record the transaction
      hatch-records 1 [
        hide-turtle
        move-to new-house
        set date ticks
        set the-house new-house
        set selling-price [sale-price] of new-house
        set renting-price [rent-price] of new-house
        file-record ([my-realtor] of new-house) self
      ]
      ;; manage the parameters of the new house, and put it on the rent market (the buy-to-let buyers must directly put their new purchase on the "rent" market)
      ask new-house [
        set myType "rent"
        set my-owner myself
        set my-occupier nobody
        set rented-to nobody
        set offered-to nobody
        put-on-market
      ]
      ;; manage the parameters of the buyer
      set time-on-market 0
      set on-cooldown? false
      set time-on-cooldown 0
      set my-ownership (lput new-house my-ownership)
      set made-offer-on nobody
      set on-market? false
      set on-market-type nobody
    ]
  ]
end 

to manage-ownership-seller [seller seller-house]
  ask seller [
    ;let my-ownership-temp my-ownership
    ;ask seller-house [set my-ownership-temp other turtle-set my-ownership-temp]
    ;set my-ownership my-ownership-temp
    set my-ownership remove seller-house my-ownership
  ]
end 

;; manages the surplus from a trade for the seller of an input house

to manage-surplus-seller [seller seller-house]
  let new-house seller-house
  ;let surplus [sale-price] of seller-house - [mortgage] of seller
  ask seller [
    ;; find the index of the seller-house
    let index-temp position seller-house my-ownership
    ;; find the mortgage of the seller-house
    let mortgage-temp item index-temp mortgage
    ;; calculate the monetary surplus from selling the house (surplus should always be above or equal 0)
    let surplus [sale-price] of seller-house - mortgage-temp
    set capital capital + surplus
    set mortgage remove-item index-temp mortgage
    set mortgage-initial remove-item index-temp mortgage-initial
    set repayment remove-item index-temp repayment
    set income-rent remove-item index-temp income-rent
    set surplus-rent remove-item index-temp surplus-rent
    set rate remove-item index-temp rate
    set rate-duration remove-item index-temp rate-duration
    set mortgage-duration remove-item index-temp mortgage-duration


    ;; surplus is higher than 0, meaning the seller made a profit above their total mortgage
    ;ifelse surplus >= 0 [set mortgage 0 set capital capital + surplus]
    ;; surplus is lower than 0, meaning the seller still has to pay a mortgage (all sale-price covers part of the mortgage)
    ;[set mortgage abs(surplus)]
    ;; calc repayment to pay back mortgage again after selling the house
    ;set repayment mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear ))
  ]
end 

;; owner function, manages capital, mortgage and repayment

to manage-surplus-buyer [buyer]
  let new-house [made-offer-on] of buyer
  ;; deduct the costs from the buyer (we are certain the owner has no my-ownership, else they will be on the buy-to-let market)
  let duty stamp-duty-land-tax [sale-price] of new-house
  let price-and-duty [sale-price] of new-house + duty
  ask buyer [
    ; if capital is not enough to pay for the house
    ifelse [sale-price] of new-house > capital [
      ; borrow as much as possible, given owner's income and value of house, choose the smaller value of two calc formula
      ; make sure the buyer adds to their current mortgage (to make sure if they are no buy-to-let their mortgage accounts for more than one house)
;      let mortgage-temp (min (list (income * Affordability / ( interestPerTick * ticksPerYear * 100 ))
;        ([ sale-price ] of new-house * MaxLoanToValue / 100 )))
      ;; after paying rest with capital, the remaining is still kept inside capital
;      set capital capital - int ([ sale-price ] of new-house - mortgage-temp) - duty

      let mortgage-temp (price-and-duty - capital)
      set capital 0

      ;; calc repayment to pay back mortgage
      let repayment-temp mortgage-temp * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * TicksPerYear ))
      ;; assign the repayment-temp and mortgage temp to their respective list for the owners
      set mortgage lput mortgage-temp mortgage
      set mortgage-initial lput mortgage-temp mortgage-initial
      set repayment lput repayment-temp repayment
      set income-rent lput 0 income-rent
      set surplus-rent lput (0 - repayment-temp) surplus-rent
      ;; assign the mortgage rate and rate duration
      set rate lput interestPerTick rate
      ifelse length my-ownership = 0
      [set rate-duration lput ((MinRateDurationM + random (MaxRateDurationM - MinRateDurationM)) * ticksPerYear) (rate-duration)]
      [set rate-duration lput ((MinRateDurationBTL + random (MaxRateDurationBTL - MinRateDurationBTL)) * ticksPerYear) (rate-duration)]
      set mortgage-duration lput (MortgageDuration * ticksPerYear) mortgage-duration
    ]
    ; or if the buyer is a cash buyer, capital pays all, mortgage, repayment both are 0, and remaining still kept in capital
    [
      ;; if the buyer is paying in cash, their mortgage and repayment do not change
      set capital capital - [sale-price] of new-house - duty
      if capital < 0 [set capital 0]
      set mortgage lput 0 mortgage
      set mortgage-initial lput 0 mortgage-initial
      set repayment lput 0 repayment
      set income-rent lput 0 income-rent
      set surplus-rent lput 0 surplus-rent
      set rate lput 0 rate
      ;; nobody in rate-duration is a dummy variable assuring that this mortgage is never checked
      set rate-duration lput nobody rate-duration
      set mortgage-duration lput nobody mortgage-duration
    ]
  ]
end 

to manage-surplus-landlord [landlord landlord-house]
  let rent-temp [rent-price] of landlord-house
  let index-temp position landlord-house [my-ownership] of landlord
  let repayment-temp item index-temp [repayment] of landlord
  ;; add the rent to the yearly income of the landlord
  ask landlord [
    set income-rent replace-item index-temp income-rent rent-temp
    set surplus-rent replace-item index-temp surplus-rent (rent-temp - repayment-temp)
  ]
end 

to manage-surplus-tenant [tenant]
  ;; assign the rent parameter of the tenant
  let new-house [made-offer-on] of tenant
  ask tenant [
    set my-rent [ rent-price ] of new-house
  ]
end 

to remove-outdates

  ;; 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-rent remove nobody sales-rent ] ;; ask realtors to remove dead records from the sales list
  ask realtors [ set sales-sold remove nobody sales-sold ] ;; 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
    ;set for-sale? false
    ;set for-rent? false
  ]
end 

to demolish-houses
   ;; 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-sold min-price-fraction * medianPriceOfHousesForSale ;; set minimum-price to be 10% of all sold-houses median price
    let minimum-price-rent min-price-fraction * medianPriceOfHousesForRent ;; set minimum-price to be 10% of all sold-houses median price
    let houses-rent houses with [myType = "rent"]
    let houses-sell houses with [myType = "mortgage"]

    ;; ask all houses, if its life is over its life limit or if the house is for sale and sale-price < minimum-price
    let houses-to-demolish (turtle-set
      houses-sell with [ (ticks > end-of-life) or  (for-sale? and sale-price <  minimum-price-sold )]
      houses-rent with [ (ticks > end-of-life) or  (for-rent? and rent-price <  minimum-price-rent )]
    )

    ask houses-to-demolish [
      ;ask realtors [ unfile-record myself ] ;; delete any record that mentions the house inside the sales of a realtor
      ask realtors [unfile-record self myself]
      ; remove the house from the locality of its surrounding houses
      if calculate-wealth? = true [ask turtle-set locality-houses [set locality-houses remove myself locality-houses]]
      ;; if the house is for mortgage and not on sale (i.e., the owner should be the occupier of the house)
      if myType = "mortgage" and for-sale? = false [
        ;; add the sale-price to the capital (this is applied as per the previous model without considering mortgage)
        ask my-owner [
          set capital capital + [sale-price] of myself
        ]
        ;; evict the current occupier
        let my-occupier-temp my-occupier
        evict my-occupier-temp
        enter-market my-occupier-temp "mortgage"
        ;; demolish the house
        die
      ]
      ;; if the house is for mortgage and for sale (i.e., there are two options: (1) the owner put a rent house on the market as a type mortgage; (2) the owner put his/her own my-house on the market)
      if myType = "mortgage" and (for-sale? = true or for-rent? = true) [
        ; If the house is offered to an agent
        if is-owner? offered-to [
          ask offered-to [set made-offer-on nobody]
        ]
        ; if the house has an owner and an occupier (these must always be the same unless there is a bug)
        if is-owner? my-owner and is-owner? my-occupier [
          ask my-owner [
            set capital capital + [sale-price] of myself
          ]

          let my-occupier-temp my-occupier
          evict my-occupier-temp
          enter-market my-occupier-temp "mortgage"

          die

        ]
        ; if the house has an owner but there is nobody occupying it (can happen if it was for rent and is now put on the mortgage market due to a downshock or low income for the owner)
        if is-owner? my-owner and not is-owner? my-occupier [
          ;; remove the house from the owner's current my-ownership
          ;let my-owner-temp my-owner
          ask my-owner [
            ;let my-ownership-temp turtle-set my-ownership
            ;ask myself [set my-ownership-temp other turtle-set my-ownership-temp]
            ;set my-ownership my-ownership-temp

            ;; remove all the items associated to the demolished house from the owner's list
            let index-temp position myself my-ownership
            set my-ownership remove-item index-temp my-ownership
            set mortgage remove-item index-temp mortgage
            set repayment remove-item index-temp repayment
            set income-rent remove-item index-temp income-rent
            set surplus-rent remove-item index-temp surplus-rent
          ]

          die
        ]

        ;; demolish the house
        ;; this is a safety net for mortgage houses (should never be reached in the code)
        die
      ]

      if myType = "rent" [
        ;; manage ownership (landlord)
        if is-owner? my-occupier [
          ;; manage occupier (tenant)
          ;; evict the occupier
          let my-occupier-temp my-occupier
          evict my-occupier-temp
          ;; enter the rent market
          enter-market my-occupier-temp "rent"
        ]
        ;let my-owner-temp my-owner
        ask my-owner [
          ;; add the capital to the landlord of the house
          set capital capital + [sale-price] of myself
          ;; remove the house from the ownership of the landlord
          ;let my-ownership-temp my-ownership
          ;ask myself [set my-ownership-temp other turtle-set my-ownership-temp]
          ;set my-ownership my-ownership-temp

          let index-temp position myself my-ownership
          set my-ownership remove-item index-temp my-ownership
          set mortgage remove-item index-temp mortgage
          set repayment remove-item index-temp repayment
          set income-rent remove-item index-temp income-rent
          set surplus-rent remove-item index-temp surplus-rent
        ]
        ;; make sure that any made offer for this house are cancelled
        if is-owner? offered-to [
          ask offered-to [set made-offer-on nobody]
        ]
        ;; demolish house
        die
      ]
      ;; safety net to assure demolishing happens (in case different types of houses are added to the model in the future)
      die
    ]
  ]
end 

to unfile-record [ input-realtors a-house ]          ;; realtor procedure
  ifelse calculate-wealth? = true [
    let A a-house
    let relevant-records records with [the-house = A]

    ask input-realtors [
      ; find all the records that must be unfiled (will be used for houses)
      let sales-to-remove filter [ s -> [the-house] of s = A ] sales-sold
      let rents-to-remove filter [ s -> [the-house] of s = A ] sales-rent

      ; delete any record that mentions the house
      if [myType] of A = "mortgage" [set sales-sold filter [ s -> [the-house] of s != A ] sales-sold]   ;; new-version]

      if [myType] of A = "rent" [set sales-rent filter [ s -> [the-house] of s != A ] sales-rent]   ;; new-version]

      ; loop through all the records sales that need to be removed
      ask turtle-set sales-to-remove [
        ; loop through all the houses that files the record sale in the current iteration
        ask turtle-set filed-at-houses [
          ; loop through all the local-sales list (each corresponding to one of the `local-realtors` of the house that filed the record in the current iteration)
          foreach local-sales [
            ; remove the record in the current iteration from the local-sales list in the current iteration
            records-list ->
            let index position records-list local-sales
            let filtered-at-index filter [a-record -> not member? a-record sales-to-remove] records-list
            set local-sales replace-item index local-sales filtered-at-index
          ]
        ]
      ]

      ask turtle-set rents-to-remove [
        ask turtle-set filed-at-houses [
          foreach local-rents [
            records-list ->
            let index position records-list local-rents
            let filtered-at-index filter [a-record -> not member? a-record rents-to-remove] records-list
            set local-rents replace-item index local-rents filtered-at-index
          ]
        ]
      ]
    ]
  ]
  ; if calculate-wealth? = false
  [
    ask input-realtors [
      ; delete any record that mentions the house
      if [myType] of a-house = "mortgage" [set sales-sold filter [ s -> [the-house] of s != a-house ] sales-sold]   ;; new-version]
      if [myType] of a-house = "rent" [set sales-rent filter [ s -> [the-house] of s != a-house ] sales-rent]   ;; new-version]
    ]
  ]
end 

to update-prices
  ;; 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? = true and mytype = "mortgage"] [  ;; ask all houses which still are for sale
    set sale-price sale-price * (1 - PriceDropRate / 100 );; to reduce its sale-price by certain amount
    set rent-price rent-price * (1 - RentDropRate / 100 )
    set on-market-period on-market-period + 1
  ]

  ask houses with [ for-rent? = true and mytype = "rent"] [  ;; ask all houses which still are for sale
    set sale-price sale-price * (1 - PriceDropRate / 100 )
    set rent-price rent-price * (1 - RentDropRate / 100 );; to reduce its sale-price by certain amount
    set on-market-period on-market-period + 1
  ]
end 

to update-owners
  ;; update owners' mortgage and repayment in each tick  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ;; manage rents
  ask owners with [is-house? my-house and count turtle-set my-ownership > 1 and sum (mortgage) > 0] [
    foreach my-ownership [ house-temp ->
      let i position house-temp my-ownership
      let mortgage-temp item i mortgage
      let repayment-temp item i repayment
      let income-rent-temp item i income-rent

      ;; replace the mortgage at index i with the new mortgage after repayment
      ;set mortgage replace-item i mortgage ( mortgage-temp - (repayment-temp - (interestPerTick * mortgage-temp)) )
      set mortgage replace-item i mortgage ( mortgage-temp - repayment-temp )
      ;; if the owner paid the full mortgage of the house, set the mortgage and repayments back to zero
      if item i mortgage <= 0 [
        set mortgage replace-item i mortgage 0
        set repayment replace-item i repayment 0
      ]
      ;; calculate capital while adding income rent to the base income every tick
      set capital capital + ( (Savings / 100) * income-surplus )
    ]
  ]

  ;; myType condition was considered againist the value 1. Modified to "mortgage" to align with the new model.
  ask owners with [ is-house? my-house and myType = "mortgage" and sum (mortgage) > 0 and count turtle-set my-ownership = 1] [  ;; ask all owners who do have one house and mortgage to pay
    set mortgage replace-item 0 mortgage ( (item 0 mortgage) - (item 0 repayment) )  ;; mortgage will be reduced due to repayment
                                                                                                             ;; add income rent to the base income every tick
    set capital capital + ( (Savings / 100) * income-surplus )
    if item 0 mortgage <= 0 [  ;; if mortgage is fully repaid, then set both mortgage and repayment to 0
      set mortgage replace-item 0 mortgage 0
      set repayment replace-item 0 repayment 0
    ]
  ]

  ;; update renters' capital in each tick  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; myType condition was considered againist the value 0, Modified to "rent" to align with the new model.
  ask owners with [ is-house? my-house and myType = "rent" ] [  ;; ask all owners who do have houses and mortgage to pay
    set capital capital + ( (SavingsRent / 100) * income-surplus )
    if capital < 0 [
      set capital 0
    ]
  ]

  ;; address the rate duration
  ask owners with [length my-ownership > 0] [
    let i 0
    let l length my-ownership
    while [i < l] [
      ;; if the rate duration reached 0,
      if item i rate-duration = 0 and item i repayment > 0 [
        ;; if there is a change in the interest rate, recalculate the mortgage and the repayment
        if item i rate != interestPerTick [
          ;; find old and new interest rates
          let old-interest (item i rate)
          let new-interest interestPerTick
          ;; find remaining mortgage
          let total-mortgage item i mortgage-initial
          ;; calculate new repayment
          let old-repayment item i repayment
          let new-repayment total-mortgage * interestPerTick / (1 - ( 1 + interestPerTick ) ^ ( - MortgageDuration * ticksPerYear ))
          set repayment replace-item i repayment new-repayment
        ]
        ;; update the owner's rate and rate-duration parameters
        set rate replace-item i rate interestPerTick
        ; if this is the first house in my-ownership list (i.e., my-house)
        ifelse i = 0
        [set rate-duration replace-item i rate-duration ((MinRateDurationM + random (MaxRateDurationM - MinRateDurationM)) * ticksPerYear)]
        [set rate-duration replace-item i rate-duration ((MinRateDurationBTL + random (MaxRateDurationBTL - MinRateDurationBTL)) * ticksPerYear)]
      ]
      let duration-temp 0
      ;; subtract 1 tick from the rate duration
      if item i rate-duration != nobody [
        set duration-temp (item i rate-duration) - 1
        set rate-duration replace-item i rate-duration duration-temp
      ]
      if item i mortgage-duration != nobody [
        set duration-temp (item i mortgage-duration) - 1
        set mortgage-duration replace-item i mortgage-duration duration-temp
      ]
      ;; increment the index in the while loop
      set i i + 1
    ]
  ]

  ;; update the surplus income of all owners
  ask owners [
    update-surplus-income
    update-cooldown
  ]
  ;; update the wealth of
  if calculate-wealth? = true [ask owners [update-wealth]]
end 

to reset-globals
  set nupShocked 0
  set ndownShocked 0
  set nUpShockedSell 0
  set nDownShockedSell 0
  set nUpShockedRent 0
  set nDownShockedRent 0
  set nForceSell 0
  set nHomeless 0
  set medianPriceOfHousesForSale 0
  set medianPRiceOfHousesForRent 0
  set medianSalePriceHouses 0
  set medianRentPriceRentHouses 0
  set investors investorsPercentage / 100
end 

to update-globals
  set medianSalePriceHouses median ([sale-price] of houses with [myType = "mortgage" and sale-price > 0])
  set medianRentPriceRentHouses median ([rent-price] of houses with [myType = "rent" and rent-price > 0])
end 

to update-visualisation
  if visualiseModeCurrent != VisualiseMode [
    if visualiseMode = "Prices" [
      ask houses with [myType = "mortgage"] [set size 0.9 set color scale-color red sale-price (max [sale-price] of houses with [mytype = "mortgage"]) (min [sale-price] of houses with [mytype = "mortgage"])]
      ask houses with [myType = "rent"] [set size 0.9 set color scale-color blue rent-price (max [rent-price] of houses with [mytype = "rent"]) (min [rent-price] of houses with [mytype = "rent"])]
      set visualiseModeCurrent "Prices"
    ]
    if visualiseMode = "Types" [
      ask houses with [myType = "mortgage"] [set size 0.9 set color red]
      ask houses with [myType = "rent"] [set size 0.9 set color sky]
      set visualiseModeCurrent "Types"
    ]
  ]
  ;; these modes have to be called every step (computationally demanding)
  if visualiseMode = "Diversity by prices" [
    ask houses [calculate-diversity]
    ask houses [set color scale-color red diversity (max [diversity] of houses) (min [diversity] of houses)]
    set visualiseModeCurrent "Diversity by prices"
  ]
  if visualiseMode = "Hotspot prices (Getis-Ord)" [
    calculate-G
    ask houses [set color palette:scale-gradient [[0 0 255] [255 255 255] [255 0 0]] G -5 5]
    set visualiseModeCurrent "Hotspot prices (Getis-Ord)"
  ]
end 

to colour-house
  if visualiseMode = "Prices" [
    if myType = "mortgage" [set size 0.9 set color scale-color red sale-price (max [sale-price] of houses with [mytype = "mortgage"]) (min [sale-price] of houses with [mytype = "mortgage"])]
    if myType = "rent" [set size 0.9 set color scale-color blue rent-price (max [rent-price] of houses with [mytype = "rent"]) (min [rent-price] of houses with [mytype = "rent"])]
    stop
  ]
  if visualiseMode = "Types" [
    if myType = "mortgage" [set size 0.9 set color red]
    if myType = "rent" [set size 0.9 set color sky]
    stop
  ]
  if visualiseMode = "Diversity by prices" [
    set color scale-color red diversity (max [diversity] of houses) (min [diversity] of houses)
  ]
end 

to calculate-diversity
  set diversity 0
  let my-neighbours houses-on neighbors
  let min-price min [sale-price] of houses with [myType = "mortgage"]
  let max-price max [sale-price] of houses with [myType = "mortgage"]
  let min-rent min [rent-price] of houses with [myType = "rent"]
  let max-rent max [rent-price] of houses with [myType = "rent"]
  let intervals 3
  let increment-price (max-price - min-price) / intervals
  let increment-rent (max-rent - min-rent) / intervals
  ifelse any? my-neighbours [
    if myType = "mortgage" [
      let threshold min-price
      while [threshold < max-price] [
        let increment-start threshold
        let increment-end threshold + increment-price
        ;; calculate diversity index
        let composite count houses-here with [(sale-price > increment-start) and (sale-price < increment-end)] + count my-neighbours with [sale-price > increment-start and sale-price < increment-end]
        let composite-total count houses-here with [sale-price > increment-start and sale-price < increment-end] + count my-neighbours
        if composite > 0 [set diversity diversity + ( (composite / composite-total) + ln(composite / composite-total) )]
        ;; add to the threshold
        set threshold threshold + increment-price
      ]
    ]
    if myType = "rent" [
      let threshold min-rent
      while [threshold < max-rent] [
        let increment-start threshold
        let increment-end threshold + increment-rent
        ;; calculate diversity index
        let composite count houses-here with [rent-price > increment-start and rent-price < increment-end]  + count my-neighbours with [rent-price > increment-start and rent-price < increment-end]
        let composite-total count houses-here with [rent-price > increment-start and rent-price < increment-end] + count my-neighbours
        if composite > 0 [set diversity diversity + ( (composite / composite-total) + ln(composite / composite-total) )]
        ;; add to the threshold
        set threshold threshold + increment-rent
      ]
    ]
  ]
  [set diversity 0]
  set diversity diversity * -1
end 

to calculate-G
  let sum-price-sqrd 0
  ask houses with [myType = "mortgage" and sale-price > 0] [set sum-price-sqrd sum-price-sqrd + (sale-price * sale-price)]
  ask houses with [myType = "mortgage"] [
    let n count houses with [myType = "mortgage" and sale-price > 0]
    ifelse any? (houses-on neighbors) with [myType = "mortgage" and sale-price > 0] [
      let w 1 / 8
      let sum-w-sqrd 0
      let sum-w w * count (houses-on neighbors) with [myType = "mortgage" and sale-price > 0]
      ask (houses-on neighbors) with [myType = "mortgage" and sale-price > 0] [set sum-w-sqrd sum-w-sqrd + (w * w)]
      let X sum [sale-price] of houses with [myType = "mortgage" and sale-price > 0] / n
      let S sqrt ( (sum-price-sqrd / n) - (X ^ 2) )
      ;type "X = " type X type "| S = " type S type " | sum-state-sqrd = " type sum-state-sqrd type " | sum-w-sqrd = " type sum-w-sqrd type "| denemonator = " type S * sqrt( (n * sum-w-sqrd) - (w * count neighbors) ^ 2) type "\n"
      set G ( (w * sum [sale-price] of (houses-on neighbors) with [myType = "mortgage" and sale-price > 0]) - (X * sum-w) ) /
            ( S * sqrt( ( (n * sum-w-sqrd) - (sum-w) ^ 2 ) / (n - 1) ) )
    ]
    [set G 0]
  ]
  let sum-rent-sqrd 0
  ask houses with [myType = "rent" and rent-price > 0] [set sum-rent-sqrd sum-rent-sqrd + (rent-price * rent-price)]
  ask houses with [myType = "rent"] [
    let n count houses with [myType = "rent" and rent-price > 0]
    ifelse any? (houses-on neighbors) with [myType = "rent" and rent-price > 0] [
      let w 1 / 8
      let sum-w-sqrd 0
      let sum-w w * count (houses-on neighbors) with [myType = "rent" and rent-price > 0]
      ask (houses-on neighbors) with [myType = "rent" and rent-price > 0] [set sum-w-sqrd sum-w-sqrd + (w * w)]
      let X sum [rent-price] of houses with [myType = "rent" and rent-price > 0] / n
      let S sqrt ( (sum-rent-sqrd / n) - (X ^ 2) )
      ;type "X = " type X type "| S = " type S type " | sum-state-sqrd = " type sum-state-sqrd type " | sum-w-sqrd = " type sum-w-sqrd type "| denemonator = " type S * sqrt( (n * sum-w-sqrd) - (w * count neighbors) ^ 2) type "\n"
      set G ( (w * sum [rent-price] of (houses-on neighbors) with [myType = "rent" and rent-price > 0]) - (X * sum-w) ) /
            ( S * sqrt( ( (n * sum-w-sqrd) - (sum-w) ^ 2 ) / (n - 1) ) )
    ]
    [set G 0]
  ]
end 

There are 8 versions of this model.

Uploaded by When Description Download
Yahya Gamal 3 days ago Addressed division by 0 error Download this version
Yahya Gamal 4 days ago Clean UI Download this version
Yahya Gamal 4 days ago Clean UI Download this version
Yahya Gamal 4 days ago Resolved profiler error Download this version
Yahya Gamal 4 days ago Revet back to the JASSS paper version Download this version
Yahya Gamal 5 days ago Fixed errors with applying setup while running Download this version
Yahya Gamal 6 days ago Fixed issues with reset-ticks Download this version
Yahya Gamal 6 days ago Initial upload Download this version

Attached files

File Type Description Last updated
UK Housing ABM Simple UI.png preview Preview for 'UK Housing ABM Simple UI' 6 days ago, by Yahya Gamal Download

This model does not have any ancestors.

This model does not have any descendants.