67 {
68
70
71
72 struct MemoryReleaser {
73 ~MemoryReleaser() { model->releaseMemory(); }
74 QuantLib::ext::shared_ptr<Model> model;
75 };
76 MemoryReleaser memoryReleaser{
model_};
77
78
79
80 auto workingContext = QuantLib::ext::make_shared<Context>(*
context_);
81
82
83
87 workingContext->constants.insert("TODAY");
88
89
90
92
93
94
95 if (
model_->trainingSamples() != Null<Size>()) {
96 auto trainingContext = QuantLib::ext::make_shared<Context>(*workingContext);
97 trainingContext->resetSize(
model_->trainingSamples());
98 struct TrainingPathToggle {
99 TrainingPathToggle(QuantLib::ext::shared_ptr<Model> model) : model(model) { model->toggleTrainingPaths(); }
100 ~TrainingPathToggle() { model->toggleTrainingPaths(); }
101 QuantLib::ext::shared_ptr<Model> model;
103 ScriptEngine trainingEngine(
ast_, trainingContext,
model_);
105 }
106
107
108
109 ScriptEngine engine(
ast_, workingContext,
model_);
110
111 QuantLib::ext::shared_ptr<PayLog> paylog;
113 paylog = QuantLib::ext::make_shared<PayLog>();
114
116
117
118
119 auto npv = workingContext->scalars.find(
npv_);
120 QL_REQUIRE(npv != workingContext->scalars.end(),
121 "did not find npv result variable '" <<
npv_ <<
"' as scalar in context");
123 "result variable '" <<
npv_ <<
"' must be of type NUMBER, got " << npv->second.which());
124 results_.value =
model_->extractT0Result(QuantLib::ext::get<RandomVariable>(npv->second));
126
127
128
132 auto s = workingContext->scalars.find(r.second);
133 bool resultSet = false;
134 if (s != workingContext->scalars.end()) {
135 boost::any t = valueToAny(
model_, s->second);
136 results_.additionalResults[r.first] = t;
138 DLOG(
"got additional result '" << r.first <<
"' referencing script variable '" << r.second <<
"'");
139 resultSet = true;
140 }
141 auto v = workingContext->arrays.find(r.second);
142 if (v != workingContext->arrays.end()) {
143 QL_REQUIRE(!resultSet, "result variable '"
144 << r.first << "' referencing script variable '" << r.second
145 << "' appears both as a scalar and an array, this is unexpected");
146 QL_REQUIRE(!v->second.empty(), "result variable '" << v->first << "' is an empty array.");
147 std::vector<double> tmpdouble;
148 std::vector<std::string> tmpstring;
149 std::vector<QuantLib::Date> tmpdate;
150 for (auto const& d : v->second) {
151 boost::any t = valueToAny(
model_, d);
152 if (t.type() == typeid(double))
153 tmpdouble.push_back(boost::any_cast<double>(t));
154 else if (t.type() == typeid(std::string))
155 tmpstring.push_back(boost::any_cast<std::string>(t));
156 else if (t.type() == typeid(QuantLib::Date))
157 tmpdate.push_back(boost::any_cast<QuantLib::Date>(t));
158 else {
159 QL_FAIL("unexpected result type '" << t.type().name() << "' for result variable '" << r.first
160 << "' referencing script variable '" << r.second << "'");
161 }
162 }
163 QL_REQUIRE((int)!tmpdouble.empty() + (int)!tmpstring.empty() + (int)!tmpdate.empty() == 1,
164 "expected exactly one result type in result array '" << v->first << "'");
165 DLOG(
"got additional result '" << r.first <<
"' referencing script variable '" << r.second
166 << "' vector of size "
167 << tmpdouble.size() + tmpstring.size() + tmpdate.size());
168 if (!tmpdouble.empty())
169 results_.additionalResults[r.first] = tmpdouble;
170 else if (!tmpstring.empty())
171 results_.additionalResults[r.first] = tmpstring;
172 else if (!tmpdate.empty())
173 results_.additionalResults[r.first] = tmpdate;
174 else {
175 QL_FAIL("got empty result vector for result variable '"
176 << r.first << "' referencing script variable '" << r.second << "', this is unexpected");
177 }
178 std::vector<double> errEst;
179 for (auto const& d : v->second) {
181 }
182 if (!errEst.empty() && errEst.front() != Null<Real>())
183 results_.additionalResults[r.first +
"_MCErrEst"] = errEst;
184 resultSet = true;
185 }
186 QL_REQUIRE(resultSet, "could not set additional result '" << r.first << "' referencing script variable '"
187 << r.second << "'");
188 }
189
190
191
192 paylog->consolidateAndSort();
193 std::vector<CashFlowResults> cashFlowResults(paylog->size());
194 std::map<Size, Size> cashflowNumber;
195 for (Size i = 0; i < paylog->size(); ++i) {
196
197
198 Real fx = 1.0;
199 Real discount = 1.0;
200 if (paylog->dates().at(i) >
model_->referenceDate()) {
201 fx =
model_->fxSpotT0(paylog->currencies().at(i),
model_->baseCcy());
202 discount =
model_->discount(
referenceDate, paylog->dates().at(i), paylog->currencies().at(i)).at(0);
203 }
204 cashFlowResults[i].amount =
model_->extractT0Result(paylog->amounts().at(i)) / fx / discount;
205 cashFlowResults[i].payDate = paylog->dates().at(i);
206 cashFlowResults[i].currency = paylog->currencies().at(i);
207 cashFlowResults[i].legNumber = paylog->legNos().at(i);
208 cashFlowResults[i].type = paylog->cashflowTypes().at(i);
209 DLOG(
"got cashflow " << QuantLib::io::iso_date(cashFlowResults[i].payDate) <<
" "
210 << cashFlowResults[i].currency << cashFlowResults[i].amount << " "
211 << cashFlowResults[i].currency <<
"-" <<
model_->baseCcy() <<
" " << fx <<
" discount("
212 << cashFlowResults[i].currency << ") " << discount);
213 if (paylog->dates().at(i) >
model_->referenceDate()) {
215 std::to_string(++cashflowNumber[paylog->legNos().at(i)]) + "_MCErrEst",
216 paylog->amounts().at(i) /
217 RandomVariable(paylog->amounts().at(i).size(), (fx * discount)));
218 }
219 }
220 results_.additionalResults[
"cashFlowResults"] = cashFlowResults;
221
222
223
224 results_.additionalResults.insert(
model_->additionalResults().begin(),
model_->additionalResults().end());
225
226 }
227
228
229
231 DLOG(
"add amc calculator to results");
232 results_.additionalResults[
"amcCalculator"] =
233 QuantLib::ext::static_pointer_cast<AmcCalculator>(QuantLib::ext::make_shared<ScriptedInstrumentAmcCalculator>(
235 }
236
238}
const Instrument::results * results_
Real addMcErrorEstimate(const std::string &label, const ValueType &v) const
#define DLOG(text)
Logging Macro (Level = Debug)
void checkDuplicateName(const QuantLib::ext::shared_ptr< Context > context, const std::string &name)