Logo

SQL Server SimpleAccrual Function

Updated 2023-10-11 14:28:36.013000

Description

Use the table-valued function SimpleAccrual to return the daily interest accruals over a range of dates for a single cash flow or a series of cash flows, using a single rate or a series of rates.

Syntax

SELECT * FROM [westclintech].[wct].[SimpleAccrual] (
       <@date_start, datetime,>
      ,<@date_end, datetime,>
      ,<@bal_start, float,>
      ,<@Rate, sql_variant,>
      ,<@Spread, sql_variant,>
      ,<@CashMvMnt, nvarchar(max),>
      ,<@Basis, nvarchar(4000),>)

Arguments

@date_start

Accrual start date. Must be of type datetime or of a type that can implicitly convert to datetime.

@date_end

Accrual end date. Must be of type datetime or of a type that can implicitly convert to datetime.

@bal_start

Starting balance. Must be of type float or of a type that can implicitly convert to float.

@Rate

The underlying interest rate for accrual purposes.

@Spread

An amount added to @Rate.

@CashMvMnt

A TSQL statement which produces the dates and amounts of any cash movements to be used in the accrual calculation.

@Basis

Day-count convention used in the accrual calculation.

Return Type

table

colNamecolDatatypecolDesc
aDatedatetimeaccrual date
Ratefloatinterest rate in effect for the accrual date
Spreadfloatspread rate in effect for the accrual date
BalBeginfloatbeginning balance for the accrual date
Movementfloatcash movement occurring on the accrual date
BalEndfloatBalBegin + Movement
InterestfloatThe daily accrual amount

Remarks

If @bal_start is NULL then @bal_start = 0.

If @date_start is NULL the @date_start =GETDATE().

If @date_end is NULL then @date_end = GETDATE().

If @Rate is NULL then @Rate = 0.

If @Spread is NULL then @Spread = 0.

If @Basis is NULL then @Basis = '3'.

Valid @basis codes are:

column 1column 2
0'BOND'
1'ACTUAL'
2'A360'
3'A365'
4'30E/360 (ISDA)','30E/360','ISDA','30E/360 ISDA','EBOND'
21'Actual/ISDA'

Examples

Example #1

In this example we accrue interest at a fixed rate with a fixed spread from 1 March 2017 to 31 March 2017. There are no cash movements during this period. Interest is accrued using the Actual / 365 day-count convention.

SELECT aDate,
       Rate,
       Spread,
       BalBegin,
       Movement,
       BalEnd,
       Interest,
       SUM(Interest) OVER (ORDER BY aDate) as [Cumulative Interest]
FROM wct.SimpleAccrual(   '20170301', --@date_start
                          '20170331', --@date_end
                          100000,     --@bal_start
                          .0075,      --@rate
                          .0250,      --@spread
                          NULL,       --@CashMvMnt
                          3           --@Basis
                      );

This produces the following result.

