CViM / src / model / SFC / banks.jl
banks.jl
Raw
"""
Define banks' actions.
"""

"""
    prev_vars!(agent::Bank) → nothing

Update banks' previous variables.
"""
function prev_vars!(agent::Bank)
    agent.deposits_prev = agent.deposits
    agent.hpm_prev = agent.hpm
    agent.loans_prev = agent.loans
    agent.ilf_rate_prev = agent.ilf_rate
    agent.ilh_rate_prev = agent.ilh_rate
    agent.id_rate_prev = agent.id_rate
    agent.advances_prev = agent.advances
    agent.bills_prev = agent.bills
    agent.lending_facility_prev = agent.lending_facility 
    agent.deposit_facility_prev = agent.deposit_facility
    agent.funding_costs_prev = agent.funding_costs
    return nothing
end

"""
    reset_vars!(agent::Bank) → nothing

Reset banks' variables.
"""
function reset_vars!(agent::Bank)
    agent.flow = 0.0
    agent.loans = 0.0 
    agent.deposits = 0.0
    agent.loans_interests = 0.0
    agent.deposits_interests = 0.0
    agent.ON_interbank = 0.0
    agent.Term_interbank = 0.0
    agent.repayment = 0.0
    agent.defaulted_loans = 0.0
    agent.belongToBank = missing
    empty!(agent.ib_customers)
    return nothing
end

"""
    hpm!(agent::Bank, μ, v) → agent.hpm

Update banks' holdings of reserves.
"""
function hpm!(agent::Bank, μ, v)
    agent.hpm = (μ + v) * agent.deposits
    return agent.hpm
end

"""
    bills!(agent::Bank, model) → agent.bills

Update banks' holdings of bills (buffer variable). If bills are negative they are set to zero and banks ask for advances as buffer variable.
"""
function bills!(agent::Bank, model) # id
    agent.bills = agent.deposits + agent.lending_facility - agent.loans - model.μ * agent.deposits - agent.deposit_facility + agent.networth

    if agent.bills < 0.0
        agent.bills = 0.0
    end
    return agent.bills
end

"""
    advances!(agent::Bank, model) → agent.advances

Update banks' advances. If bills are negative, advances act as buffer variable, otherwise banks ask for a proportion of current deposits.
"""
function advances!(agent::Bank, model) # alternative id
    if agent.bills == 0.0 
        agent.advances = agent.loans + agent.deposit_facility + agent.hpm - agent.deposits - agent.lending_facility - agent.networth
    else
        agent.advances = model.v * agent.deposits
    end
    return agent.advances
end

"""
    update_status!(agent::Bank) → agent.status

Update banks' status in the interbank market: borrower, lender or neutral.
"""
function update_status!(agent::Bank)
    if agent.flow < 0 && abs(agent.flow) > (agent.hpm - agent.hpm_prev)
        agent.status = :borrower
    elseif agent.flow > 0 && agent.flow > (agent.hpm - agent.hpm_prev)
        agent.status = :lender
    else
        agent.status = :neutral
    end
    return agent.status
end

"""
    ib_tot_demand!(agent::Bank) → agent.ib_tot_demand

Deficit banks define their total demand for reserves as dependent on their current outflow and `ΔH`.
"""
function ib_tot_demand!(agent::Bank)
    if agent.status == :borrower    
        agent.ib_tot_demand = abs(agent.flow) - (agent.hpm - agent.hpm_prev)
    end
    return agent.ib_tot_demand
end

"""
    ib_tot_supply!(agent::Bank) → agent.ib_tot_supply

Surplus banks define their total demand for reserves as dependent on their current inflow and `ΔH`.
"""
function ib_tot_supply!(agent::Bank)
    if agent.status == :lender
        agent.ib_tot_supply = agent.flow - (agent.hpm - agent.hpm_prev)
    end
    return agent.ib_tot_supply
end

"""
    update_liq_preferences!(agent::Bank, model) → agent.liq_pref

Banks update their liquidity preferences which are anchored to their value types `agent.liq_values` at initialization and 
adjust the value according to i) changes in overnight and term rates, and ii) their interbank status, such that:
1) if overnight (term) rates increase (decrease), borrowers (lenders) would prefer longer (shorter) maturity interbank contracts;
2) if overnight (term) rates decrease (increase), borrowers (lenders) would prefer shorter (longer) maturity interbank contracts;
"""
function update_liq_preferences!(agent::Bank, model)
    if model.ion - model.ion_prev > 0 || model.iterm - model.iterm_prev < 0
        if agent.status == :borrower
            agent.liq_pref -= agent.liq_pref * model.pref 
        elseif agent.status == :lender
            agent.liq_pref += agent.liq_pref * model.pref
        end
    elseif model.ion - model.ion_prev < 0 || model.iterm - model.iterm_prev > 0
        if agent.status == :borrower
            agent.liq_pref += agent.liq_pref * model.pref
        elseif agent.status == :lender
            agent.liq_pref -= agent.liq_pref * model.pref
        end
    end
    agent.liq_pref = max(0.0, min(agent.liq_pref, 1.0))
    return agent.liq_pref
