Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

CurveFitting.cpp

00001 // C++ includes
00002 
00003 #include <iostream>
00004 #include <fstream>
00005 #include <iomanip>
00006 #include <cmath>
00007 
00008 using std::cout;
00009 using std::cerr;
00010 using std::endl;
00011 using std::setw;
00012 
00013 // personal headers
00014 #include <ql/date.hpp>
00015 #include <ql/array.hpp>
00016 #include <ql/Math/matrix.hpp>
00017 #include <ql/errors.hpp>
00018 
00019 #include <portability.h>
00020 #include <leastsquare.h>
00021 #include <timer.h>
00022 
00023 using QuantLib::Date;
00024 using QuantLib::Array;
00025 using QuantLib::Math::Matrix;
00026 using QuantLib::Math::transpose;
00027 using QuantLib::Error;
00028 
00029 
00030 
00031 inline
00032 std::ostream& operator<< (std::ostream& os, const QuantLib::Array& v)
00033 {
00034   size_t i, sz = v.size();
00035  
00036   os << "[";
00037   for (i=0; i<sz-1; ++i)
00038     os << v[i] << " ";
00039   os << v[sz-1] 
00040      << "]" 
00041      << std::endl;
00042   
00043   return os;
00044 }
00045 
00052 class BraceVolatilityFunction {
00054   double a_, b_, c_, d_;
00055 public :
00057   inline BraceVolatilityFunction(double a, double b, double c, double d)
00058     : a_(a), b_(b), c_(c), d_(d) {}
00060   inline ~BraceVolatilityFunction() {}
00061 
00063   inline double operator() (double t) 
00064   { return (a_+b_*t)*exp(-c_*t) + d_; }
00065 
00067   inline double da(double t) 
00068   { return exp(-c_*t); }
00069 
00071   inline double db(double t) 
00072   { return t*exp(-c_*t); }
00073 
00075   inline double dc(double t) 
00076   { return -t*(a_+b_*t)*exp(-c_*t); }
00077 
00079   inline double dd(double t) 
00080   { return 1.; }
00081 };
00082 
00083 
00089 class CurveFittingProblem 
00090   : public LeastSquareProblem<Array,Matrix > {
00091   const Array &ttm_;
00092   const Array &target_;
00093 public :
00098   CurveFittingProblem(const Array& ttm, const Array& target)
00099     : ttm_(ttm), target_(target) {}
00101   virtual ~CurveFittingProblem() {}
00102 
00104   virtual int size() { return ttm_.size(); }
00105 
00107   virtual void targetAndValue(const Array& abcd, 
00108                   Array& target, 
00109                   Array& fct2fit)
00110   {
00111     BraceVolatilityFunction bvf(abcd[0],abcd[1],abcd[2],abcd[3]);
00112     target = target_;// target values
00113     for (int i=0; i<ttm_.size(); ++i)
00114       fct2fit[i] = bvf(ttm_[i]);
00115   }
00116 
00118   virtual void targetValueAndfirstDerivative(const Array& abcd, 
00119                          Matrix& grad_fct2fit, 
00120                          Array& target, 
00121                          Array& fct2fit)
00122   {
00123     BraceVolatilityFunction bvf(abcd[0],abcd[1],abcd[2],abcd[3]);
00124     target = target_;// target values
00125     for (int i=0; i<ttm_.size(); ++i) {
00126       // function value at current point abcd
00127       fct2fit[i] = bvf(ttm_[i]);
00128       /*
00129     matrix of first derivatives :
00130     the derivatives with respect to the parameter a,b,c,d
00131     are stored by row.
00132       */
00133     grad_fct2fit[i][0] = bvf.da(ttm_[i]);
00134     grad_fct2fit[i][1] = bvf.db(ttm_[i]);
00135     grad_fct2fit[i][2] = bvf.dc(ttm_[i]);
00136     grad_fct2fit[i][3] = bvf.dd(ttm_[i]);
00137     }
00138 
00139   }
00140   };
00141 
00142 /*
00143   We define here an inverse problem to show how to fit
00144   parametric function to data. 
00145 */
00146 int main()
00147 {
00148   /*
00149     Parameter values that produce the volatility hump.
00150     Consider it as optimal values of the curve fitting
00151     problem.
00152   */
00153   double abcd_[4] = {0.147014, 0.057302, 0.249964, 0.148556 };
00154   Array abcd(4);
00155   abcd[0] = abcd_[0];
00156   abcd[1] = abcd_[1];
00157   abcd[2] = abcd_[2];
00158   abcd[3] = abcd_[3];
00159 
00160   cout << "Optimal values  : " << abcd << endl;
00161 
00162   // Define the target volatility function
00163   BraceVolatilityFunction bvf(abcd[0],abcd[1],abcd[2],abcd[3]);
00164 
00165   Timer t;
00166   t.start();
00167   try {
00168  
00169     double t, 
00170       startDate = 0.0, // start date of volatilty
00171       endDate = 20., // end date of volatility
00172       period = 0.25; // period length between values (in year fraction : quarterly)
00173 
00174     int i, periodNumber = (int)(endDate / period); // number of period
00175 
00176     Array targetValue(periodNumber), timeToMaturity(periodNumber);
00177     // Fill target and time to maturity arrays
00178     for (i=0; i<periodNumber; ++i) {
00179       t = startDate + i*period;
00180       timeToMaturity[i] = t;
00181       targetValue[i] = bvf(t);
00182     }
00183 
00184     // Accuracy of the optimization method
00185     double accuracy = 1e-10;// It is the square of the accuracy
00186     // Maximum number of iterations
00187     int maxiter = 10000;
00188 
00189     Array initialValue(4, 0.1);
00190         
00191     // Least square optimizer
00192     NonLinearLeastSquare<Array > lsqnonlin(accuracy,maxiter);
00193 
00194     // Define the least square problem
00195     CurveFittingProblem cfp(timeToMaturity, targetValue);
00196      
00197     // Set initial values
00198     lsqnonlin.setInitialValue(initialValue);
00199     // perform fitting
00200     Array solution = lsqnonlin.Perform(cfp);
00201         
00202     cout << endl 
00203      << "Optimal values  : " << abcd
00204      << "Solution values : " << solution
00205      << "Solution Error  : " << (solution - abcd ) << endl;
00206 
00207     // save in given format
00208     BraceVolatilityFunction bvf2(solution[0],solution[1],solution[2],solution[3]);
00209 
00210     // Gnuplot format
00211     /*
00212       std::ofstream file("curve.dta");
00213       for (i=0; i<periodNumber; ++i) {
00214       t = startDate + i*period;
00215       file << setw(8) << t << setw(20) << bvf(t) << setw(20) << bvf2(t) << endl;
00216       }
00217     */
00218         
00219     std::ofstream file("curve.csv");
00220     const char separator[] = ", ";
00221     // CSV format
00222     for (i=0; i<periodNumber; ++i) {
00223       t = startDate + i*period;
00224       file << t << separator << bvf(t) << separator << bvf2(t) << endl;
00225     }
00226     file.close();
00227 
00228   }
00229  catch(Error & e)
00230    {
00231      cerr << e.what() << endl;;
00232    }
00233  t.stop();
00234 
00235  cout << "Ellapsed time : " << (double) t << " seconds." << endl;
00236 
00237 
00238  return 1;
00239 }

Generated at Wed Nov 7 16:25:59 2001 for Optimization by doxygen1.2.9 written by Dimitri van Heesch, © 1997-2001