• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lballabio / QuantLib / 21977695464

13 Feb 2026 06:54AM UTC coverage: 74.195% (+0.02%) from 74.172%
21977695464

Pull #2414

github

web-flow
Merge aadca585a into ef7a958e8
Pull Request #2414: Add FX Forward instrument, engine, and tests

115 of 124 new or added lines in 3 files covered. (92.74%)

345 existing lines in 25 files now uncovered.

57462 of 77447 relevant lines covered (74.2%)

8773293.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.31
/ql/instruments/fxforward.cpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2026 Chirag Desai
5

6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8

9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <https://www.quantlib.org/license.shtml>.
14

15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19

20
#include <ql/instruments/fxforward.hpp>
21
#include <ql/settings.hpp>
22
#include <ql/time/calendars/nullcalendar.hpp>
23

24
namespace QuantLib {
25

26
    FxForward::FxForward(Real sourceNominal,
16✔
27
                         const Currency& sourceCurrency,
28
                         Real targetNominal,
29
                         const Currency& targetCurrency,
30
                         const Date& maturityDate,
31
                         bool paySourceCurrency,
32
                         Natural settlementDays,
33
                         const Calendar& paymentCalendar)
16✔
34
    : sourceNominal_(sourceNominal), sourceCurrency_(sourceCurrency), targetNominal_(targetNominal),
16✔
35
      targetCurrency_(targetCurrency), maturityDate_(maturityDate),
16✔
36
      paySourceCurrency_(paySourceCurrency), settlementDays_(settlementDays),
16✔
37
      paymentCalendar_(paymentCalendar.empty() ? NullCalendar() : paymentCalendar),
16✔
38
      fairForwardRate_(Null<Real>()),
16✔
39
      npvSourceCurrency_(Null<Real>()), npvTargetCurrency_(Null<Real>()) {
32✔
40
        QL_REQUIRE(!sourceCurrency.empty(), "source currency must not be empty");
16✔
41
        QL_REQUIRE(!targetCurrency.empty(), "target currency must not be empty");
16✔
42
        QL_REQUIRE(sourceCurrency != targetCurrency,
16✔
43
                   "source and target currencies must be different");
44
        QL_REQUIRE(sourceNominal > 0.0, "source nominal must be positive");
16✔
45
        QL_REQUIRE(targetNominal > 0.0, "target nominal must be positive");
16✔
46
    }
16✔
47

48
    FxForward::FxForward(Real sourceNominal,
2✔
49
                         const Currency& sourceCurrency,
50
                         const Currency& targetCurrency,
51
                         Real forwardRate,
52
                         const Date& maturityDate,
53
                         bool paySourceCurrency,
54
                         Natural settlementDays,
55
                         const Calendar& paymentCalendar)
2✔
56
    : sourceNominal_(sourceNominal), sourceCurrency_(sourceCurrency),
2✔
57
      targetNominal_(sourceNominal * forwardRate), targetCurrency_(targetCurrency),
2✔
58
      maturityDate_(maturityDate), paySourceCurrency_(paySourceCurrency),
2✔
59
      settlementDays_(settlementDays),
2✔
60
      paymentCalendar_(paymentCalendar.empty() ? NullCalendar() : paymentCalendar),
2✔
61
      fairForwardRate_(Null<Real>()), npvSourceCurrency_(Null<Real>()),
2✔
62
      npvTargetCurrency_(Null<Real>()) {
4✔
NEW
63
        QL_REQUIRE(!sourceCurrency.empty(), "source currency must not be empty");
×
64
        QL_REQUIRE(!targetCurrency.empty(), "target currency must not be empty");
2✔
65
        QL_REQUIRE(sourceCurrency != targetCurrency,
2✔
66
                   "source and target currencies must be different");
67
        QL_REQUIRE(sourceNominal > 0.0, "source nominal must be positive");
2✔
68
        QL_REQUIRE(forwardRate > 0.0, "forward rate must be positive");
2✔
69
    }
2✔
70

71

72
    bool FxForward::isExpired() const {
15✔
73
        return maturityDate_ < Settings::instance().evaluationDate();
15✔
74
    }
75

76
    Date FxForward::settlementDate() const {
23✔
77
        return paymentCalendar_.advance(Settings::instance().evaluationDate(),
23✔
78
                                        settlementDays_, Days);
23✔
79
    }
80

81
    void FxForward::setupArguments(PricingEngine::arguments* args) const {
13✔
82
        auto* arguments = dynamic_cast<FxForward::arguments*>(args);
13✔
83
        QL_REQUIRE(arguments != nullptr, "wrong argument type");
13✔
84

85
        arguments->sourceNominal = sourceNominal_;
13✔
86
        arguments->sourceCurrency = sourceCurrency_;
87
        arguments->targetNominal = targetNominal_;
13✔
88
        arguments->targetCurrency = targetCurrency_;
89
        arguments->maturityDate = maturityDate_;
13✔
90
        arguments->paySourceCurrency = paySourceCurrency_;
13✔
91
        arguments->settlementDate = settlementDate();
13✔
92
    }
13✔
93

94
    void FxForward::fetchResults(const PricingEngine::results* r) const {
13✔
95
        Instrument::fetchResults(r);
13✔
96

97
        const auto* results = dynamic_cast<const FxForward::results*>(r);
13✔
98
        QL_REQUIRE(results != nullptr, "wrong result type");
13✔
99

100
        fairForwardRate_ = results->fairForwardRate;
13✔
101
        npvSourceCurrency_ = results->npvSourceCurrency;
13✔
102
        npvTargetCurrency_ = results->npvTargetCurrency;
13✔
103
    }
13✔
104

105
    Real FxForward::fairForwardRate() const {
3✔
106
        calculate();
3✔
107
        QL_REQUIRE(fairForwardRate_ != Null<Real>(), "fair forward rate not available");
3✔
108
        return fairForwardRate_;
3✔
109
    }
110

NEW
111
    Real FxForward::npvSourceCurrency() const {
×
NEW
112
        calculate();
×
NEW
113
        QL_REQUIRE(npvSourceCurrency_ != Null<Real>(), "NPV in source currency not available");
×
NEW
114
        return npvSourceCurrency_;
×
115
    }
116

NEW
117
    Real FxForward::npvTargetCurrency() const {
×
NEW
118
        calculate();
×
NEW
119
        QL_REQUIRE(npvTargetCurrency_ != Null<Real>(), "NPV in target currency not available");
×
NEW
120
        return npvTargetCurrency_;
×
121
    }
122

123
    void FxForward::arguments::validate() const {
13✔
124
        QL_REQUIRE(sourceNominal != Null<Real>(), "source nominal not set");
13✔
125
        QL_REQUIRE(targetNominal != Null<Real>(), "target nominal not set");
13✔
126
        QL_REQUIRE(!sourceCurrency.empty(), "source currency not set");
13✔
127
        QL_REQUIRE(!targetCurrency.empty(), "target currency not set");
13✔
128
        QL_REQUIRE(maturityDate != Date(), "maturity date not set");
13✔
129
        QL_REQUIRE(settlementDate != Date(), "settlement date not set");
13✔
130
    }
13✔
131

132
    void FxForward::results::reset() {
13✔
133
        Instrument::results::reset();
13✔
134
        fairForwardRate = Null<Real>();
13✔
135
        npvSourceCurrency = Null<Real>();
13✔
136
        npvTargetCurrency = Null<Real>();
13✔
137
    }
13✔
138

139
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc