forked from econ-ark/HARK
/
Chinese_Growth.py
297 lines (231 loc) · 15.6 KB
/
Chinese_Growth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
"""
China's high net saving rate (approximately 25%) is a puzzle for economists, particularly in
light of a consistently high income growth rate.
If the last exercise made you worry that invoking difficult-to-measure "uncertainty" can explain
anything (e.g. "the stock market fell today because the risk aversion of the representative
agent increased"), the next exercise may reassure you. It is designed to show that there are
limits to the phenomena that can be explained by invoking uncertainty.
It asks "what beliefs about uncertainty would Chinese consumers need to hold in order to generate a
saving rate of 25%, given the rapid pace of Chinese growth"?
####################################################################################################
####################################################################################################
The first step is to create the ConsumerType we want to solve the model for.
Model set up:
* "Standard" infinite horizon consumption/savings model, with mortality and
permanent and temporary shocks to income
* Markov state that represents the state of the Chinese economy (to be detailed later)
* Ex-ante heterogeneity in consumers' discount factors
In our experiment, consumers will live in a stationary, low-growth environment (intended to
approximate China before 1978). Then, unexpectedly, income growth will surge at the same time
that income uncertainty increases (intended to approximate the effect of economic reforms in China
since 1978.) Consumers believe the high-growth, high-uncertainty state is highly persistent, but
temporary.
HARK's MarkovConsumerType will be a very convient way to run this experiment. So we need to
prepare the parameters to create that ConsumerType, and then create it.
"""
from __future__ import division, print_function
### First bring in default parameter values from cstwPMC. We will change these as necessary.
# Now, bring in what we need from the cstwMPC parameters
from builtins import str
from builtins import range
import HARK.cstwMPC.SetupParamsCSTW as cstwParams
# Initialize the cstwMPC parameters
from copy import deepcopy
init_China_parameters = deepcopy(cstwParams.init_infinite)
### Now, change the parameters as necessary
import numpy as np
# For a Markov model, we need a Markov transition array. Create that array.
# Remember, for this simple example, we just have a low-growth state, and a high-growth state
StateCount = 2 #number of Markov states
ProbGrowthEnds = (1./160.) #probability agents assign to the high-growth state ending
MrkvArray = np.array([[1.,0.],[ProbGrowthEnds,1.-ProbGrowthEnds]]) #Markov array
init_China_parameters['MrkvArray'] = [MrkvArray] #assign the Markov array as a parameter
# One other parameter to change: the number of agents in simulation
# We want to increase this, because later on when we vastly increase the variance of the permanent
# income shock, things get wonky.
# It is important to note that we need to change this value here, before we have used the parameters
# to initialize the MarkovConsumerType. This is because this parameter is used during initialization.
# Other parameters that are not used during initialization can also be assigned here,
# by changing the appropriate value in the init_China_parameters_dictionary; however,
# they can also be changed later, by altering the appropriate attribute of the initialized
# MarkovConsumerType.
init_China_parameters['AgentCount'] = 10000
### Import and initialize the HARK ConsumerType we want
### Here, we bring in an agent making a consumption/savings decision every period, subject
### to transitory and permanent income shocks, AND a Markov shock
from HARK.ConsumptionSaving.ConsMarkovModel import MarkovConsumerType
ChinaExample = MarkovConsumerType(**init_China_parameters)
# Currently, Markov states can differ in their interest factor, permanent growth factor,
# survival probability, and income distribution. Each of these needs to be specifically set.
# Do that here, except income distribution. That will be done later, because we want to examine
# the effects of different income distributions.
ChinaExample.assignParameters(PermGroFac = [np.array([1.,1.06 ** (.25)])], #needs to be a list, with 0th element of shape of shape (StateCount,)
Rfree = np.array(StateCount*[init_China_parameters['Rfree']]), #need to be an array, of shape (StateCount,)
LivPrb = [np.array(StateCount*[init_China_parameters['LivPrb']][0])], #needs to be a list, with 0th element of shape of shape (StateCount,)
cycles = 0)
ChinaExample.track_vars = ['aNrmNow','cNrmNow','pLvlNow'] # Names of variables to be tracked
####################################################################################################
####################################################################################################
"""
Now, add in ex-ante heterogeneity in consumers' discount factors
"""
# The cstwMPC parameters do not define a discount factor, since there is ex-ante heterogeneity
# in the discount factor. To prepare to create this ex-ante heterogeneity, first create
# the desired number of consumer types
num_consumer_types = 7 # declare the number of types we want
ChineseConsumerTypes = [] # initialize an empty list
for nn in range(num_consumer_types):
# Now create the types, and append them to the list ChineseConsumerTypes
newType = deepcopy(ChinaExample)
ChineseConsumerTypes.append(newType)
## Now, generate the desired ex-ante heterogeneity, by giving the different consumer types
## each with their own discount factor
# First, decide the discount factors to assign
from HARK.utilities import approxUniform
bottomDiscFac = 0.9800
topDiscFac = 0.9934
DiscFac_list = approxUniform(N=num_consumer_types,bot=bottomDiscFac,top=topDiscFac)[1]
# Now, assign the discount factors we want to the ChineseConsumerTypes
for j in range(num_consumer_types):
ChineseConsumerTypes[j].DiscFac = DiscFac_list[j]
####################################################################################################
####################################################################################################
"""
Now, write the function to perform the experiment.
Recall that all parameters have been assigned appropriately, except for the income process.
This is because we want to see how much uncertainty needs to accompany the high-growth state
to generate the desired high savings rate.
Therefore, among other things, this function will have to initialize and assign
the appropriate income process.
"""
# First create the income distribution in the low-growth state, which we will not change
from HARK.ConsumptionSaving.ConsIndShockModel import constructLognormalIncomeProcessUnemployment
import HARK.ConsumptionSaving.ConsumerParameters as IncomeParams
LowGrowthIncomeDstn = constructLognormalIncomeProcessUnemployment(IncomeParams)[0][0]
# Remember the standard deviation of the permanent income shock in the low-growth state for later
LowGrowth_PermShkStd = IncomeParams.PermShkStd
def calcNatlSavingRate(PrmShkVar_multiplier,RNG_seed = 0):
"""
This function actually performs the experiment we want.
Remember this experiment is: get consumers into the steady-state associated with the low-growth
regime. Then, give them an unanticipated shock that increases the income growth rate
and permanent income uncertainty at the same time. What happens to the path for
the national saving rate? Can an increase in permanent income uncertainty
explain the high Chinese saving rate since economic reforms began?
The inputs are:
* PrmShkVar_multiplier, the number by which we want to multiply the variance
of the permanent shock in the low-growth state to get the variance of the
permanent shock in the high-growth state
* RNG_seed, an integer to seed the random number generator for simulations. This useful
because we are going to run this function for different values of PrmShkVar_multiplier,
and we may not necessarily want the simulated agents in each run to experience
the same (normalized) shocks.
"""
# First, make a deepcopy of the ChineseConsumerTypes (each with their own discount factor),
# because we are going to alter them
ChineseConsumerTypesNew = deepcopy(ChineseConsumerTypes)
# Set the uncertainty in the high-growth state to the desired amount, keeping in mind
# that PermShkStd is a list of length 1
PrmShkStd_multiplier = PrmShkVar_multiplier ** .5
IncomeParams.PermShkStd = [LowGrowth_PermShkStd[0] * PrmShkStd_multiplier]
# Construct the appropriate income distributions
HighGrowthIncomeDstn = constructLognormalIncomeProcessUnemployment(IncomeParams)[0][0]
# To calculate the national saving rate, we need national income and national consumption
# To get those, we are going to start national income and consumption at 0, and then
# loop through each agent type and see how much they contribute to income and consumption.
NatlIncome = 0.
NatlCons = 0.
for ChineseConsumerTypeNew in ChineseConsumerTypesNew:
### For each consumer type (i.e. each discount factor), calculate total income
### and consumption
# First give each ConsumerType their own random number seed
RNG_seed += 19
ChineseConsumerTypeNew.seed = RNG_seed
# Set the income distribution in each Markov state appropriately
ChineseConsumerTypeNew.IncomeDstn = [[LowGrowthIncomeDstn,HighGrowthIncomeDstn]]
# Solve the problem for this ChineseConsumerTypeNew
ChineseConsumerTypeNew.solve()
"""
Now we are ready to simulate.
This case will be a bit different than most, because agents' *perceptions* of the probability
of changes in the Chinese economy will differ from the actual probability of changes.
Specifically, agents think there is a 0% chance of moving out of the low-growth state, and
that there is a (1./160) chance of moving out of the high-growth state. In reality, we
want the Chinese economy to reach the low growth steady state, and then move into the
high growth state with probability 1. Then we want it to persist in the high growth
state for 40 years.
"""
## Now, simulate 500 quarters to get to steady state, then 40 years of high growth
ChineseConsumerTypeNew.T_sim = 660
# Ordinarily, the simulate method for a MarkovConsumerType randomly draws Markov states
# according to the transition probabilities in MrkvArray *independently* for each simulated
# agent. In this case, however, we want the discrete state to be *perfectly coordinated*
# across agents-- it represents a macroeconomic state, not a microeconomic one! In fact,
# we don't want a random history at all, but rather a specific, predetermined history: 125
# years of low growth, followed by 40 years of high growth.
# To do this, we're going to "hack" our consumer type a bit. First, we set the attribute
# MrkvPrbsInit so that all of the initial Markov states are in the low growth state. Then
# we initialize the simulation and run it for 500 quarters. However, as we do not
# want the Markov state to change during this time, we change its MrkvArray to always be in
# the low growth state with probability 1.
ChineseConsumerTypeNew.MrkvPrbsInit = np.array([1.0,0.0]) # All consumers born in low growth state
ChineseConsumerTypeNew.MrkvArray[0] = np.array([[1.0,0.0],[1.0,0.0]]) # Stay in low growth state
ChineseConsumerTypeNew.initializeSim() # Clear the history and make all newborn agents
ChineseConsumerTypeNew.simulate(500) # Simulate 500 quarders of data
# Now we want the high growth state to occur for the next 160 periods. We change the initial
# Markov probabilities so that any agents born during this time (to replace an agent who
# died) is born in the high growth state. Moreover, we change the MrkvArray to *always* be
# in the high growth state with probability 1. Then we simulate 160 more quarters.
ChineseConsumerTypeNew.MrkvPrbsInit = np.array([0.0,1.0]) # All consumers born in low growth state
ChineseConsumerTypeNew.MrkvArray[0] = np.array([[0.0,1.0],[0.0,1.0]]) # Stay in low growth state
ChineseConsumerTypeNew.simulate(160) # Simulate 160 quarders of data
# Now, get the aggregate income and consumption of this ConsumerType over time
IncomeOfThisConsumerType = np.sum((ChineseConsumerTypeNew.aNrmNow_hist*ChineseConsumerTypeNew.pLvlNow_hist*
(ChineseConsumerTypeNew.Rfree[0] - 1.)) +
ChineseConsumerTypeNew.pLvlNow_hist, axis=1)
ConsOfThisConsumerType = np.sum(ChineseConsumerTypeNew.cNrmNow_hist*ChineseConsumerTypeNew.pLvlNow_hist,axis=1)
# Add the income and consumption of this ConsumerType to national income and consumption
NatlIncome += IncomeOfThisConsumerType
NatlCons += ConsOfThisConsumerType
# After looping through all the ConsumerTypes, calculate and return the path of the national
# saving rate
NatlSavingRate = (NatlIncome - NatlCons) / NatlIncome
return NatlSavingRate
####################################################################################################
####################################################################################################
"""
Now we can use the function we just defined to calculate the path of the national saving rate
following the economic reforms, for a given value of the increase to the variance of permanent
income accompanying the reforms. We are going to graph this path for various values for this
increase.
Remember, we want to see if any plausible value for this increase can explain the high
Chinese saving rate.
"""
# Declare the number of periods before the reforms to plot in the graph
quarters_before_reform_to_plot = 5
# Declare the quarters we want to plot results for
quarters_to_plot = np.arange(-quarters_before_reform_to_plot ,160,1)
# Create a list to hold the paths of the national saving rate
NatlSavingsRates = []
# Create a list of floats to multiply the variance of the permanent shock to income by
PermShkVarMultipliers = (1.,2.,4.,8.,11.)
# Loop through the desired multipliers, then get the path of the national saving rate
# following economic reforms, assuming that the variance of the permanent income shock
# was multiplied by the given multiplier
index = 0
for PermShkVarMultiplier in PermShkVarMultipliers:
NatlSavingsRates.append(calcNatlSavingRate(PermShkVarMultiplier,RNG_seed = index)[-160 - quarters_before_reform_to_plot :])
index +=1
# We've calculated the path of the national saving rate as we wanted
# All that's left is to graph the results!
import pylab as plt
plt.ylabel('Natl Savings Rate')
plt.xlabel('Quarters Since Economic Reforms')
plt.plot(quarters_to_plot,NatlSavingsRates[0],label=str(PermShkVarMultipliers[0]) + ' x variance')
plt.plot(quarters_to_plot,NatlSavingsRates[1],label=str(PermShkVarMultipliers[1]) + ' x variance')
plt.plot(quarters_to_plot,NatlSavingsRates[2],label=str(PermShkVarMultipliers[2]) + ' x variance')
plt.plot(quarters_to_plot,NatlSavingsRates[3],label=str(PermShkVarMultipliers[3]) + ' x variance')
plt.plot(quarters_to_plot,NatlSavingsRates[4],label=str(PermShkVarMultipliers[4]) + ' x variance')
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
ncol=2, mode="expand", borderaxespad=0.) #put the legend on top
plt.show()