Java tutorial
/* * This file is part of CRISIS, an economics simulator. * * Copyright (C) 2015 John Kieran Phillips * * CRISIS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CRISIS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CRISIS. If not, see <http://www.gnu.org/licenses/>. */ package eu.crisis_economics.abm.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.math3.stat.descriptive.rank.Median; import org.javatuples.Triplet; import com.google.common.eventbus.Subscribe; import com.google.common.primitives.Doubles; import com.google.inject.Injector; import kcl.waterloo.math.ArrayUtils; import sim.engine.SimState; import sim.util.Bag; import ai.aitia.meme.paramsweep.platform.mason.recording.annotation.Recorder; import ai.aitia.meme.paramsweep.platform.mason.recording.annotation.RecorderSource; import ai.aitia.meme.paramsweep.platform.mason.recording.annotation.Recorder.RecordTime; import eu.crisis_economics.abm.agent.ComputeCapitalAdequacyRatioOperation; import eu.crisis_economics.abm.agent.ComputeRiskWeightedAssetsOperation; import eu.crisis_economics.abm.bank.BadBank; import eu.crisis_economics.abm.bank.Bank; import eu.crisis_economics.abm.bank.CommercialBank; import eu.crisis_economics.abm.bank.central.CentralBank; import eu.crisis_economics.abm.bank.central.CentralBankStrategy; import eu.crisis_economics.abm.contracts.Contract; import eu.crisis_economics.abm.contracts.DepositAccount; import eu.crisis_economics.abm.contracts.Employee; import eu.crisis_economics.abm.contracts.loans.Loan; import eu.crisis_economics.abm.contracts.loans.RepoLoan; import eu.crisis_economics.abm.contracts.stocks.StockAccount; import eu.crisis_economics.abm.contracts.stocks.UniqueStockExchange; import eu.crisis_economics.abm.events.BankDividendDecisionMadeEvent; import eu.crisis_economics.abm.firm.ClearingFirm; import eu.crisis_economics.abm.firm.Firm; import eu.crisis_economics.abm.firm.LoanStrategyFirm; import eu.crisis_economics.abm.firm.MacroFirm; import eu.crisis_economics.abm.firm.StockReleasingFirm; import eu.crisis_economics.abm.fund.BaseFund; import eu.crisis_economics.abm.fund.MutualFund; import eu.crisis_economics.abm.fund.Fund; import eu.crisis_economics.abm.fund.NoiseTraderFund; import eu.crisis_economics.abm.fund.PortfolioFund; import eu.crisis_economics.abm.government.Government; import eu.crisis_economics.abm.household.ConsumerHousehold; import eu.crisis_economics.abm.household.DepositingHousehold; import eu.crisis_economics.abm.household.Household; import eu.crisis_economics.abm.household.MacroHousehold; import eu.crisis_economics.abm.markets.clearing.ClearingHouse; import eu.crisis_economics.abm.markets.clearing.SimpleLabourMarket; import eu.crisis_economics.abm.markets.clearing.heterogeneous.ClearingLoanMarket; import eu.crisis_economics.abm.markets.clearing.heterogeneous.ClearingMarketUtils; import eu.crisis_economics.abm.markets.nonclearing.CommercialLoanMarket; import eu.crisis_economics.abm.markets.nonclearing.DepositMarket; import eu.crisis_economics.abm.markets.nonclearing.InterbankLoanMarket; import eu.crisis_economics.abm.markets.nonclearing.StockMarket; import eu.crisis_economics.abm.model.configuration.AbstractPublicConfiguration; import eu.crisis_economics.abm.model.plumbing.AbstractPlumbingConfiguration; import eu.crisis_economics.abm.model.plumbing.AgentGroup; import eu.crisis_economics.abm.model.plumbing.BaseAgentGroup; import eu.crisis_economics.abm.model.plumbing.Plumbing; import eu.crisis_economics.abm.simulation.CustomSimulationCycleOrdering; import eu.crisis_economics.abm.simulation.NamedEventOrderings; import eu.crisis_economics.abm.simulation.Simulation; import eu.crisis_economics.utilities.ArrayUtil; import eu.crisis_economics.utilities.Pair; /** * An abstract base class for simulation models. Implementations of this class should * provide the following methods: * * <ul> * <li> {@link #getAgentBindings()}, which should provide a {@link ConfigurationComponent} * specifying which {@link Agent}{@code s} and market structures to use, and * <li> {@link #getPlumbing()} which should specify the {@link Plumbing} structure to be * used to create and connect {@link Agent}{@code s} and market structures together. * </ul> * * @author phillips * @author bochmann */ /* * Recorder notes: * // LP: lower priority, not originally included, to speed up simulation * and reduce size of log file; * // C: composite data, that can be calculated later, and need not be done * during the simulation; * // U: unnecessary data. * * (a) avg(loanInterestRates): * is an equally weighted measure - not volume-weighted. This was replaced with * "meanLoanInterestRate" so that it remains correct when variable loan rates exist. * (b) */ @Recorder(value = "./MasterModel.csv", recordAt = RecordTime.END_OF_ITERATION, sources = { "aggregateBankCashReservesMinusLiabilitiesToCentralBank", // C "aggregateBankAssets", // C "aggregateBankLeverage", // C "aggEmployment", // LP "AggregateCommercialLoans", // C "aggregateFundAssets", "aggregateHouseholdNetContributionsToFunds", "AggregateInterbankLoans", "avg(bankCapitalAdequacyRatio)", "sd(bankCapitalAdequacyRatio)", "bankCapitalAdequacyRatio", "avg(bankCashReserves)", "sd(bankCashReserves)", "bankCashReserves", "sum(bankCashReserves)", "avg(bankCommercialLoans)", "sd(bankCommercialLoans)", "bankCommercialLoans", "avg(bankDepositAccountHoldings)", "sd(bankDepositAccountHoldings)", "bankDepositAccountHoldings", "avg(bankDepositsFromHouseholds)", "sd(bankDepositsFromHouseholds)", "bankDepositsFromHouseholds", "avg(bankEquity)", "sd(bankEquity)", "bankEquity", "sum(bankEquity)", "avg(bankInterbankLoans)", "sd(bankInterbankLoans)", "bankInterbankLoans", "sum(bankInterbankLoans)", "avg(BankLeverage)", "sd(BankLeverage)", "BankLeverage", "bankLoans", // LP "avg(bankLoans)", // C "sd(bankLoans)", // C "avg(bankRiskWeightedAssets)", "sd(bankRiskWeightedAssets)", "bankRiskWeightedAssets", "BankruptcyEvents", "BanksStockPortfolios", "avg(bankStockPrice)", "sd(bankStockPrice)", "min(bankStockPrice)", "median(bankStockPrice)", "max(bankStockPrice)", "bankStockPrice", "avg(bankTotalAssets)", "sd(bankTotalAssets)", "bankTotalAssets", "CBdepositVolume", "CBequity", // C "CBLoanVolume", "CBovernightDepositRate", "CBrefinancingRate", "CommercialLoansToGDPratio", "dividendPriceRatio", // C "avg(firmDividend)", "sd(firmDividend)", "firmDividend", "min(firmDividend)", "median(firmDividend)", "max(firmDividend)", "avg(firmEquity)", "sd(firmEquity)", "firmEquity", "min(firmEquity)", "median(firmEquity)", "max(firmEquity)", "sum(firmEquity)", // LP "avg(firmGoodsSellingPrice)", "sd(firmGoodsSellingPrice)", "firmGoodsSellingPrice", "min(firmGoodsSellingPrice)", "median(firmGoodsSellingPrice)", "max(firmGoodsSellingPrice)", /* "firmLastChangeInStockPrice)", // C "avg(firmLastChangeInStockPrice)", // C "sd(firmLastChangeInStockPrice)", // C "min(firmLastChangeInStockPrice)", // C "median(firmLastChangeInStockPrice)", // C "max(firmLastChangeInStockPrice)", // C */ "firmLoansDividedByLoansPlusEquity", // C "avg(firmLoansDividedByLoansPlusEquity)", // C "sd(firmLoansDividedByLoansPlusEquity)", // C "min(firmLoansDividedByLoansPlusEquity)", // C "median(firmLoansDividedByLoansPlusEquity)", // C "max(firmLoansDividedByLoansPlusEquity)", // C "firmLoansPerEquity", // LP "avg(firmLoansPerEquity)", // LP "sd(firmLoansPerEquity)", // LP "min(firmLoansPerEquity)", // LP "median(firmLoansPerEquity)", // LP "max(firmLoansPerEquity)", // LP "firmLogStockReturn", // LP "avg(firmLogStockReturn)", // LP "sd(firmLogStockReturn)", // LP "min(firmLogStockReturn)", // LP "median(firmLogStockReturn)", // LP "max(firmLogStockReturn)", // LP "min(firmProduction)", "median(firmProduction)", "max(firmProduction)", "avg(firmProduction)", "sd(firmProduction)", "firmProduction", "min(firmProfit)", "median(firmProfit)", "max(firmProfit)", "avg(firmProfit)", "sd(firmProfit)", "firmProfit", "min(firmRevenue)", "median(firmRevenue)", "max(firmRevenue)", "avg(firmRevenue)", "sd(firmRevenue)", "firmRevenue", "min(firmStockPrice)", "median(firmStockPrice)", "max(firmStockPrice)", "avg(firmStockPrice)", "sd(firmStockPrice)", "firmStockPrice", "FirmPercentileStockPrices", "avg(firmTotalAssets)", "sd(firmTotalAssets)", "firmTotalAssets", "min(firmTotalAssets)", "median(firmTotalAssets)", "max(firmTotalAssets)", "firmTotalStockReturn", // LP "avg(firmTotalStockReturn)", // LP "sd(firmTotalStockReturn)", // LP "min(firmTotalStockReturn)", // LP "median(firmTotalStockReturn)", // LP "max(firmTotalStockReturn)", // LP "GDP", "avg(fundBalance)", "sd(fundBalance)", "fundBalance", "avg(fundEmissionPrice)", "sd(fundEmissionPrice)", "fundEmissionPrice", "avg(fundEquity)", "sd(fundEquity)", "fundEquity", "avg(fundPercentageValueInBonds)", "sd(fundPercentageValueInBonds)", "fundPercentageValueInBonds", "avg(fundPercentageValueInBankBonds)", "sd(fundPercentageValueInBankBonds)", "fundPercentageValueInBankBonds", "avg(fundPercentageValueInGovernmentBonds)", "sd(fundPercentageValueInGovernmentBonds)", "fundPercentageValueInGovernmentBonds", "avg(fundPercentageValueInStocks)", "sd(fundPercentageValueInStocks)", "fundPercentageValueInStocks", "avg(fundPercentageValueInBankStocks)", "sd(fundPercentageValueInBankStocks)", "fundPercentageValueInBankStocks", "avg(fundPercentageValueInFirmStocks)", "sd(fundPercentageValueInFirmStocks)", "fundPercentageValueInFirmStocks", "avg(fundTotalAssets)", "sd(fundTotalAssets)", "fundTotalAssets", // "min(fundTotalAssets)", // "median(fundTotalAssets)", // "max(fundTotalAssets)", "avg(fundUnreservedCash)", "sd(fundUnreservedCash)", "fundUnreservedCash", "CapitalGainsTaxRate", "DividendTaxRate", "IncomeTaxRate", "ValueAddedTaxRate", "GovernmentCashReserve", "GovernmentUnreservedCash", "PublicSectorWorkforce", "PercentageEmployeesWorkingInPublicSector", "PercentageHouseholdsWorkingInPublicSector", "PercentageOfPopulationOnWelfare", "GovernmentCumulativeBailoutCosts", "GovernmentTaxRevenue", "GovernmentBudget", "GovernmentEquity", "GovernmentTotalAssets", "GovernmentTotalLiabilities", "min(householdConsumptionBudget)", "median(householdConsumptionBudget)", "max(householdConsumptionBudget)", "avg(householdConsumptionBudget)", "sd(householdConsumptionBudget)", "householdConsumptionBudget", // "skew(householdConsumptionBudget)", // "kurtosis(householdConsumptionBudget)", "householdEquity", "sum(householdEquity)", // LP "min(householdFundContribution)", "median(householdFundContribution)", "max(householdFundContribution)", "avg(householdFundContribution)", "sd(householdFundContribution)", "householdFundContribution", "min(householdSavings)", "median(householdSavings)", "max(householdSavings)", "avg(householdSavings)", "sd(householdSavings)", "householdSavings", // "skew(householdSavings)", // "kurtosis(householdSavings)", "min(householdTotalAssets)", "median(householdTotalAssets)", "max(householdTotalAssets)", "avg(householdTotalAssets)", "sd(householdTotalAssets)", "householdTotalAssets", "min(householdTotalCashSpentOnGoods)", "median(householdTotalCashSpentOnGoods)", "max(householdTotalCashSpentOnGoods)", "avg(householdTotalCashSpentOnGoods)", "sd(householdTotalCashSpentOnGoods)", "householdTotalCashSpentOnGoods", // "skew(householdTotalCashSpentOnGoods)", // "kurtosis(householdTotalCashSpentOnGoods)", "min(householdTotalIncome)", "median(householdTotalIncome)", "max(householdTotalIncome)", "avg(householdTotalIncome)", "sd(householdTotalIncome)", "householdTotalIncome", // "skew(householdTotalIncome)", // "kurtosis(householdTotalIncome)", "min(householdTotalRemuneration)", "median(householdTotalRemuneration)", "max(householdTotalRemuneration)", "avg(householdTotalRemuneration)", "sd(householdTotalRemuneration)", "householdTotalRemuneration", // "skew(householdTotalRemuneration)", // "kurtosis(householdTotalRemuneration)", /* "min(householdWelfareAllowance)", "median(householdWelfareAllowance)", "max(householdWelfareAllowance)", "avg(householdWelfareAllowance)", "sd(householdWelfareAllowance)", "householdWelfareAllowance", */ // "loanInterestRates", // U // "avg(loanInterestRates)", // U "meanLabourBidPrice", // LP "meanLoanInterestRate", "negativeAggregateBankLiabilitiesToCentralBank", // LP // "stockIndexArray", // U "TaxMoneySpentForBanks", "TotalProduction", // LP "UnemploymentPercentage", "MinUnsoldGoods", "AverageUnsoldGoods", "MaxUnsoldGoods", // "lastChangeInGDP", // "relativeChangeInGDP", // "objectiveFunctionValue", // "GDPvolatilityObjectiveFunction", /* "bankUniqueName", "firmUniqueName", "fundUniqueName", "householdUniqueName" */ }) public abstract class AbstractModel extends Simulation { private static final long serialVersionUID = -5386104326393190433L; /* * * Population * * */ private AgentGroup population = new BaseAgentGroup(); /* * * Standalone Collections for @Recorders * * */ @RecorderSource(value = "fund", collectionLengthMember = "getNumberOfFundsForRecorderSampling()", innerType = BaseFund.class) protected Bag funds = new Bag(); int getNumberOfFundsForRecorderSampling() { /** * XXX * * @Recorder sources are currently not compatible with empty collections. */ return Math.max(1, funds.size()); } @RecorderSource(value = "bank", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()", innerType = CommercialBank.class) protected Bag banks = new Bag(); int getNumberOfCommercialBanksForRecorderSampling() { /** * XXX * * @Recorder sources are currently not compatible with empty collections. */ return Math.max(1, banks.size()); } @RecorderSource(value = "centralBank", collectionLength = 1, innerType = CentralBank.class) protected Bag centralBanks = new Bag(); @RecorderSource(value = "badBank", collectionLength = 1, innerType = BadBank.class) protected Bag badBanks = new Bag(); @RecorderSource(value = "household", collectionLengthMember = "getNumberOfHouseholdsForRecorderSampling()", innerType = Household.class) protected Bag households = new Bag(); int getNumberOfHouseholdsForRecorderSampling() { /** * XXX * * @Recorder sources are currently not compatible with empty collections. */ return Math.max(1, households.size()); } @RecorderSource(value = "government", collectionLength = 1, innerType = Government.class) protected Bag governments = new Bag(); @RecorderSource(value = "firm", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()", innerType = Firm.class) protected Bag firms = new Bag(); int getNumberOfFirmsForRecorderSampling() { /** * XXX * * @Recorder sources are currently not compatible with empty collections. */ return Math.max(1, firms.size()); } /* * * Ctors * * */ /** * Create a {@link AbstractModel} model object. This constructor * is equivalent to {@link #AbstractModel}{@code (1L)}. */ public AbstractModel() { this(1L); } /** * Create a {@link AbstractModel} model with a custom seed. */ public AbstractModel(final long seed) { super(seed); } abstract protected AbstractPublicConfiguration getAgentBindings(); abstract protected AbstractPlumbingConfiguration getPlumbing(); @Override public void start() { final AbstractPublicConfiguration agentsConfiguration = getAgentBindings(); agentsConfiguration.checkParameterValidity(); final AbstractPlumbingConfiguration plumbingConfiguration = getPlumbing(); plumbingConfiguration.checkParameterValidity(); final Injector injector = agentsConfiguration.createInjector(); final Plumbing plumbing = plumbingConfiguration.createInjector().getInstance(Plumbing.class); super.start(); population = plumbing.populate(injector); funds = new Bag(population.getAgentsOfType(Fund.class)); banks = new Bag(population.getAgentsOfType(CommercialBank.class)); centralBanks = new Bag(population.getAgentsOfType(CentralBank.class)); badBanks = new Bag(population.getAgentsOfType(BadBank.class)); households = new Bag(population.getAgentsOfType(Household.class)); governments = new Bag(population.getAgentsOfType(Government.class)); firms = new Bag(population.getAgentsOfType(Firm.class)); System.out.printf("---------------------------------------------\n" + "Financial System with Macroeconomy Simulation\n" + "Simulation Begins \n" + "---------------------------------------------\n"); for (NamedEventOrderings event : NamedEventOrderings.values()) { Simulation.repeat(this, "inspectTotalCashInSystem", CustomSimulationCycleOrdering.create(event, -1)); } for (NamedEventOrderings event : NamedEventOrderings.values()) { Simulation.repeat(this, "inspectTotalCashInSystem", CustomSimulationCycleOrdering.create(event, 100)); } Simulation.repeat(this, "printVerboseState", NamedEventOrderings.AFTER_ALL); Simulation.repeat(this, "resetMemories", NamedEventOrderings.BEFORE_ALL); events().register(this); } @SuppressWarnings("unused") // Scheduled private void printVerboseState() { final AgentGroupPrinter printer = new AgentGroupPrinter(); printer.print(population); } public final AgentGroup getPopulation() { return population; } private List<Pair<Double, Double>> cashRecords = new ArrayList<Pair<Double, Double>>(); /** * A diagnostic tool for inspecting the total cash in the simulation. * * TODO: remove */ @SuppressWarnings("unused") // Scheduled private void inspectTotalCashInSystem() { double totalCashInSystem = 0.; System.out.printf("----------------------------------\n" + "Cash Inspection:\n"); for (Object obj : getBanks()) { final Bank bank = (Bank) obj; System.out.printf("Bank %s cash: %16.10g\n", bank.getUniqueName(), bank.getCashReserveValue()); totalCashInSystem += bank.getCashReserveValue(); } if (hasGovernment()) totalCashInSystem += getGovernment().getCashReserveValue(); System.out.printf("Total cash in system, time %g: %16.10g\n", Simulation.getTime(), totalCashInSystem); System.out.printf("----------------------------------\n"); cashRecords.add(Pair.create(Simulation.getTime(), totalCashInSystem)); } @SuppressWarnings("unused") private void resetMemories() { bankLeveragesAfterPendingDividends.clear(); aggreateBankEquityAfterPendingDividend = 0.; aggreateBankRiskyAssetsAfterPendingDividend = 0.; } /* * * GUIs * * */ /** * Notes: * Do we need to repeat this method here in order for the charts to be created? */ @RecorderSource("meanLabourBidPrice") public double getMeanLabourBidPrice() { return population.getMarketsOfType(SimpleLabourMarket.class).get(0).getInstrument(1) .getDemandWeightedBidWage(); } public double getAvgWealth() { try { double ret = 0.0; ret = getAggregateWealth(); return ret / getNumberOfHouseholds(); } catch (NullPointerException e) { return 0; } } @RecorderSource("AggregateHouseholdWealth") public double getAggregateWealth() { double ret = 0.0; for (final DepositingHousehold household : population.getAgentsOfType(DepositingHousehold.class)) ret += household.getCash(); return ret; } /** * Notes: Problem - this currently returns nominal demand (the budget * allocated for consumption. To get actual household consumption, need to * use goods account / repository to calculate? * * @return */ @RecorderSource(value = "householdConsumptionBudget", collectionLengthMember = "getNumberOfHouseholdsForRecorderSampling()") public List<Double> getHouseholdConsumption() { final List<Double> ret = Doubles.asList(new double[getNumberOfHouseholdsForRecorderSampling()]); int index = 0; for (final ConsumerHousehold household : population.getAgentsOfType(ConsumerHousehold.class)) ret.set(index++, household.getConsumptionBudget()); return ret; } @RecorderSource(value = "bankDepositsFromHouseholds", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankDepositsFromHouseholds() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) { double sumDepositValue = 0.; for (final DepositAccount deposit : bank.getLiabilitiesDeposits()) if (deposit.getDepositor() instanceof Household) sumDepositValue += deposit.getValue(); ret.set(index++, sumDepositValue); } return ret; } /** * XXX * * The current @Recorder structure is not entirely compatible with * collections of heterogenous agent types (Eg. collections of agents of * type Firm, but with distinct implementations). * * Many of the existing @Recorder sources for our model files make the * assumption that Firm collections are, infact, populated with MacroFirm * agents. These agents are cast before accessing public method in the * MacroFirm implementation. This unfortunately means that alternative * implementations of Firm cannot be used with the recorder structure. * * Due to limitations in Aitia @Recorder code, potentially the only good * solutions to issue at present would be to (a) extract visitor operations * for each recorder method not contracted by Firm, (b) contract every * operation sampled by @Recorder code, or (c) check for the implementing * type in the body of the following methods. The latter, although very far * from ideal, is the technique used for the time being. */ /** * Selling price of goods manufactured by firms */ @RecorderSource(value = "firmGoodsSellingPrice", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") public List<Double> getFirmSellingPrices() { final List<Double> salePrices = new ArrayList<Double>(); for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) salePrices.add(firm.getGoodsSellingPrice()); final List<Double> result = new ArrayList<Double>(Collections.nCopies(getNumberOfFirms(), 0.)); for (int i = 0; i < salePrices.size(); ++i) result.set(i, salePrices.get(i)); return result; } @RecorderSource("aggEmployment") public double getAggEmployment() { double ret = 0.; for (Employee employee : population.getAgentsOfType(Employee.class)) ret += employee.getLabourAmountEmployed(); return ret; } public double getTotalWorkforceSize() { double ret = 0.; for (Household agent : getHouseholds()) ret += ((Employee) agent).getMaximumLabourSupply(); return ret; } @RecorderSource("UnemploymentPercentage") public double getUnemploymentPercentage() { return 100 * (1. - getAggEmployment() / getTotalWorkforceSize()); } /** * XXX * * Incompatible with interchangeable {@link Firm} {@link Agent}{@code s}. * Result will be {@code zero} for non-{@link MacroFirm} {@link Agent}{@code s}. */ @RecorderSource("GDP") public double getGDP() { if (Simulation.getTime() <= 0.) return 0.; double gdp = 0.; for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) { // TODO: gdp += firm.getProduction() * firm.getGoodsSellingPrice(); Map<String, Double> amountOfGoodsPurchased = firm.getGoodsPurchased(), effectivePricesOfPurchasedGoods = firm.getPriceOfGoodsPurchased(); for (final Entry<String, Double> record : amountOfGoodsPurchased.entrySet()) { /* * Subtract input goods exchanged during the production process. */ gdp -= record.getValue() * effectivePricesOfPurchasedGoods.get(record.getKey()); } } return gdp; } @RecorderSource("CommercialLoansToGDPratio") public double getCommercialLoansToGDPratio() { if (Simulation.getTime() <= 0.) return 0.; return getAggregateCommercialLoans() / getGDP(); } public Number getAvgFirmEquity() { double ret = 0.; for (final Firm firm : getFirms()) ret += firm.getEquity(); return ret / getFirms().size(); } public Number getAvgFirmAssets() { double ret = 0.; for (final Firm firm : getFirms()) ret += firm.getTotalAssets(); return ret / getFirms().size(); } public Number getAvgFirmLiabilities() { double ret = 0.; for (final Firm firm : getFirms()) ret += firm.getTotalLiabilities(); return ret / getFirms().size(); } /** * XXX * * Incompatible with interchangeable {@link Firm} {@link Agent}{@code s}. * Result will be {@code zero} for non-{@link MacroFirm} {@link Agent}{@code s}. */ public Number getAggMaxAskedLoan() { double ret = 0.; for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) ret += firm.getMaxAskedLoan(); return ret; } public Number getAggEffectiveLoan() { double ret = 0.; for (final Firm firm : population.getAgentsOfType(Firm.class)) { final List<Loan> loanLiabilities = firm.getLiabilitiesLoans(); for (final Loan loan : loanLiabilities) ret += loan.getValue(); } return ret; } @RecorderSource("AverageUnsoldGoods") public Number getAverageUnsoldGoods() { double ret = 0.; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret += firm.getUnsold(); if (ret == 0.) return 0.; else return ret / getFirms().size(); } @RecorderSource("MaxUnsoldGoods") public Number getMaxUnsoldGoods() { double ret = 0.; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret = Math.max(ret, firm.getUnsold()); return ret; } @RecorderSource("MinUnsoldGoods") public Number getMinUnsoldGoods() { double ret = Double.MAX_VALUE; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret = Math.min(ret, firm.getUnsold()); return ret; } public double getAvgPrice() { double ret = 0., totalProduction = 0., pq = 0.; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) { pq += firm.getProduction() * firm.getGoodsSellingPrice(); totalProduction += firm.getProduction(); } ret = pq / totalProduction; return ret; } public Number getAvgProfit() { double ret = 0.; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret += firm.getProfit(); if (ret == 0.) return 0.; else return ret / getFirms().size(); } public Number getMinProfits() { double ret = Double.MAX_VALUE; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret = Math.min(ret, firm.getProfit()); return ret; } public Number getMaxProfits() { double ret = 0.; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret = Math.max(ret, firm.getProfit()); return ret; } public Number getAggDividend() { double ret = 0.; for (final StockReleasingFirm firm : population.getAgentsOfType(StockReleasingFirm.class)) ret += firm.getCurrentDividend(); return ret; } /** * XXX * * Not compatible with non-{@link MacroFirm} {@link Agent}{@code s}. */ public Number getAverageMarkUp() { double ret = 0.; for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) ret += firm.getMarkUp(); if (ret == 0.) return 0.; else return ret / getFirms().size(); } /** * XXX * * Not compatible with non-{@link MacroFirm} {@link Agent}{@code s}. */ public Number getMaxMarkUp() { double ret = 0.; for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) ret = Math.max(ret, firm.getMarkUp()); return ret; } public Number getMinMarkUp() { double ret = 1.e2; for (final MacroFirm firm : population.getAgentsOfType(MacroFirm.class)) ret = Math.min(ret, firm.getMarkUp()); return ret; } public Number getAggHouseholdConsumption() { double ret = 0.; for (final ConsumerHousehold household : population.getAgentsOfType(ConsumerHousehold.class)) ret += household.getConsumptionBudget(); return ret; } public Number getAggHouseholdDeposits() { double ret = 0.; for (final DepositingHousehold household : population.getAgentsOfType(DepositingHousehold.class)) ret += household.getDepositValue(); return ret; } public Number getAggBankInvestments() { double ret = 0.; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) ret += bank.getAssetsInLoans() + bank.getAssetsInStock(); return ret; } @RecorderSource("AggregateCommercialLoans") public double getAggregateCommercialLoans() { double sum = 0.; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) sum += bank.getCommercialLoans(); return sum; } public double getAggBankInvestmentsInStocks() { double ret = 0.; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) ret += bank.getAssetsInStock(); return ret; } /** * Get the aggregate value of fund assets. */ @RecorderSource("aggregateFundAssets") public Number getAggregateFundAssets() { double result = 0.; for (final Fund fund : population.getAgentsOfType(Fund.class)) result += fund.getTotalAssets(); return result; } /** * Compute the total, current, aggregate {@link Fund} investment by instrument. This * method returns a {@link List} of size 5 with the following format:<br><br> * * record:<br> * (1) the aggregate {@link Fund} cash reserve value;<br> * (2) the aggregate value of {@link Fund} investments in {@link Firm} stocks;<br> * (3) the aggregate value of {@link Fund} investments in {@link Bank} stocks;<br> * (4) the aggregate value of {@link Fund} investments in {@link Government} * {@link Bonds};<br> * (5) the aggregate value of {@link Fund} investments in {@link Bank} {@link Bonds}; * <br><br> * * This method includes {@link MutualFund}{@code s} as well as {@link NoiseTraderFund} * {@code s} when computing the overall investment size. */ public List<Double> getAggreateFundAssetsByInvestmentType() { try { double[] result = new double[5]; for (final Fund agent : getFunds()) { final PortfolioFund fund = (PortfolioFund) agent; final double fundAssets = fund.getTotalAssets(), fundCashReserve = fund.getUnallocatedCash(), fundInvestmentInFirmStocks = fund.getPercentageValueInFirmStocks() * fundAssets, fundInvestmentInBankStocks = fund.getPercentageValueInBankStocks() * fundAssets, fundInvestmentInGovernmentBonds = fund.getPercentageValueInGovernmentBonds() * fundAssets, fundInvestmentInBankBonds = fund.getPercentageValueInBankBonds() * fundAssets; result[0] += fundCashReserve; result[1] += fundInvestmentInFirmStocks; result[2] += fundInvestmentInBankStocks; result[3] += fundInvestmentInGovernmentBonds; result[4] += fundInvestmentInBankBonds; } // Normalize to cumulative percentages double total = (result[0] + result[1] + result[2] + result[3] + result[4]); for (int i = 4; i >= 0; --i) for (int j = 0; j < i; ++j) result[i] += result[j]; for (int i = 0; i < 5; ++i) result[i] /= total * 1.e-2; return ArrayUtils.toArrayList(result); } catch (final Exception failed) { return Arrays.asList(0., 0., 0., 0., 0.); } } /** * Compute the total, current, aggregate {@link Bank} investment by instrument. This * method returns a {@link List} of size 5 with the following format:<br><br> * * record:<br> * (1) the aggregate {@link Bank} cash reserve value;<br> * (2) the aggregate value of {@link Bank} investments in {@link Firm} stocks;<br> * (3) the aggregate value of {@link Bank} investments in {@link Bank} stocks;<br> * (4) the aggregate value of {@link Bank} investments in {@link Government} * {@link Bonds};<br> * (5) the aggregate value of {@link Bank} investments in {@link Firm} {@link Loans}; * <br><br> * * Each measurement is expressed as a percentage of total asset values held by all * {@link Bank}{@code s}. */ public List<Double> getAggreateBankAssetsByInvestmentType() { double[] result = new double[5]; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) { double valueOfBankShares = 0., valueOfFirmShares = 0., valueOfGilts = 0., valueOfFirmLoans = 0.; for (final Contract contract : bank.getAssets()) if (contract instanceof StockAccount) { final StockAccount stockAccount = (StockAccount) contract; if (stockAccount.getReleaser() instanceof Bank) valueOfBankShares += stockAccount.getValue(); else if (stockAccount.getReleaser() instanceof Firm) valueOfFirmShares += stockAccount.getValue(); } else if (contract instanceof Loan) { final Loan loan = (Loan) contract; if (hasGovernment() && loan.getBorrower() == getGovernment()) valueOfGilts += loan.getValue(); else if (loan.getBorrower() instanceof Firm) valueOfFirmLoans += loan.getValue(); } result[0] += bank.getCashReserveValue(); result[1] += valueOfFirmShares; result[2] += valueOfBankShares; result[3] += valueOfGilts; result[4] += valueOfFirmLoans; } // Normalize to cumulative percentages double total = (result[0] + result[1] + result[2] + result[3] + result[4]); for (int i = 4; i >= 0; --i) for (int j = 0; j < i; ++j) result[i] += result[j]; for (int i = 0; i < 5; ++i) result[i] /= total * 1.e-2; return ArrayUtils.toArrayList(result); } /** * XXX * * This implementation is specific to MacroHousehold and will break if * an alternative household agent is used. */ @RecorderSource("aggregateHouseholdNetContributionsToFunds") public Number getAggregateHouseholdFundContribution() { double result = 0.; // TODO for (final Fund fund : population.getAgentsOfType(Fund.class)) result += fund.getTotalLiabilities(); return result; } @RecorderSource("GovernmentTaxRevenue") public double getTaxRevenue() { return hasGovernment() ? getGovernment().getTaxRevenue() : 0.; } @RecorderSource("GovernmentBudget") public double getTotalExpensesBudget() { return hasGovernment() ? getGovernment().getTotalExpensesBudget() : 0.; } @RecorderSource("GovernmentCashReserve") public double getGovernmentCashReserveValue() { return hasGovernment() ? getGovernment().getCashReserveValue() : 0.; } @RecorderSource("GovernmentUnreservedCash") public double getUnreservedCash() { return hasGovernment() ? getGovernment().getUnallocatedCash() : 0.; } @RecorderSource("GovernmentEquity") public double getGovernmentEquity() { return hasGovernment() ? getGovernment().getEquity() : 0.; } @RecorderSource("GovernmentTotalAssets") public double getTotalGovernmentAssets() { return hasGovernment() ? getGovernment().getTotalAssets() : 0.; } @RecorderSource("GovernmentTotalLiabilities") public double getTotalGovernmentLiabilities() { return hasGovernment() ? getGovernment().getTotalLiabilities() : 0.; } @RecorderSource("GovernmentCumulativeBailoutCosts") public double getGovernmentCumulativeBailoutCosts() { return hasGovernment() ? getGovernment().getTotalLiquiditySpentOnBailouts() : 0.; } @RecorderSource("PublicSectorWorkforce") public double getPublicSectorWorkforce() { return hasGovernment() ? getGovernment().getLabourForce() : 0.; } @RecorderSource("PublicSectorWorkforcePerTotalAvailableWorkforcePercentage") public double getPublicSectorWorkforcePerTotalAvailableWorkforcePercentage() { return getPublicSectorWorkforce() * 1.e2 / getTotalWorkforceSize(); } @RecorderSource("PublicSectorWorkforcePerTotalEmployedPercentage") public double getPublicSectorWorkforcePerTotalEmployedPercentage() { return getPublicSectorWorkforce() * 1.e2 / getAggEmployment(); } @RecorderSource("CapitalGainsTaxRate") public double getCapitalGainsTaxLevel() { return hasGovernment() ? getGovernment().getCapitalGainsTaxLevel() : 0.; } @RecorderSource("DividendTaxRate") public double getDividendTaxLevel() { return hasGovernment() ? getGovernment().getDividendTaxLevel() : 0.; } @RecorderSource("IncomeTaxRate") public double getIncomeTaxRate() { return hasGovernment() ? getGovernment().getLabourTaxLevel() : 0.; } @RecorderSource("ValueAddedTaxRate") public double getValueAddedTaxRate() { return hasGovernment() ? getGovernment().getGoodsTaxLevel() : 0.; } public int getNumberOfWelfareRecipients() { return hasGovernment() ? getGovernment().getNumberOfWelfareRecipients() : 0; } @RecorderSource("PercentageOfPopulationOnWelfare") public double getPercentageOfPopulationReceivingWelfareBenefits() { return getNumberOfWelfareRecipients() * 1.e2 / getNumberOfHouseholds(); } @Override public void step(final SimState state) { super.step(state); this.updateGDP(); } double lastGDP = 0., currentGDP = 0.; private void updateGDP() { lastGDP = currentGDP; currentGDP = this.getGDP(); } @RecorderSource("lastChangeInGDP") public double getLastChangeInGDP() { if (Simulation.getTime() <= 0.) { return 0.; } else { double dGDP = currentGDP - lastGDP; return dGDP; } } @RecorderSource("relativeChangeInGDP") public double relativeChangeInGDP() { return this.getLastChangeInGDP() / currentGDP; } @RecorderSource("GDPvolatilityObjectiveFunction") public double GDPvolatilityObjectiveFunction() { return (Math.abs(this.relativeChangeInGDP()) - 0.1); } public double getInterestRate() { try { final ClearingLoanMarket market = getClearingHouse().getMarketsOfType(ClearingLoanMarket.class).get(0); // TODO return ClearingMarketUtils.estimateLastReturnRateForLoanMarkets(market, Arrays.asList("Commercial Loan")); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("dividendPriceRatio") /* * Warning - this measurement is merely the dividend-price ratio and does * not include gains/losses due to change in share price (a.k.a. capital gains). */ public double getStockReturn() { double ret = 0.; final List<StockReleasingFirm> firms = population.getAgentsOfType(StockReleasingFirm.class); for (final StockReleasingFirm firm : firms) { try { double price = UniqueStockExchange.Instance.getStockPrice(firm), divPerShare = ((ClearingFirm) firm).getDividendPerShare(); ret += divPerShare / price; } catch (final NullPointerException e) { } } if (firms.size() == 0) return 0.; return ret / getFirms().size(); } @RecorderSource("AggregateInterbankLoans") public double getAggregateInterbankLoans() { double sum = 0.; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) sum += bank.getInterbankLoans(); return sum; } @RecorderSource("CommercialLoansToProductionRatio") public double getCommercialLoansToProductionRatio() { return getAggregateCommercialLoans() / getTotalProduction(); } /** * Get the maximum, minimum and average stock price for firms. * @return A tripplet of doubles, with format * [min. stock price, mean stock price, max. stock price] */ public final Triplet<Double, Double, Double> getFirmStockPrices() { double avgStockPrice = 0., minStockPrice = Double.MAX_VALUE, maxStockPrice = -1.; int numStocksCounted = 0; for (final Firm agent : getFirms()) { final StockReleasingFirm firm = (StockReleasingFirm) agent; try { double pricePerShare = UniqueStockExchange.Instance.getStockPrice(firm); avgStockPrice += pricePerShare; minStockPrice = Math.min(minStockPrice, pricePerShare); maxStockPrice = Math.max(maxStockPrice, pricePerShare); ++numStocksCounted; } catch (final NullPointerException e) { } } if (numStocksCounted > 0) avgStockPrice /= numStocksCounted; return new Triplet<Double, Double, Double>(minStockPrice, avgStockPrice, maxStockPrice); } /** * Get the maximum, minimum and average {@link Bank} stock price. * * @return A tripplet of doubles, with format * [min. stock price, mean stock price, max. stock price] */ public final Triplet<Double, Double, Double> getBankStockPrices() { double avgStockPrice = 0., minStockPrice = Double.MAX_VALUE, maxStockPrice = -1.; int numStocksCounted = 0; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) { final double pricePerShare = UniqueStockExchange.Instance.getStockPrice(bank); avgStockPrice += pricePerShare; minStockPrice = Math.min(minStockPrice, pricePerShare); maxStockPrice = Math.max(maxStockPrice, pricePerShare); ++numStocksCounted; } if (numStocksCounted > 0) avgStockPrice /= numStocksCounted; return new Triplet<Double, Double, Double>(minStockPrice, avgStockPrice, maxStockPrice); } @RecorderSource(value = "FirmPercentileStockPrices", collectionLength = 10) public List<Double> getPercentileFirmStockPrices() { final int numPercentilesToPlot = 10; List<Double> result = new ArrayList<Double>(), allFirmStockPrices = new ArrayList<Double>(); for (final Firm firm : population.getAgentsOfType(StockReleasingFirm.class)) allFirmStockPrices.add(UniqueStockExchange.Instance.getStockPrice(firm.getUniqueName())); for (int i = 0; i < numPercentilesToPlot; ++i) { final double medianPercentile = (1. / numPercentilesToPlot) * (i + 1); Median median = new Median(); median.setData(ArrayUtil.toPrimitive(allFirmStockPrices.toArray(new Double[0]))); result.add(median.evaluate(medianPercentile * 1.e2)); } return result; } @RecorderSource(value = "firmStockPrice", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") // TODO: is this redundant? public List<Double> getFirmStockPriceOvertime() { List<Double> allFirmStockPrices = new ArrayList<Double>(); for (final Firm firm : population.getAgentsOfType(StockReleasingFirm.class)) allFirmStockPrices.add(UniqueStockExchange.Instance.getStockPrice(firm.getUniqueName())); return allFirmStockPrices; } /** * This method is as {@link #getFirmStockPrices()}, with the exception that the * return value is an array of size 3 and not a tripplet of doubles. * @author Ross Richardson */ @RecorderSource(value = "getFirmStockPrices", collectionLength = 3) public final double[] getFirmStockPricesAsArray() { final double[] minAvgMaxArray = new double[3]; minAvgMaxArray[0] = this.getFirmStockPrices().getValue0(); minAvgMaxArray[1] = this.getFirmStockPrices().getValue1(); minAvgMaxArray[2] = this.getFirmStockPrices().getValue2(); return minAvgMaxArray; } /** * This method is equivalent to {@link #getFirmStockPrices()}{@code .getValue1()}. */ @RecorderSource("stockIndexAvg") public double getAverageFirmStockPrice() { return this.getFirmStockPrices().getValue1(); } public Number getAvgBankEquity() { double ret = 0.0; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) ret += bank.getEquity(); return ret / getBanks().size(); } @RecorderSource(value = "bankStockPrice", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") // TODO: is this redundant? public List<Double> getBankStockPriceOvertime() { List<Double> allBankStockPrices = new ArrayList<Double>(); for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) allBankStockPrices.add(UniqueStockExchange.Instance.getStockPrice(bank.getUniqueName())); return allBankStockPrices; } private Map<String, Double> bankLeveragesAfterPendingDividends = new HashMap<String, Double>(); private double aggreateBankRiskyAssetsAfterPendingDividend = 0., aggreateBankEquityAfterPendingDividend; @Subscribe public void listenForBankDividendDecisions(final BankDividendDecisionMadeEvent event) { bankLeveragesAfterPendingDividends.put(event.getBankName(), event.getLeverageAfterDividend()); aggreateBankRiskyAssetsAfterPendingDividend += event.getEffectiveRiskyAssetsValue(); aggreateBankEquityAfterPendingDividend += event.getEffectiveEquity(); } public Number getAvgBankLeverage() { double ret = 0.; for (final Double value : bankLeveragesAfterPendingDividends.values()) ret += value; if (bankLeveragesAfterPendingDividends.size() == 0) return 0.; return ret / bankLeveragesAfterPendingDividends.size(); } @RecorderSource(value = "BankLeverage", collectionLengthMember = "getNumberOfBanks()") public List<Double> getBankLeverageOverTime() { // TODO: temporary return Collections.unmodifiableList(new ArrayList<Double>(bankLeveragesAfterPendingDividends.values())); } @RecorderSource("avgProduction") public double getAvgProduction() { double ret = 0.; final List<LoanStrategyFirm> firms = population.getAgentsOfType(LoanStrategyFirm.class); for (final LoanStrategyFirm firm : firms) ret += firm.getProduction(); if (firms.isEmpty()) return 0.; return ret / getFirms().size(); } @RecorderSource("TotalProduction") public double getTotalProduction() { double totalProduction = 0; for (LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) totalProduction += firm.getProduction(); return totalProduction; } public Number getTotalEmployment() { double ret = 0.; for (final ClearingFirm firm : population.getAgentsOfType(ClearingFirm.class)) ret += firm.getEmployment(); return ret; } @RecorderSource("AggregateBankDeposits") public double getAggregateBankDeposits() { double ret = 0.; List<Double> depositArr = getBankDepositsOverTime(); for (int i = 0; i < depositArr.size(); i++) ret += depositArr.get(i).doubleValue(); return ret; } @RecorderSource(value = "bankLiabilitiesToCentralBank", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankLiabilitiesToCentralBank() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) { double valueBorrowedFromCentralBank = 0.0; for (int i = 0; i < ((Bank) bank).getLiabilities().size(); i++) { if (((Bank) bank).getLiabilities().get(i) instanceof Loan) if (((Loan) ((Bank) bank).getLiabilities().get(i)).getLender() instanceof CentralBank) valueBorrowedFromCentralBank += ((Bank) bank).getLiabilities().get(i).getValue(); if (((Bank) bank).getLiabilities().get(i) instanceof RepoLoan) if (((RepoLoan) ((Bank) bank).getLiabilities().get(i)).getLender() instanceof CentralBank) valueBorrowedFromCentralBank += ((Bank) bank).getLiabilities().get(i).getValue(); } ret.set(index++, valueBorrowedFromCentralBank); } return ret; } @RecorderSource("negativeAggregateBankLiabilitiesToCentralBank") public double getNegativeAggregateBankLiabilitiesToCentralBank() { double ret = 0; for (int i = 0; i < getBankLiabilitiesToCentralBank().size(); i++) ret -= getBankLiabilitiesToCentralBank().get(i); return ret; } @RecorderSource("aggregateBankCashReservesMinusLiabilitiesToCentralBank") public double getAggregateBankCashReservesMinusLiabilitiesToCentralBank() { return getAggregateBankCashReserves() + getNegativeAggregateBankLiabilitiesToCentralBank(); } @RecorderSource("CBLoanVolume") public double getCBLoanVolume() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return ((CentralBankStrategy) centralBank.getStrategy()).getCBLoanVolumeFor(centralBank); } catch (final NullPointerException e) { return 0.; } } /** * Not currently working - returning a large number error.... * * @return */ @RecorderSource("CBequity") public double getCBequity() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return centralBank.getEquity(); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("CBdepositVolume") public double getOvernightVolume() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return ((CentralBankStrategy) centralBank.getStrategy()).getOvernightDepositVolume(centralBank); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("BankruptcyEvents") public double getCrisisInterventions() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return ((CentralBankStrategy) centralBank.getStrategy()).getCrisisInterventions().size(); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("CBrefinancingRate") public double getKeyInterestRate() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return ((CentralBankStrategy) centralBank.getStrategy()).getRefinancingRate(); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("CBovernightDepositRate") public double getCBovernightDepositRate() { try { final List<CentralBank> agents = population.getAgentsOfType(CentralBank.class); if (agents.isEmpty()) return 0.; final CentralBank centralBank = agents.get(0); return ((CentralBankStrategy) centralBank.getStrategy()).getOvernightDepositRate(); } catch (final NullPointerException e) { return 0.; } } @RecorderSource("TaxMoneySpentForBanks") public double getTaxMoneySpentForBanks() { return hasGovernment() ? getGovernment().getTotalLiquiditySpentOnBailouts() : 0.; } // Misc. getters. public final List<Household> getHouseholds() { return population.getAgentsOfType(Household.class); } @Override public int getNumberOfBanks() { return population.getAgentsOfType(CommercialBank.class).size(); } @Override public int getNumberOfFirms() { return population.getAgentsOfType(Firm.class).size(); } @Override public int getNumberOfHouseholds() { return population.getAgentsOfType(Household.class).size(); } @Override public DepositMarket getDepositMarket() { final List<DepositMarket> markets = population.getMarketsOfType(DepositMarket.class); if (markets.isEmpty()) return null; return markets.get(0); } @Override public CommercialLoanMarket getCommercialLoanMarket() { final List<CommercialLoanMarket> markets = population.getMarketsOfType(CommercialLoanMarket.class); if (markets.isEmpty()) return null; return markets.get(0); } @Override public InterbankLoanMarket getInterbankLoanMarket() { final List<InterbankLoanMarket> markets = population.getMarketsOfType(InterbankLoanMarket.class); if (markets.isEmpty()) return null; return markets.get(0); } @Override public StockMarket getStockMarket() { final List<StockMarket> markets = population.getMarketsOfType(StockMarket.class); if (markets.isEmpty()) return null; return markets.get(0); } @RecorderSource(value = "firmProfit", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") public List<Double> getProfit() { final List<Double> profit = Doubles.asList(new double[getNumberOfFirmsForRecorderSampling()]); int index = 0; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) profit.set(index++, firm.getProfit()); return profit; } public List<Double> getAllLoanVolumes() { final ArrayList<Double> ret = new ArrayList<Double>(); for (final Contract act : Contract.getContracts()) { if (act instanceof Loan) { final Loan loan = (Loan) act; ret.add(loan.getLoanPrincipalValue()); } } return ret; } public List<Double> getAllStockAccountVolumes() { final ArrayList<Double> ret = new ArrayList<Double>(); for (final Contract act : Contract.getContracts()) { if (act instanceof StockAccount) { final StockAccount stockAccount = (StockAccount) act; ret.add(stockAccount.getQuantity()); } } return ret; } @RecorderSource(value = "bankCashReserves", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankCashOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) ret.set(index++, bank.getCashReserveValue()); return ret; } @RecorderSource(value = "BanksStockPortfolios", collectionLengthMember = "getBanksStockPortfoliosArrayLengthForRecorderSources()") public List<Double> getBanksStockPortfolios() { final List<Double> ret = Doubles.asList(new double[getBanksStockPortfoliosArrayLengthForRecorderSources()]); int index = 0; for (final CommercialBank bank : population.getAgentsOfType(CommercialBank.class)) { final List<Double> stockInvestments = bank.getStockPortfolio(); for (double value : stockInvestments) ret.set(index++, value); } return ret; } public int getBanksStockPortfoliosArrayLengthForRecorderSources() { return getNumberOfBanks() * (getNumberOfFirms() + population.getAgentsOfType(CommercialBank.class).size()); } @RecorderSource("aggregateBankAssets") public double getAggregateBankAssets() { double ret = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) ret += bank.getTotalAssets(); return ret; } public double getAggregateBankEquity() { double ret = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) ret += bank.getEquity(); return ret; } public double getAggregateBankCashReserves() { double ret = 0; for (int i = 0; i < getBankCashOverTime().size(); i++) ret += getBankCashOverTime().get(i); return ret; } @RecorderSource("aggregateBankLeverage") public double getAggregateBankLeverage() { return aggreateBankRiskyAssetsAfterPendingDividend / aggreateBankEquityAfterPendingDividend; } @RecorderSource(value = "bankCapitalAdequacyRatio", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankCapitalAdequacyRatioOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) { double CAR = bank .accept(new ComputeCapitalAdequacyRatioOperation(new ComputeRiskWeightedAssetsOperation())); ret.set(index++, CAR); } return ret; } @RecorderSource(value = "bankRiskWeightedAssets", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankRiskWeightedAssetsOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) { double RWA = bank.accept(new ComputeRiskWeightedAssetsOperation()); ret.set(index++, RWA); } return ret; } @RecorderSource(value = "bankDepositAccountHoldings", collectionLengthMember = "getNumberOfCommercialBanksForRecorderSampling()") public List<Double> getBankDepositsOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfCommercialBanksForRecorderSampling()]); int index = 0; for (final Bank bank : population.getAgentsOfType(CommercialBank.class)) { double sumDepositValue = 0.0; for (final DepositAccount deposit : bank.getLiabilitiesDeposits()) sumDepositValue += deposit.getValue(); ret.set(index++, sumDepositValue); } return ret; } @RecorderSource(value = "householdEquity", collectionLengthMember = "getNumberOfHouseholdsForRecorderSampling()") public List<Double> getHouseholdEquity() { final List<Double> ret = Doubles.asList(new double[getNumberOfHouseholdsForRecorderSampling()]); int index = 0; for (final Household household : population.getAgentsOfType(Household.class)) ret.set(index++, household.getEquity()); return ret; } @RecorderSource(value = "householdSavings", collectionLengthMember = "getNumberOfHouseholdsForRecorderSampling()") public List<Double> getHouseholdSavingsOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfHouseholdsForRecorderSampling()]); int index = 0; for (final DepositingHousehold household : population.getAgentsOfType(DepositingHousehold.class)) ret.set(index++, household.getDepositValue()); return ret; } /** * XXX * * Incompatible with interchangeable {@link Household} {@link Agent}{@code s}. * Result will be {@code zero} for non-{@link MacroHousehold} {@link Agent}{@code s}. */ @RecorderSource(value = "householdWelfareAllowance", collectionLengthMember = "getNumberOfHouseholdsForRecorderSampling()") public List<Double> getHouseholdWelfareOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfHouseholdsForRecorderSampling()]); int index = 0; for (final MacroHousehold household : population.getAgentsOfType(MacroHousehold.class)) ret.set(index++, household.getWelfareAllowance()); return ret; } @RecorderSource(value = "firmDividend", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") // TODO: is this redundant? public List<Double> getFirmDividendOverTime() { final List<Double> dividends = Doubles.asList(new double[getNumberOfFirmsForRecorderSampling()]); int index = 0; for (final StockReleasingFirm firm : population.getAgentsOfType(StockReleasingFirm.class)) dividends.set(index++, firm.getCurrentDividend()); return dividends; } @RecorderSource(value = "firmLoansPerEquity", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") // TODO: is this redundant? public List<Double> getFirmLoansPerEquityOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfFirmsForRecorderSampling()]); int index = 0; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret.set(index++, firm.getLoansPerEquity()); return ret; } @RecorderSource(value = "firmProduction", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") // TODO: is this redundant? public List<Double> getFirmProductionOverTime() { final List<Double> profit = Doubles.asList(new double[getNumberOfFirmsForRecorderSampling()]); int index = 0; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) profit.set(index++, firm.getProduction()); return profit; } @RecorderSource(value = "firmRevenue", collectionLengthMember = "getNumberOfFirmsForRecorderSampling()") // TODO: is this redundant? public List<Double> getFirmRevenueOverTime() { final List<Double> ret = Doubles.asList(new double[getNumberOfFirmsForRecorderSampling()]); int index = 0; for (final LoanStrategyFirm firm : population.getAgentsOfType(LoanStrategyFirm.class)) ret.set(index++, firm.getRevenue()); return ret; } /* * Also note there is another RecorderSource for interest rates - see MarketClearingModel.java * for getInterestRate() method */ @RecorderSource("loanInterestRates") public List<Double> getInterestRates() { List<Double> result = new ArrayList<Double>(); for (Object bankObject : getBanks()) { Bank bank = (Bank) bankObject; List<Loan> loans = bank.getAssetLoans(); for (Loan loan : loans) { result.add(loan.getInterestRate()); } } return result; } /* * Also note there is another RecorderSource for interest rates - see MarketClearingModel.java * for getInterestRate() method. * * XXX * * This method will not give current mean loan interest rate when the maturity of * loans is greater than one time-step! */ @RecorderSource("meanLoanInterestRate") public double getMeanLoanInterestRate() { double result = 0, totalVolume = 0; for (final Bank bank : population.getAgentsOfType(Bank.class)) { final List<Loan> loans = bank.getAssetLoans(); for (final Loan loan : loans) { double volume = loan.getLoanPrincipalValue(); result += loan.getInterestRate() * volume; totalVolume += volume; } } result /= totalVolume; return result; } @Override public List<Bank> getBanks() { return population.getAgentsOfType(Bank.class); } @Override public List<Bank> getRegularBanks() { return ArrayUtil.castList(population.getAgentsOfType(CommercialBank.class)); } @Override public List<Firm> getFirms() { return population.getAgentsOfType(Firm.class); } @Override public List<Fund> getFunds() { return population.getAgentsOfType(Fund.class); } @Override public Government getGovernment() { final List<Government> result = population.getAgentsOfType(Government.class); return result.isEmpty() ? null : result.get(0); } @Override public CentralBank getCentralBank() { final List<CentralBank> result = population.getAgentsOfType(CentralBank.class); return result.isEmpty() ? null : result.get(0); } @Override public BadBank getBadBank() { final List<BadBank> result = population.getAgentsOfType(BadBank.class); return result.isEmpty() ? null : result.get(0); } @Override public ClearingHouse getClearingHouse() { final List<ClearingHouse> result = population.getMarketsOfType(ClearingHouse.class); return result.isEmpty() ? null : result.get(0); } }