-
Basics Part 1 2
-
Lecture1.1
-
Lecture1.2
-
-
Basics Part 2 1
-
Lecture2.1
-
-
Credit Migration 2
-
Lecture3.1
-
Lecture3.2
-
-
Vasicek Model 2
-
Lecture4.1
-
Lecture4.2
-
-
Payments 2
-
Lecture5.1
-
Lecture5.2
-
-
Complete System 2
-
Lecture6.1
-
Lecture6.2
-
Monthly Transitions
For our simulations, we will want to use monthly transitions. We can use this same markov chain but need to convert it to monthly probabilities. The code below achieves that, but you don’t need to delve into it deeply, just run it to get the monthly markov chain.
#Convert to monthly transition matrix
u, V = np.linalg.eig(transition_matrix)
P = V
D = np.diag(u)
transition_matrix_monthly = pd.DataFrame(P.dot(D ** (1/12)).dot(np.linalg.inv(P)),
index=["AAA", "AA", "A", "BBB", "BB", "B", "CCC", "Default"],
columns=["AAA", "AA", "A", "BBB", "BB", "B", "CCC", "Default"])
#Get rid of the rounding error negative numbers
transition_matrix_monthly = transition_matrix_monthly.clip(0)
#Renormalize
transition_matrix_monthly = transition_matrix_monthly.multiply(1/transition_matrix_monthly.sum(axis=1), axis=0)
To re-run the cadCAD simulations, we need to run the following code. It will clear the prior simulation.
import pathos
pathos.helpers.shutdown()
configs.clear()
Now we just need to change the credit migration function to use the monthly version and update the T parameters in the simulation configuration to be 360 (equal to 30 years).
#Function to transition the matrix randomly, switch to monthly
def credit_migration(_params, substep, sH, s):
new_ratings = s['portfolio'].map(lambda x: np.random.RandomState().choice(
transition_matrix_monthly.index,
p=transition_matrix_monthly.loc[x].values))
return {"ratings": new_ratings}
#Update the ratings
def update_portfolio(_params, substep, sH, s, _input):
return ('portfolio', _input['ratings'])
#Function to value the portfolio, for now just finding default %
def value_portfolio(_params, substep, sH, s):
return {"default": (s['portfolio'] == "Default").sum() / len(s['portfolio'])}
#Update the value
def update_value(_params, substep, sH, s, _input):
return ('default', _input['default'])
#Create partial updates
PSUBs = [
{
"policies": {
"migration_policy": credit_migration,
},
"variables": {
"portfolio": update_portfolio,
}
},
{
"policies": {
"valuation_policy": value_portfolio,
},
"variables": {
"default": update_value,
}
}
]
sim_config_dict = {
'T': range(360),
'N': 50}
c = config_sim(sim_config_dict)
exp = Experiment()
exp.append_configs(
initial_state = initial_state,
partial_state_update_blocks = PSUBs,
sim_configs = c
)
#Execute!
exec_mode = ExecutionMode()
local_mode_ctx = ExecutionContext(context=exec_mode.single_mode)
simulation = Executor(exec_context=local_mode_ctx, configs=configs)
raw_result, field, sessions = simulation.execute()
result = pd.DataFrame(raw_result)
Like we did before, find the expected default for the monthly transition.
#Find the predicted default rate based on markov chain for monthly
transition_matrices = [pd.DataFrame(np.diag([1]*8),index=transition_matrix_monthly.index, columns=transition_matrix_monthly.columns)]
for _ in range(360):
transition_matrices.append(transition_matrices[-1].dot(transition_matrix_monthly))
predicted = pd.Series([1/3, 1/3, 1/3, 0, 0, 0, 0, 0], index=transition_matrix_monthly.index)
predicted = pd.Series([predicted.dot(x)['Default'] for x in transition_matrices],index=list(range(361)))
print(predicted)
And finally, plot the average vs. predicted.
#Plot the predicted vs. simulated
result[result['substep'] == 2].groupby("timestep")['default'].mean().plot(kind='line')
predicted.plot(kind='line')
plt.xlabel("Month")
plt.ylabel("Percent Defaulted")
plt.title("Monthly Credit Migration (Average)")
plt.legend(['Simulated', 'Predicted'])
plt.show()
Prev
Yearly Transitions
Next
Building the Model