SlideShare a Scribd company logo
1 of 43
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%.
No predictor corrector, no brownian bridge. 131072 simulations. No displaced diffusion, no
stochastic volatility.
Diff = BS-MC
Abbreviations : BS :=Black-Scholes (closed form), DD :=Displaced Diffusion (closed form), MC :=Monte
Carlo.
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%.
Predictor corrector + brownian bridge. 131072 simulations. No displaced diffusion, no stochastic
volatility.
Diff = BS-MC
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%.
Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, no stochastic
volatility.
Diff=DD-MC
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%.
Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, no stochastic
volatility.
Diff=DD-MC
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%.
Predictor corrector + brownian bridge. 131072 simulations. No Displaced diffusion, stochastic
volatility = 150%, kappa=1.
Diff=Heston-MC
Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%.
Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, stochastic
volatility = 150%, kappa=1.
MC only.
#include "stdafx.h"
#include "LMMTest.h"
#include <boost/make_shared.hpp>
namespace QLib
{
using namespace MonteCarloEngine;
void LMMTest()
{
int n = 65536;
size_t nCaplets = 39;
double strike = 0.06;
double skew = 1.0;
double volatility = 0.2;
bool useStochVol = true;
bool usepredcorr = true;
bool useSobol = false;
bool usebrownianbridge = true;
double kappaSV = 1.0;
double sigmaSV = 1.5;
size_t startIdx = 1;
int nFactors = 1;
double deterministicBasis = 0.001 * 0;
/*std::cout << "Enter nSimus: ";
std::cin >> n;
std::cout << "Enter nCaplets: ";
std::cin >> nCaplets;
std::cout << "Enter startIdx: ";
std::cin >> startIdx;
std::cout << "Enter strike: ";
std::cin >> strike;
std::cout << "Enter skew: ";
std::cin >> skew;
std::cout << "Enter volatility: ";
std::cin >> volatility;
std::cout << "Enter useSV: ";
std::cin >> useStochVol;
std::cout << "Enter usePC: ";
std::cin >> usepredcorr;
std::cout << "Enter useBB: ";
std::cin >> usebrownianbridge;
std::cout << "Enter kappaSV: ";
std::cin >> kappaSV;
std::cout << "Enter sigmaSV: ";
std::cin >> sigmaSV;*/
Date base_date(2015, 8, 18);
// TO FIX
boost::shared_ptr<MarketData> market = CreateTestMarket(base_date);
Currency base_ccy("USD");
CurveType type(base_ccy);
Date pricing_date = base_date;
std::string tenor = "3M";
size_t nTimeSteps = 40;
// int nFactors = 1;
double rho = 0.0;
double lambda = 0.1;
boost::shared_ptr<const TimeStructure> lts = boost::shared_ptr<const
TimeStructure>(new TimeStructure(base_date, tenor, nTimeSteps));
boost::shared_ptr<const LMMCorrelationStructure> corr_model =
boost::shared_ptr<const LMMCorrelationStructure>(new LMMCorrelationStructure(rho, lambda,
nFactors, lts));
boost::shared_ptr<const LMMVolatilityStructure> vol_model =
boost::shared_ptr<const LMMVolatilityStructure>(new LMMVolatilityStructure(volatility,
lts, skew));
boost::shared_ptr<const LMMCovarianceStructure> cov_model =
boost::shared_ptr<LMMCovarianceStructure>(new LMMCovarianceStructure(vol_model,
corr_model));
boost::shared_ptr<const LMMStochasticVolatilityStructure> stoch_vol_model;
if (useStochVol)
{
double theta = 1.0;
double kappa = kappaSV;
double sigma = sigmaSV;
stoch_vol_model =
boost::shared_ptr<LMMStochasticVolatilityStructure>(new
LMMStochasticVolatilityStructure(theta, kappa, sigma, lts));
}
std::string rc_name = "usd_dfcurve";
std::string rc_ccy = "USD";
DateTime pricing_datetime = date_to_datetime(pricing_date);
size_t n_dates = nTimeSteps + 1;
std::vector<DateTime> rc_dates(n_dates);
std::vector<double> dfs(n_dates);
rc_dates[0] = date_to_datetime(base_date);
dfs[0] = 1.0;
double dpy = 365.0;
double rate = 0.03;
for (size_t i = 1; i < n_dates; i++)
{
rc_dates[i] = date_to_datetime(AddTenor(lts->getDate(i - 1), tenor));
double days = DateTimeDiff(rc_dates[i], rc_dates[i - 1]);
dfs[i] = dfs[i - 1] / (1.0 + (rate)* days / dpy);
}
std::string interp = "PieceWiseConstant";
Enum::Interpolation::Enum interp_type = Enum::Interpolation::which(interp);
// TO FIX
std::string interp_vals = "LinearRates";
Enum::IRInterpolationData::Enum interp_what =
Enum::IRInterpolationData::which(interp_vals);
TimeCalculator time_calculator;
boost::shared_ptr<const YieldCurve> df_curve = boost::shared_ptr<const
YieldCurve>(
new RateCurve(
rc_name,
rc_ccy,
pricing_datetime,
rc_dates,
dfs,
interp_type,
interp_what,
time_calculator)
);
LMM core_model(
pricing_date,
base_ccy,
df_curve,
df_curve,
cov_model,
stoch_vol_model,
deterministicBasis
);
boost::shared_ptr<LMM> lmm_ptr = boost::make_shared<LMM>(core_model);
LiborMarketModelMC::config_type config;
config.core_model_ptr_ = lmm_ptr;
config.use_brownian_bridge_ = usebrownianbridge;
config.use_predictor_corrector_ = usepredcorr;
config.use_stoch_vol_ = useStochVol;
config.base_ccy = base_ccy;
boost::gregorian::date_duration start = lts->getDate(startIdx) - lts-
>getDate(0);
std::vector<Date> opt_mat;
Date startDate = base_date + DateDuration(start);
Date exerciseDate = startDate - DateDuration(2);
opt_mat.push_back(exerciseDate);
size_t idx = lts->getTimeIndex(startDate);
for (size_t i = 1; i < nCaplets; i++)
{
boost::gregorian::date_duration diff = lts->getDate(idx + i) - lts-
>getDate(idx + i - 1);
double days = diff.days();
startDate += DateDuration((long)days);
exerciseDate = startDate - DateDuration(2);
opt_mat.push_back(exerciseDate);
}
double notional = 1.0;
std::vector<Payoff> payoffs;
payoffs.push_back(IRCap::create(base_ccy, opt_mat, tenor, notional, strike,
true));
Controller<LiborMarketModelMC, Payoff, AccumulatorPVConvergence,
PathAccumulatorPV> controller;
controller.configure(config, payoffs.begin(), payoffs.end(), *market);
if (useSobol)
controller.use_sobol();
Controller<LiborMarketModelMC, Payoff, AccumulatorPVConvergence,
PathAccumulatorPV>::return_type results = controller.run(n);
for (size_t i = 0; i < results.size(); ++i) print_conv_table(results[i]);
// analytical price
TimeCalculator timeCalc;
std::vector<double> hestonParams;
hestonParams.push_back(1.0 * volatility * volatility); // v0
hestonParams.push_back(kappaSV);
hestonParams.push_back(1.0 * volatility * volatility); // theta SV
hestonParams.push_back(sigmaSV * volatility);
hestonParams.push_back(0.0); // rho
XHeston xheston(pricing_datetime, timeCalc, hestonParams);
double analytic_call = 0.0;
double analytic_call_heston = 0.0;
double bs_call = 0.0;
for (size_t i = 0; i < opt_mat.size(); i++)
{
boost::gregorian::date_duration diff = lts->getDate(i + idx + 1) -
lts->getDate(i + idx);
double days = diff.days();
Date sd = opt_mat[i] + DateDuration(2);
Date pd = sd + DateDuration((long)days);
double P_Tsd = df_curve->df(date_to_datetime(sd));
double P_Tpd = df_curve->df(date_to_datetime(pd));
double dcf = YearFraction(sd, AddTenor(sd, tenor));
double fwd_rate = (P_Tsd / P_Tpd - 1.0) / dcf;
analytic_call += ShiftedLogNormal::price(true, P_Tpd, fwd_rate,
strike, YearFraction(base_date, opt_mat[i]), volatility, skew); // *dcf;
bs_call += BlackScholes::price(true, P_Tpd, fwd_rate, strike,
YearFraction(base_date, opt_mat[i]), volatility); // *dcf;
analytic_call_heston += P_Tpd * fwd_rate * xheston.vanilla(true,
YearFraction(base_date, opt_mat[i]), strike / fwd_rate); // *dcf;
}
std::cout << "Market value DD " << analytic_call << std::endl;
std::cout << "Market value BS " << bs_call << std::endl;
std::cout << "Market value Heston " << analytic_call_heston << std::endl;
double diff = analytic_call_heston - results[0].results_[0].first;
std::cout << "Difference" << diff << std::endl;
}
}
/*
LMMProcess
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#pragma once
#include <boost/shared_ptr.hpp>
#include "../DiscretisationScheme/LMMSchemeBase.h"
#include "../DiscretisationScheme/DiscretisationSchemeBase.h"
#include "BrownianIncrements.h"
#include "../../../Utils/Matrix.h"
#include "../../../Utils/Vector.h"
#include "../../../Core/Exception.h"
#include "BrownianBridge.h"
namespace QLib
{
namespace MonteCarloEngine
{
class LMMProcess
{
public:
typedef Matrix result_type;
typedef boost::shared_ptr<const LMMSchemeBase> lmm_scheme_ptr_type;
typedef boost::shared_ptr<const DiscretisationSchemeBase>
lmm_stoch_vol_scheme_ptr_type;
result_type create_result() const
{
return result_type(size1(), size2());
}
struct buffer_type
{
Vector bridged_variates;
Matrix increments;
};
buffer_type create_buffer() const
{
buffer_type buffer;
buffer.increments.resize(inc_func_.size1(),
inc_func_.size2());
buffer.bridged_variates.resize(input_size());
return buffer;
}
LMMProcess(const Vector& initialStates,
const CovarianceStructure& cov_struct, // just to initialise
the B_Bridge
size_t nFactors,
const Vector& time_grid,
const std::vector<size_t>& obs_idx,
bool use_brownian_bridge = false,
bool use_stoch_vol = false)
: initialStates_(initialStates),
nLibors_(initialStates_.size()),
inc_func_(nFactors, time_grid),
obs_idx_(obs_idx),
use_brownian_bridge_(use_brownian_bridge),
bridge_(cov_struct),
use_stoch_vol_(use_stoch_vol),
nFactors_(inc_func_.size2())
{
}
Matrix & operator() (const Vector& input, Matrix& output,
buffer_type& buffer) const;
void set_main_scheme(lmm_scheme_ptr_type scheme) { main_scheme_ =
scheme; }
void set_stoch_vol_scheme(lmm_stoch_vol_scheme_ptr_type scheme) {
stoch_vol_scheme_ = scheme; }
bool use_stoch_vol() const { return use_stoch_vol_; }
size_t input_size() const { return inc_func_.input_size(); }
size_t size1() const { return inc_func_.size1(); }
size_t size2() const { return nLibors_; }
private:
Vector initialStates_;
size_t nLibors_;
BrownianIncrements inc_func_;
std::vector<size_t> obs_idx_;
lmm_scheme_ptr_type main_scheme_;
lmm_stoch_vol_scheme_ptr_type stoch_vol_scheme_;
bool use_brownian_bridge_;
BrownianBridgeMultiD bridge_;
bool use_stoch_vol_;
int nFactors_;
};
}
}
/*
LMMProcess class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#include "stdafx.h"
#include "LMMProcess.h"
namespace QLib
{
namespace MonteCarloEngine
{
Matrix & LMMProcess::operator() (const Vector& input, Matrix& output,
buffer_type& buffer) const
{
QLIB_ASSERT((output.size1() == size1()) && (output.size2() ==
size2()), "blabla");
size_t nLibors = initialStates_.size();
size_t nTimes = inc_func_.size1();
Matrix liborStates(nTimes, nLibors);
size_t nVolFactors, nLmmFactors;
if (use_stoch_vol_)
{
nLmmFactors = nFactors_ - 1;
nVolFactors = 1;
}
else
{
nLmmFactors = nFactors_;
nVolFactors = 0;
}
Vector bmIncrements(nLmmFactors + nVolFactors);
Vector lmmBmIncrements(nLmmFactors);
double variance = 1.0;
Vector varianceAtTimeIndex(1);
varianceAtTimeIndex[0] = variance;
Vector volBmIncrements(1);
if (use_brownian_bridge_)
bridge_.generate_path(input,buffer.bridged_variates);
for (size_t timeIndex = 0; timeIndex < nTimes; timeIndex++)
{
if (use_brownian_bridge_)
inc_func_(buffer.bridged_variates, bmIncrements,
timeIndex);
else
inc_func_(input, bmIncrements, timeIndex);
for (size_t i = 0; i < nLmmFactors; i++)
lmmBmIncrements[i] = bmIncrements[i];
for (size_t j = 0; j < nVolFactors; j++)
volBmIncrements[j] = bmIncrements[nLmmFactors + j];
if (timeIndex != 0)
{
if (use_stoch_vol_)
{
varianceAtTimeIndex = stoch_vol_scheme_-
>evolve(varianceAtTimeIndex,volBmIncrements,timeIndex);
variance = varianceAtTimeIndex[0];
}
row(liborStates, timeIndex) = main_scheme_-
>evolve(row(liborStates, timeIndex - 1), lmmBmIncrements, inc_func_.time_inc(timeIndex),
inc_func_.time_grid(timeIndex), initialStates_, variance);
}
else
row(liborStates, 0) = initialStates_;
row(output, timeIndex) = row(liborStates, timeIndex);
}
return output;
}
}
}
/*
CovarianceStructure
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#pragma once
#include <boost/shared_ptr.hpp>
#include "../../../Utils/Vector.h"
#include "../../../Utils/Matrix.h"
#include "../../../Core/Exception.h"
namespace QLib
{
namespace MonteCarloEngine
{
class CovarianceStructure
{
public:
CovarianceStructure(size_t dimension = 0,
size_t steps = 0)
: dimension_(dimension), covariances_(steps)
{
for (size_t i = 0; i < steps; ++i)
covariances_[i] = IdentityMatrix(dimension);
}
~CovarianceStructure() {}
void set_covariance(size_t step, const Matrix& covariance)
{
QLIB_ASSERT(step < steps(), "blabla");
QLIB_ASSERT(covariance.size1() == dimension_ &&
covariance.size2() == dimension_, "blabla");
covariances_[step] = covariance;
}
Matrix const & covariance(size_t i) const { return covariances_[i]; }
std::vector<Matrix> const& covariances() const { return covariances_;
}
size_t dimension()const { return dimension_; }
size_t steps() const { return covariances_.size(); }
private:
size_t dimension_;
std::vector<Matrix> covariances_;
};
}
}
/*
BrownianIncrements
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#pragma once
#include "../../../Utils/Vector.h"
#include <boost/shared_ptr.hpp>
#include "../../../Core/Exception.h"
namespace QLib
{
namespace MonteCarloEngine
{
class BrownianIncrements
{
public:
BrownianIncrements(size_t nFactorsTotal, const Vector& time_grid) :
nFactorsTotal_(nFactorsTotal), time_grid_(time_grid) {}
// size_t input_size() const { return time_grid_.size(); } // CHECK
size_t input_size() const { return size1() * size2(); }
size_t input_dimension() const { return nFactorsTotal_; }
size_t size1() const { return time_grid_.size(); }
size_t size2() const { return nFactorsTotal_; } // make stuff cleaner
later
Vector& operator()(Vector const& input, Vector& output, std::size_t
i) const;
double time_inc(size_t i) const
{
if (i == 0)
return time_grid_[0];
else
return time_grid_[i] - time_grid_[i - 1];
}
double time_grid(size_t i) const { return time_grid_[i]; }
private:
size_t nFactorsTotal_;
Vector time_grid_;
};
// TO FIX
inline Vector& BrownianIncrements::operator() (const Vector& input, Vector&
output, size_t i) const
{
QLIB_ASSERT(output.size() == size2(),"blabla");
VectorConstRef in(input, boost::numeric::ublas::range(i *
nFactorsTotal_, (i + 1) * nFactorsTotal_));
output = in; // prod(sample_struct.root(i), in); // don't use this!
too long and useless
return output;
}
}
}
/*
LiborMarketModelMC class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#include "stdafx.h"
#include <boost/pointer_cast.hpp>
#include "LiborMarketModelMC.h"
#include "../Observation/AdjZCBondObservation.h"
#include "../../../Model/LMM/LMMCovarianceStructure.h"
#include "../../../Core/Exception.h"
const double num_days = 365.25;
namespace QLib
{
namespace MonteCarloEngine
{
LiborMarketModelMC::LiborMarketModelMC(const config_type& config, const
std::vector<PrimeRequest>& requests) : config_(config), parser_(requests), dates_(0)
{
for (std::set<Currency>::const_iterator it =
parser_.currencies().begin(); it != parser_.currencies().end(); it++)
QLIB_ASSERT((*it)==config_.base_ccy, "blabla")
boost::shared_ptr<LMM> lmm_ptr = config_.core_model_ptr_;
nFactors_ = lmm_ptr->numOfFactors();
}
boost::shared_ptr<LMMSimulation>
LiborMarketModelMC::calibrate(const MarketData& mkt, const Sampler&
sampler) const
{
boost::shared_ptr<LMM> lmm_ptr = config_.core_model_ptr_;
int nLibors = lmm_ptr->numOfLibors();
Vector initialStates(nLibors);
const std::vector<double>& initSt = config_.core_model_ptr_-
>getInitialDates();
for (int i = 0; i < nLibors; i++)
initialStates[i] = initSt[i];
for (std::map<Currency, size_t>::const_iterator it =
ccy_factor.begin(); it != ccy_factor.end(); ++it)
QLIB_ASSERT(!((*it).first == config_.base_ccy), "blabla");
const boost::shared_ptr<const LMMCovarianceStructure>&
lmmCovarianceStructure = lmm_ptr->getLMMCovarianceStructure();
std::vector<Date> firstDate = lmmCovarianceStructure->getDates();
std::vector<Date> datesUnion(firstDate.size());
std::vector<Date>::iterator itDates;
std::vector<Date> lmm_grid = firstDate;
std::vector<std::size_t> obs_idx;
std::set<Date>::const_iterator obs_date_it =
parser_.observationDates().begin();
while ((obs_date_it != parser_.observationDates().end()) &&
(*obs_date_it <= datetime_to_date(mkt.getPricingDate())))
++obs_date_it;
datesUnion.resize(firstDate.size() + std::distance(obs_date_it,
parser_.observationDates().end()));
itDates = std::set_union (firstDate.begin(), firstDate.end(),
obs_date_it, parser_.observationDates().end(), datesUnion.begin());
datesUnion.resize(itDates - datesUnion.begin());
std::vector<Date>::iterator mc_grid_it = datesUnion.begin();
size_t obs_pos = 0;
for (std::set<Date>::const_iterator it = obs_date_it; it !=
parser_.observationDates().end(); it++)
{
while ((mc_grid_it != datesUnion.end()) && (*mc_grid_it <
*it))
{
++mc_grid_it;
++obs_pos;
}
obs_idx.push_back(obs_pos);
}
std::vector<double> mc_time_grid(datesUnion.size());
Vector mc_time_grid_vec(datesUnion.size());
for (size_t i = 0; i < datesUnion.size(); i++)
{
boost::gregorian::days dd = datesUnion[i] -
datetime_to_date(mkt.getPricingDate());
mc_time_grid[i] = dd.days() / num_days;
mc_time_grid_vec[i] = mc_time_grid[i];
}
std::map<Date, size_t> date_to_step;
size_t step = 0;
for (std::vector<Date>::iterator it = datesUnion.begin(); it !=
datesUnion.end(); ++it)
date_to_step.insert(std::make_pair(*it, step++));
size_t nFactorsTotal = config_.use_stoch_vol_ ? nFactors_ + 1 :
nFactors_;
CovarianceStructure cov_struct(nFactorsTotal, mc_time_grid.size());
for (size_t i = 0; i < mc_time_grid.size(); ++i)
{
double dt = (i == 0) ? 1.0 : mc_time_grid[i] - mc_time_grid[i
- 1];
Matrix cov(cov_struct.dimension(), cov_struct.dimension(),
0.0);
for (size_t j = 0; j < nFactorsTotal; ++j)
{
cov(j, j) = dt;
for (size_t k = 0; k < j; ++k)
cov(j, k) = cov(k, j) = 0.0;
}
cov_struct.set_covariance(i, cov);
}
// create Process
process_type lmm_process(initialStates, cov_struct, nFactorsTotal,
mc_time_grid_vec, obs_idx, config_.use_brownian_bridge_, config_.use_stoch_vol_);
// create schemes
lmm_scheme_ptr_type lmm_scheme =
LMMSchemeFactory::getInstance().createScheme("LogEuler", lmmCovarianceStructure,
nFactors_, config_.use_stoch_vol_, config_.use_predictor_corrector_);
lmm_process.set_main_scheme(lmm_scheme);
bool use_stoch_vol = config_.use_stoch_vol_;
if (use_stoch_vol)
{
const boost::shared_ptr<const
LMMStochasticVolatilityStructure>& lmmSVStructure = lmm_ptr-
>getLMMStochasticVolatilityStructure();
std::vector<double> kappa = lmmSVStructure->getKappa();
std::vector<double> theta = lmmSVStructure->getTheta();
std::vector<double> sigma = lmmSVStructure->getSigma();
boost::shared_ptr<const TimeStructure> ts = lmmSVStructure-
>getTimeStructure();
lmm_stoch_vol_scheme_ptr_type lmm_sv_scheme =
CIRSchemeFactory::getInstance().createScheme("QE", kappa, theta, sigma, ts, datesUnion);
lmm_process.set_stoch_vol_scheme(lmm_sv_scheme);
}
boost::shared_ptr<simulation_type> simulation(new
simulation_type(lmm_process, sampler.nbr_req()));
for (AtomicParser::df_map_type::const_iterator it =
parser_.dfRequests().begin(); it != parser_.dfRequests().end(); ++it)
{
const Date obs_date = (*it).first.first;
if (obs_date > datetime_to_date(mkt.getPricingDate()))
{
simulation->handle_int_.set((*it).second, simulation-
>atomic_observations_.size());
const Date sett_date = (*it).first.second.date();
Currency ccy =
(*it).first.second.curveType().currency();
CurveType::curve_types crv_type =
(*it).first.second.curveType().type();
size_t timeStep = date_to_step.find(obs_date)->second;
size_t index = 0;
std::vector<Date> mc_grid_past;
size_t n_past_dates = timeStep + 2;
for (size_t i = 0; i < n_past_dates; ++i)
{
mc_grid_past.push_back(datesUnion[i]);
}
boost::shared_ptr<Observation<Matrix>> obs(new
AdjZCBondObservation(crv_type, mc_grid_past, sett_date, timeStep, index,
boost::static_pointer_cast<IRBaseModel>(config_.core_model_ptr_)));
simulation->atomic_observations_.push_back(obs);
}
}
sampler.get_derived_observations(simulation->derived_observations_,
simulation-
>atomic_observations_.size(),
simulation->handle_int_,
mkt);
return simulation;
}
}
}
/*
LMMSchemeFactory class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#include "stdafx.h"
#include "LMMSchemeFactory.h"
#include <utility>
namespace QLib
{
namespace MonteCarloEngine
{
LMMSchemeFactory::LMMSchemeFactory()
{
scheme_container_.insert(std::pair<std::string,
create_scheme_func>("LogEuler", LMMSchemeHelper<LMMLogEulerScheme>::Create));
}
LMMSchemeFactory & LMMSchemeFactory::getInstance()
{
static LMMSchemeFactory theFactory;
return theFactory;
}
boost::shared_ptr<LMMSchemeBase> LMMSchemeFactory::createScheme(const
std::string& scheme_id
, const boost::shared_ptr<const LMMCovarianceStructure>&
lmm_covariance_structure
, size_t dimension, bool use_stoch_vol = false, bool
use_pred_corr = false)
{
std::map<std::string, create_scheme_func>::const_iterator scheme_idx
= scheme_container_.find(scheme_id);
if (scheme_idx == scheme_container_.end())
QLIB_THROW("blabla");
return (*scheme_idx).second(lmm_covariance_structure, dimension,
use_stoch_vol, use_pred_corr);
}
}
}
#include "stdafx.h"
#include "LMMLogEulerScheme.h"
namespace QLib
{
namespace MonteCarloEngine
{
/*Vector LMMLogEulerScheme::evolve(const Vector& previousLiborsStates, const
Vector& bmIncrements, double dt, double simDate, const Vector& initialLibors, double
varianceAtTimeIndex) const
{
QLIB_ASSERT(bmIncrements.size() == factors_dimension(), "blabla");
int ltsTimeIndex = liborsTimeStructure_->getTimeIndex(simDate);
double deltaT = liborsTimeStructure_->getTime(ltsTimeIndex + 1) -
liborsTimeStructure_->getTime(ltsTimeIndex);
double stochasticVarianceTermDrift = 1.0;
double stochasticVolatilityTermDiffusion = 1.0;
if (useStochasticVol_)
{
stochasticVarianceTermDrift *= 0.5 * (previousVariance_ +
varianceAtTimeIndex);
stochasticVolatilityTermDiffusion *=
std::sqrt(stochasticVarianceTermDrift);
}
previousVariance_ = varianceAtTimeIndex;
getLogShiftedLiborsDrift(ltsTimeIndex, previousLiborsStates,
initialLibors, deltaT);
for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++)
{
double driftOfLogShiftedLibor = drift_[liborIndex];
double initialLibor = initialLibors[liborIndex];
if (driftOfLogShiftedLibor != driftOfLogShiftedLibor)
{
nextLiborsStates_[liborIndex] =
std::numeric_limits<double>::quiet_NaN();
increments_[liborIndex] =
std::numeric_limits<double>::quiet_NaN();
}
else
{
lmmCovarianceStructure_->getFactorLoadings(simDate,
liborIndex, previousLiborsStates, factorLoadings_);
double diffusionOfLogShiftedLibor = 0.0;
for (int factorIndex = 0; factorIndex < nLiborsFactors_;
factorIndex++)
{
double factorLoading =
factorLoadings_[factorIndex];
double brownianIncrement =
bmIncrements[factorIndex] * std::sqrt(dt);
diffusionOfLogShiftedLibor += factorLoading *
brownianIncrement;
}
double increment = diffusionOfLogShiftedLibor *
stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor *
stochasticVarianceTermDrift;
increments_[liborIndex] = increment;
double skew = lmmCovarianceStructure_-
>getSkew(ltsTimeIndex, liborIndex);
nextLiborsStates_[liborIndex] =
transform(previousLiborsStates[liborIndex], initialLibor, skew, increment);
}
}
if (usePredictorCorrector_)
{
driftPreviousStates_ = drift_;
getLogShiftedLiborsDrift(ltsTimeIndex, nextLiborsStates_,
initialLibors, deltaT);
for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++)
{
double driftOfLogShiftedLiborPreviousStates =
driftPreviousStates_[liborIndex];
double driftOfLogShiftedLiborsNextStates =
drift_[liborIndex];
double initialLibor = initialLibors[liborIndex];
double adjustment = (driftOfLogShiftedLiborsNextStates -
driftOfLogShiftedLiborPreviousStates) * 0.5 * dt * stochasticVarianceTermDrift;
double increment = increments_[liborIndex] + adjustment;
double skew = lmmCovarianceStructure_-
>getSkew(ltsTimeIndex, liborIndex);
nextLiborsStates_[liborIndex] =
transform(previousLiborsStates[liborIndex], initialLibor, skew, increment);
}
}
return nextLiborsStates_;
} // LMMLogEulerScheme::evolve*/
// new evolve: no impact on regular pillars dates
Vector LMMLogEulerScheme::evolve(const Vector& previousLiborsStates, const
Vector& bmIncrements, double dt, double simDate, const Vector& initialLibors, double
varianceAtTimeIndex) const
{
QLIB_ASSERT(bmIncrements.size() == factors_dimension(), "blabla");
int ltsTimeIndex = liborsTimeStructure_->getTimeIndex(simDate);
double deltaT = liborsTimeStructure_->getTime(ltsTimeIndex + 1) -
liborsTimeStructure_->getTime(ltsTimeIndex);
double stochasticVarianceTermDrift = 1.0;
double stochasticVolatilityTermDiffusion = 1.0;
if (useStochasticVol_)
{
stochasticVarianceTermDrift *= 0.5 * (previousVariance_ +
varianceAtTimeIndex);
stochasticVolatilityTermDiffusion *=
std::sqrt(stochasticVarianceTermDrift);
}
previousVariance_ = varianceAtTimeIndex;
getLogShiftedLiborsDrift(ltsTimeIndex, previousLiborsStates,
initialLibors, deltaT);
for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++)
{
double driftOfLogShiftedLibor = drift_[liborIndex];
double initialLibor = initialLibors[liborIndex];
if (driftOfLogShiftedLibor != driftOfLogShiftedLibor)
{
nextLiborsStates_[liborIndex] =
std::numeric_limits<double>::quiet_NaN();
increments_[liborIndex] =
std::numeric_limits<double>::quiet_NaN();
}
else
{
if (liborIndex == ltsTimeIndex)
{
int appliedLiborIndex = (liborIndex == nLibors_ -
1) ? liborIndex : liborIndex + 1;
double diffusionOfLogShiftedLibor = 0.0;
double vol = lmmCovarianceStructure_-
>getVol(liborIndex, appliedLiborIndex);
double skew = lmmCovarianceStructure_-
>getSkew(liborIndex, appliedLiborIndex);
lmmCovarianceStructure_-
>getVolWeightedFactorLoadings(vol, liborIndex, previousLiborsStates, factorLoadings_);
for (int factorIndex = 0; factorIndex <
nLiborsFactors_; factorIndex++)
{
double factorLoading =
factorLoadings_[factorIndex];
double brownianIncrement =
bmIncrements[factorIndex] * std::sqrt(dt);
diffusionOfLogShiftedLibor +=
factorLoading * brownianIncrement;
}
double increment = diffusionOfLogShiftedLibor *
stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor *
stochasticVarianceTermDrift;
increments_[liborIndex] = increment;
// double skew = lmmCovarianceStructure_-
>getSkew(ltsTimeIndex, liborIndex);
nextLiborsStates_[liborIndex] =
transform(previousLiborsStates[liborIndex], initialLibor, skew, increment);
}
else
{
lmmCovarianceStructure_-
>getFactorLoadings(simDate, liborIndex, previousLiborsStates, factorLoadings_);
double diffusionOfLogShiftedLibor = 0.0;
for (int factorIndex = 0; factorIndex <
nLiborsFactors_; factorIndex++)
{
double factorLoading =
factorLoadings_[factorIndex];
double brownianIncrement =
bmIncrements[factorIndex] * std::sqrt(dt);
diffusionOfLogShiftedLibor +=
factorLoading * brownianIncrement;
}
double increment = diffusionOfLogShiftedLibor *
stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor *
stochasticVarianceTermDrift;
increments_[liborIndex] = increment;
double skew = lmmCovarianceStructure_-
>getSkew(ltsTimeIndex, liborIndex);
nextLiborsStates_[liborIndex] =
transform(previousLiborsStates[liborIndex], initialLibor, skew, increment);
}
}
}
if (usePredictorCorrector_)
{
driftPreviousStates_ = drift_;
getLogShiftedLiborsDrift(ltsTimeIndex, nextLiborsStates_,
initialLibors, deltaT);
for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++)
{
double driftOfLogShiftedLiborPreviousStates =
driftPreviousStates_[liborIndex];
double driftOfLogShiftedLiborsNextStates =
drift_[liborIndex];
double initialLibor = initialLibors[liborIndex];
double adjustment = (driftOfLogShiftedLiborsNextStates -
driftOfLogShiftedLiborPreviousStates) * 0.5 * dt * stochasticVarianceTermDrift;
double increment = increments_[liborIndex] + adjustment;
double skew = lmmCovarianceStructure_-
>getSkew(ltsTimeIndex, liborIndex);
nextLiborsStates_[liborIndex] =
transform(previousLiborsStates[liborIndex], initialLibor, skew, increment);
}
}
return nextLiborsStates_;
} // LMMLogEulerScheme::evolve
/*void LMMLogEulerScheme::getLogShiftedLiborsDrift(int ltsTimeIndex, const
Vector &liborsAtTimeIndex, const Vector& initialLibors, double deltaT) const
{
int firstLiborIndex = ltsTimeIndex + 1;
for (int liborIndex = 0; liborIndex < firstLiborIndex; ++liborIndex)
drift_[liborIndex] = std::numeric_limits<double>::quiet_NaN();
for (int liborIndex = firstLiborIndex; liborIndex < nLibors_;
++liborIndex)
drift_[liborIndex] = 0.0;
for (int factorIndex = 0; factorIndex < nLiborsFactors_;
++factorIndex)
covarianceTerms_[factorIndex] = 0.0;
for (int liborIndex = firstLiborIndex; liborIndex < nLibors_;
liborIndex++)
{
double libor = liborsAtTimeIndex[liborIndex];
double initialLibor = initialLibors[liborIndex];
double skew = lmmCovarianceStructure_->getSkew(ltsTimeIndex,
liborIndex);
double temp = deltaT * (skew * libor + (1 - skew) *
initialLibor) / (1.0 + deltaT * libor) / skew;
lmmCovarianceStructure_->getFactorLoadings(ltsTimeIndex,
liborIndex, liborsAtTimeIndex, factorLoadings_);
for (int factorIndex = 0; factorIndex < nLiborsFactors_;
factorIndex++)
{
covarianceTerms_[factorIndex] += temp *
factorLoadings_[factorIndex];
drift_[liborIndex] += covarianceTerms_[factorIndex] *
factorLoadings_[factorIndex];
}
double variance = lmmCovarianceStructure_-
>getCovariance(ltsTimeIndex, liborIndex, liborIndex, liborsAtTimeIndex, factorLoadings1_,
factorLoadings2_);
drift_[liborIndex] -= 0.5 * variance;
}
} // LMMLogEulerScheme::getLogShiftedLiborsDrift*/
// new getLSLD: no impact on relular pillars dates
void LMMLogEulerScheme::getLogShiftedLiborsDrift(int ltsTimeIndex, const
Vector &liborsAtTimeIndex, const Vector& initialLibors, double deltaT) const
{
int firstLiborIndex = ltsTimeIndex + 1;
for (int liborIndex = 0; liborIndex < firstLiborIndex; ++liborIndex)
drift_[liborIndex] = std::numeric_limits<double>::quiet_NaN();
for (int liborIndex = ltsTimeIndex; liborIndex < nLibors_;
++liborIndex)
drift_[liborIndex] = 0.0;
for (int factorIndex = 0; factorIndex < nLiborsFactors_;
++factorIndex)
covarianceTerms_[factorIndex] = 0.0;
for (int liborIndex = firstLiborIndex; liborIndex < nLibors_;
liborIndex++)
{
double libor = liborsAtTimeIndex[liborIndex];
double initialLibor = initialLibors[liborIndex];
double skew = lmmCovarianceStructure_->getSkew(ltsTimeIndex,
liborIndex);
double temp = deltaT * (skew * libor + (1 - skew) *
initialLibor) / (1.0 + deltaT * libor) / skew;
lmmCovarianceStructure_->getFactorLoadings(ltsTimeIndex,
liborIndex, liborsAtTimeIndex, factorLoadings_);
for (int factorIndex = 0; factorIndex < nLiborsFactors_;
factorIndex++)
{
covarianceTerms_[factorIndex] += temp *
factorLoadings_[factorIndex];
drift_[liborIndex] += covarianceTerms_[factorIndex] *
factorLoadings_[factorIndex];
}
double variance = lmmCovarianceStructure_-
>getCovariance(ltsTimeIndex, liborIndex, liborIndex, liborsAtTimeIndex, factorLoadings1_,
factorLoadings2_);
drift_[liborIndex] -= 0.5 * variance;
// drift_[liborIndex];
if (liborIndex == firstLiborIndex)
drift_[firstLiborIndex - 1] = drift_[liborIndex];
}
} // LMMLogEulerScheme::getLogShiftedLiborsDrift
double LMMLogEulerScheme::transform(double previousLibor, double
initialLibor, double skew, double increment) const
{
double libor;
libor = (skew * previousLibor + (1 - skew) * initialLibor) *
std::exp(increment);
libor -= (1 - skew) * initialLibor;
libor /= skew;
return libor;
}
}
}
/*
CirQEScheme class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#include "stdafx.h"
#include "CirQEScheme.h"
namespace QLib
{
namespace MonteCarloEngine
{
const double to_year_frac = 1.0 / 365;
const double QE_psi = 1.5;
CirQEScheme::CirQEScheme(const std::vector<double>& kappa,
const std::vector<double>& theta,
const std::vector<double>& sigma,
const boost::shared_ptr<const TimeStructure>& ts,
const std::vector<Date>& time_grid)
{
size_t nSteps = ts->getSize();
QLIB_ASSERT(kappa.size() == nSteps+1 && theta.size() == nSteps+1 &&
sigma.size() == nSteps+1, "blabla");
ts_ = ts;
time_grid_ = time_grid;
theta_ = theta;
sigma_ = sigma;
kappa_ = kappa;
}
Vector CirQEScheme::evolve(const Vector& previousValueV, const Vector&
bmIncrementsV, size_t timeIndex) const
{
Date simDate = time_grid_[timeIndex];
int tsTimeIndex = ts_->getTimeIndex(simDate);
double previousValue = previousValueV[0];
double bmIncrement = bmIncrementsV[0];
double dt = nbDays(time_grid_[timeIndex-1], time_grid_[timeIndex]) *
to_year_frac;
//double sqrtdt = std::sqrt(dt);
//bmIncrement *= sqrtdt;
double theta = theta_[tsTimeIndex];
double kappa = kappa_[tsTimeIndex];
double sigma = sigma_[tsTimeIndex];
double tmp = std::exp(-kappa * dt);
double m = theta + (previousValue - theta) * tmp;
double s2 = previousValue * sigma * sigma * tmp / kappa * (1 - tmp) +
theta * sigma * sigma / (2 * kappa) * (1 - tmp) * (1 - tmp);
double psi = s2 / (m*m);
Vector variance(1);
if (psi <= QE_psi)
{
double b = std::sqrt(2 / psi - 1 + std::sqrt(2 / psi * (2 /
psi - 1)));
double a = m / (1 + b*b);
variance[0] = a * (b + bmIncrement) * (b + bmIncrement);
}
else
{
double p = (psi - 1) * (psi + 1);
double beta = (1 - p) / m;
double u = boost::math::cdf(norm_,bmIncrement);
variance[0] = (u <= p) ? 0 : 1 / beta * std::log((1-p)/(1-u));
}
return variance;
}
}
}
/*
VolatilityModel class.
Factor reduction performed using Eigen library.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#pragma once
#include "../../Utils/Vector.h"
#include "../../DateTime/TimeStructure.h"
#include <boostshared_ptr.hpp>
namespace QLib
{
class LMMVolatilityStructure
{
public:
LMMVolatilityStructure(double volatility, const boost::shared_ptr<const
TimeStructure>& lts, double skew = 0.0);
double getVolatilityLogSpace(int timeIdx, int liborIdx) const;
double getSkew(size_t timeIdx, size_t liborIdx) const { return skew_; }
const boost::shared_ptr<const TimeStructure>& getLiborsTimeStructure() const
{ return liborsTimeStructure_; }
private:
double volatility_;
double skew_;
boost::shared_ptr<const TimeStructure> liborsTimeStructure_;
};
/*
LMMStochasticVolatilityModel class.
Factor reduction performed using Eigen library.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#pragma once
#include "../../Utils/Vector.h"
#include "../../DateTime/TimeStructure.h"
#include <boostshared_ptr.hpp>
namespace QLib
{
class LMMStochasticVolatilityStructure
{
public:
LMMStochasticVolatilityStructure(double theta, double kappa, double sigma,
const boost::shared_ptr<const TimeStructure>& lts);
const std::vector<double>& getKappa() const { return kappa_; }
const std::vector<double>& getTheta() const { return theta_; }
const std::vector<double>& getSigma() const { return sigma_; }
const boost::shared_ptr<const TimeStructure>& getTimeStructure() const {
return timeStructure_; }
private:
std::vector<double> kappa_;
std::vector<double> theta_;
std::vector<double> sigma_;
boost::shared_ptr<const TimeStructure> timeStructure_;
};
}
/*
CovarianceModel class.
Built from a volatility model along with a correlation model.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#include "stdafx.h"
#include "LMMCovarianceStructure.h"
namespace QLib
{
LMMCovarianceStructure::LMMCovarianceStructure(const boost::shared_ptr<const
LMMVolatilityStructure>& vs, const boost::shared_ptr<const LMMCorrelationStructure>& cs)
{
volatilityStructure_ = vs;
correlationStructure_ = cs;
boost::shared_ptr<const TimeStructure> lts_vol = vs-
>getLiborsTimeStructure();
boost::shared_ptr<const TimeStructure> lts_corr = cs-
>getLiborsTimeStructure();
QLIB_ASSERT(lts_vol == lts_corr, "blabla");
liborsTimeStructure_ = lts_vol;
nFactors_ = cs->numOfFactors();
}
void LMMCovarianceStructure::getFactorLoadings(int timeIdx, int liborIdx, const
Vector& liborsAtTimeIndex, Vector& factorLoadings) const
{
int fls = factorLoadings.size();
QLIB_ASSERT(fls == nFactors_, "blabla");
double volatilityLS = volatilityStructure_->getVolatilityLogSpace(timeIdx,
liborIdx);
for (int factorIdx = 0; factorIdx < nFactors_; factorIdx++)
factorLoadings[factorIdx] = volatilityLS * correlationStructure_-
>getFactorLoading(liborIdx, factorIdx);
}
void LMMCovarianceStructure::getFactorLoadings(double time, int liborIdx, const
Vector& liborsAtTimeIndex, Vector& factorLoadings) const
{
Date date_0 = liborsTimeStructure_->getDate(0);
Date date = date_0 + DateDuration(static_cast<long>(365.0 * time));
int timeIndex = liborsTimeStructure_->getTimeIndex(date);
getFactorLoadings(timeIndex, liborIdx, liborsAtTimeIndex, factorLoadings);
}
double LMMCovarianceStructure::getCovariance(int timeIdx, int liborIdx_1, int
liborIdx_2, const Vector& liborsAtTimeIndex, Vector& factorLoadings_1, Vector&
factorLoadings_2) const
{
int fls1 = factorLoadings_1.size();
int fls2 = factorLoadings_2.size();
QLIB_ASSERT(fls1 == fls2 == nFactors_, "blabla");
getFactorLoadings(timeIdx, liborIdx_1, liborsAtTimeIndex, factorLoadings_1);
getFactorLoadings(timeIdx, liborIdx_2, liborsAtTimeIndex, factorLoadings_2);
double result = 0.0;
for (size_t i = 0; i < factorLoadings_1.size(); i++)
result += factorLoadings_1[i] * factorLoadings_2[i];
return result;
}
double LMMCovarianceStructure::getVol(int timeIndex, int liborIndex) const
{
return volatilityStructure_->getVolatilityLogSpace(timeIndex, liborIndex);
}
void LMMCovarianceStructure::getVolWeightedFactorLoadings(double vol, int
liborIndex, const Vector& liborsAtTimeIndex, Vector& factorLoadings) const
{
int fls = factorLoadings.size();
QLIB_ASSERT(fls == nFactors_, "blabla");
for (int factorIndex = 0; factorIndex < nFactors_; factorIndex++)
factorLoadings[factorIndex] = vol * correlationStructure_-
>getFactorLoading(liborIndex, factorIndex);
}
}
/*
CorrelationModel class.
Factor reduction performed using Eigen library.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#include "stdafx.h"
#include "LMMCorrelationStructure.h"
// #include "../../Math/LinearAlgebra/SpectralDecomposition.h"
#include <cmath>
namespace QLib
{
LMMCorrelationStructure::LMMCorrelationStructure(double rho, double lambda, int
nFactors, const boost::shared_ptr<const TimeStructure>& lts)
{
rho_ = rho;
lambda_ = lambda;
nFactors_ = nFactors;
liborsTimeStructure_ = lts;
int nLibors = lts->getSize();
correlationMatrix_.resize(nLibors, nLibors);
factorMatrix_.resize(nLibors, nFactors);
init();
}
void LMMCorrelationStructure::init()
{
int n = liborsTimeStructure_->getSize();
for (int i = 0; i < n; ++i)
{
correlationMatrix_(i, i) = 1.0;
for (int j = i + 1; j < n; ++j)
{
double ti = liborsTimeStructure_->getTime(i);
double tj = liborsTimeStructure_->getTime(j);
double correl = rho_ + (1 - rho_)*std::exp(-lambda_ *
std::abs(ti - tj));
correlationMatrix_(i, j) = correl;
correlationMatrix_(j, i) = correl;
}
}
doFactorReduction();
}
void LMMCorrelationStructure::doFactorReduction()
{
// TO FIX
int n = liborsTimeStructure_->getSize();
for (int i = 0; i < n; i++)
factorMatrix_(i, 0) = 1;
/*Matrix eigenValues, eigenVectors;
LinearAlgebra::getEigenSystem(correlationMatrix_, eigenVectors,
eigenValues);
int n = eigenValues.size1();
for (int col = 0; col < n; col++)
{
QLIB_ASSERT(eigenValues(col, 0) >= 0, "blabla");
double sqrtLambda = std::sqrt(eigenValues(col, 0));
for (int row = 0; row < n; row++)
eigenVectors(row, col) *= sqrtLambda;
}
for (int col = 0; col < nFactors_; col++)
for (int row = 0; row < n; row++)
factorMatrix_(row, col) = eigenVectors(row, n - 1 - col);
for (int row = 0; row < n; row++)
{
double norm = 0.0;
for (int col = 0; col < nFactors_; col++)
norm += factorMatrix_(row, col) * factorMatrix_(row, col);
norm = std::sqrt(norm);
for (int col = 0; col < nFactors_; col++)
factorMatrix_(row, col) /= norm;
}*/
}
double LMMCorrelationStructure::getFactorLoading(int liborIndex, int factorIndex)
const
{
double factorLoading = factorMatrix_(liborIndex, factorIndex);
return factorLoading;
}
}
/*
LiborMarketModel class.
Built from a covariance model. Does not contain the Monte-Carlo parameters information.
Does not contain the liborProcess neither.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#include "stdafx.h"
#include <cmath>
#include "../LMM/LiborMarketModel.h"
#include <boost/range/algorithm_ext/is_sorted.hpp>
#include "../../Math/Interpolation.h"
namespace QLib
{
void LMM::initialize(const std::vector<Date> & dates, const std::vector<double>&
vols)
{
QLIB_ASSERT(pricingDate_ == dates[0], "blabla");
QLIB_ASSERT(boost::is_sorted(dates), "blabla");
LMM::precompute();
}
void LMM::precompute()
{
size_t nLibors = numOfLibors();
DateTime todayDate = indexCurve_->valueDate();
for (size_t liborIndex = 0; liborIndex < nLibors; liborIndex++)
{
double startTime = liborsTimeStructure_->getTime(liborIndex) * 365.0;
DateTime startDate = DateTimeAddDiff(startTime, todayDate);
double deltaT = liborsTimeStructure_->getTimeStep(liborIndex) *
365.0;
DateTime endDate = DateTimeAddDiff(startTime + deltaT, todayDate);
double df = indexCurve_->df(startDate, endDate);
double initialForwardRate = (1.0 / df - 1.0) / deltaT * 365.0;
initialStates_.push_back(initialForwardRate);
}
}
double LMM::zcb(CurveType::curve_types crv_type, const Date& t, const Date& T, const
Vector& states) const
{
QLIB_ASSERT(t <= T, "blabla");
if (t == T)
return 1.0;
double lastLiborState = crv_type == CurveType::discount ?
states[states.size() - 1] : states[states.size() - 1] + deterministicBasis_;
Date firstDate = liborsTimeStructure_->getDate(0);
double tyf = YearFraction(firstDate, t);
double Tyf = YearFraction(firstDate, T);
int firstLiborIndex = liborsTimeStructure_->getTimeIndex(t);
bool is_tALiborDate = true;
if (liborsTimeStructure_->getDate(firstLiborIndex) < t)
{
is_tALiborDate = false;
firstLiborIndex += 1;
}
int lastLiborIndex = liborsTimeStructure_->getTimeIndex(T);
if (liborsTimeStructure_->getDate(lastLiborIndex) == T)
lastLiborIndex -= 1;
double zcb = 1.0;
for (int liborIndex = firstLiborIndex; liborIndex < lastLiborIndex;
liborIndex++)
{
double libor = CurveType::discount ? states[liborIndex] :
states[liborIndex] + deterministicBasis_;
zcb *= 1.0 / (1.0 + liborsTimeStructure_->getTimeStep(liborIndex)*
libor);
}
double libor = states[firstLiborIndex];
if (libor != libor)
libor = lastLiborState;
if (!is_tALiborDate)
{
double tstart1 = liborsTimeStructure_->getTime(firstLiborIndex - 1);
double tstart2 = liborsTimeStructure_->getTime(firstLiborIndex);
double period = tstart2 - tstart1;
zcb *= 1.0 / (1.0 + period * libor);
period = tyf - tstart1;
zcb *= (1.0 + period * libor);
}
if (firstLiborIndex > lastLiborIndex)
{
double tend1 = liborsTimeStructure_->getTime(lastLiborIndex);
double tend2 = liborsTimeStructure_->getTime(lastLiborIndex+1);
libor = lastLiborState;
double period = tend2 - tend1;
zcb *= (1.0 + period * libor);
period = Tyf - tend1;
zcb /= (1.0 + period * libor);
}
else
{
double t1 = liborsTimeStructure_->getTime(lastLiborIndex);
libor = CurveType::discount ? states[lastLiborIndex] :
states[lastLiborIndex] + deterministicBasis_;
double period = Tyf - t1;
zcb *= 1.0 / (1.0 + period * libor);
}
return zcb;
}
/*
TimeStructure class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
Framework inspired from finmath (Java library)
http://finmath.net/
*/
#include "stdafx.h"
#include "TimeStructure.h"
namespace QLib
{
TimeStructure::TimeStructure(const Date& initialDate, const std::string& tenor,
size_t nTimeSteps)
{
dates_.push_back(initialDate);
Date lastDate = initialDate;
for (size_t timeIndex = 0; timeIndex < nTimeSteps; timeIndex++)
{
Date nD = AddTenor(lastDate, tenor);
Date nextDate = nD;
dates_.push_back(nextDate);
lastDate = nD;
}
}
size_t TimeStructure::getTimeIndex(const Date& date) const
{
std::vector<Date>::const_iterator mIt = std::find(dates_.begin(),
dates_.end(), date);
if (mIt != dates_.end())
return mIt - dates_.begin();
else
{
std::vector<Date>::const_iterator it =
std::lower_bound(dates_.begin(), dates_.end(), date);
if (it == dates_.begin())
return 0;
else if (it == dates_.end())
return dates_.size() - 1;
else
return it - dates_.begin() - 1;
}
}
size_t TimeStructure::getTimeIndex(double time) const
{
Date d1 = dates_[0];
Date d2 = d1 + DateDuration(static_cast<long>(time * 365.0));
return getTimeIndex(d2);
}
double TimeStructure::getTimeStep(size_t timeIndex) const
{
QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be
between 0 and size of time line");
Date d1 = dates_[timeIndex];
Date d2 = dates_[timeIndex + 1];
double timeStep = YearFraction(d1, d2);
return timeStep;
}
// TO FIX
double TimeStructure::getTime(size_t timeIndex) const
{
QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be
between 0 and size of time line");
Date d1 = dates_[0];
Date d2 = dates_[timeIndex];
double time = YearFraction(d1, d2);
return time;
}
Date TimeStructure::getDate(size_t timeIndex) const
{
QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be
between 0 and size of time line");
Date date = dates_[timeIndex];
return date;
}
}
#include "stdafx.h"
#include "AdjZCBondObservation.h"
namespace QLib
{
namespace MonteCarloEngine
{
double AdjZCBondObservation::operator() (Matrix const& m) const
{
std::size_t n_dates = sim_dates_.size();
double numeraire = 1.0;
size_t nLibors = m.size2();
Vector states(nLibors + 1);
states[nLibors] = std::numeric_limits<double>::quiet_NaN();
const boost::shared_ptr<const TimeStructure>& lts = core_model_ptr_-
>getLiborTimeStructure();
const std::vector<Date> & libor_dates = lts->getDates();
size_t idxStepLS = lts->getTimeIndex(sim_dates_[step_]);
Date d = lts->getDate(idxStepLS);
size_t idx = sdts_.getTimeIndex(d);
numeraire *= 1.0 / core_model_ptr_->df(crv_type_, libor_dates[0],
libor_dates[1]);
double lastLiborState = m(idx, index_ * nLibors + idxStepLS);
states[nLibors] = lastLiborState;
if (n_dates > 2)
{
numeraire = 1.0;
for (size_t i = 0; i < idxStepLS + 1; i++)
{
Date d = lts->getDate(i);
size_t idx = sdts_.getTimeIndex(d);
for (size_t liborIndex = 0; liborIndex < nLibors;
liborIndex++)
states[liborIndex] = m(idx, index_ * nLibors +
liborIndex);
numeraire = numeraire * (1.0 / core_model_ptr_-
>zcb(crv_type_, libor_dates[i], libor_dates[i + 1], states));
}
for (size_t liborIndex = 0; liborIndex < nLibors;
liborIndex++)
states[liborIndex] = m(step_, index_ * nLibors +
liborIndex);
numeraire *= core_model_ptr_->zcb(crv_type_,
sim_dates_[step_], libor_dates[idxStepLS + 1], states);
}
return core_model_ptr_->zcb(crv_type_, sim_dates_[step_], T_, states)
/ numeraire;
}
}
}
/*
SwapRateObservable class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#include "stdafx.h"
#include "../../../MarketData/MarketData.h"
#include "SwapRateObservable.h"
#include "../Observation/SwapRateObservation.h"
#include "DiscountFactorObservable.h"
#include "Sampler.h"
#include "../../../Core/Exception.h"
namespace QLib
{
namespace MonteCarloEngine
{
SwapRateObservable::SwapRateObservable(CurveType const& curve, const Date&
start, std::string swapTenor) : start_(start), swapTenor_(swapTenor)
{
size_t n = swapTenor.length();
size_t nmr = boost::lexical_cast<size_t>(swapTenor.substr(0, n - 1));
nPeriods_ = nmr * 4;
Date sd = start_;
for (size_t i = 0; i < nPeriods_; i++)
{
Date nextDate = AddTenor(sd, "3M");
dcfs_[i] = YearFraction(sd, AddTenor(sd, "3M"));
sd = nextDate;
}
}
SwapRateObservable::~SwapRateObservable() {}
std::string SwapRateObservable::description() const
{
std::stringstream ss;
ss << curve_.currency().code() << "-" << swapTenor_;
return ss.str();
}
ObservableImpl::obs_ref_type
SwapRateObservable::requestPrimeReferences(Sampler & sampler, Date date) const
{
// Date start = date + DateDuration(2);
QLIB_ASSERT(date <= start_, "blabla");
obs_ref_type references(nPeriods_+1);
references[0] = sampler.makeRequest(date, new
DiscountFactorObservable(curve_, start_));
Date sd = start_;
for (size_t i = 0; i < nPeriods_; i++)
{
Date nextDate = AddTenor(sd, "3M");
references[i+1] = sampler.makeRequest(date, new
DiscountFactorObservable(curve_, nextDate));
sd = nextDate;
}
return references;
}
boost::shared_ptr < Observation<Vector>>
SwapRateObservable::observation(ObservableImpl::obs_ref_type refs) const
{
return boost::shared_ptr < Observation<Vector>>(new
SwapRateObservation(refs, dcfs_));
}
double SwapRateObservable::fixing(const Date& date, const MarketData&
market) const
{
/*Date d = AddTenor(start_, tenor_);
std::stringstream oss;
oss << "IR.FIXING." << curve_.currency().code() << "." << tenor_;
return market.getFixing(oss.str(), date);*/
return 0.0;
}
}
}
/*
IRCap class.
Author: Xavier Charvet
charvetx@yahoo.fr
Copyright LC Software 2015
*/
#include "stdafx.h"
#include "IRSwaption.h"
#include "../Observable/Sampler.h"
#include "../Observation/HandleInterface.h"
#include "../Observable/DiscountFactorObservable.h"
#include "../Observable/SwapRateObservable.h"
#include "../Observable/Observable.h"
namespace QLib
{
namespace MonteCarloEngine
{
// two ways of doing the request: either we use the swap rate observable
(one cash flow) or we use the forward Libor Observables
// second option is multi-curve ready but we start with the first one for
convenience
CashFlows IRSwaption::request(Sampler & sampler)
{
CashFlows flows;
flows.resize(1);
rate_h_.resize(nPeriods_);
size_t idx = 0;
Date startDate = exerciseDate_ + DateDuration(2);
for (size_t idx = 0; idx < nPeriods_; idx++)
{
Date paymentDate = AddTenor(startDate, "3M");
rate_h_[idx] = sampler.makeRequest(exerciseDate_,
Observable(new DiscountFactorObservable(curve_, paymentDate)));
dcfs_[idx] = YearFraction(startDate, paymentDate);
startDate = paymentDate;
++idx;
}
rate_h_[nPeriods_] = sampler.makeRequest(exerciseDate_,
Observable(new SwapRateObservable(curve_, startDate, swapTenor_)));
return flows;
}
IRSwaption::calculator_type IRSwaption::create_calculator(const
HandleInterface& hi) const
{
std::vector<ObservationHandle> obs_h(rate_h_.size());
for (size_t i = 0; i < rate_h_.size(); i++)
obs_h[i] = hi(rate_h_[i]);
return IRSwaptionCalculator(obs_h, notional_, strike_, dcfs_);
}
}
}

