fig, ax = plt.subplots(figsize=(12, 7))
# Prepare data
categories = ['Gross\nYield', 'Fees', 'Expected\nLoss', 'AAA\nInterest', 'A\nInterest',
'BBB\nInterest', 'Equity\nResidual']
gross = total_volume * gross_yield
fees = total_volume * (servicing_fee + trustee_fee)
exp_loss = total_volume * expected_loss_annual
aaa_int = payments_df[payments_df['Rating'] == 'AAA']['Annual_Interest'].values[0]
a_int = payments_df[payments_df['Rating'] == 'A']['Annual_Interest'].values[0]
bbb_int = payments_df[payments_df['Rating'] == 'BBB']['Annual_Interest'].values[0]
values = [gross/1e6, -fees/1e6, -exp_loss/1e6, -aaa_int/1e6, -a_int/1e6, -bbb_int/1e6, -equity_residual/1e6]
# Colors
colors = [COLORS['success'], COLORS['warning'], COLORS['danger'],
COLORS['AAA'], COLORS['A'], COLORS['BBB'], COLORS['Equity']]
# Running total for waterfall
running_total = [0]
for i, val in enumerate(values[:-1]):
running_total.append(running_total[-1] + val)
# Plot
bottom = 0
for i, (cat, val, color) in enumerate(zip(categories, values, colors)):
if i == 0:
ax.bar(cat, val, color=color, edgecolor='white', linewidth=1.5)
bottom = val
else:
if val < 0:
ax.bar(cat, abs(val), bottom=bottom + val, color=color, edgecolor='white', linewidth=1.5)
bottom = bottom + val
else:
ax.bar(cat, val, bottom=bottom, color=color, edgecolor='white', linewidth=1.5)
bottom = bottom + val
ax.axhline(y=0, color='black', linewidth=0.5)
ax.set_ylabel('Annual Cash Flow ($ Millions)')
ax.set_title('Cash Flow Waterfall Analysis', fontweight='bold', fontsize=14)
# Add value labels
for i, (cat, val) in enumerate(zip(categories, values)):
y_pos = running_total[i] + val/2 if i > 0 else val/2
label = f'${abs(val):,.0f}M'
ax.annotate(label, xy=(i, y_pos), ha='center', va='center', fontsize=9, fontweight='bold', color='white')
plt.tight_layout()
plt.show()