Skip to content

Commit

Permalink
edits
Browse files Browse the repository at this point in the history
  • Loading branch information
alecloudenback committed Feb 7, 2025
1 parent 8a89cb0 commit e2c2a98
Showing 1 changed file with 55 additions and 18 deletions.
73 changes: 55 additions & 18 deletions src/financial_math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,11 @@ end


"""
_residutal_duration(curve,cashflows,time)
_residual_duration(curve, cashflows, time)
Return the duration of the cashflows for the cashflows that occur at or after `time`, weighted by the overall contribution to the present value.
Return the residual duration for cashflows occurring at or after `time`, weighted by their proportional contribution to the total present value.
## Extended Help
This is useful when looking to segment the duration into key rates.
This measure decomposes overall portfolio duration by attributing the “remaining” duration to cashflows beyond a given horizon. It is useful for cash flow duration contribution analysis, which focuses on how each cashflow’s timing impacts the overall duration rather than isolating sensitivities at specific curve points.
"""
function _residual_duration(time, cashflows)
fcf = filter(c -> c.time >= time, cashflows)
Expand All @@ -446,14 +444,11 @@ function _residual_duration(time, cashflows)
end

"""
_duration_cf(curve, cashflows)
_duration_cf(curve,cashflows,time)
For each cashflow in `cashflows`, compute its partial duration contribution. Each cashflow’s duration is weighted by its proportion of the aggregate present value so that the sum of partial durations equals the overall portfolio duration.
For every cashflow in `cashflows`, return a partial duration associated with that cashflow. If the cashflows are dynamic, the duration may not be correct.
## Extended Help
This is useful when looking to segment the duration into key rates.
This function forms the basis for our cash flow duration contribution analysis, breaking down the overall duration into weighted pieces assigned to each cashflow.
"""
function _duration_cf(curve, cashflows)
p = FinanceCore.pv(curve, cashflows)
Expand All @@ -468,10 +463,21 @@ abstract type WeightShape end
struct Triangular <: WeightShape end
struct Rectangular <: WeightShape end

# TODO: How to handle where points aren't well ordered unique set?
# banding takes care of it, but do we want to lose that in the response?
# TODO: Triangular algorithm depends on the above answers.
function krds(curve, cashflows, points, ::Rectangular)
"""
duration_contributions(curve, cashflows, points, ::Rectangular)
Calculate the cash flow duration contributions segmented by bands defined from `points`
using a rectangular (uniform) weighting scheme. In each band, every cashflow whose time
falls between the band's lower (low) and upper (high) bounds is given full weight, meaning
its partial duration contribution is applied in full.
The bands are determined using _segment_reals, which returns a named tuple for each band
with the fields: low, high, and point (the central reference).
This function decomposes the overall portfolio duration into contributions from each band,
facilitating an analysis of how cashflows at different maturities contribute to total duration.
"""
function duration_contributions(curve, cashflows, points, ::Rectangular)
dcf = _duration_cf(curve, cashflows)
bands = _segment_reals(points)

Expand All @@ -485,21 +491,52 @@ function krds(curve, cashflows, points, ::Rectangular)
(; band=band, krd=krd)
end
end
function krds(curve, cashflows, points, ::Triangular)

"""
duration_contributions(curve, cashflows, points, ::Triangular)
Calculate the cash flow duration contributions segmented by bands defined from `points`
using a triangular (linearly graded) weighting scheme. Within each band, cashflows are
weighted based on their proximity to the band’s central point:
- In a middle band, cashflows before the central point are assigned a weight that increases
linearly from the band's lower bound to the central point, while cashflows after are
linearly decreased from the central point to the band's upper bound.
- In the first band (with low == -Inf), cashflows on the finite side (c.time >= low) receive
full weight if they are no later than the central point; those after the central point have
their weights linearly decreased.
- In the last band (with high == Inf), cashflows on the finite side (c.time < high) receive
full weight if they are no earlier than the central point; those before the central point have
weights linearly increased.
The bands are determined via _segment_reals, which returns each band as a named tuple with
low, high, and point. This function provides a refined breakdown of overall duration by assigning
differentiated weights to cashflows according to their timing relative to the band’s center.
"""
function duration_contributions(curve, cashflows, points, ::Triangular)
dcf = _duration_cf(curve, cashflows)
bands = _segment_reals(points)

map(bands) do band
low, high, point = band.low, band.high, band.point
krd = 0.0
isfirst = band == first(bands)
islast = band == last(bands)

for c in dcf
if c.time >= low && c.time < high
# Calculate weights based on proximity to the central point
if c.time <= point
weight = max(0, (c.time - low) / (point - low))
weight = if isfirst
1
else
max(0, (c.time - low) / (point - low))
end
else
weight = max(0, (high - c.time) / (high - point))
if islast
1
else
weight = max(0, (high - c.time) / (high - point))
end
end
krd += c.partial_duration * weight
end
Expand Down

0 comments on commit e2c2a98

Please sign in to comment.