aDateRateSpreadBalBeginMovementBalEndInterestCumulative Interest
2017-03-01 00:00:00.0000.00750.02510000001000008.90410958904118.9041095890411
2017-03-02 00:00:00.0000.00750.02510000001000008.904109589041117.8082191780822
2017-03-03 00:00:00.0000.00750.02510000001000008.904109589041126.7123287671233
2017-03-04 00:00:00.0000.00750.02510000001000008.904109589041135.6164383561644
2017-03-05 00:00:00.0000.00750.02510000001000008.904109589041144.5205479452055
2017-03-06 00:00:00.0000.00750.02510000001000008.904109589041153.4246575342466
2017-03-07 00:00:00.0000.00750.02510000001000008.904109589041162.3287671232877
2017-03-08 00:00:00.0000.00750.02510000001000008.904109589041171.2328767123288
2017-03-09 00:00:00.0000.00750.02510000001000008.904109589041180.1369863013699
2017-03-10 00:00:00.0000.00750.02510000001000008.904109589041189.041095890411
2017-03-11 00:00:00.0000.00750.02510000001000008.904109589041197.9452054794521
2017-03-12 00:00:00.0000.00750.02510000001000008.9041095890411106.849315068493
2017-03-13 00:00:00.0000.00750.02510000001000008.9041095890411115.753424657534
2017-03-14 00:00:00.0000.00750.02510000001000008.9041095890411124.657534246575
2017-03-15 00:00:00.0000.00750.02510000001000008.9041095890411133.561643835616
2017-03-16 00:00:00.0000.00750.02510000001000008.9041095890411142.465753424658
2017-03-17 00:00:00.0000.00750.02510000001000008.9041095890411151.369863013699
2017-03-18 00:00:00.0000.00750.02510000001000008.9041095890411160.27397260274
2017-03-19 00:00:00.0000.00750.02510000001000008.9041095890411169.178082191781
2017-03-20 00:00:00.0000.00750.02510000001000008.9041095890411178.082191780822
2017-03-21 00:00:00.0000.00750.02510000001000008.9041095890411186.986301369863
2017-03-22 00:00:00.0000.00750.02510000001000008.9041095890411195.890410958904
2017-03-23 00:00:00.0000.00750.02510000001000008.9041095890411204.794520547945
2017-03-24 00:00:00.0000.00750.02510000001000008.9041095890411213.698630136986
2017-03-25 00:00:00.0000.00750.02510000001000008.9041095890411222.602739726027
2017-03-26 00:00:00.0000.00750.02510000001000008.9041095890411231.506849315069
2017-03-27 00:00:00.0000.00750.02510000001000008.9041095890411240.41095890411
2017-03-28 00:00:00.0000.00750.02510000001000008.9041095890411249.315068493151
2017-03-29 00:00:00.0000.00750.02510000001000008.9041095890411258.219178082192
2017-03-30 00:00:00.0000.00750.02510000001000008.9041095890411267.123287671233
2017-03-31 00:00:00.0000.00750.02510000001000008.9041095890411276.027397260274

Example #2

In this example the balance changes during the accrual period. Note that there can be multiple cash movements for the same day.

SELECT *
INTO #cm
FROM
(
    VALUES
        ('20170301', 15000),
        ('20170308', -7500),
        ('20170315', 2200),
        ('20170315', 3750),
        ('20170322', -50000),
        ('20170329', 22500)
) n (dt, amt);
SELECT aDate,
       Rate,
       Spread,
       BalBegin,
       Movement,
       BalEnd,
       Interest,
       SUM(Interest) OVER (ORDER BY aDate) as [Cumulative Interest]
FROM wct.SimpleAccrual(   '20170301',          --@date_start
                          '20170331',          --@date_end
                          100000,              --@bal_start
                          .0075,               --@rate
                          .0250,               --@spread
                          'SELECT * FROM #cm', --@CashMvMnt
                          3                    --@Basis
                      );

This produces the following result.