end

"""
    ib_on_demand!(agent::Bank) → agent.ib_on_demand

Banks define their demand for overnight interbank loans dependent on their liquidity preferences.
"""
function ib_on_demand!(agent::Bank)
    if agent.status == :borrower
        agent.ib_on_demand = agent.ib_tot_demand * agent.liq_pref
    end
    return agent.ib_on_demand
end

"""
    ib_term_demand!(agent::Bank) → agent.ib_term_demand

Banks define their demand for term interbank loans as a residual.
"""
function ib_term_demand!(agent::Bank)
    if agent.status == :borrower
        agent.ib_term_demand = agent.ib_tot_demand - agent.ib_on_demand
    end
    return agent.ib_term_demand
end

"""
    ib_on_supply!(agent::Bank) → agent.ib_on_supply

Banks define their supply for overnight interbank loans dependent on their liquidity preferences.
"""
function ib_on_supply!(agent::Bank)
    if agent.status == :lender
        agent.ib_on_supply = agent.ib_tot_supply * agent.liq_pref
    end
    return agent.ib_on_supply
end

"""
    ib_term_supply!(agent::Bank) → agent.ib_term_supply

Banks define their supply for term interbank loans as a residual.
"""
function ib_term_supply!(agent::Bank)
    if agent.status == :lender
        agent.ib_term_supply = agent.ib_tot_supply - agent.ib_on_supply
    end
    return agent.ib_term_supply
end

"""
    update_ib_demand_supply!(agent::Bank) → agent

Updates demand and supply in the interbank market based on the above functions.
"""
function update_ib_demand_supply!(agent::Bank)
    CViM.ib_tot_demand!(agent)
    CViM.ib_tot_supply!(agent)
    CViM.ib_on_demand!(agent)
    CViM.ib_term_demand!(agent)
    CViM.ib_on_supply!(agent)
    CViM.ib_term_supply!(agent)
    return agent
end

"""
    ib_on!(agent::Bank, model) → agent.ON_interbank

Updates banks' overnight stocks.
"""
function ib_on!(agent::Bank, model)
    if agent.status == :borrower && !ismissing(agent.belongToBank)
        if agent.ib_on_demand > model[agent.belongToBank].ib_on_supply
            agent.ON_interbank = model[agent.belongToBank].ib_on_supply
            model[agent.belongToBank].ON_interbank += agent.ON_interbank
        elseif agent.ib_on_demand <= model[agent.belongToBank].ib_on_supply
            agent.ON_interbank = agent.ib_on_demand
            model[agent.belongToBank].ON_interbank += agent.ON_interbank
        end
    end
    return agent.ON_interbank
end

"""
    ib_term!(agent::Bank, model) → agent.Term_interbank

Updates banks' term stocks.
"""
function ib_term!(agent::Bank, model)
    if agent.status == :borrower && !ismissing(agent.belongToBank)
        if agent.ib_term_demand > model[agent.belongToBank].ib_term_supply
            agent.Term_interbank = model[agent.belongToBank].ib_term_supply
            model[agent.belongToBank].Term_interbank += agent.Term_interbank
        elseif agent.ib_term_demand <= model[agent.belongToBank].ib_term_supply
            agent.Term_interbank = agent.ib_term_demand
            model[agent.belongToBank].Term_interbank += agent.Term_interbank
        end
    end
    return agent.Term_interbank
end

"""
    lending_facility!(agent::Bank) → agent.lending_facility

Deficit banks that do not find a suitable partner in the interbank market access the central bank's lending facility
to cover their outflows.    
"""
function lending_facility!(agent::Bank)
    if agent.status == :borrower && ismissing(agent.belongToBank)
        agent.lending_facility = agent.ib_tot_demand
    end
    return agent.lending_facility
end

