@@ -4,14 +4,13 @@ jupytext:
4
4
extension : .md
5
5
format_name : myst
6
6
format_version : 0.13
7
- jupytext_version : 1.14.5
7
+ jupytext_version : 1.16.1
8
8
kernelspec :
9
9
display_name : Python 3 (ipykernel)
10
10
language : python
11
11
name : python3
12
12
---
13
13
14
- +++ {"user_expressions": [ ] }
15
14
16
15
# Consumption Smoothing
17
16
@@ -48,7 +47,6 @@ import matplotlib.pyplot as plt
48
47
from collections import namedtuple
49
48
```
50
49
51
- +++ {"user_expressions": [ ] }
52
50
53
51
The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{ y_t\} _ {t=0}^T$ of non-financial income and chooses a consumption stream $\{ c_t\} _ {t=0}^T$.
54
52
@@ -156,8 +154,6 @@ def creat_cs_model(R=1.05, g1=1, g2=1/2, T=65):
156
154
β_seq=β_seq, T=65)
157
155
```
158
156
159
- +++ {"user_expressions": []}
160
-
161
157
162
158
## Friedman-Hall consumption-smoothing model
163
159
@@ -206,7 +202,6 @@ $$ (eq:conssmoothing)
206
202
207
203
Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell.
208
204
209
- +++ {"user_expressions": []}
210
205
211
206
## Mechanics of Consumption smoothing model
212
207
@@ -301,7 +296,7 @@ This can be interpreted as a student debt.
301
296
302
297
The non-financial process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward.
303
298
304
- The drop in non-financial income late in life reflects retirement from work.
299
+ The drop in non-financial income late in life reflects retirement from work.
305
300
306
301
```{code-cell} ipython3
307
302
# Financial wealth
@@ -348,7 +343,138 @@ def welfare(model, c_seq):
348
343
print('Welfare:', welfare(cs_model, c_seq))
349
344
```
350
345
351
- +++ {"user_expressions": []}
346
+ ### Experiments
347
+
348
+ In this section we experiment consumption smoothing behavior under different setups.
349
+
350
+ First we write a function `plot_cs` that generate graphs above based on a consumption smoothing model `cs_model`.
351
+
352
+ This helps us repeat the steps shown above
353
+
354
+ ```{code-cell} ipython3
355
+ def plot_cs(model, # consumption smoothing model
356
+ a0, # initial financial wealth
357
+ y_seq # non-financial income process
358
+ ):
359
+
360
+ # Compute optimal consumption
361
+ c_seq, a_seq, h0 = compute_optimal(model, a0, y_seq)
362
+
363
+ # Sequence length
364
+ T = cs_model.T
365
+
366
+ # Generate plot
367
+ plt.plot(range(T+1), y_seq, label='non-financial income')
368
+ plt.plot(range(T+1), c_seq, label='consumption')
369
+ plt.plot(range(T+2), a_seq, label='financial wealth')
370
+ plt.plot(range(T+2), np.zeros(T+2), '--')
371
+
372
+ plt.legend()
373
+ plt.xlabel(r'$t$')
374
+ plt.ylabel(r'$c_t,y_t,a_t$')
375
+ plt.show()
376
+ ```
377
+
378
+ #### Experiment 1: one-time gain/loss
379
+
380
+ We first assume a one-time windfall of $W_0$ in year 21 of the income sequence $y$.
381
+
382
+ We'll make $W_0$ big - positive to indicate a one-time windfall, and negative to indicate a one-time "disaster".
383
+
384
+ ```{code-cell} ipython3
385
+ # Windfall W_0 = 20
386
+ y_seq_pos = np.concatenate(
387
+ [np.ones(21), np.array([20]), np.ones(44)])
388
+
389
+ plot_cs(cs_model, a0, y_seq_pos)
390
+ ```
391
+
392
+ ```{code-cell} ipython3
393
+ # Disaster W_0 = -20
394
+ y_seq_neg = np.concatenate(
395
+ [np.ones(21), np.array([-20]), np.ones(44)])
396
+
397
+ plot_cs(cs_model, a0, y_seq_neg)
398
+ ```
399
+
400
+ #### Experiment 2: permanent wage gain/loss
401
+
402
+ Now we assume a permanent increase in income of $W$ in year 21 of the $y$-sequence.
403
+
404
+ Again we can study positive and negative cases
405
+
406
+ ```{code-cell} ipython3
407
+ # Positive permanent income change W = 0.5 when t >= 21
408
+ y_seq_pos = np.concatenate(
409
+ [np.ones(21), np.repeat(1.5, 45)])
410
+
411
+ plot_cs(cs_model, a0, y_seq_pos)
412
+ ```
413
+
414
+ ```{code-cell} ipython3
415
+ # Negative permanent income change W = -0.5 when t >= 21
416
+ y_seq_neg = np.concatenate(
417
+ [np.ones(21), np.repeat(0.5, 45)])
418
+
419
+ plot_cs(cs_model, a0, y_seq_neg)
420
+ ```
421
+
422
+ #### Experiment 3: a late starter
423
+
424
+ Now we simulate a $y$ sequence in which a person gets zero for 46 years, and then works and gets 1 for the last 20 years of life (a "late starter")
425
+
426
+ ```{code-cell} ipython3
427
+ # Late starter
428
+ y_seq_late = np.concatenate(
429
+ [np.zeros(46), np.ones(20)])
430
+
431
+ plot_cs(cs_model, a0, y_seq_late)
432
+ ```
433
+
434
+ #### Experiment 4: geometric earner
435
+
436
+ Now we simulate a geometric $y$ sequence in which a person gets $y_t = \lambda^t y_0$ in first 46 years.
437
+
438
+ We first experiment with $\lambda = 1.05$
439
+
440
+ ```{code-cell} ipython3
441
+ # Geometric earner parameters where λ = 1.05
442
+ λ = 1.05
443
+ y_0 = 1
444
+ t_max = 46
445
+
446
+ # Generate geometric y sequence
447
+ geo_seq = λ ** np.arange(t_max) * y_0
448
+ y_seq_geo = np.concatenate(
449
+ [geo_seq, np.zeros(20)])
450
+
451
+ plot_cs(cs_model, a0, y_seq_geo)
452
+ ```
453
+
454
+ Now we show the behavior when $\lambda = 0.95$
455
+
456
+ ```{code-cell} ipython3
457
+ λ = 0.95
458
+
459
+ geo_seq = λ ** np.arange(t_max) * y_0
460
+ y_seq_geo = np.concatenate(
461
+ [geo_seq, np.zeros(20)])
462
+
463
+ plot_cs(cs_model, a0, y_seq_geo)
464
+ ```
465
+
466
+ What happens when $\lambda$ is negative
467
+
468
+ ```{code-cell} ipython3
469
+ λ = -0.05
470
+
471
+ geo_seq = λ ** np.arange(t_max) * y_0
472
+ y_seq_geo = np.concatenate(
473
+ [geo_seq, np.zeros(20)])
474
+
475
+ plot_cs(cs_model, a0, y_seq_geo)
476
+ ```
477
+
352
478
353
479
### Feasible consumption variations
354
480
@@ -435,7 +561,6 @@ def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1):
435
561
return cvar_seq
436
562
```
437
563
438
- +++ {"user_expressions": []}
439
564
440
565
We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$
441
566
@@ -473,7 +598,6 @@ plt.ylabel(r'$c_t$')
473
598
plt.show()
474
599
```
475
600
476
- +++ {"user_expressions": []}
477
601
478
602
We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters.
479
603
@@ -498,7 +622,6 @@ def welfare_rel(ξ1, ϕ):
498
622
welfare_vec = np.vectorize(welfare_rel)
499
623
```
500
624
501
- +++ {"user_expressions": []}
502
625
503
626
Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives
504
627
@@ -518,7 +641,6 @@ plt.xlabel(r'$\xi_1$')
518
641
plt.show()
519
642
```
520
643
521
- +++ {"user_expressions": []}
522
644
523
645
The same can be done on $\phi$
524
646
0 commit comments