aDateRateSpreadBalBeginMovementBalEndInterestCumulative Interest
2017-03-01 00:00:00.0000.00750.0251000001500011500010.239726027397310.2397260273973
2017-03-02 00:00:00.0000.00750.025115000011500010.239726027397320.4794520547945
2017-03-03 00:00:00.0000.00750.025115000011500010.239726027397330.7191780821918
2017-03-04 00:00:00.0000.00750.025115000011500010.239726027397340.958904109589
2017-03-05 00:00:00.0000.00750.025115000011500010.239726027397351.1986301369863
2017-03-06 00:00:00.0000.00750.025115000011500010.239726027397361.4383561643836
2017-03-07 00:00:00.0000.00750.025115000011500010.239726027397371.6780821917808
2017-03-08 00:00:00.0000.00750.025115000-75001075009.5719178082191881.25
2017-03-09 00:00:00.0000.00750.02510750001075009.5719178082191890.8219178082192
2017-03-10 00:00:00.0000.00750.02510750001075009.57191780821918100.393835616438
2017-03-11 00:00:00.0000.00750.02510750001075009.57191780821918109.965753424658
2017-03-12 00:00:00.0000.00750.02510750001075009.57191780821918119.537671232877
2017-03-13 00:00:00.0000.00750.02510750001075009.57191780821918129.109589041096
2017-03-14 00:00:00.0000.00750.02510750001075009.57191780821918138.681506849315
2017-03-15 00:00:00.0000.00750.025107500595011345010.1017123287671148.783219178082
2017-03-16 00:00:00.0000.00750.025113450011345010.1017123287671158.884931506849
2017-03-17 00:00:00.0000.00750.025113450011345010.1017123287671168.986643835616
2017-03-18 00:00:00.0000.00750.025113450011345010.1017123287671179.088356164384
2017-03-19 00:00:00.0000.00750.025113450011345010.1017123287671189.190068493151
2017-03-20 00:00:00.0000.00750.025113450011345010.1017123287671199.291780821918
2017-03-21 00:00:00.0000.00750.025113450011345010.1017123287671209.393493150685
2017-03-22 00:00:00.0000.00750.025113450-50000634505.64965753424658215.043150684932
2017-03-23 00:00:00.0000.00750.025634500634505.64965753424658220.692808219178
2017-03-24 00:00:00.0000.00750.025634500634505.64965753424658226.342465753425
2017-03-25 00:00:00.0000.00750.025634500634505.64965753424658231.992123287671
2017-03-26 00:00:00.0000.00750.025634500634505.64965753424658237.641780821918
2017-03-27 00:00:00.0000.00750.025634500634505.64965753424658243.291438356164
2017-03-28 00:00:00.0000.00750.025634500634505.64965753424658248.941095890411
2017-03-29 00:00:00.0000.00750.0256345022500859507.65308219178082256.594178082192
2017-03-30 00:00:00.0000.00750.025859500859507.65308219178082264.247260273973
2017-03-31 00:00:00.0000.00750.025859500859507.65308219178082271.900342465754

It's not necessary to use a temp table to pass the cash flows into the function. The following SQL produces the same result.

SELECT aDate,
       Rate,
       Spread,
       BalBegin,
       Movement,
       BalEnd,
       Interest,
       SUM(Interest) OVER (ORDER BY aDate) as [Cumulative Interest]
FROM wct.SimpleAccrual(
                          '20170301', --@date_start
                          '20170331', --@date_end
                          100000,     --@bal_start
                          .0075,      --@rate
                          .0250,      --@spread
                          'SELECT
            *
        FROM (VALUES
             (''20170301'',15000)
            ,(''20170308'',-7500)
            ,(''20170315'',2200)
            ,(''20170315'',3750)
            ,(''20170322'',-50000)
            ,(''20170329'',22500)
            )n(dt,amt)'   ,
                                      --@CashMvMnt
                          3           --@Basis
                      );

Example #3

In this example, not only are there cash movements, but the rates change as well.

SELECT *
INTO #cm
FROM
(
    VALUES
        ('20170301', 15000),
        ('20170308', -7500),
        ('20170315', 2200),
        ('20170315', 3750),
        ('20170322', -50000),
        ('20170329', 22500)
) n (dt, amt);
SELECT *
INTO #rm
FROM
(
    VALUES
        ('20170301', .0075),
        ('20170315', .00875),
        ('20170329', 0.0093625)
) n (dt, rate);
SELECT aDate,
       Rate,
       Spread,
       BalBegin,
       Movement,
       BalEnd,
       Interest,
       SUM(Interest) OVER (ORDER BY aDate) as [Cumulative Interest]
FROM wct.SimpleAccrual(   '20170301',          --@date_start
                          '20170331',          --@date_end
                          100000,              --@bal_start
                          'SELECT * FROM #rm', --@rate
                          .0250,               --@spread
                          'SELECT * FROM #cm', --@CashMvMnt
                          3                    --@Basis
                      );

