From 82e48b5131786ad63463ad177a8656ee71173d19 Mon Sep 17 00:00:00 2001 From: MFEshinhyunjin <42334069+MFEshinhyunjin@users.noreply.github.com> Date: Tue, 13 Nov 2018 14:47:41 +0900 Subject: [PATCH] Nelson-Siegel and Svensson Bond curve fitting Nelson-Siegel and Svensson Bond curve fitting with Python --- NS SS bond curve.py | 132 ++++++++++++++++++++++++ sswtioil.csv | 244 ++++++++++++++++++++++++++++++++++++++++++++ sswtioil.xlsx | Bin 0 -> 16384 bytes 3 files changed, 376 insertions(+) create mode 100644 NS SS bond curve.py create mode 100644 sswtioil.csv create mode 100644 sswtioil.xlsx diff --git a/NS SS bond curve.py b/NS SS bond curve.py new file mode 100644 index 0000000..034c277 --- /dev/null +++ b/NS SS bond curve.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Nov 12 10:12:45 2018 + +@author: Shinhyunjin +""" + +""" +Topic: Nelson-Siegel Curve Smoothing Technique +Sources: Generating a Yield Curve with Nelson-Seigel Method in Excel -> https://www.youtube.com/watch?v=GsZRJmDcDbY + Data fitting using fmin -> http://glowingpython.blogspot.it/2011/05/curve-fitting-using-fmin.html + +Comment: Refer to the above video for an explanation of the method. Also see https://github.com/MaximumBeings/public/blob/master/NSSandNS.txt + for an MS Excel version of the NSS and NS method. Though the code works very + well, we noticed that the Excel version fitted our original data better because the solver in Excel is pretty powerful. Nonetheless, + this is a very good implementation of the NSS method. We try to fit the curve by minimizing the sum of squared errors using the + NS formula. It is an iterative method that tries to guess the values for the NS parameters so you need to try different initial + values. Feed the program with a set of initial values and observe the curve plot and change the parameters to get better fits. A good + starting set of initial values is array([0.01,0.01,0.01,1.00]) but can be changed to get a better fit. +""" + + + +import pylab +from numpy import * +from scipy.optimize import fmin +import pandas as pd +import os +import numpy as np +import matplotlib.pyplot as plt + + +### Nelson - Siegel ### + +pre1 = os.path.dirname(os.path.realpath('C:/Users/Shinhyunjin/Dropbox/hw1data.xlsx')) +fname1 = 'hw1data.xlsx' +path1 = os.path.join(pre1, fname1) +df1 = pd.read_excel(path1) +data = pd.DataFrame(df1) + + +#print "" +# parametric function, x is the independent variable +# and c are the parameters. +# it's a polynomial of degree 2 +fp = lambda c, x: c[0]+(c[1]+c[2])*(c[3]/x)*(1-exp(-x/c[3])-c[2]*exp(-x/c[3])) + +# error function to minimize +e = lambda p, x, y: ((fp(p,x)-y)**2).sum() + + +# generating data with noise + +y = np.array(data['YTM']/100) #The periods for which data are available, skip the periods with empty rate +x = np.array(data['TAU']) #Available rates only + +# fitting the data with fmin +p0 = array([0.01,0.01,0.01,1.00]) # initial parameter value +p = fmin(e, p0, args=(x,y)) +c = p +j=[] + +for h in x: + j.append(c[0]+(c[1]+c[2])*(c[3]/h)*(1-exp(-h/c[3])-c[2]*exp(-h/c[3]))) + + +#print "" +print ('Initial Parameters: ', p0) +print ('Estimated Parameters: ', p) + + + +#To display interpolated data. +h = x +rateTable = pd.DataFrame.from_items([('Period', h),('NS', j)]) +print(rateTable.to_string()) + +#xx = +pylab.plot(x,y, 'b') +pylab.plot(x, fp(p,x), 'ro') +pylab.title('Nelson-Siegel') +pylab.show() + + + +#### Svensson #### + +# parametric function, x is the independent variable +# and c are the parameters. +# it's a polynomial of degree 2 +fp2 = lambda c2, x: (c2[0])+ (c2[1]*((1- exp(-x/c2[4]))/(x/c2[4])))+ (c2[2]*((((1-exp(-x/c2[4]))/(x/c2[4])))- (exp(-x/c2[4]))))+ (c2[3]*((((1-exp(-x/c2[5]))/(x/c2[5])))- (exp(-x/c2[5])))) +real_p = array([0.02,0.01,0.01,0.01,1.00,1.00]) + +# error function to minimize +e2 = lambda p2, x, y: ((fp2(p2,x)-y)**2).sum() + +# generating data with noise + +# fitting the data with fmin +p02 = array([0.01,0.01,0.01,0.01,0.01,1.00,1.00]) # initial parameter value +p2 = fmin(e2, p02, args=(x,y)) +c2 = p2 +j2=[] +for h2 in x: + j2.append((c2[0])+ (c2[1]*((1- exp(-h2/c2[4]))/(h2/c2[4])))+ (c2[2]*((((1-exp(-h2/c2[4]))/(h2/c2[4])))- (exp(-h2/c2[4]))))+ (c2[3]*((((1-exp(-h2/c2[5]))/(h2/c2[5])))- (exp(-h2/c2[5]))))) + +print ('Initial Parameters: ', p02) + +print ('Estimated Parameters: ', p2) + + +#To display interpolated data. + +h2 = x +rateTable = pd.DataFrame.from_items([('Period', h2),('NSS', j2)]) +print(rateTable.to_string()) + + +#xx = array([1,2,5,10,25,30]) +plt.title('Result') +plt.grid(True) +plt.plot(x, y, 'g') +plt.plot(x, fp2(p2,x), '--', label = 'SS') +plt.plot(x, fp2(p2,x), 'bo') +plt.plot(x, fp(p,x), 'ro') +plt.plot(x, fp(p,x), ':', label = 'NS') +plt.legend(loc=0) +plt.xlabel('Mat') +plt.ylabel('YTM') + +plt.show() + diff --git a/sswtioil.csv b/sswtioil.csv new file mode 100644 index 0000000..2bf9e04 --- /dev/null +++ b/sswtioil.csv @@ -0,0 +1,244 @@ +date,close,volume +2018-11-09,21860,38677 +2018-11-08,22235,13358 +2018-11-07,22240,7751 +2018-11-06,22625,26615 +2018-11-05,22615,10842 +2018-11-02,22950,12808 +2018-11-01,23370,6178 +2018-10-31,23895,10443 +2018-10-30,24180,7659 +2018-10-29,24235,5681 +2018-10-26,23985,8381 +2018-10-25,23915,3319 +2018-10-24,23985,30060 +2018-10-23,24875,2859 +2018-10-22,25055,3311 +2018-10-19,24840,6769 +2018-10-18,25115,7725 +2018-10-17,25920,3739 +2018-10-16,25725,9848 +2018-10-15,25820,2893 +2018-10-12,25790,6459 +2018-10-11,25915,8100 +2018-10-10,26880,4190 +2018-10-08,26560,19906 +2018-10-05,26910,5151 +2018-10-04,27395,25589 +2018-10-02,27260,28117 +2018-10-01,26430,13509 +2018-09-28,25975,2115 +2018-09-27,26030,38746 +2018-09-21,25320,1977 +2018-09-20,25605,19900 +2018-09-19,25055,5205 +2018-09-18,24625,2965 +2018-09-17,24740,2189 +2018-09-14,24650,3961 +2018-09-13,25065,14313 +2018-09-12,25040,9086 +2018-09-11,24265,1571 +2018-09-10,24495,1035 +2018-09-07,24390,1391 +2018-09-06,24600,3038 +2018-09-05,24785,3732 +2018-09-04,25215,2212 +2018-09-03,25005,2401 +2018-08-31,25180,13915 +2018-08-30,25005,42834 +2018-08-29,24575,61957 +2018-08-28,24630,4604 +2018-08-27,24585,17955 +2018-08-24,24530,12493 +2018-08-23,24350,14580 +2018-08-22,23720,4000 +2018-08-21,23555,9907 +2018-08-20,23375,543 +2018-08-17,23275,5454 +2018-08-16,23165,35758 +2018-08-14,24000,9871 +2018-08-13,24035,27421 +2018-08-10,23625,16041 +2018-08-09,23815,24546 +2018-08-08,24565,2391 +2018-08-07,24590,1668 +2018-08-06,24390,26440 +2018-08-03,24490,2027 +2018-08-02,24095,4039 +2018-08-01,24280,5034 +2018-07-31,24760,26428 +2018-07-30,24520,1124 +2018-07-27,24665,1766 +2018-07-26,24645,2762 +2018-07-25,24430,6838 +2018-07-24,24070,23609 +2018-07-23,24190,2353 +2018-07-20,24270,15085 +2018-07-19,24020,4506 +2018-07-18,23735,23613 +2018-07-17,23785,5200 +2018-07-16,24615,4096 +2018-07-13,24650,6027 +2018-07-12,24735,10228 +2018-07-11,25600,9351 +2018-07-10,25795,2815 +2018-07-09,25760,2351 +2018-07-06,25475,5964 +2018-07-05,25680,8114 +2018-07-04,25960,19263 +2018-07-03,26035,5424 +2018-07-02,25525,27808 +2018-06-29,25505,19344 +2018-06-28,25235,6776 +2018-06-27,24595,14079 +2018-06-26,23765,7281 +2018-06-25,23775,9001 +2018-06-22,23050,1696 +2018-06-21,22755,1670 +2018-06-20,22830,2120 +2018-06-19,22660,2353 +2018-06-18,22305,6302 +2018-06-15,23220,1451 +2018-06-14,23090,682 +2018-06-12,23010,621 +2018-06-11,22795,1134 +2018-06-08,22840,7277 +2018-06-07,22595,3759 +2018-06-05,22565,3629 +2018-06-04,22820,1678 +2018-06-01,23250,2010 +2018-05-31,23645,3313 +2018-05-30,23130,1806 +2018-05-29,23120,3887 +2018-05-28,23100,8572 +2018-05-25,24470,3888 +2018-05-24,24855,2566 +2018-05-23,25005,6238 +2018-05-21,24950,11257 +2018-05-18,24895,11549 +2018-05-17,24870,5268 +2018-05-16,24690,5601 +2018-05-15,24565,6343 +2018-05-14,24435,6537 +2018-05-11,24720,8108 +2018-05-10,24885,8937 +2018-05-09,24345,7149 +2018-05-08,24285,6686 +2018-05-04,23720,962 +2018-05-03,23485,2803 +2018-05-02,23435,2796 +2018-04-30,23535,1647 +2018-04-27,23565,1430 +2018-04-26,23670,2115 +2018-04-25,23480,5683 +2018-04-24,24000,2118 +2018-04-23,23660,1547 +2018-04-20,23660,4875 +2018-04-19,23830,2664 +2018-04-18,23275,1393 +2018-04-17,23080,2418 +2018-04-16,23145,3024 +2018-04-13,23160,6079 +2018-04-12,23180,11824 +2018-04-11,22570,33607 +2018-04-10,22215,3054 +2018-04-09,21600,15288 +2018-04-06,21850,355 +2018-04-05,22035,522 +2018-04-04,21880,27127 +2018-04-03,21850,3569 +2018-04-02,22575,703 +2018-03-30,22390,497 +2018-03-29,22375,2782 +2018-03-28,22360,1300 +2018-03-27,22720,7760 +2018-03-26,22675,845 +2018-03-23,22520,1114 +2018-03-22,22525,16781 +2018-03-21,21960,5399 +2018-03-20,21635,1099 +2018-03-19,21445,11645 +2018-03-16,21180,1390 +2018-03-15,21095,3923 +2018-03-14,21010,3437 +2018-03-13,21220,937 +2018-03-12,21375,4300 +2018-03-09,20835,2573 +2018-03-08,21155,1377 +2018-03-07,21445,823 +2018-03-06,21620,1857 +2018-03-05,21250,944 +2018-03-02,21065,13615 +2018-02-28,21660,1602 +2018-02-27,22015,1321 +2018-02-26,22000,1772 +2018-02-23,21630,3356 +2018-02-22,21065,1132 +2018-02-21,21100,2858 +2018-02-20,21440,1009 +2018-02-19,21470,17845 +2018-02-14,20425,1613 +2018-02-13,20555,2965 +2018-02-12,20610,1933 +2018-02-09,20880,14094 +2018-02-08,21265,6084 +2018-02-07,21935,5776 +2018-02-06,21850,10332 +2018-02-05,22380,2315 +2018-02-02,22745,4872 +2018-02-01,22320,2122 +2018-01-31,22005,4318 +2018-01-30,22315,9906 +2018-01-29,22825,6765 +2018-01-26,22510,2785 +2018-01-25,22835,6897 +2018-01-24,22190,2394 +2018-01-23,22030,3597 +2018-01-22,21800,2579 +2018-01-19,21720,4515 +2018-01-18,22030,3831 +2018-01-17,21930,9339 +2018-01-16,22175,8404 +2018-01-15,22185,4435 +2018-01-12,21820,3494 +2018-01-11,21845,4932 +2018-01-10,21850,9899 +2018-01-09,21385,2203 +2018-01-08,21180,3327 +2018-01-05,21320,1647 +2018-01-04,21380,16966 +2018-01-03,20770,7894 +2018-01-02,20895,3411 +2017-12-28,20535,3463 +2017-12-27,20515,9791 +2017-12-26,20155,4842 +2017-12-22,20030,4635 +2017-12-21,19995,7034 +2017-12-20,19885,1499 +2017-12-19,19765,673 +2017-12-18,19830,5575 +2017-12-15,19720,3386 +2017-12-14,19555,6769 +2017-12-13,19855,1442 +2017-12-12,20135,2307 +2017-12-11,19700,5892 +2017-12-08,19520,2279 +2017-12-07,19325,15604 +2017-12-06,19775,1261 +2017-12-05,19790,3119 +2017-12-04,19960,559 +2017-12-01,19865,5407 +2017-11-30,19805,21065 +2017-11-29,19840,41557 +2017-11-28,19880,1899 +2017-11-27,20190,23006 +2017-11-24,20160,3308 +2017-11-23,19955,6844 +2017-11-22,19905,8028 +2017-11-21,19475,1062 +2017-11-20,19580,2896 +2017-11-17,19145,807 +2017-11-16,19145,428 +2017-11-15,19060,6791 +2017-11-14,19565,3999 +2017-11-13,19625,6933 diff --git a/sswtioil.xlsx b/sswtioil.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4972e82809f6220ec03ba3d52c9f4fa9ff6c2d22 GIT binary patch literal 16384 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