More Related Content

Similar to Libor Market Model

DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdf
DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdfDoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdf
DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdfaathiauto
 
Story of static code analyzer development
Story of static code analyzer developmentStory of static code analyzer development
Story of static code analyzer developmentAndrey Karpov
 
re:mobidyc the overview
re:mobidyc the overviewre:mobidyc the overview
re:mobidyc the overviewESUG
 
3장 자동적으로 움직이는 게임 에이전트 생성법_2
3장 자동적으로 움직이는 게임 에이전트 생성법_23장 자동적으로 움직이는 게임 에이전트 생성법_2
3장 자동적으로 움직이는 게임 에이전트 생성법_2suitzero
 
Write a Matlab code (a computerized program) for calculating plane st.docx
 Write a Matlab code (a computerized program) for calculating plane st.docx Write a Matlab code (a computerized program) for calculating plane st.docx
Write a Matlab code (a computerized program) for calculating plane st.docxajoy21
 
C Recursion, Pointers, Dynamic memory management
C Recursion, Pointers, Dynamic memory managementC Recursion, Pointers, Dynamic memory management
C Recursion, Pointers, Dynamic memory managementSreedhar Chowdam
 
Router Queue Simulation in C++ in MMNN and MM1 conditions
Router Queue Simulation in C++ in MMNN and MM1 conditionsRouter Queue Simulation in C++ in MMNN and MM1 conditions
Router Queue Simulation in C++ in MMNN and MM1 conditionsMorteza Mahdilar
 
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyGrejoJoby1
 
#include iostream #includeData.h #includePerson.h#in.pdf
#include iostream #includeData.h #includePerson.h#in.pdf#include iostream #includeData.h #includePerson.h#in.pdf
#include iostream #includeData.h #includePerson.h#in.pdfannucommunication1
 
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in Nagios
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in NagiosNagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in Nagios
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in NagiosNagios
 
Dynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using TimeDynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using TimeMagnify Analytic Solutions
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2goMoriyoshi Koizumi
 
Lesson 17. Pattern 9. Mixed arithmetic
Lesson 17. Pattern 9. Mixed arithmeticLesson 17. Pattern 9. Mixed arithmetic
Lesson 17. Pattern 9. Mixed arithmeticPVS-Studio
 
A scrupulous code review - 15 bugs in C++ code
A scrupulous code review - 15 bugs in C++ codeA scrupulous code review - 15 bugs in C++ code
A scrupulous code review - 15 bugs in C++ codePVS-Studio LLC
 
Constraint Programming in Haskell
Constraint Programming in HaskellConstraint Programming in Haskell
Constraint Programming in HaskellDavid Overton
 
Options pricing using Lattice models
Options pricing using Lattice modelsOptions pricing using Lattice models
Options pricing using Lattice modelsQuasar Chunawala
 

Similar to Libor Market Model (20)

DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdf
DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdfDoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdf
DoublyList-cpp- #include -DoublyList-h- using namespace std- void Doub.pdf
 
Story of static code analyzer development
Story of static code analyzer developmentStory of static code analyzer development
Story of static code analyzer development
 
re:mobidyc the overview
re:mobidyc the overviewre:mobidyc the overview
re:mobidyc the overview
 
3장 자동적으로 움직이는 게임 에이전트 생성법_2
3장 자동적으로 움직이는 게임 에이전트 생성법_23장 자동적으로 움직이는 게임 에이전트 생성법_2
3장 자동적으로 움직이는 게임 에이전트 생성법_2
 
Write a Matlab code (a computerized program) for calculating plane st.docx
 Write a Matlab code (a computerized program) for calculating plane st.docx Write a Matlab code (a computerized program) for calculating plane st.docx
Write a Matlab code (a computerized program) for calculating plane st.docx
 
C Recursion, Pointers, Dynamic memory management
C Recursion, Pointers, Dynamic memory managementC Recursion, Pointers, Dynamic memory management
C Recursion, Pointers, Dynamic memory management
 
CLIM Undergraduate Workshop: (Attachment) Performing Extreme Value Analysis (...
CLIM Undergraduate Workshop: (Attachment) Performing Extreme Value Analysis (...CLIM Undergraduate Workshop: (Attachment) Performing Extreme Value Analysis (...
CLIM Undergraduate Workshop: (Attachment) Performing Extreme Value Analysis (...
 
Code
CodeCode
Code
 
Router Queue Simulation in C++ in MMNN and MM1 conditions
Router Queue Simulation in C++ in MMNN and MM1 conditionsRouter Queue Simulation in C++ in MMNN and MM1 conditions
Router Queue Simulation in C++ in MMNN and MM1 conditions
 
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
 
#include iostream #includeData.h #includePerson.h#in.pdf
#include iostream #includeData.h #includePerson.h#in.pdf#include iostream #includeData.h #includePerson.h#in.pdf
#include iostream #includeData.h #includePerson.h#in.pdf
 
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in Nagios
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in NagiosNagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in Nagios
Nagios Conference 2014 - Rob Seiwert - Graphing and Trend Prediction in Nagios
 
Dynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using TimeDynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using Time
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2go
 
Lesson 17. Pattern 9. Mixed arithmetic
Lesson 17. Pattern 9. Mixed arithmeticLesson 17. Pattern 9. Mixed arithmetic
Lesson 17. Pattern 9. Mixed arithmetic
 
CPP Homework Help
CPP Homework HelpCPP Homework Help
CPP Homework Help
 
A scrupulous code review - 15 bugs in C++ code
A scrupulous code review - 15 bugs in C++ codeA scrupulous code review - 15 bugs in C++ code
A scrupulous code review - 15 bugs in C++ code
 
Constraint Programming in Haskell
Constraint Programming in HaskellConstraint Programming in Haskell
Constraint Programming in Haskell
 
Options pricing using Lattice models
Options pricing using Lattice modelsOptions pricing using Lattice models
Options pricing using Lattice models
 
Strategy Synthesis for Data-Aware Dynamic Systems with Multiple Actors
Strategy Synthesis for Data-Aware Dynamic Systems with Multiple ActorsStrategy Synthesis for Data-Aware Dynamic Systems with Multiple Actors
Strategy Synthesis for Data-Aware Dynamic Systems with Multiple Actors
 

Recently uploaded

Call Girls in Gomti Nagar - 7388211116 - With room Service
Call Girls in Gomti Nagar - 7388211116  - With room ServiceCall Girls in Gomti Nagar - 7388211116  - With room Service
Call Girls in Gomti Nagar - 7388211116 - With room Servicediscovermytutordmt
 
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...lizamodels9
 
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...Dipal Arora
 
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesDipal Arora
 
Event mailer assignment progress report .pdf
Event mailer assignment progress report .pdfEvent mailer assignment progress report .pdf
Event mailer assignment progress report .pdftbatkhuu1
 
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779Best VIP Call Girls Noida Sector 40 Call Me: 8448380779
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779Delhi Call girls
 
Cash Payment 9602870969 Escort Service in Udaipur Call Girls
Cash Payment 9602870969 Escort Service in Udaipur Call GirlsCash Payment 9602870969 Escort Service in Udaipur Call Girls
Cash Payment 9602870969 Escort Service in Udaipur Call GirlsApsara Of India
 
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature Set
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature SetCreating Low-Code Loan Applications using the Trisotech Mortgage Feature Set
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature SetDenis Gagné
 
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...Lviv Startup Club
 
7.pdf This presentation captures many uses and the significance of the number...
7.pdf This presentation captures many uses and the significance of the number...7.pdf This presentation captures many uses and the significance of the number...
7.pdf This presentation captures many uses and the significance of the number...Paul Menig
 
Boost the utilization of your HCL environment by reevaluating use cases and f...
Boost the utilization of your HCL environment by reevaluating use cases and f...Boost the utilization of your HCL environment by reevaluating use cases and f...
Boost the utilization of your HCL environment by reevaluating use cases and f...Roland Driesen
 
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRL
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRLMONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRL
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRLSeo
 
Pharma Works Profile of Karan Communications
Pharma Works Profile of Karan CommunicationsPharma Works Profile of Karan Communications
Pharma Works Profile of Karan Communicationskarancommunications
 
M.C Lodges -- Guest House in Jhang.
M.C Lodges --  Guest House in Jhang.M.C Lodges --  Guest House in Jhang.
M.C Lodges -- Guest House in Jhang.Aaiza Hassan
 
VIP Call Girls In Saharaganj ( Lucknow ) 🔝 8923113531 🔝 Cash Payment (COD) 👒
VIP Call Girls In Saharaganj ( Lucknow  ) 🔝 8923113531 🔝  Cash Payment (COD) 👒VIP Call Girls In Saharaganj ( Lucknow  ) 🔝 8923113531 🔝  Cash Payment (COD) 👒
VIP Call Girls In Saharaganj ( Lucknow ) 🔝 8923113531 🔝 Cash Payment (COD) 👒anilsa9823
 
GD Birla and his contribution in management
GD Birla and his contribution in managementGD Birla and his contribution in management
GD Birla and his contribution in managementchhavia330
 
0183760ssssssssssssssssssssssssssss00101011 (27).pdf
0183760ssssssssssssssssssssssssssss00101011 (27).pdf0183760ssssssssssssssssssssssssssss00101011 (27).pdf
0183760ssssssssssssssssssssssssssss00101011 (27).pdfRenandantas16
 
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service Jamshedpur
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service JamshedpurVIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service Jamshedpur
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service JamshedpurSuhani Kapoor
 

Recently uploaded (20)

Call Girls in Gomti Nagar - 7388211116 - With room Service
Call Girls in Gomti Nagar - 7388211116  - With room ServiceCall Girls in Gomti Nagar - 7388211116  - With room Service
Call Girls in Gomti Nagar - 7388211116 - With room Service
 
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...
Call Girls In DLf Gurgaon ➥99902@11544 ( Best price)100% Genuine Escort In 24...
 
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
 
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
 
Event mailer assignment progress report .pdf
Event mailer assignment progress report .pdfEvent mailer assignment progress report .pdf
Event mailer assignment progress report .pdf
 
Nepali Escort Girl Kakori \ 9548273370 Indian Call Girls Service Lucknow ₹,9517
Nepali Escort Girl Kakori \ 9548273370 Indian Call Girls Service Lucknow ₹,9517Nepali Escort Girl Kakori \ 9548273370 Indian Call Girls Service Lucknow ₹,9517
Nepali Escort Girl Kakori \ 9548273370 Indian Call Girls Service Lucknow ₹,9517
 
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779Best VIP Call Girls Noida Sector 40 Call Me: 8448380779
Best VIP Call Girls Noida Sector 40 Call Me: 8448380779
 
Cash Payment 9602870969 Escort Service in Udaipur Call Girls
Cash Payment 9602870969 Escort Service in Udaipur Call GirlsCash Payment 9602870969 Escort Service in Udaipur Call Girls
Cash Payment 9602870969 Escort Service in Udaipur Call Girls
 
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature Set
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature SetCreating Low-Code Loan Applications using the Trisotech Mortgage Feature Set
Creating Low-Code Loan Applications using the Trisotech Mortgage Feature Set
 
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...
Yaroslav Rozhankivskyy: Три складові і три передумови максимальної продуктивн...
 
7.pdf This presentation captures many uses and the significance of the number...
7.pdf This presentation captures many uses and the significance of the number...7.pdf This presentation captures many uses and the significance of the number...
7.pdf This presentation captures many uses and the significance of the number...
 
Boost the utilization of your HCL environment by reevaluating use cases and f...
Boost the utilization of your HCL environment by reevaluating use cases and f...Boost the utilization of your HCL environment by reevaluating use cases and f...
Boost the utilization of your HCL environment by reevaluating use cases and f...
 
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRL
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRLMONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRL
MONA 98765-12871 CALL GIRLS IN LUDHIANA LUDHIANA CALL GIRL
 
VVVIP Call Girls In Greater Kailash ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Greater Kailash ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...VVVIP Call Girls In Greater Kailash ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Greater Kailash ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
 
Pharma Works Profile of Karan Communications
Pharma Works Profile of Karan CommunicationsPharma Works Profile of Karan Communications
Pharma Works Profile of Karan Communications
 
M.C Lodges -- Guest House in Jhang.
M.C Lodges --  Guest House in Jhang.M.C Lodges --  Guest House in Jhang.
M.C Lodges -- Guest House in Jhang.
 
VIP Call Girls In Saharaganj ( Lucknow ) 🔝 8923113531 🔝 Cash Payment (COD) 👒
VIP Call Girls In Saharaganj ( Lucknow  ) 🔝 8923113531 🔝  Cash Payment (COD) 👒VIP Call Girls In Saharaganj ( Lucknow  ) 🔝 8923113531 🔝  Cash Payment (COD) 👒
VIP Call Girls In Saharaganj ( Lucknow ) 🔝 8923113531 🔝 Cash Payment (COD) 👒
 
GD Birla and his contribution in management
GD Birla and his contribution in managementGD Birla and his contribution in management
GD Birla and his contribution in management
 
0183760ssssssssssssssssssssssssssss00101011 (27).pdf
0183760ssssssssssssssssssssssssssss00101011 (27).pdf0183760ssssssssssssssssssssssssssss00101011 (27).pdf
0183760ssssssssssssssssssssssssssss00101011 (27).pdf
 
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service Jamshedpur
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service JamshedpurVIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service Jamshedpur
VIP Call Girl Jamshedpur Aashi 8250192130 Independent Escort Service Jamshedpur
 

Libor Market Model

  • 1. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%. No predictor corrector, no brownian bridge. 131072 simulations. No displaced diffusion, no stochastic volatility. Diff = BS-MC Abbreviations : BS :=Black-Scholes (closed form), DD :=Displaced Diffusion (closed form), MC :=Monte Carlo.
  • 2. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%. Predictor corrector + brownian bridge. 131072 simulations. No displaced diffusion, no stochastic volatility. Diff = BS-MC
  • 3. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. ATM strike 3%. Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, no stochastic volatility. Diff=DD-MC
  • 4. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%. Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, no stochastic volatility. Diff=DD-MC
  • 5. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%. Predictor corrector + brownian bridge. 131072 simulations. No Displaced diffusion, stochastic volatility = 150%, kappa=1. Diff=Heston-MC
  • 6. Mersenne-Twister 19937. Initial flat 3M forward rates 3%. LNVol 20%. Cap 10Y/3M. strike 6%. Predictor corrector + brownian bridge. 131072 simulations. Displaced diffusion q=0.7, stochastic volatility = 150%, kappa=1. MC only.
  • 7. #include "stdafx.h" #include "LMMTest.h" #include <boost/make_shared.hpp> namespace QLib { using namespace MonteCarloEngine; void LMMTest() { int n = 65536; size_t nCaplets = 39; double strike = 0.06; double skew = 1.0; double volatility = 0.2; bool useStochVol = true; bool usepredcorr = true; bool useSobol = false; bool usebrownianbridge = true; double kappaSV = 1.0; double sigmaSV = 1.5; size_t startIdx = 1; int nFactors = 1; double deterministicBasis = 0.001 * 0; /*std::cout << "Enter nSimus: "; std::cin >> n; std::cout << "Enter nCaplets: "; std::cin >> nCaplets; std::cout << "Enter startIdx: "; std::cin >> startIdx; std::cout << "Enter strike: "; std::cin >> strike; std::cout << "Enter skew: "; std::cin >> skew; std::cout << "Enter volatility: "; std::cin >> volatility; std::cout << "Enter useSV: "; std::cin >> useStochVol; std::cout << "Enter usePC: "; std::cin >> usepredcorr; std::cout << "Enter useBB: "; std::cin >> usebrownianbridge; std::cout << "Enter kappaSV: "; std::cin >> kappaSV; std::cout << "Enter sigmaSV: "; std::cin >> sigmaSV;*/ Date base_date(2015, 8, 18); // TO FIX boost::shared_ptr<MarketData> market = CreateTestMarket(base_date); Currency base_ccy("USD"); CurveType type(base_ccy);
  • 8. Date pricing_date = base_date; std::string tenor = "3M"; size_t nTimeSteps = 40; // int nFactors = 1; double rho = 0.0; double lambda = 0.1; boost::shared_ptr<const TimeStructure> lts = boost::shared_ptr<const TimeStructure>(new TimeStructure(base_date, tenor, nTimeSteps)); boost::shared_ptr<const LMMCorrelationStructure> corr_model = boost::shared_ptr<const LMMCorrelationStructure>(new LMMCorrelationStructure(rho, lambda, nFactors, lts)); boost::shared_ptr<const LMMVolatilityStructure> vol_model = boost::shared_ptr<const LMMVolatilityStructure>(new LMMVolatilityStructure(volatility, lts, skew)); boost::shared_ptr<const LMMCovarianceStructure> cov_model = boost::shared_ptr<LMMCovarianceStructure>(new LMMCovarianceStructure(vol_model, corr_model)); boost::shared_ptr<const LMMStochasticVolatilityStructure> stoch_vol_model; if (useStochVol) { double theta = 1.0; double kappa = kappaSV; double sigma = sigmaSV; stoch_vol_model = boost::shared_ptr<LMMStochasticVolatilityStructure>(new LMMStochasticVolatilityStructure(theta, kappa, sigma, lts)); } std::string rc_name = "usd_dfcurve"; std::string rc_ccy = "USD"; DateTime pricing_datetime = date_to_datetime(pricing_date); size_t n_dates = nTimeSteps + 1; std::vector<DateTime> rc_dates(n_dates); std::vector<double> dfs(n_dates); rc_dates[0] = date_to_datetime(base_date); dfs[0] = 1.0; double dpy = 365.0; double rate = 0.03; for (size_t i = 1; i < n_dates; i++) { rc_dates[i] = date_to_datetime(AddTenor(lts->getDate(i - 1), tenor)); double days = DateTimeDiff(rc_dates[i], rc_dates[i - 1]); dfs[i] = dfs[i - 1] / (1.0 + (rate)* days / dpy); } std::string interp = "PieceWiseConstant"; Enum::Interpolation::Enum interp_type = Enum::Interpolation::which(interp); // TO FIX std::string interp_vals = "LinearRates";
  • 9. Enum::IRInterpolationData::Enum interp_what = Enum::IRInterpolationData::which(interp_vals); TimeCalculator time_calculator; boost::shared_ptr<const YieldCurve> df_curve = boost::shared_ptr<const YieldCurve>( new RateCurve( rc_name, rc_ccy, pricing_datetime, rc_dates, dfs, interp_type, interp_what, time_calculator) ); LMM core_model( pricing_date, base_ccy, df_curve, df_curve, cov_model, stoch_vol_model, deterministicBasis ); boost::shared_ptr<LMM> lmm_ptr = boost::make_shared<LMM>(core_model); LiborMarketModelMC::config_type config; config.core_model_ptr_ = lmm_ptr; config.use_brownian_bridge_ = usebrownianbridge; config.use_predictor_corrector_ = usepredcorr; config.use_stoch_vol_ = useStochVol; config.base_ccy = base_ccy; boost::gregorian::date_duration start = lts->getDate(startIdx) - lts- >getDate(0); std::vector<Date> opt_mat; Date startDate = base_date + DateDuration(start); Date exerciseDate = startDate - DateDuration(2); opt_mat.push_back(exerciseDate); size_t idx = lts->getTimeIndex(startDate); for (size_t i = 1; i < nCaplets; i++) { boost::gregorian::date_duration diff = lts->getDate(idx + i) - lts- >getDate(idx + i - 1); double days = diff.days(); startDate += DateDuration((long)days); exerciseDate = startDate - DateDuration(2); opt_mat.push_back(exerciseDate); }
  • 10. double notional = 1.0; std::vector<Payoff> payoffs; payoffs.push_back(IRCap::create(base_ccy, opt_mat, tenor, notional, strike, true)); Controller<LiborMarketModelMC, Payoff, AccumulatorPVConvergence, PathAccumulatorPV> controller; controller.configure(config, payoffs.begin(), payoffs.end(), *market); if (useSobol) controller.use_sobol(); Controller<LiborMarketModelMC, Payoff, AccumulatorPVConvergence, PathAccumulatorPV>::return_type results = controller.run(n); for (size_t i = 0; i < results.size(); ++i) print_conv_table(results[i]); // analytical price TimeCalculator timeCalc; std::vector<double> hestonParams; hestonParams.push_back(1.0 * volatility * volatility); // v0 hestonParams.push_back(kappaSV); hestonParams.push_back(1.0 * volatility * volatility); // theta SV hestonParams.push_back(sigmaSV * volatility); hestonParams.push_back(0.0); // rho XHeston xheston(pricing_datetime, timeCalc, hestonParams); double analytic_call = 0.0; double analytic_call_heston = 0.0; double bs_call = 0.0; for (size_t i = 0; i < opt_mat.size(); i++) { boost::gregorian::date_duration diff = lts->getDate(i + idx + 1) - lts->getDate(i + idx); double days = diff.days(); Date sd = opt_mat[i] + DateDuration(2); Date pd = sd + DateDuration((long)days); double P_Tsd = df_curve->df(date_to_datetime(sd)); double P_Tpd = df_curve->df(date_to_datetime(pd)); double dcf = YearFraction(sd, AddTenor(sd, tenor)); double fwd_rate = (P_Tsd / P_Tpd - 1.0) / dcf; analytic_call += ShiftedLogNormal::price(true, P_Tpd, fwd_rate, strike, YearFraction(base_date, opt_mat[i]), volatility, skew); // *dcf; bs_call += BlackScholes::price(true, P_Tpd, fwd_rate, strike, YearFraction(base_date, opt_mat[i]), volatility); // *dcf; analytic_call_heston += P_Tpd * fwd_rate * xheston.vanilla(true, YearFraction(base_date, opt_mat[i]), strike / fwd_rate); // *dcf; } std::cout << "Market value DD " << analytic_call << std::endl; std::cout << "Market value BS " << bs_call << std::endl;
  • 11. std::cout << "Market value Heston " << analytic_call_heston << std::endl; double diff = analytic_call_heston - results[0].results_[0].first; std::cout << "Difference" << diff << std::endl; } } /* LMMProcess charvetx@yahoo.fr Copyright LC Software 2015 */ #pragma once #include <boost/shared_ptr.hpp> #include "../DiscretisationScheme/LMMSchemeBase.h" #include "../DiscretisationScheme/DiscretisationSchemeBase.h" #include "BrownianIncrements.h" #include "../../../Utils/Matrix.h" #include "../../../Utils/Vector.h" #include "../../../Core/Exception.h" #include "BrownianBridge.h" namespace QLib { namespace MonteCarloEngine { class LMMProcess { public: typedef Matrix result_type; typedef boost::shared_ptr<const LMMSchemeBase> lmm_scheme_ptr_type; typedef boost::shared_ptr<const DiscretisationSchemeBase> lmm_stoch_vol_scheme_ptr_type; result_type create_result() const { return result_type(size1(), size2()); } struct buffer_type
  • 12. { Vector bridged_variates; Matrix increments; }; buffer_type create_buffer() const { buffer_type buffer; buffer.increments.resize(inc_func_.size1(), inc_func_.size2()); buffer.bridged_variates.resize(input_size()); return buffer; } LMMProcess(const Vector& initialStates, const CovarianceStructure& cov_struct, // just to initialise the B_Bridge size_t nFactors, const Vector& time_grid, const std::vector<size_t>& obs_idx, bool use_brownian_bridge = false, bool use_stoch_vol = false) : initialStates_(initialStates), nLibors_(initialStates_.size()), inc_func_(nFactors, time_grid), obs_idx_(obs_idx), use_brownian_bridge_(use_brownian_bridge), bridge_(cov_struct), use_stoch_vol_(use_stoch_vol), nFactors_(inc_func_.size2()) { } Matrix & operator() (const Vector& input, Matrix& output, buffer_type& buffer) const; void set_main_scheme(lmm_scheme_ptr_type scheme) { main_scheme_ = scheme; } void set_stoch_vol_scheme(lmm_stoch_vol_scheme_ptr_type scheme) { stoch_vol_scheme_ = scheme; } bool use_stoch_vol() const { return use_stoch_vol_; } size_t input_size() const { return inc_func_.input_size(); } size_t size1() const { return inc_func_.size1(); } size_t size2() const { return nLibors_; } private: Vector initialStates_; size_t nLibors_; BrownianIncrements inc_func_; std::vector<size_t> obs_idx_;
  • 13. lmm_scheme_ptr_type main_scheme_; lmm_stoch_vol_scheme_ptr_type stoch_vol_scheme_; bool use_brownian_bridge_; BrownianBridgeMultiD bridge_; bool use_stoch_vol_; int nFactors_; }; } } /* LMMProcess class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 */ #include "stdafx.h" #include "LMMProcess.h" namespace QLib { namespace MonteCarloEngine { Matrix & LMMProcess::operator() (const Vector& input, Matrix& output, buffer_type& buffer) const { QLIB_ASSERT((output.size1() == size1()) && (output.size2() == size2()), "blabla"); size_t nLibors = initialStates_.size(); size_t nTimes = inc_func_.size1(); Matrix liborStates(nTimes, nLibors); size_t nVolFactors, nLmmFactors; if (use_stoch_vol_) { nLmmFactors = nFactors_ - 1; nVolFactors = 1; } else { nLmmFactors = nFactors_; nVolFactors = 0; }
  • 14. Vector bmIncrements(nLmmFactors + nVolFactors); Vector lmmBmIncrements(nLmmFactors); double variance = 1.0; Vector varianceAtTimeIndex(1); varianceAtTimeIndex[0] = variance; Vector volBmIncrements(1); if (use_brownian_bridge_) bridge_.generate_path(input,buffer.bridged_variates); for (size_t timeIndex = 0; timeIndex < nTimes; timeIndex++) { if (use_brownian_bridge_) inc_func_(buffer.bridged_variates, bmIncrements, timeIndex); else inc_func_(input, bmIncrements, timeIndex); for (size_t i = 0; i < nLmmFactors; i++) lmmBmIncrements[i] = bmIncrements[i]; for (size_t j = 0; j < nVolFactors; j++) volBmIncrements[j] = bmIncrements[nLmmFactors + j]; if (timeIndex != 0) { if (use_stoch_vol_) { varianceAtTimeIndex = stoch_vol_scheme_- >evolve(varianceAtTimeIndex,volBmIncrements,timeIndex); variance = varianceAtTimeIndex[0]; } row(liborStates, timeIndex) = main_scheme_- >evolve(row(liborStates, timeIndex - 1), lmmBmIncrements, inc_func_.time_inc(timeIndex), inc_func_.time_grid(timeIndex), initialStates_, variance); } else row(liborStates, 0) = initialStates_; row(output, timeIndex) = row(liborStates, timeIndex); } return output; } } } /* CovarianceStructure charvetx@yahoo.fr
  • 15. Copyright LC Software 2015 */ #pragma once #include <boost/shared_ptr.hpp> #include "../../../Utils/Vector.h" #include "../../../Utils/Matrix.h" #include "../../../Core/Exception.h" namespace QLib { namespace MonteCarloEngine { class CovarianceStructure { public: CovarianceStructure(size_t dimension = 0, size_t steps = 0) : dimension_(dimension), covariances_(steps) { for (size_t i = 0; i < steps; ++i) covariances_[i] = IdentityMatrix(dimension); } ~CovarianceStructure() {} void set_covariance(size_t step, const Matrix& covariance) { QLIB_ASSERT(step < steps(), "blabla"); QLIB_ASSERT(covariance.size1() == dimension_ && covariance.size2() == dimension_, "blabla"); covariances_[step] = covariance; } Matrix const & covariance(size_t i) const { return covariances_[i]; } std::vector<Matrix> const& covariances() const { return covariances_; } size_t dimension()const { return dimension_; } size_t steps() const { return covariances_.size(); } private: size_t dimension_; std::vector<Matrix> covariances_; };
  • 16. } } /* BrownianIncrements charvetx@yahoo.fr Copyright LC Software 2015 */ #pragma once #include "../../../Utils/Vector.h" #include <boost/shared_ptr.hpp> #include "../../../Core/Exception.h" namespace QLib { namespace MonteCarloEngine { class BrownianIncrements { public: BrownianIncrements(size_t nFactorsTotal, const Vector& time_grid) : nFactorsTotal_(nFactorsTotal), time_grid_(time_grid) {} // size_t input_size() const { return time_grid_.size(); } // CHECK size_t input_size() const { return size1() * size2(); } size_t input_dimension() const { return nFactorsTotal_; } size_t size1() const { return time_grid_.size(); } size_t size2() const { return nFactorsTotal_; } // make stuff cleaner later Vector& operator()(Vector const& input, Vector& output, std::size_t i) const; double time_inc(size_t i) const { if (i == 0) return time_grid_[0]; else return time_grid_[i] - time_grid_[i - 1]; } double time_grid(size_t i) const { return time_grid_[i]; } private: size_t nFactorsTotal_; Vector time_grid_; };
  • 17. // TO FIX inline Vector& BrownianIncrements::operator() (const Vector& input, Vector& output, size_t i) const { QLIB_ASSERT(output.size() == size2(),"blabla"); VectorConstRef in(input, boost::numeric::ublas::range(i * nFactorsTotal_, (i + 1) * nFactorsTotal_)); output = in; // prod(sample_struct.root(i), in); // don't use this! too long and useless return output; } } } /* LiborMarketModelMC class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 */ #include "stdafx.h" #include <boost/pointer_cast.hpp> #include "LiborMarketModelMC.h" #include "../Observation/AdjZCBondObservation.h" #include "../../../Model/LMM/LMMCovarianceStructure.h" #include "../../../Core/Exception.h" const double num_days = 365.25; namespace QLib { namespace MonteCarloEngine { LiborMarketModelMC::LiborMarketModelMC(const config_type& config, const std::vector<PrimeRequest>& requests) : config_(config), parser_(requests), dates_(0) { for (std::set<Currency>::const_iterator it = parser_.currencies().begin(); it != parser_.currencies().end(); it++) QLIB_ASSERT((*it)==config_.base_ccy, "blabla") boost::shared_ptr<LMM> lmm_ptr = config_.core_model_ptr_; nFactors_ = lmm_ptr->numOfFactors(); } boost::shared_ptr<LMMSimulation> LiborMarketModelMC::calibrate(const MarketData& mkt, const Sampler& sampler) const
  • 18. { boost::shared_ptr<LMM> lmm_ptr = config_.core_model_ptr_; int nLibors = lmm_ptr->numOfLibors(); Vector initialStates(nLibors); const std::vector<double>& initSt = config_.core_model_ptr_- >getInitialDates(); for (int i = 0; i < nLibors; i++) initialStates[i] = initSt[i]; for (std::map<Currency, size_t>::const_iterator it = ccy_factor.begin(); it != ccy_factor.end(); ++it) QLIB_ASSERT(!((*it).first == config_.base_ccy), "blabla"); const boost::shared_ptr<const LMMCovarianceStructure>& lmmCovarianceStructure = lmm_ptr->getLMMCovarianceStructure(); std::vector<Date> firstDate = lmmCovarianceStructure->getDates(); std::vector<Date> datesUnion(firstDate.size()); std::vector<Date>::iterator itDates; std::vector<Date> lmm_grid = firstDate; std::vector<std::size_t> obs_idx; std::set<Date>::const_iterator obs_date_it = parser_.observationDates().begin(); while ((obs_date_it != parser_.observationDates().end()) && (*obs_date_it <= datetime_to_date(mkt.getPricingDate()))) ++obs_date_it; datesUnion.resize(firstDate.size() + std::distance(obs_date_it, parser_.observationDates().end())); itDates = std::set_union (firstDate.begin(), firstDate.end(), obs_date_it, parser_.observationDates().end(), datesUnion.begin()); datesUnion.resize(itDates - datesUnion.begin()); std::vector<Date>::iterator mc_grid_it = datesUnion.begin(); size_t obs_pos = 0; for (std::set<Date>::const_iterator it = obs_date_it; it != parser_.observationDates().end(); it++) { while ((mc_grid_it != datesUnion.end()) && (*mc_grid_it < *it)) { ++mc_grid_it; ++obs_pos; } obs_idx.push_back(obs_pos); } std::vector<double> mc_time_grid(datesUnion.size()); Vector mc_time_grid_vec(datesUnion.size()); for (size_t i = 0; i < datesUnion.size(); i++) {
  • 19. boost::gregorian::days dd = datesUnion[i] - datetime_to_date(mkt.getPricingDate()); mc_time_grid[i] = dd.days() / num_days; mc_time_grid_vec[i] = mc_time_grid[i]; } std::map<Date, size_t> date_to_step; size_t step = 0; for (std::vector<Date>::iterator it = datesUnion.begin(); it != datesUnion.end(); ++it) date_to_step.insert(std::make_pair(*it, step++)); size_t nFactorsTotal = config_.use_stoch_vol_ ? nFactors_ + 1 : nFactors_; CovarianceStructure cov_struct(nFactorsTotal, mc_time_grid.size()); for (size_t i = 0; i < mc_time_grid.size(); ++i) { double dt = (i == 0) ? 1.0 : mc_time_grid[i] - mc_time_grid[i - 1]; Matrix cov(cov_struct.dimension(), cov_struct.dimension(), 0.0); for (size_t j = 0; j < nFactorsTotal; ++j) { cov(j, j) = dt; for (size_t k = 0; k < j; ++k) cov(j, k) = cov(k, j) = 0.0; } cov_struct.set_covariance(i, cov); } // create Process process_type lmm_process(initialStates, cov_struct, nFactorsTotal, mc_time_grid_vec, obs_idx, config_.use_brownian_bridge_, config_.use_stoch_vol_); // create schemes lmm_scheme_ptr_type lmm_scheme = LMMSchemeFactory::getInstance().createScheme("LogEuler", lmmCovarianceStructure, nFactors_, config_.use_stoch_vol_, config_.use_predictor_corrector_); lmm_process.set_main_scheme(lmm_scheme); bool use_stoch_vol = config_.use_stoch_vol_; if (use_stoch_vol) { const boost::shared_ptr<const LMMStochasticVolatilityStructure>& lmmSVStructure = lmm_ptr- >getLMMStochasticVolatilityStructure(); std::vector<double> kappa = lmmSVStructure->getKappa(); std::vector<double> theta = lmmSVStructure->getTheta(); std::vector<double> sigma = lmmSVStructure->getSigma(); boost::shared_ptr<const TimeStructure> ts = lmmSVStructure- >getTimeStructure();
  • 20. lmm_stoch_vol_scheme_ptr_type lmm_sv_scheme = CIRSchemeFactory::getInstance().createScheme("QE", kappa, theta, sigma, ts, datesUnion); lmm_process.set_stoch_vol_scheme(lmm_sv_scheme); } boost::shared_ptr<simulation_type> simulation(new simulation_type(lmm_process, sampler.nbr_req())); for (AtomicParser::df_map_type::const_iterator it = parser_.dfRequests().begin(); it != parser_.dfRequests().end(); ++it) { const Date obs_date = (*it).first.first; if (obs_date > datetime_to_date(mkt.getPricingDate())) { simulation->handle_int_.set((*it).second, simulation- >atomic_observations_.size()); const Date sett_date = (*it).first.second.date(); Currency ccy = (*it).first.second.curveType().currency(); CurveType::curve_types crv_type = (*it).first.second.curveType().type(); size_t timeStep = date_to_step.find(obs_date)->second; size_t index = 0; std::vector<Date> mc_grid_past; size_t n_past_dates = timeStep + 2; for (size_t i = 0; i < n_past_dates; ++i) { mc_grid_past.push_back(datesUnion[i]); } boost::shared_ptr<Observation<Matrix>> obs(new AdjZCBondObservation(crv_type, mc_grid_past, sett_date, timeStep, index, boost::static_pointer_cast<IRBaseModel>(config_.core_model_ptr_))); simulation->atomic_observations_.push_back(obs); } } sampler.get_derived_observations(simulation->derived_observations_, simulation- >atomic_observations_.size(), simulation->handle_int_, mkt); return simulation; } } }
  • 21. /* LMMSchemeFactory class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 */ #include "stdafx.h" #include "LMMSchemeFactory.h" #include <utility> namespace QLib { namespace MonteCarloEngine { LMMSchemeFactory::LMMSchemeFactory() { scheme_container_.insert(std::pair<std::string, create_scheme_func>("LogEuler", LMMSchemeHelper<LMMLogEulerScheme>::Create)); } LMMSchemeFactory & LMMSchemeFactory::getInstance() { static LMMSchemeFactory theFactory; return theFactory; } boost::shared_ptr<LMMSchemeBase> LMMSchemeFactory::createScheme(const std::string& scheme_id , const boost::shared_ptr<const LMMCovarianceStructure>& lmm_covariance_structure , size_t dimension, bool use_stoch_vol = false, bool use_pred_corr = false) { std::map<std::string, create_scheme_func>::const_iterator scheme_idx = scheme_container_.find(scheme_id); if (scheme_idx == scheme_container_.end()) QLIB_THROW("blabla"); return (*scheme_idx).second(lmm_covariance_structure, dimension, use_stoch_vol, use_pred_corr); } } }
  • 22. #include "stdafx.h" #include "LMMLogEulerScheme.h" namespace QLib { namespace MonteCarloEngine { /*Vector LMMLogEulerScheme::evolve(const Vector& previousLiborsStates, const Vector& bmIncrements, double dt, double simDate, const Vector& initialLibors, double varianceAtTimeIndex) const { QLIB_ASSERT(bmIncrements.size() == factors_dimension(), "blabla"); int ltsTimeIndex = liborsTimeStructure_->getTimeIndex(simDate); double deltaT = liborsTimeStructure_->getTime(ltsTimeIndex + 1) - liborsTimeStructure_->getTime(ltsTimeIndex); double stochasticVarianceTermDrift = 1.0; double stochasticVolatilityTermDiffusion = 1.0; if (useStochasticVol_) { stochasticVarianceTermDrift *= 0.5 * (previousVariance_ + varianceAtTimeIndex); stochasticVolatilityTermDiffusion *= std::sqrt(stochasticVarianceTermDrift); } previousVariance_ = varianceAtTimeIndex; getLogShiftedLiborsDrift(ltsTimeIndex, previousLiborsStates, initialLibors, deltaT); for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++) { double driftOfLogShiftedLibor = drift_[liborIndex]; double initialLibor = initialLibors[liborIndex]; if (driftOfLogShiftedLibor != driftOfLogShiftedLibor) { nextLiborsStates_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); increments_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); } else { lmmCovarianceStructure_->getFactorLoadings(simDate, liborIndex, previousLiborsStates, factorLoadings_); double diffusionOfLogShiftedLibor = 0.0; for (int factorIndex = 0; factorIndex < nLiborsFactors_; factorIndex++) { double factorLoading = factorLoadings_[factorIndex];
  • 23. double brownianIncrement = bmIncrements[factorIndex] * std::sqrt(dt); diffusionOfLogShiftedLibor += factorLoading * brownianIncrement; } double increment = diffusionOfLogShiftedLibor * stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor * stochasticVarianceTermDrift; increments_[liborIndex] = increment; double skew = lmmCovarianceStructure_- >getSkew(ltsTimeIndex, liborIndex); nextLiborsStates_[liborIndex] = transform(previousLiborsStates[liborIndex], initialLibor, skew, increment); } } if (usePredictorCorrector_) { driftPreviousStates_ = drift_; getLogShiftedLiborsDrift(ltsTimeIndex, nextLiborsStates_, initialLibors, deltaT); for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++) { double driftOfLogShiftedLiborPreviousStates = driftPreviousStates_[liborIndex]; double driftOfLogShiftedLiborsNextStates = drift_[liborIndex]; double initialLibor = initialLibors[liborIndex]; double adjustment = (driftOfLogShiftedLiborsNextStates - driftOfLogShiftedLiborPreviousStates) * 0.5 * dt * stochasticVarianceTermDrift; double increment = increments_[liborIndex] + adjustment; double skew = lmmCovarianceStructure_- >getSkew(ltsTimeIndex, liborIndex); nextLiborsStates_[liborIndex] = transform(previousLiborsStates[liborIndex], initialLibor, skew, increment); } } return nextLiborsStates_; } // LMMLogEulerScheme::evolve*/ // new evolve: no impact on regular pillars dates Vector LMMLogEulerScheme::evolve(const Vector& previousLiborsStates, const Vector& bmIncrements, double dt, double simDate, const Vector& initialLibors, double varianceAtTimeIndex) const { QLIB_ASSERT(bmIncrements.size() == factors_dimension(), "blabla");
  • 24. int ltsTimeIndex = liborsTimeStructure_->getTimeIndex(simDate); double deltaT = liborsTimeStructure_->getTime(ltsTimeIndex + 1) - liborsTimeStructure_->getTime(ltsTimeIndex); double stochasticVarianceTermDrift = 1.0; double stochasticVolatilityTermDiffusion = 1.0; if (useStochasticVol_) { stochasticVarianceTermDrift *= 0.5 * (previousVariance_ + varianceAtTimeIndex); stochasticVolatilityTermDiffusion *= std::sqrt(stochasticVarianceTermDrift); } previousVariance_ = varianceAtTimeIndex; getLogShiftedLiborsDrift(ltsTimeIndex, previousLiborsStates, initialLibors, deltaT); for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++) { double driftOfLogShiftedLibor = drift_[liborIndex]; double initialLibor = initialLibors[liborIndex]; if (driftOfLogShiftedLibor != driftOfLogShiftedLibor) { nextLiborsStates_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); increments_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); } else { if (liborIndex == ltsTimeIndex) { int appliedLiborIndex = (liborIndex == nLibors_ - 1) ? liborIndex : liborIndex + 1; double diffusionOfLogShiftedLibor = 0.0; double vol = lmmCovarianceStructure_- >getVol(liborIndex, appliedLiborIndex); double skew = lmmCovarianceStructure_- >getSkew(liborIndex, appliedLiborIndex); lmmCovarianceStructure_- >getVolWeightedFactorLoadings(vol, liborIndex, previousLiborsStates, factorLoadings_); for (int factorIndex = 0; factorIndex < nLiborsFactors_; factorIndex++) { double factorLoading = factorLoadings_[factorIndex]; double brownianIncrement = bmIncrements[factorIndex] * std::sqrt(dt); diffusionOfLogShiftedLibor += factorLoading * brownianIncrement; }
  • 25. double increment = diffusionOfLogShiftedLibor * stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor * stochasticVarianceTermDrift; increments_[liborIndex] = increment; // double skew = lmmCovarianceStructure_- >getSkew(ltsTimeIndex, liborIndex); nextLiborsStates_[liborIndex] = transform(previousLiborsStates[liborIndex], initialLibor, skew, increment); } else { lmmCovarianceStructure_- >getFactorLoadings(simDate, liborIndex, previousLiborsStates, factorLoadings_); double diffusionOfLogShiftedLibor = 0.0; for (int factorIndex = 0; factorIndex < nLiborsFactors_; factorIndex++) { double factorLoading = factorLoadings_[factorIndex]; double brownianIncrement = bmIncrements[factorIndex] * std::sqrt(dt); diffusionOfLogShiftedLibor += factorLoading * brownianIncrement; } double increment = diffusionOfLogShiftedLibor * stochasticVolatilityTermDiffusion + dt * driftOfLogShiftedLibor * stochasticVarianceTermDrift; increments_[liborIndex] = increment; double skew = lmmCovarianceStructure_- >getSkew(ltsTimeIndex, liborIndex); nextLiborsStates_[liborIndex] = transform(previousLiborsStates[liborIndex], initialLibor, skew, increment); } } } if (usePredictorCorrector_) { driftPreviousStates_ = drift_; getLogShiftedLiborsDrift(ltsTimeIndex, nextLiborsStates_, initialLibors, deltaT); for (int liborIndex = 0; liborIndex < nLibors_; liborIndex++) { double driftOfLogShiftedLiborPreviousStates = driftPreviousStates_[liborIndex]; double driftOfLogShiftedLiborsNextStates = drift_[liborIndex]; double initialLibor = initialLibors[liborIndex]; double adjustment = (driftOfLogShiftedLiborsNextStates - driftOfLogShiftedLiborPreviousStates) * 0.5 * dt * stochasticVarianceTermDrift; double increment = increments_[liborIndex] + adjustment;
  • 26. double skew = lmmCovarianceStructure_- >getSkew(ltsTimeIndex, liborIndex); nextLiborsStates_[liborIndex] = transform(previousLiborsStates[liborIndex], initialLibor, skew, increment); } } return nextLiborsStates_; } // LMMLogEulerScheme::evolve /*void LMMLogEulerScheme::getLogShiftedLiborsDrift(int ltsTimeIndex, const Vector &liborsAtTimeIndex, const Vector& initialLibors, double deltaT) const { int firstLiborIndex = ltsTimeIndex + 1; for (int liborIndex = 0; liborIndex < firstLiborIndex; ++liborIndex) drift_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); for (int liborIndex = firstLiborIndex; liborIndex < nLibors_; ++liborIndex) drift_[liborIndex] = 0.0; for (int factorIndex = 0; factorIndex < nLiborsFactors_; ++factorIndex) covarianceTerms_[factorIndex] = 0.0; for (int liborIndex = firstLiborIndex; liborIndex < nLibors_; liborIndex++) { double libor = liborsAtTimeIndex[liborIndex]; double initialLibor = initialLibors[liborIndex]; double skew = lmmCovarianceStructure_->getSkew(ltsTimeIndex, liborIndex); double temp = deltaT * (skew * libor + (1 - skew) * initialLibor) / (1.0 + deltaT * libor) / skew; lmmCovarianceStructure_->getFactorLoadings(ltsTimeIndex, liborIndex, liborsAtTimeIndex, factorLoadings_); for (int factorIndex = 0; factorIndex < nLiborsFactors_; factorIndex++) { covarianceTerms_[factorIndex] += temp * factorLoadings_[factorIndex]; drift_[liborIndex] += covarianceTerms_[factorIndex] * factorLoadings_[factorIndex]; } double variance = lmmCovarianceStructure_- >getCovariance(ltsTimeIndex, liborIndex, liborIndex, liborsAtTimeIndex, factorLoadings1_, factorLoadings2_); drift_[liborIndex] -= 0.5 * variance;
  • 27. } } // LMMLogEulerScheme::getLogShiftedLiborsDrift*/ // new getLSLD: no impact on relular pillars dates void LMMLogEulerScheme::getLogShiftedLiborsDrift(int ltsTimeIndex, const Vector &liborsAtTimeIndex, const Vector& initialLibors, double deltaT) const { int firstLiborIndex = ltsTimeIndex + 1; for (int liborIndex = 0; liborIndex < firstLiborIndex; ++liborIndex) drift_[liborIndex] = std::numeric_limits<double>::quiet_NaN(); for (int liborIndex = ltsTimeIndex; liborIndex < nLibors_; ++liborIndex) drift_[liborIndex] = 0.0; for (int factorIndex = 0; factorIndex < nLiborsFactors_; ++factorIndex) covarianceTerms_[factorIndex] = 0.0; for (int liborIndex = firstLiborIndex; liborIndex < nLibors_; liborIndex++) { double libor = liborsAtTimeIndex[liborIndex]; double initialLibor = initialLibors[liborIndex]; double skew = lmmCovarianceStructure_->getSkew(ltsTimeIndex, liborIndex); double temp = deltaT * (skew * libor + (1 - skew) * initialLibor) / (1.0 + deltaT * libor) / skew; lmmCovarianceStructure_->getFactorLoadings(ltsTimeIndex, liborIndex, liborsAtTimeIndex, factorLoadings_); for (int factorIndex = 0; factorIndex < nLiborsFactors_; factorIndex++) { covarianceTerms_[factorIndex] += temp * factorLoadings_[factorIndex]; drift_[liborIndex] += covarianceTerms_[factorIndex] * factorLoadings_[factorIndex]; } double variance = lmmCovarianceStructure_- >getCovariance(ltsTimeIndex, liborIndex, liborIndex, liborsAtTimeIndex, factorLoadings1_, factorLoadings2_); drift_[liborIndex] -= 0.5 * variance; // drift_[liborIndex]; if (liborIndex == firstLiborIndex) drift_[firstLiborIndex - 1] = drift_[liborIndex]; } } // LMMLogEulerScheme::getLogShiftedLiborsDrift
  • 28. double LMMLogEulerScheme::transform(double previousLibor, double initialLibor, double skew, double increment) const { double libor; libor = (skew * previousLibor + (1 - skew) * initialLibor) * std::exp(increment); libor -= (1 - skew) * initialLibor; libor /= skew; return libor; } } } /* CirQEScheme class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/ */ #include "stdafx.h" #include "CirQEScheme.h" namespace QLib { namespace MonteCarloEngine { const double to_year_frac = 1.0 / 365; const double QE_psi = 1.5; CirQEScheme::CirQEScheme(const std::vector<double>& kappa, const std::vector<double>& theta, const std::vector<double>& sigma, const boost::shared_ptr<const TimeStructure>& ts, const std::vector<Date>& time_grid) { size_t nSteps = ts->getSize(); QLIB_ASSERT(kappa.size() == nSteps+1 && theta.size() == nSteps+1 && sigma.size() == nSteps+1, "blabla"); ts_ = ts;
  • 29. time_grid_ = time_grid; theta_ = theta; sigma_ = sigma; kappa_ = kappa; } Vector CirQEScheme::evolve(const Vector& previousValueV, const Vector& bmIncrementsV, size_t timeIndex) const { Date simDate = time_grid_[timeIndex]; int tsTimeIndex = ts_->getTimeIndex(simDate); double previousValue = previousValueV[0]; double bmIncrement = bmIncrementsV[0]; double dt = nbDays(time_grid_[timeIndex-1], time_grid_[timeIndex]) * to_year_frac; //double sqrtdt = std::sqrt(dt); //bmIncrement *= sqrtdt; double theta = theta_[tsTimeIndex]; double kappa = kappa_[tsTimeIndex]; double sigma = sigma_[tsTimeIndex]; double tmp = std::exp(-kappa * dt); double m = theta + (previousValue - theta) * tmp; double s2 = previousValue * sigma * sigma * tmp / kappa * (1 - tmp) + theta * sigma * sigma / (2 * kappa) * (1 - tmp) * (1 - tmp); double psi = s2 / (m*m); Vector variance(1); if (psi <= QE_psi) { double b = std::sqrt(2 / psi - 1 + std::sqrt(2 / psi * (2 / psi - 1))); double a = m / (1 + b*b); variance[0] = a * (b + bmIncrement) * (b + bmIncrement); } else { double p = (psi - 1) * (psi + 1); double beta = (1 - p) / m; double u = boost::math::cdf(norm_,bmIncrement); variance[0] = (u <= p) ? 0 : 1 / beta * std::log((1-p)/(1-u)); } return variance; } } } /*
  • 30. VolatilityModel class. Factor reduction performed using Eigen library. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/ */ #pragma once #include "../../Utils/Vector.h" #include "../../DateTime/TimeStructure.h" #include <boostshared_ptr.hpp> namespace QLib { class LMMVolatilityStructure { public: LMMVolatilityStructure(double volatility, const boost::shared_ptr<const TimeStructure>& lts, double skew = 0.0); double getVolatilityLogSpace(int timeIdx, int liborIdx) const; double getSkew(size_t timeIdx, size_t liborIdx) const { return skew_; } const boost::shared_ptr<const TimeStructure>& getLiborsTimeStructure() const { return liborsTimeStructure_; } private: double volatility_; double skew_; boost::shared_ptr<const TimeStructure> liborsTimeStructure_; }; /* LMMStochasticVolatilityModel class. Factor reduction performed using Eigen library. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/
  • 31. */ #pragma once #include "../../Utils/Vector.h" #include "../../DateTime/TimeStructure.h" #include <boostshared_ptr.hpp> namespace QLib { class LMMStochasticVolatilityStructure { public: LMMStochasticVolatilityStructure(double theta, double kappa, double sigma, const boost::shared_ptr<const TimeStructure>& lts); const std::vector<double>& getKappa() const { return kappa_; } const std::vector<double>& getTheta() const { return theta_; } const std::vector<double>& getSigma() const { return sigma_; } const boost::shared_ptr<const TimeStructure>& getTimeStructure() const { return timeStructure_; } private: std::vector<double> kappa_; std::vector<double> theta_; std::vector<double> sigma_; boost::shared_ptr<const TimeStructure> timeStructure_; }; } /* CovarianceModel class. Built from a volatility model along with a correlation model. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015
  • 32. Framework inspired from finmath (Java library) http://finmath.net/ */ #include "stdafx.h" #include "LMMCovarianceStructure.h" namespace QLib { LMMCovarianceStructure::LMMCovarianceStructure(const boost::shared_ptr<const LMMVolatilityStructure>& vs, const boost::shared_ptr<const LMMCorrelationStructure>& cs) { volatilityStructure_ = vs; correlationStructure_ = cs; boost::shared_ptr<const TimeStructure> lts_vol = vs- >getLiborsTimeStructure(); boost::shared_ptr<const TimeStructure> lts_corr = cs- >getLiborsTimeStructure(); QLIB_ASSERT(lts_vol == lts_corr, "blabla"); liborsTimeStructure_ = lts_vol; nFactors_ = cs->numOfFactors(); } void LMMCovarianceStructure::getFactorLoadings(int timeIdx, int liborIdx, const Vector& liborsAtTimeIndex, Vector& factorLoadings) const { int fls = factorLoadings.size(); QLIB_ASSERT(fls == nFactors_, "blabla"); double volatilityLS = volatilityStructure_->getVolatilityLogSpace(timeIdx, liborIdx); for (int factorIdx = 0; factorIdx < nFactors_; factorIdx++) factorLoadings[factorIdx] = volatilityLS * correlationStructure_- >getFactorLoading(liborIdx, factorIdx); } void LMMCovarianceStructure::getFactorLoadings(double time, int liborIdx, const Vector& liborsAtTimeIndex, Vector& factorLoadings) const { Date date_0 = liborsTimeStructure_->getDate(0); Date date = date_0 + DateDuration(static_cast<long>(365.0 * time)); int timeIndex = liborsTimeStructure_->getTimeIndex(date); getFactorLoadings(timeIndex, liborIdx, liborsAtTimeIndex, factorLoadings); } double LMMCovarianceStructure::getCovariance(int timeIdx, int liborIdx_1, int liborIdx_2, const Vector& liborsAtTimeIndex, Vector& factorLoadings_1, Vector& factorLoadings_2) const { int fls1 = factorLoadings_1.size(); int fls2 = factorLoadings_2.size();
  • 33. QLIB_ASSERT(fls1 == fls2 == nFactors_, "blabla"); getFactorLoadings(timeIdx, liborIdx_1, liborsAtTimeIndex, factorLoadings_1); getFactorLoadings(timeIdx, liborIdx_2, liborsAtTimeIndex, factorLoadings_2); double result = 0.0; for (size_t i = 0; i < factorLoadings_1.size(); i++) result += factorLoadings_1[i] * factorLoadings_2[i]; return result; } double LMMCovarianceStructure::getVol(int timeIndex, int liborIndex) const { return volatilityStructure_->getVolatilityLogSpace(timeIndex, liborIndex); } void LMMCovarianceStructure::getVolWeightedFactorLoadings(double vol, int liborIndex, const Vector& liborsAtTimeIndex, Vector& factorLoadings) const { int fls = factorLoadings.size(); QLIB_ASSERT(fls == nFactors_, "blabla"); for (int factorIndex = 0; factorIndex < nFactors_; factorIndex++) factorLoadings[factorIndex] = vol * correlationStructure_- >getFactorLoading(liborIndex, factorIndex); } } /* CorrelationModel class. Factor reduction performed using Eigen library. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/ */ #include "stdafx.h" #include "LMMCorrelationStructure.h" // #include "../../Math/LinearAlgebra/SpectralDecomposition.h" #include <cmath>
  • 34. namespace QLib { LMMCorrelationStructure::LMMCorrelationStructure(double rho, double lambda, int nFactors, const boost::shared_ptr<const TimeStructure>& lts) { rho_ = rho; lambda_ = lambda; nFactors_ = nFactors; liborsTimeStructure_ = lts; int nLibors = lts->getSize(); correlationMatrix_.resize(nLibors, nLibors); factorMatrix_.resize(nLibors, nFactors); init(); } void LMMCorrelationStructure::init() { int n = liborsTimeStructure_->getSize(); for (int i = 0; i < n; ++i) { correlationMatrix_(i, i) = 1.0; for (int j = i + 1; j < n; ++j) { double ti = liborsTimeStructure_->getTime(i); double tj = liborsTimeStructure_->getTime(j); double correl = rho_ + (1 - rho_)*std::exp(-lambda_ * std::abs(ti - tj)); correlationMatrix_(i, j) = correl; correlationMatrix_(j, i) = correl; } } doFactorReduction(); } void LMMCorrelationStructure::doFactorReduction() { // TO FIX int n = liborsTimeStructure_->getSize(); for (int i = 0; i < n; i++) factorMatrix_(i, 0) = 1; /*Matrix eigenValues, eigenVectors; LinearAlgebra::getEigenSystem(correlationMatrix_, eigenVectors, eigenValues); int n = eigenValues.size1(); for (int col = 0; col < n; col++) { QLIB_ASSERT(eigenValues(col, 0) >= 0, "blabla"); double sqrtLambda = std::sqrt(eigenValues(col, 0)); for (int row = 0; row < n; row++) eigenVectors(row, col) *= sqrtLambda; } for (int col = 0; col < nFactors_; col++)
  • 35. for (int row = 0; row < n; row++) factorMatrix_(row, col) = eigenVectors(row, n - 1 - col); for (int row = 0; row < n; row++) { double norm = 0.0; for (int col = 0; col < nFactors_; col++) norm += factorMatrix_(row, col) * factorMatrix_(row, col); norm = std::sqrt(norm); for (int col = 0; col < nFactors_; col++) factorMatrix_(row, col) /= norm; }*/ } double LMMCorrelationStructure::getFactorLoading(int liborIndex, int factorIndex) const { double factorLoading = factorMatrix_(liborIndex, factorIndex); return factorLoading; } } /* LiborMarketModel class. Built from a covariance model. Does not contain the Monte-Carlo parameters information. Does not contain the liborProcess neither. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/ */ #include "stdafx.h" #include <cmath> #include "../LMM/LiborMarketModel.h" #include <boost/range/algorithm_ext/is_sorted.hpp> #include "../../Math/Interpolation.h" namespace QLib { void LMM::initialize(const std::vector<Date> & dates, const std::vector<double>& vols) { QLIB_ASSERT(pricingDate_ == dates[0], "blabla");
  • 36. QLIB_ASSERT(boost::is_sorted(dates), "blabla"); LMM::precompute(); } void LMM::precompute() { size_t nLibors = numOfLibors(); DateTime todayDate = indexCurve_->valueDate(); for (size_t liborIndex = 0; liborIndex < nLibors; liborIndex++) { double startTime = liborsTimeStructure_->getTime(liborIndex) * 365.0; DateTime startDate = DateTimeAddDiff(startTime, todayDate); double deltaT = liborsTimeStructure_->getTimeStep(liborIndex) * 365.0; DateTime endDate = DateTimeAddDiff(startTime + deltaT, todayDate); double df = indexCurve_->df(startDate, endDate); double initialForwardRate = (1.0 / df - 1.0) / deltaT * 365.0; initialStates_.push_back(initialForwardRate); } } double LMM::zcb(CurveType::curve_types crv_type, const Date& t, const Date& T, const Vector& states) const { QLIB_ASSERT(t <= T, "blabla"); if (t == T) return 1.0; double lastLiborState = crv_type == CurveType::discount ? states[states.size() - 1] : states[states.size() - 1] + deterministicBasis_; Date firstDate = liborsTimeStructure_->getDate(0); double tyf = YearFraction(firstDate, t); double Tyf = YearFraction(firstDate, T); int firstLiborIndex = liborsTimeStructure_->getTimeIndex(t); bool is_tALiborDate = true; if (liborsTimeStructure_->getDate(firstLiborIndex) < t) { is_tALiborDate = false; firstLiborIndex += 1; } int lastLiborIndex = liborsTimeStructure_->getTimeIndex(T); if (liborsTimeStructure_->getDate(lastLiborIndex) == T) lastLiborIndex -= 1; double zcb = 1.0; for (int liborIndex = firstLiborIndex; liborIndex < lastLiborIndex; liborIndex++) {
  • 37. double libor = CurveType::discount ? states[liborIndex] : states[liborIndex] + deterministicBasis_; zcb *= 1.0 / (1.0 + liborsTimeStructure_->getTimeStep(liborIndex)* libor); } double libor = states[firstLiborIndex]; if (libor != libor) libor = lastLiborState; if (!is_tALiborDate) { double tstart1 = liborsTimeStructure_->getTime(firstLiborIndex - 1); double tstart2 = liborsTimeStructure_->getTime(firstLiborIndex); double period = tstart2 - tstart1; zcb *= 1.0 / (1.0 + period * libor); period = tyf - tstart1; zcb *= (1.0 + period * libor); } if (firstLiborIndex > lastLiborIndex) { double tend1 = liborsTimeStructure_->getTime(lastLiborIndex); double tend2 = liborsTimeStructure_->getTime(lastLiborIndex+1); libor = lastLiborState; double period = tend2 - tend1; zcb *= (1.0 + period * libor); period = Tyf - tend1; zcb /= (1.0 + period * libor); } else { double t1 = liborsTimeStructure_->getTime(lastLiborIndex); libor = CurveType::discount ? states[lastLiborIndex] : states[lastLiborIndex] + deterministicBasis_; double period = Tyf - t1; zcb *= 1.0 / (1.0 + period * libor); } return zcb; } /* TimeStructure class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 Framework inspired from finmath (Java library) http://finmath.net/ */
  • 38. #include "stdafx.h" #include "TimeStructure.h" namespace QLib { TimeStructure::TimeStructure(const Date& initialDate, const std::string& tenor, size_t nTimeSteps) { dates_.push_back(initialDate); Date lastDate = initialDate; for (size_t timeIndex = 0; timeIndex < nTimeSteps; timeIndex++) { Date nD = AddTenor(lastDate, tenor); Date nextDate = nD; dates_.push_back(nextDate); lastDate = nD; } } size_t TimeStructure::getTimeIndex(const Date& date) const { std::vector<Date>::const_iterator mIt = std::find(dates_.begin(), dates_.end(), date); if (mIt != dates_.end()) return mIt - dates_.begin(); else { std::vector<Date>::const_iterator it = std::lower_bound(dates_.begin(), dates_.end(), date); if (it == dates_.begin()) return 0; else if (it == dates_.end()) return dates_.size() - 1; else return it - dates_.begin() - 1; } } size_t TimeStructure::getTimeIndex(double time) const { Date d1 = dates_[0]; Date d2 = d1 + DateDuration(static_cast<long>(time * 365.0)); return getTimeIndex(d2); } double TimeStructure::getTimeStep(size_t timeIndex) const { QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be between 0 and size of time line"); Date d1 = dates_[timeIndex]; Date d2 = dates_[timeIndex + 1]; double timeStep = YearFraction(d1, d2); return timeStep; }
  • 39. // TO FIX double TimeStructure::getTime(size_t timeIndex) const { QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be between 0 and size of time line"); Date d1 = dates_[0]; Date d2 = dates_[timeIndex]; double time = YearFraction(d1, d2); return time; } Date TimeStructure::getDate(size_t timeIndex) const { QLIB_ASSERT(timeIndex >= 0 && timeIndex < dates_.size(), "timeIndex must be between 0 and size of time line"); Date date = dates_[timeIndex]; return date; } } #include "stdafx.h" #include "AdjZCBondObservation.h" namespace QLib { namespace MonteCarloEngine { double AdjZCBondObservation::operator() (Matrix const& m) const { std::size_t n_dates = sim_dates_.size(); double numeraire = 1.0; size_t nLibors = m.size2(); Vector states(nLibors + 1); states[nLibors] = std::numeric_limits<double>::quiet_NaN(); const boost::shared_ptr<const TimeStructure>& lts = core_model_ptr_- >getLiborTimeStructure(); const std::vector<Date> & libor_dates = lts->getDates(); size_t idxStepLS = lts->getTimeIndex(sim_dates_[step_]); Date d = lts->getDate(idxStepLS); size_t idx = sdts_.getTimeIndex(d); numeraire *= 1.0 / core_model_ptr_->df(crv_type_, libor_dates[0], libor_dates[1]);
  • 40. double lastLiborState = m(idx, index_ * nLibors + idxStepLS); states[nLibors] = lastLiborState; if (n_dates > 2) { numeraire = 1.0; for (size_t i = 0; i < idxStepLS + 1; i++) { Date d = lts->getDate(i); size_t idx = sdts_.getTimeIndex(d); for (size_t liborIndex = 0; liborIndex < nLibors; liborIndex++) states[liborIndex] = m(idx, index_ * nLibors + liborIndex); numeraire = numeraire * (1.0 / core_model_ptr_- >zcb(crv_type_, libor_dates[i], libor_dates[i + 1], states)); } for (size_t liborIndex = 0; liborIndex < nLibors; liborIndex++) states[liborIndex] = m(step_, index_ * nLibors + liborIndex); numeraire *= core_model_ptr_->zcb(crv_type_, sim_dates_[step_], libor_dates[idxStepLS + 1], states); } return core_model_ptr_->zcb(crv_type_, sim_dates_[step_], T_, states) / numeraire; } } } /* SwapRateObservable class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 */ #include "stdafx.h" #include "../../../MarketData/MarketData.h" #include "SwapRateObservable.h" #include "../Observation/SwapRateObservation.h" #include "DiscountFactorObservable.h" #include "Sampler.h" #include "../../../Core/Exception.h"
  • 41. namespace QLib { namespace MonteCarloEngine { SwapRateObservable::SwapRateObservable(CurveType const& curve, const Date& start, std::string swapTenor) : start_(start), swapTenor_(swapTenor) { size_t n = swapTenor.length(); size_t nmr = boost::lexical_cast<size_t>(swapTenor.substr(0, n - 1)); nPeriods_ = nmr * 4; Date sd = start_; for (size_t i = 0; i < nPeriods_; i++) { Date nextDate = AddTenor(sd, "3M"); dcfs_[i] = YearFraction(sd, AddTenor(sd, "3M")); sd = nextDate; } } SwapRateObservable::~SwapRateObservable() {} std::string SwapRateObservable::description() const { std::stringstream ss; ss << curve_.currency().code() << "-" << swapTenor_; return ss.str(); } ObservableImpl::obs_ref_type SwapRateObservable::requestPrimeReferences(Sampler & sampler, Date date) const { // Date start = date + DateDuration(2); QLIB_ASSERT(date <= start_, "blabla"); obs_ref_type references(nPeriods_+1); references[0] = sampler.makeRequest(date, new DiscountFactorObservable(curve_, start_)); Date sd = start_; for (size_t i = 0; i < nPeriods_; i++) { Date nextDate = AddTenor(sd, "3M"); references[i+1] = sampler.makeRequest(date, new DiscountFactorObservable(curve_, nextDate)); sd = nextDate; } return references; } boost::shared_ptr < Observation<Vector>> SwapRateObservable::observation(ObservableImpl::obs_ref_type refs) const { return boost::shared_ptr < Observation<Vector>>(new SwapRateObservation(refs, dcfs_)); } double SwapRateObservable::fixing(const Date& date, const MarketData& market) const
  • 42. { /*Date d = AddTenor(start_, tenor_); std::stringstream oss; oss << "IR.FIXING." << curve_.currency().code() << "." << tenor_; return market.getFixing(oss.str(), date);*/ return 0.0; } } } /* IRCap class. Author: Xavier Charvet charvetx@yahoo.fr Copyright LC Software 2015 */ #include "stdafx.h" #include "IRSwaption.h" #include "../Observable/Sampler.h" #include "../Observation/HandleInterface.h" #include "../Observable/DiscountFactorObservable.h" #include "../Observable/SwapRateObservable.h" #include "../Observable/Observable.h" namespace QLib { namespace MonteCarloEngine { // two ways of doing the request: either we use the swap rate observable (one cash flow) or we use the forward Libor Observables // second option is multi-curve ready but we start with the first one for convenience CashFlows IRSwaption::request(Sampler & sampler) { CashFlows flows; flows.resize(1); rate_h_.resize(nPeriods_); size_t idx = 0; Date startDate = exerciseDate_ + DateDuration(2); for (size_t idx = 0; idx < nPeriods_; idx++) { Date paymentDate = AddTenor(startDate, "3M"); rate_h_[idx] = sampler.makeRequest(exerciseDate_, Observable(new DiscountFactorObservable(curve_, paymentDate)));
  • 43. dcfs_[idx] = YearFraction(startDate, paymentDate); startDate = paymentDate; ++idx; } rate_h_[nPeriods_] = sampler.makeRequest(exerciseDate_, Observable(new SwapRateObservable(curve_, startDate, swapTenor_))); return flows; } IRSwaption::calculator_type IRSwaption::create_calculator(const HandleInterface& hi) const { std::vector<ObservationHandle> obs_h(rate_h_.size()); for (size_t i = 0; i < rate_h_.size(); i++) obs_h[i] = hi(rate_h_[i]); return IRSwaptionCalculator(obs_h, notional_, strike_, dcfs_); } } }