"""
    deposit_facility!(agent::Bank) → agent.deposit_facility

Surplus banks that do not find a suitable partner in the interbank market access the central bank's deposit facility
to deposit their excess reserves deriving from payment inflows.    
"""
function deposit_facility!(agent::Bank)
    if agent.status == :lender && isempty(agent.ib_customers)
        agent.deposit_facility = agent.ib_tot_supply
    end
    return agent.deposit_facility
end

"""
    funding_costs!(agent::Bank, icb, ion, iterm) → agent.funding_costs

Banks compute their funding costs.
"""
function funding_costs!(agent::Bank, icb, ion, iterm, icbl)
    if agent.status == :borrower
        if !ismissing(agent.belongToBank)
            if agent.ON_interbank > 0.0 && agent.Term_interbank > 0.0
                agent.funding_costs = (icb + ion + iterm)/3
            elseif agent.ON_interbank > 0.0 && agent.Term_interbank == 0.0
                agent.funding_costs = (icb + ion)/2
            elseif agent.ON_interbank == 0.0 && agent.Term_interbank > 0.0
                agent.funding_costs = (icb + iterm)/2
            end
        else
            agent.funding_costs = (icb + icbl)/2
        end
    else
        agent.funding_costs = icb
    end
    return agent.funding_costs
end

"""
    credit_rates!(agent::Bank, χ1, χ2, χ3) → agent.ilf_rate, agent.ilh_rate, agent.id_rate

Banks determine lending and deposit rates on the credit market.
"""
function credit_rates!(agent::Bank, χ1, χ2, χ3)
    agent.ilf_rate = agent.funding_costs_prev + χ1
    agent.ilh_rate = agent.funding_costs_prev + χ2
    agent.id_rate = agent.funding_costs_prev - χ3
    return agent.ilf_rate, agent.ilh_rate, agent.id_rate
end

"""
    interests_payments!(agent::Bank, model) → model

Banks make interest payments on bills, reserves and advances.
"""
function interests_payments!(agent::Bank, model)
    agent.bills_interests = model.ib * agent.bills_prev
    agent.hpm_interests = model.icb * agent.hpm_prev
    agent.advances_interests = model.icb * agent.advances_prev
    agent.lending_facility_interests = model.icbl * agent.lending_facility_prev
    agent.deposit_facility_interests = model.icbd * agent.deposit_facility_prev
    return model
end

"""
    profits!(agent::Bank) → agent.profits

Banks compute their profits.
"""
function profits!(agent::Bank)
    agent.profits = agent.loans_interests + agent.hpm_interests + agent.bills_interests + agent.deposit_facility_interests - 
                agent.deposits_interests - agent.advances_interests - agent.lending_facility_interests # + agent.repayment
    return agent.profits
end

"""
    networth!(agent::Bank) → agent.networth

Banks update their networth.
"""
function networth!(agent::Bank)
    agent.networth += agent.repayment - agent.defaulted_loans # agent.loans + agent.deposit_facility + agent.hpm  + agent.bills - agent.deposits - agent.advances - agent.lending_facility
    return agent.networth
end

"""
    current_balance!(agent::Bank) → agent.balance_current

Update banks' current balances for SFC checks.
"""
function current_balance!(agent::Bank)
    agent.balance_current = agent.loans_interests + agent.hpm_interests + agent.bills_interests + agent.deposit_facility_interests -
         agent.deposits_interests - agent.advances_interests  - agent.profits - agent.lending_facility_interests # + agent.repayment
    return agent.balance_current
end

"""
    capital_balance!(agent::Bank) → agent.balance_capital

Update banks' capital balances for SFC checks.
"""
function capital_balance!(agent::Bank)
    agent.balance_capital = (agent.advances - agent.advances_prev) + (agent.deposits - agent.deposits_prev) + 
        (agent.lending_facility - agent.lending_facility_prev) - 
        (agent.loans - agent.loans_prev) - 
        (agent.bills - agent.bills_prev) -
        (agent.hpm - agent.hpm_prev) - 
        (agent.deposit_facility - agent.deposit_facility_prev) + agent.repayment - agent.defaulted_loans

    if abs(agent.balance_capital) > 1e-06
        println(agent.id)
    end
    return agent.balance_capital
end

"""
    SFC!(agent::Bank, model) → model

Define banks' SFC actions and update their accounting.
"""
function SFC!(agent::Bank, model)
    CViM.hpm!(agent, model.μ, model.v)
    CViM.networth!(agent)
    CViM.bills!(agent, model)
    CViM.advances!(agent, model)
    CViM.capital_balance!(agent)
    return model
end