This produces the following result.

aDateRateSpreadBalBeginMovementBalEndInterestCumulative Interest
2017-03-01 00:00:00.0000.00750.0251000001500011500010.239726027397310.2397260273973
2017-03-02 00:00:00.0000.00750.025115000011500010.239726027397320.4794520547945
2017-03-03 00:00:00.0000.00750.025115000011500010.239726027397330.7191780821918
2017-03-04 00:00:00.0000.00750.025115000011500010.239726027397340.958904109589
2017-03-05 00:00:00.0000.00750.025115000011500010.239726027397351.1986301369863
2017-03-06 00:00:00.0000.00750.025115000011500010.239726027397361.4383561643836
2017-03-07 00:00:00.0000.00750.025115000011500010.239726027397371.6780821917808
2017-03-08 00:00:00.0000.00750.025115000-75001075009.5719178082191881.25
2017-03-09 00:00:00.0000.00750.02510750001075009.5719178082191890.8219178082192
2017-03-10 00:00:00.0000.00750.02510750001075009.57191780821918100.393835616438
2017-03-11 00:00:00.0000.00750.02510750001075009.57191780821918109.965753424658
2017-03-12 00:00:00.0000.00750.02510750001075009.57191780821918119.537671232877
2017-03-13 00:00:00.0000.00750.02510750001075009.57191780821918129.109589041096
2017-03-14 00:00:00.0000.00750.02510750001075009.57191780821918138.681506849315
2017-03-15 00:00:00.0000.008750.025107500595011345010.4902397260274149.171746575342
2017-03-16 00:00:00.0000.008750.025113450011345010.4902397260274159.66198630137
2017-03-17 00:00:00.0000.008750.025113450011345010.4902397260274170.152226027397
2017-03-18 00:00:00.0000.008750.025113450011345010.4902397260274180.642465753425
2017-03-19 00:00:00.0000.008750.025113450011345010.4902397260274191.132705479452
2017-03-20 00:00:00.0000.008750.025113450011345010.4902397260274201.622945205479
2017-03-21 00:00:00.0000.008750.025113450011345010.4902397260274212.113184931507
2017-03-22 00:00:00.0000.008750.025113450-50000634505.86695205479452217.980136986301
2017-03-23 00:00:00.0000.008750.025634500634505.86695205479452223.847089041096
2017-03-24 00:00:00.0000.008750.025634500634505.86695205479452229.71404109589
2017-03-25 00:00:00.0000.008750.025634500634505.86695205479452235.580993150685
2017-03-26 00:00:00.0000.008750.025634500634505.86695205479452241.447945205479
2017-03-27 00:00:00.0000.008750.025634500634505.86695205479452247.314897260274
2017-03-28 00:00:00.0000.008750.025634500634505.86695205479452253.181849315069
2017-03-29 00:00:00.0000.00936250.0256345022500859508.09166267123288261.273511986301
2017-03-30 00:00:00.0000.00936250.025859500859508.09166267123288269.365174657534
2017-03-31 00:00:00.0000.00936250.025859500859508.09166267123288277.456837328767

Example #4

In this example, there are cash movements, the rates change, and the spread changes.

SELECT
    *
INTO
    #cm
FROM (VALUES
     ('20170301',15000)
    ,('20170308',-7500)
    ,('20170315',2200)
    ,('20170315',3750)
    ,('20170322',-50000)
    ,('20170329',22500)
    )n(dt,amt);
 
SELECT
    *
INTO
    #rm
FROM (
    VALUES
     ('20170301', .0075)
    ,('20170315',.00875)
    ,('20170329',0.0093625)
    )n(dt,rate);
 
SELECT
    *
INTO
    #s
FROM (
    VALUES
     ('20170301',.0250)
    ,('20170315',.0275)
    )n(dt,rate);
 
SELECT
     aDate
    ,Rate
    ,Spread
    ,BalBegin
    ,Movement
    ,BalEnd
    ,Interest
    ,SUM(Interest) OVER (ORDER BY aDate) as [Cumulative Interest]
FROM
    wct.SimpleAccrual(
         '20170301'        --@date_start
        ,'20170331'        --@date_end
        ,100000            --@bal_start
        ,'SELECT * FROM #rm'    --@rate
        ,'SELECT * FROM #s'    --@spread
        ,'SELECT * FROM #cm'    --@CashMvMnt
        ,3                    --@Basis
        );

This produces the following result.

aDateRateSpreadBalBeginMovementBalEndInterestCumulative Interest
2017-03-01 00:00:00.0000.00750.0251000001500011500010.239726027397310.2397260273973
2017-03-02 00:00:00.0000.00750.025115000011500010.239726027397320.4794520547945
2017-03-03 00:00:00.0000.00750.025115000011500010.239726027397330.7191780821918
2017-03-04 00:00:00.0000.00750.025115000011500010.239726027397340.958904109589
2017-03-05 00:00:00.0000.00750.025115000011500010.239726027397351.1986301369863
2017-03-06 00:00:00.0000.00750.025115000011500010.239726027397361.4383561643836
2017-03-07 00:00:00.0000.00750.025115000011500010.239726027397371.6780821917808
2017-03-08 00:00:00.0000.00750.025115000-75001075009.5719178082191881.25
2017-03-09 00:00:00.0000.00750.02510750001075009.5719178082191890.8219178082192
2017-03-10 00:00:00.0000.00750.02510750001075009.57191780821918100.393835616438
2017-03-11 00:00:00.0000.00750.02510750001075009.57191780821918109.965753424658
2017-03-12 00:00:00.0000.00750.02510750001075009.57191780821918119.537671232877
2017-03-13 00:00:00.0000.00750.02510750001075009.57191780821918129.109589041096
2017-03-14 00:00:00.0000.00750.02510750001075009.57191780821918138.681506849315
2017-03-15 00:00:00.0000.008750.0275107500595011345011.2672945205479149.948801369863
2017-03-16 00:00:00.0000.008750.0275113450011345011.2672945205479161.216095890411
2017-03-17 00:00:00.0000.008750.0275113450011345011.2672945205479172.483390410959
2017-03-18 00:00:00.0000.008750.0275113450011345011.2672945205479183.750684931507
2017-03-19 00:00:00.0000.008750.0275113450011345011.2672945205479195.017979452055
2017-03-20 00:00:00.0000.008750.0275113450011345011.2672945205479206.285273972603
2017-03-21 00:00:00.0000.008750.0275113450011345011.2672945205479217.552568493151
2017-03-22 00:00:00.0000.008750.0275113450-50000634506.30154109589041223.854109589041
2017-03-23 00:00:00.0000.008750.0275634500634506.30154109589041230.155650684932
2017-03-24 00:00:00.0000.008750.0275634500634506.30154109589041236.457191780822
2017-03-25 00:00:00.0000.008750.0275634500634506.30154109589041242.758732876712
2017-03-26 00:00:00.0000.008750.0275634500634506.30154109589041249.060273972603
2017-03-27 00:00:00.0000.008750.0275634500634506.30154109589041255.361815068493
2017-03-28 00:00:00.0000.008750.0275634500634506.30154109589041261.663356164384
2017-03-29 00:00:00.0000.00936250.02756345022500859508.68036130136986270.343717465753
2017-03-30 00:00:00.0000.00936250.0275859500859508.68036130136986279.024078767123
2017-03-31 00:00:00.0000.00936250.0275859500859508.68036130136986287.704440068493

See Also

ACCRINT - Calculate the accrued interest for a security that pays periodic interest.

ACCRINTM - Calculate the accrued interest for a security that pays interest at maturity.

BONDINT - Accrued interest on a bond paying regular, periodic interest