Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/experimental/commodities/energycommodity.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2008 J. Erik Radmall
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
 <http://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/currencies/exchangeratemanager.hpp>
21
#include <ql/experimental/commodities/commoditysettings.hpp>
22
#include <ql/experimental/commodities/energycommodity.hpp>
23
#include <ql/experimental/commodities/unitofmeasureconversionmanager.hpp>
24
#include <iomanip>
25
#include <utility>
26
27
namespace QuantLib {
28
29
    EnergyDailyPosition::EnergyDailyPosition(const Date& date,
30
                                             Real payLegPrice,
31
                                             Real receiveLegPrice,
32
                                             bool unrealized)
33
0
    : date(date), quantityAmount(0), payLegPrice(payLegPrice),
34
0
      receiveLegPrice(receiveLegPrice), unrealized(unrealized) {}
35
36
    std::ostream& operator<<(std::ostream& out,
37
0
                             const EnergyDailyPositions& dailyPositions) {
38
0
        out << std::setw(12) << std::left << "positions"
39
0
            << std::setw(12) << std::right << "pay"
40
0
            << std::setw(12) << std::right << "receive"
41
0
            << std::setw(10) << std::right << "qty"
42
0
            << std::setw(14) << std::right << "delta"
43
0
            << std::setw(10) << std::right << "open" << std::endl;
44
45
0
        for (const auto& i : dailyPositions) {
46
0
            const EnergyDailyPosition& dailyPosition = i.second;
47
0
            out << std::setw(4) << io::iso_date(i.first) << "  " << std::setw(12) << std::right
48
0
                << std::fixed << std::setprecision(6) << dailyPosition.payLegPrice << std::setw(12)
49
0
                << std::right << std::fixed << std::setprecision(6) << dailyPosition.receiveLegPrice
50
0
                << std::setw(10) << std::right << std::fixed << std::setprecision(2)
51
0
                << dailyPosition.quantityAmount << std::setw(14) << std::right << std::fixed
52
0
                << std::setprecision(2) << dailyPosition.riskDelta << std::setw(10) << std::right
53
0
                << std::fixed << std::setprecision(2)
54
0
                << (dailyPosition.unrealized ? dailyPosition.quantityAmount : 0) << std::endl;
55
0
        }
56
57
0
        return out;
58
0
    }
59
60
61
62
63
64
0
    void EnergyCommodity::setupArguments(PricingEngine::arguments* args) const {
65
0
        auto* arguments = dynamic_cast<EnergyCommodity::arguments*>(args);
66
0
        QL_REQUIRE(arguments != nullptr, "wrong argument type");
67
        //arguments->legs = legs_;
68
        //arguments->payer = payer_;
69
0
    }
70
71
0
    void EnergyCommodity::fetchResults(const PricingEngine::results* r) const {
72
0
        Instrument::fetchResults(r);
73
0
        const auto* results = dynamic_cast<const EnergyCommodity::results*>(r);
74
0
        QL_REQUIRE(results != nullptr, "wrong result type");
75
0
    }
76
77
    EnergyCommodity::EnergyCommodity(CommodityType commodityType,
78
                                     const ext::shared_ptr<SecondaryCosts>& secondaryCosts)
79
0
    : Commodity(secondaryCosts), commodityType_(std::move(commodityType)) {}
80
81
0
    const CommodityType& EnergyCommodity::commodityType() const {
82
0
        return commodityType_;
83
0
    }
84
85
86
    Real EnergyCommodity::calculateUomConversionFactor(
87
                                       const CommodityType& commodityType,
88
                                       const UnitOfMeasure& fromUnitOfMeasure,
89
0
                                       const UnitOfMeasure& toUnitOfMeasure) {
90
0
        if (toUnitOfMeasure != fromUnitOfMeasure) {
91
0
            UnitOfMeasureConversion uomConv =
92
0
                UnitOfMeasureConversionManager::instance().lookup(
93
0
                           commodityType, fromUnitOfMeasure, toUnitOfMeasure);
94
0
            return uomConv.conversionFactor();
95
0
        }
96
97
0
        return 1;
98
0
    }
99
100
    Real EnergyCommodity::calculateFxConversionFactor(
101
                                                 const Currency& fromCurrency,
102
                                                 const Currency& toCurrency,
103
0
                                                 const Date& evaluationDate) {
104
0
        if (fromCurrency != toCurrency) {
105
0
            ExchangeRate exchRate = ExchangeRateManager::instance().lookup(
106
0
                                   fromCurrency, toCurrency,
107
0
                                   evaluationDate /*, ExchangeRate::Direct*/);
108
0
            if (fromCurrency == exchRate.target())
109
0
                return 1.0 / exchRate.rate();
110
0
            return exchRate.rate();
111
0
        }
112
0
        return 1;
113
0
    }
114
115
    Real EnergyCommodity::calculateUnitCost(const CommodityType& commodityType,
116
                                            const CommodityUnitCost& unitCost,
117
0
                                            const Date& evaluationDate) const {
118
0
        if (unitCost.amount().value() != 0) {
119
0
            const Currency& baseCurrency =
120
0
                CommoditySettings::instance().currency();
121
0
            const UnitOfMeasure baseUnitOfMeasure =
122
0
                CommoditySettings::instance().unitOfMeasure();
123
0
            Real unitCostUomConversionFactor =
124
0
                calculateUomConversionFactor(commodityType,
125
0
                                             unitCost.unitOfMeasure(),
126
0
                                             baseUnitOfMeasure);
127
0
            Real unitCostFxConversionFactor =
128
0
                calculateFxConversionFactor(unitCost.amount().currency(),
129
0
                                            baseCurrency, evaluationDate);
130
0
            return unitCost.amount().value() * unitCostUomConversionFactor
131
0
                 * unitCostFxConversionFactor;
132
0
        }
133
0
        return 0;
134
0
    }
135
136
    void EnergyCommodity::calculateSecondaryCostAmounts(
137
                                           const CommodityType& commodityType,
138
                                           Real totalQuantityValue,
139
0
                                           const Date& evaluationDate) const {
140
0
        secondaryCostAmounts_.clear();
141
0
        if (secondaryCosts_ != nullptr) {
142
0
            const Currency& baseCurrency =
143
0
                CommoditySettings::instance().currency();
144
0
            try {
145
0
                for (auto & i : *secondaryCosts_) {
146
0
                    if (ext::any_cast<CommodityUnitCost>(&i.second) != nullptr) {
147
0
                        Real value =
148
0
                            calculateUnitCost(
149
0
                                commodityType,
150
0
                                ext::any_cast<CommodityUnitCost>(i.second),
151
0
                                evaluationDate) * totalQuantityValue;
152
0
                        secondaryCostAmounts_[i.first] =
153
0
                            Money(baseCurrency, value);
154
0
                    } else if (ext::any_cast<Money>(&i.second) != nullptr) {
155
0
                        const Money& amount = ext::any_cast<Money>(i.second);
156
0
                        Real fxConversionFactor =
157
0
                            calculateFxConversionFactor(amount.currency(),
158
0
                                                        baseCurrency,
159
0
                                                        evaluationDate);
160
0
                        secondaryCostAmounts_[i.first] =
161
0
                            Money(baseCurrency,
162
0
                                  amount.value() * fxConversionFactor);
163
0
                    }
164
0
                }
165
0
            } catch (const std::exception& e) {
166
0
                QL_FAIL("error calculating secondary costs: " << e.what());
167
0
            }
168
0
        }
169
0
    }
170
171
}
172