Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
cashflow.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include "toplevelfixture.hpp"
20#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <ql/currencies/all.hpp>
23#include <ql/indexes/indexmanager.hpp>
24#include <ql/quotes/simplequote.hpp>
25#include <ql/termstructures/yield/flatforward.hpp>
26#include <ql/time/calendars/target.hpp>
27#include <ql/time/daycounters/actualactual.hpp>
31
32using namespace QuantLib;
33using namespace QuantExt;
34using namespace boost::unit_test_framework;
35using namespace std;
36
37BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
38
39BOOST_AUTO_TEST_SUITE(CashFlowTest)
40
41BOOST_AUTO_TEST_CASE(testFXLinkedCashFlow) {
42
43 BOOST_TEST_MESSAGE("Testing FX Linked CashFlow");
44
45 // Test today = 5 Jan 2016
46 Settings::instance().evaluationDate() = Date(5, Jan, 2016);
47 Date today = Settings::instance().evaluationDate();
48
49 Date cfDate1(5, Jan, 2015); // historical
50 Date cfDate2(5, Jan, 2016); // today
51 Date cfDate3(5, Jan, 2017); // future
52
53 Real foreignAmount = 1000000; // 1M
54 QuantLib::ext::shared_ptr<SimpleQuote> sq = QuantLib::ext::make_shared<SimpleQuote>(123.45);
55 Handle<Quote> spot(sq);
56 DayCounter dc = ActualActual(ActualActual::ISDA);
57 Calendar cal = TARGET();
58 Handle<YieldTermStructure> domYTS(QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.005, dc))); // JPY
59 Handle<YieldTermStructure> forYTS(QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.03, dc))); // USD
60 // TODO foreign/domestic vs source/target
61 QuantLib::ext::shared_ptr<FxIndex> fxIndex =
62 QuantLib::ext::make_shared<FxIndex>("FX::USDJPY", 0, USDCurrency(), JPYCurrency(), TARGET(), spot, domYTS, forYTS);
63
64 FXLinkedCashFlow fxlcf1(cfDate1, cfDate1, foreignAmount, fxIndex);
65 FXLinkedCashFlow fxlcf2(cfDate2, cfDate2, foreignAmount, fxIndex);
66 FXLinkedCashFlow fxlcf3(cfDate3, cfDate3, foreignAmount, fxIndex);
67
68 // Add historical and todays fixing
69 fxIndex->addFixing(cfDate1, 112.0);
70 fxIndex->addFixing(cfDate2, sq->value());
71
72 BOOST_TEST_MESSAGE("Check historical flow is correct");
73 BOOST_CHECK_CLOSE(fxlcf1.amount(), 112000000.0, 1e-10);
74
75 BOOST_TEST_MESSAGE("Check todays flow is correct");
76 BOOST_CHECK_CLOSE(fxlcf2.amount(), 123450000.0, 1e-10);
77
78 BOOST_TEST_MESSAGE("Check future (expected) flow is correct");
79 Real fwd = sq->value() * domYTS->discount(cfDate3) / forYTS->discount(cfDate3);
80 BOOST_CHECK_CLOSE(fxlcf3.amount(), foreignAmount * fwd, 1e-10);
81
82 // Now move forward in time, check historical value is still correct
83 Settings::instance().evaluationDate() = Date(1, Feb, 2016);
84 sq->setValue(150.0);
85 domYTS->update();
86 forYTS->update();
87 BOOST_CHECK_CLOSE(fxlcf1.amount(), 112000000.0, 1e-10);
88
89 // check forward quote is still valid
90 fwd = sq->value() * domYTS->discount(cfDate3) / forYTS->discount(cfDate3);
91 BOOST_CHECK_CLOSE(fxlcf3.amount(), foreignAmount * fwd, 1e-10);
92
93 // reset
94 Settings::instance().evaluationDate() = today;
95}
96
97BOOST_AUTO_TEST_CASE(testEquityCoupon) {
98
99 BOOST_TEST_MESSAGE("Testing Equity Coupon");
100
101 // Test today = 5 Jan 2016
102 Settings::instance().evaluationDate() = Date(5, Jan, 2016);
103 Date today = Settings::instance().evaluationDate();
104
105 Date cfDate1(4, Dec, 2015);
106 Date cfDate2(5, Apr, 2016); // future
107 Date fixingDate1(31, Dec, 2015);
108 Date fixingDate2(1, Apr, 2016);
109
110 Real nominal = 1000000; // 1M - in USD
111 string eqName = "SP5";
112 QuantLib::ext::shared_ptr<SimpleQuote> sq = QuantLib::ext::make_shared<SimpleQuote>(2100);
113 Handle<Quote> spot(sq);
114 DayCounter dc = ActualActual(ActualActual::ISDA);
115 Calendar cal = TARGET();
116 Currency ccy = USDCurrency();
117 Natural fixingLag = 2;
118 Real divFactor = 1.0;
119 Handle<YieldTermStructure> dividend(
120 QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.01, dc))); // Dividend Curve
121 Handle<YieldTermStructure> equityforecast(
122 QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.02, dc))); // Equity Forecast Curve
123
124 QuantLib::ext::shared_ptr<EquityIndex2> eqIndex =
125 QuantLib::ext::make_shared<EquityIndex2>(eqName, cal, ccy, spot, equityforecast, dividend);
126
127 eqIndex->addFixing(cfDate1, 2000);
128 eqIndex->addFixing(fixingDate1, 1980);
129
130 // Price Return coupon
131 EquityCoupon eq1(cfDate2, nominal, today, cfDate2, 0, eqIndex, dc, EquityReturnType::Price);
132 // Total Return Coupon
133 EquityCoupon eq2(cfDate2, nominal, today, cfDate2, 0, eqIndex, dc, EquityReturnType::Total, divFactor);
134 // historical starting coupon
135 EquityCoupon eq3(cfDate2, nominal, cfDate1, cfDate2, 0, eqIndex, dc, EquityReturnType::Price);
136 // Total Return Coupon with fixing lag
137 EquityCoupon eq4(cfDate2, nominal, today, cfDate2, fixingLag, eqIndex, dc, EquityReturnType::Total);
138
139 // Fx Index, coupon and underlying have different currency
140 Handle<YieldTermStructure> domYTS(QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.01, dc))); // EUR
141 Handle<YieldTermStructure> forYTS(QuantLib::ext::shared_ptr<YieldTermStructure>(new FlatForward(0, cal, 0.02, dc))); // USD
142 Handle<Quote> fxSpot(QuantLib::ext::make_shared<SimpleQuote>(1.1));
143 QuantLib::ext::shared_ptr<FxIndex> fxIndex =
144 QuantLib::ext::make_shared<FxIndex>("FX::EURUSD", 2, EURCurrency(), USDCurrency(), TARGET(), fxSpot, domYTS, forYTS);
145 // Add historical and todays fixing
146 fxIndex->addFixing(cfDate1, 1.09);
147
148 // Total return coupon with underlying in different ccy - Base ccy EUR, and underlying SP5 in USD
149 EquityCoupon eq5(cfDate2, nominal, today, cfDate2, 0, eqIndex, dc, EquityReturnType::Total, 1.0, false,
150 Null<Real>(), Null<Real>(), Date(), Date(), Date(), Date(), Date(), fxIndex);
151
152 QuantLib::ext::shared_ptr<EquityCouponPricer> pricer1(new EquityCouponPricer());
153 QuantLib::ext::shared_ptr<EquityCouponPricer> pricer2(new EquityCouponPricer());
154 QuantLib::ext::shared_ptr<EquityCouponPricer> pricer3(new EquityCouponPricer());
155 QuantLib::ext::shared_ptr<EquityCouponPricer> pricer4(new EquityCouponPricer());
156 QuantLib::ext::shared_ptr<EquityCouponPricer> pricer5(new EquityCouponPricer());
157 eq1.setPricer(pricer1);
158 eq2.setPricer(pricer2);
159 eq3.setPricer(pricer3);
160 eq4.setPricer(pricer4);
161 eq5.setPricer(pricer5);
162
163 // Price Return coupon
164 Time dt = dc.yearFraction(today, cfDate2);
165 Real forward = spot->value() * std::exp((0.02 - 0.01) * dt);
166 Real expectedAmount = nominal * (forward - spot->value()) / spot->value();
167 BOOST_TEST_MESSAGE("Check Price Return is correct.");
168 BOOST_CHECK_CLOSE(eq1.amount(), expectedAmount, 1e-10);
169
170 // Total Return Coupon
171 forward = spot->value() * std::exp((0.02 - 0.01) * dt);
172 Real div = spot->value() * std::exp((0.02) * dt) - forward;
173 expectedAmount = nominal * (forward + divFactor * div - spot->value()) / spot->value();
174 BOOST_TEST_MESSAGE("Check Total Return is correct");
175 BOOST_CHECK_CLOSE(eq2.amount(), expectedAmount, 1e-10);
176
177 // Historical starting Price Return coupon
178 forward = spot->value() * std::exp((0.02 - 0.01) * dt);
179 expectedAmount = nominal * (forward - eqIndex->fixing(cfDate1)) / eqIndex->fixing(cfDate1);
180 BOOST_TEST_MESSAGE("Check Historical starting Price Return is correct.");
181 BOOST_CHECK_CLOSE(eq3.amount(), expectedAmount, 1e-10);
182
183 // Total Return Coupon with fixing lag
184 dt = dc.yearFraction(today, fixingDate2);
185 forward = spot->value() * std::exp(0.02 * dt);
186 expectedAmount = nominal * (forward - eqIndex->fixing(fixingDate1)) / eqIndex->fixing(fixingDate1);
187 BOOST_TEST_MESSAGE("Check Total Return fixing lag handling is correct.");
188 BOOST_CHECK_CLOSE(eq4.amount(), expectedAmount, 1e-10);
189
190 // Total return coupon with underlying in different ccy
191 dt = dc.yearFraction(today, cfDate2);
192 forward = spot->value() * std::exp((0.02 - 0.01) * dt);
193 div = spot->value() * std::exp((0.02) * dt) - forward;
194 expectedAmount =
195 nominal * ((forward + div) * fxIndex->fixing(cfDate2) - spot->value() * 1.1) / (spot->value() * 1.1);
196 BOOST_TEST_MESSAGE("Check Total Return with underlying in different ccy handling is correct.");
197 BOOST_CHECK_CLOSE(eq5.amount(), expectedAmount, 1e-10);
198}
199
200BOOST_AUTO_TEST_SUITE_END()
201
202BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(testFXLinkedCashFlow)
Definition: cashflow.cpp:41
void setPricer(const QuantLib::ext::shared_ptr< EquityCouponPricer > &)
Real amount() const override
Pricer for equity coupons.
Real amount() const override
coupon paying the return on an equity
Pricer for equity coupons.
An FX linked cashflow.
Fixture that can be used at top level.