27#include <ql/errors.hpp>
31#define TRACE(message, n) \
32 { DLOGGERSTREAM(message << " at " << to_string((n).locationInfo) << '\n'); }
38class ASTIndexExtractor :
public AcyclicVisitor,
39 public Visitor<ASTNode>,
40 public Visitor<FunctionPayNode>,
41 public Visitor<FunctionLogPayNode>,
42 public Visitor<FunctionNpvNode>,
43 public Visitor<FunctionNpvMemNode>,
44 public Visitor<FunctionDiscountNode>,
45 public Visitor<FunctionFwdCompNode>,
46 public Visitor<FunctionFwdAvgNode>,
47 public Visitor<FunctionAboveProbNode>,
48 public Visitor<FunctionBelowProbNode>,
49 public Visitor<VarEvaluationNode> {
51 ASTIndexExtractor(std::map<std::string, std::set<QuantLib::Date>>& indexEvalDates,
52 std::map<std::string, std::set<QuantLib::Date>>& indexFwdDates,
53 std::map<std::string, std::set<QuantLib::Date>>& payObsDates,
54 std::map<std::string, std::set<QuantLib::Date>>& payPayDates,
55 std::map<std::string, std::set<QuantLib::Date>>& discountObsDates,
56 std::map<std::string, std::set<QuantLib::Date>>& discountPayDates,
57 std::map<std::string, std::set<QuantLib::Date>>& fwdCompAvgFixingDates,
58 std::map<std::string, std::set<QuantLib::Date>>& fwdCompAvgEvalDates,
59 std::map<std::string, std::set<QuantLib::Date>>& fwdCompAvgStartEndDates,
60 std::map<std::string, std::set<QuantLib::Date>>& probFixingDates,
61 std::set<QuantLib::Date>& regressionDates, Context& context, ASTNode*& lastVisitedNode)
70 void visit(ASTNode& n)
override {
77 std::string getVariableName(
const ASTNodePtr p) {
79 auto var = QuantLib::ext::dynamic_pointer_cast<VariableNode>(p);
81 TRACE(
"getVariableName(" << var->name <<
")", *p);
84 QL_FAIL(
"not a variable identifier");
90 auto cn = QuantLib::ext::dynamic_pointer_cast<ConstantNumberNode>(p);
92 TRACE(
"getConstantNumber(" << cn->value <<
")", *p);
98 std::vector<ValueType> getVariableValues(
const std::string&
name) {
99 std::vector<ValueType> result;
106 if (
name ==
"TODAY") {
110 if (scalar !=
context_.scalars.end()) {
111 result = std::vector<ValueType>(1, scalar->second);
115 if (array !=
context_.arrays.end()) {
116 result = array->second;
119 QL_REQUIRE(found,
"variable '" <<
name <<
"' is not defined.");
123 result.erase(std::remove_if(result.begin(), result.end(),
125 return v.which() == ValueTypeWhich::Event &&
126 QuantLib::ext::get<EventVec>(v).value == Date();
132 void visit(VarEvaluationNode& n)
override {
134 std::string indexVariable = getVariableName(n.args[0]);
135 std::string datesVariable = getVariableName(n.args[1]);
136 std::string fwdDatesVariable = n.args[2] ? getVariableName(n.args[2]) :
"";
138 TRACE(
"varEvaluation(" << indexVariable <<
", " << datesVariable <<
", " << fwdDatesVariable <<
")", n);
139 std::vector<ValueType> indexValues = getVariableValues(indexVariable);
140 std::vector<ValueType> datesValues = getVariableValues(datesVariable);
141 std::vector<ValueType> fwdDatesValues =
142 fwdDatesVariable.empty() ? std::vector<ValueType>() : getVariableValues(fwdDatesVariable);
143 for (
auto const& v : indexValues)
144 TRACE(
"got index " << v, n);
145 for (
auto const& v : datesValues)
146 TRACE(
"got date " << v, n);
147 for (
auto const& v : fwdDatesValues)
148 TRACE(
"got fwd date " << v, n);
149 for (
auto const& i : indexValues) {
150 for (
auto const& d : datesValues) {
153 indexEvalDates_[QuantLib::ext::get<IndexVec>(i).value].insert(QuantLib::ext::get<EventVec>(d).
value);
155 for (
auto const& d : fwdDatesValues) {
158 indexFwdDates_[QuantLib::ext::get<IndexVec>(i).value].insert(QuantLib::ext::get<EventVec>(d).
value);
161 visit(
static_cast<ASTNode&
>(n));
164 void processPayOrDiscountNode(std::map<std::string, std::set<QuantLib::Date>>& obsDates,
165 std::map<std::string, std::set<QuantLib::Date>>& payDates, ASTNode& n,
166 const Size indexObs,
const Size indexPay,
const Size indexCurr) {
168 std::string obsDateVariable = getVariableName(n.args[indexObs]);
169 std::vector<ValueType> obsDateValues = getVariableValues(obsDateVariable);
170 std::string payDateVariable = getVariableName(n.args[indexPay]);
171 std::vector<ValueType> payDateValues = getVariableValues(payDateVariable);
172 std::string currencyVariable = getVariableName(n.args[indexCurr]);
173 std::vector<ValueType> currencyValues = getVariableValues(currencyVariable);
175 TRACE(
"pay(" << obsDateVariable <<
"," << payDateVariable <<
"," << currencyVariable <<
")", n);
176 for (
auto const& v : obsDateValues)
177 TRACE(
"got obs date " << v, n);
178 for (
auto const& v : payDateValues)
179 TRACE(
"got pay date " << v, n);
180 for (
auto const& v : currencyValues)
181 TRACE(
"got currency " << v, n);
182 for (
auto const& v : obsDateValues) {
184 for (
auto const& c : currencyValues) {
186 obsDates[QuantLib::ext::get<CurrencyVec>(c).value].insert(QuantLib::ext::get<EventVec>(v).
value);
189 for (
auto const& v : payDateValues) {
191 for (
auto const& c : currencyValues) {
193 payDates[QuantLib::ext::get<CurrencyVec>(c).value].insert(QuantLib::ext::get<EventVec>(v).
value);
196 visit(
static_cast<ASTNode&
>(n));
202 void visit(FunctionDiscountNode& n)
override {
206 void processFwdCompAvg(ASTNode& n) {
208 std::string indexVariable = getVariableName(n.args[0]);
209 std::vector<ValueType> indexValues = getVariableValues(indexVariable);
210 std::string obsDateVariable = getVariableName(n.args[1]);
211 std::vector<ValueType> obsDateValues = getVariableValues(obsDateVariable);
212 std::string startDateVariable = getVariableName(n.args[2]);
213 std::vector<ValueType> startDateValues = getVariableValues(startDateVariable);
214 std::string endDateVariable = getVariableName(n.args[3]);
215 std::vector<ValueType> endDateValues = getVariableValues(endDateVariable);
216 std::vector<ValueType> lookbackValues{RandomVariable(1, 0.0)};
217 std::vector<ValueType> fixingDaysValues{RandomVariable(1, 0.0)};
219 auto value = getConstantNumber(n.args[6]);
220 if (
value != Null<Real>())
221 lookbackValues = std::vector<ValueType>{RandomVariable(1,
value)};
223 std::string lookbackVariable = getVariableName(n.args[6]);
224 lookbackValues = getVariableValues(lookbackVariable);
228 auto value = getConstantNumber(n.args[8]);
229 if (
value != Null<Real>()) {
230 fixingDaysValues = std::vector<ValueType>{RandomVariable(1,
value)};
232 std::string fixingDaysVariable = getVariableName(n.args[8]);
233 fixingDaysValues = getVariableValues(fixingDaysVariable);
237 TRACE(
"fwd[comp|avg](" << indexVariable <<
"," << obsDateVariable <<
"," << startDateVariable <<
","
238 << endDateVariable <<
")",
240 for (
auto const& i : indexValues)
241 TRACE(
"got index " << i, n);
242 for (
auto const& v : obsDateValues)
243 TRACE(
"got obs date " << v, n);
244 for (
auto const& v : startDateValues)
245 TRACE(
"got start date " << v, n);
246 for (
auto const& v : endDateValues)
247 TRACE(
"got end date " << v, n);
248 for (
auto const& i : indexValues) {
250 std::string indexName = QuantLib::ext::get<IndexVec>(i).value;
251 IndexInfo ind(indexName);
252 auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(ind.irIbor());
256 DLOG(
"skipping index " << i <<
"since it is not an overnight index.");
259 for (
auto const& v : obsDateValues) {
263 Date minStart = Date::maxDate();
264 Date maxEnd = Date::minDate();
265 for (
auto const& v : startDateValues) {
267 minStart = std::min(minStart, QuantLib::ext::get<EventVec>(v).
value);
269 for (
auto const& w : endDateValues) {
271 maxEnd = std::max(maxEnd, QuantLib::ext::get<EventVec>(w).
value);
273 if (minStart >= maxEnd)
275 RandomVariable lookback, fixingDays;
276 for (
auto const& l : lookbackValues) {
278 lookback = QuantLib::ext::get<RandomVariable>(l);
279 QL_REQUIRE(lookback.deterministic(),
"expected arg #7 (lookback) to be deterministic");
280 for (
auto const& f : fixingDaysValues) {
282 fixingDays = QuantLib::ext::get<RandomVariable>(f);
283 QL_REQUIRE(fixingDays.deterministic(),
"expected arg #9 (fixingDays) to be deterministic");
286 maxEnd, 1.0, minStart, maxEnd, on, 1.0, 0.0, Date(), Date(), DayCounter(),
false,
false,
287 static_cast<Integer
>(lookback.at(0)) * Days, 0,
static_cast<Natural
>(fixingDays.at(0)));
289 DLOG(
"adding " << cpn.
fixingDates().size() <<
" fixing dates for index " << indexName);
297 visit(
static_cast<ASTNode&
>(n));
300 void visit(FunctionFwdCompNode& n)
override { processFwdCompAvg(n); }
302 void visit(FunctionFwdAvgNode& n)
override { processFwdCompAvg(n); }
304 void processProbNode(ASTNode& n) {
306 std::string indexVariable = getVariableName(n.args[0]);
307 std::vector<ValueType> indexValues = getVariableValues(indexVariable);
308 std::string obsDate1Variable = getVariableName(n.args[1]);
309 std::vector<ValueType> obsDate1Values = getVariableValues(obsDate1Variable);
310 std::string obsDate2Variable = getVariableName(n.args[2]);
311 std::vector<ValueType> obsDate2Values = getVariableValues(obsDate2Variable);
313 TRACE(
"prob(" << indexVariable <<
"," << obsDate1Variable <<
"," << obsDate2Variable, n);
314 for (
auto const& i : indexValues)
315 TRACE(
"got index " << i, n);
316 for (
auto const& v : obsDate1Values)
317 TRACE(
"got obs date 1 " << v, n);
318 for (
auto const& v : obsDate2Values)
319 TRACE(
"got obs date 2 " << v, n);
320 for (
auto const& i : indexValues) {
322 std::string indexName = QuantLib::ext::get<IndexVec>(i).value;
323 Date minDate = Date::maxDate(), maxDate = Date::minDate();
324 for (
auto const& v : obsDate1Values) {
326 Date d = QuantLib::ext::get<EventVec>(v).value;
333 for (
auto const& v : obsDate2Values) {
335 Date d = QuantLib::ext::get<EventVec>(v).value;
343 Calendar fixingCalendar;
344 IndexInfo ind(indexName);
346 Date today = Settings::instance().evaluationDate();
347 fixingCalendar = ind.comm(today)->fixingCalendar();
349 fixingCalendar = ind.index()->fixingCalendar();
351 DLOG(
"adding prob fixing dates from " << QuantLib::io::iso_date(minDate) <<
" to "
352 << QuantLib::io::iso_date(maxDate) <<
" for " << indexName);
353 for (Date d = minDate; d <= maxDate; ++d) {
354 if (fixingCalendar.isBusinessDay(d)) {
361 void visit(FunctionAboveProbNode& n)
override {
363 visit(
static_cast<ASTNode&
>(n));
366 void visit(FunctionBelowProbNode& n)
override {
368 visit(
static_cast<ASTNode&
>(n));
371 void processNpvNode(ASTNode& n) {
373 std::string obsDateVariable = getVariableName(n.args[1]);
374 std::vector<ValueType> obsDateValues = getVariableValues(obsDateVariable);
376 TRACE(
"npv(" << obsDateVariable <<
")", n);
377 for (
auto const& v : obsDateValues) {
381 visit(
static_cast<ASTNode&
>(n));
384 void visit(FunctionNpvNode& n)
override { processNpvNode(n); }
386 void visit(FunctionNpvMemNode& n)
override { processNpvNode(n); }
417 root_->accept(runner);
418 }
catch (
const std::exception& e) {
419 std::ostringstream errorMessage;
420 errorMessage <<
"Error during static script analysis: " << e.what() <<
" at "
422 <<
" - see log for more details.";
425 ALOG(errorMessage.str());
427 QL_FAIL(errorMessage.str());
430 DLOG(
"Static analyser finished without errors.");
const std::vector< Date > & valueDates() const
const std::vector< Date > & fixingDates() const
std::map< std::string, std::set< QuantLib::Date > > discountPayDates_
const QuantLib::ext::shared_ptr< Context > context_
std::map< std::string, std::set< QuantLib::Date > > indexEvalDates_
std::map< std::string, std::set< QuantLib::Date > > payObsDates_
std::map< std::string, std::set< QuantLib::Date > > fwdCompAvgStartEndDates_
std::set< QuantLib::Date > regressionDates_
std::map< std::string, std::set< QuantLib::Date > > probFixingDates_
std::map< std::string, std::set< QuantLib::Date > > payPayDates_
std::map< std::string, std::set< QuantLib::Date > > discountObsDates_
std::map< std::string, std::set< QuantLib::Date > > fwdCompAvgFixingDates_
std::map< std::string, std::set< QuantLib::Date > > indexFwdDates_
std::map< std::string, std::set< QuantLib::Date > > fwdCompAvgEvalDates_
void run(const std::string &script="")
#define TRACE(message, n)
ASTNode *& lastVisitedNode_
SafeStack< ValueType > value
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define ALOG(text)
Logging Macro (Level = Alert)
#define LOGGERSTREAM(text)
std::string printCodeContext(std::string script, const ASTNode *loc, bool compact)
std::string to_string(const LocationInfo &l)
boost::variant< RandomVariable, EventVec, CurrencyVec, IndexVec, DaycounterVec, Filter > ValueType
QuantLib::ext::shared_ptr< ASTNode > ASTNodePtr
Serializable Credit Default Swap.
std::map< std::string, std::set< QuantLib::Date > > & payPayDates_
std::map< std::string, std::set< QuantLib::Date > > & indexFwdDates_
std::map< std::string, std::set< QuantLib::Date > > & discountObsDates_
std::map< std::string, std::set< QuantLib::Date > > & payObsDates_
std::map< std::string, std::set< QuantLib::Date > > & fwdCompAvgEvalDates_
std::map< std::string, std::set< QuantLib::Date > > & indexEvalDates_
std::map< std::string, std::set< QuantLib::Date > > & probFixingDates_
std::map< std::string, std::set< QuantLib::Date > > & fwdCompAvgStartEndDates_
std::map< std::string, std::set< QuantLib::Date > > & discountPayDates_
std::map< std::string, std::set< QuantLib::Date > > & fwdCompAvgFixingDates_
std::set< QuantLib::Date > & regressionDates_
LocationInfo locationInfo