From: Luigi B. <lui...@gm...> - 2024-08-30 15:47:11
|
Hi—hmm, I don't know what the new property or rule should be. It looks like a very specific case, and the Schedule code is already kind of a mess (in fact, I've been wondering if we should keep all those combinations in a single constructor or if we should migrate some cases to separate builder methods). A function that creates the custom date vector and passes it to the schedule is probably not the worst solution. Luigi On Thu, Aug 29, 2024 at 9:38 AM Francois Botha <ig...@gm...> wrote: > Hi Luigi, > > Thanks again for your informative blog post. As before, it triggered > something. One of the nuances of valuing our local bonds is that some bonds > pay semiannual coupons on 28 Feb and 31 Aug every year, whether it is a > leap year or not. The Feb coupon is always payable on 28 Feb (with > Following business day convention otherwise). One of these bonds also > matures on 28 Feb 2048 (the South African R2048 bond), which is in a leap > year. This makes the normal schedule generation not possible (as far as I > know), so I usually have to build a custom date vector and pass it to a > schedule. > > Is this solvable in a more elegant way? I originally thought of adding a > new DateGeneration:NoLeapDays enum value, but this feature is probably > something one would want to use in conjunction with the existing > DateGeneration values. Maybe then a new class/property on the schedule to > enable this? > > Looking forward to your comments (and next blog post). > > thanks > Francois Botha > > > On Thu, 29 Aug 2024 at 07:31, Luigi Ballabio from Implementing QuantLib < > imp...@su...> wrote: > >> Hello again! This post was originally published in the March 2024 issue >> of Wilmott Magazine. >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ >> Forwarded this email? Subscribe here >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9pbXBsZW1lbnRpbmdxdWFudGxpYi5zdWJzdGFjay5jb20vc3Vic2NyaWJlP3V0bV9zb3VyY2U9ZW1haWwmdXRtX2NhbXBhaWduPWVtYWlsLXN1YnNjcmliZSZyPTZuNzR2Jm5leHQ9aHR0cHMlM0ElMkYlMkZpbXBsZW1lbnRpbmdxdWFudGxpYi5zdWJzdGFjay5jb20lMkZwJTJGc2NoZWR1bGVzLWluLXF1YW50bGliIiwicCI6MTQ4MDcyMzU5LCJzIjoyNDMxMTI5LCJmIjp0cnVlLCJ1IjoxMTE2MDAzMSwiaWF0IjoxNzI0OTA5NDYwLCJleHAiOjE3Mjc1MDE0NjAsImlzcyI6InB1Yi0wIiwic3ViIjoibGluay1yZWRpcmVjdCJ9.g-lp_1nL_0_WmPfMTi8LL4h8y2E5GSg3djDV7OV0jjg?> >> for more >> >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9pbXBsZW1lbnRpbmdxdWFudGxpYi5zdWJzdGFjay5jb20vcC9zY2hlZHVsZXMtaW4tcXVhbnRsaWI_dXRtX2NhbXBhaWduPWVtYWlsLWhhbGYtcG9zdCZyPTZuNzR2JnRva2VuPWV5SjFjMlZ5WDJsa0lqb3hNVEUyTURBek1Td2ljRzl6ZEY5cFpDSTZNVFE0TURjeU16VTVMQ0pwWVhRaU9qRTNNalE1TURrME5qQXNJbVY0Y0NJNk1UY3lOelV3TVRRMk1Dd2lhWE56SWpvaWNIVmlMVEkwTXpFeE1qa2lMQ0p6ZFdJaU9pSndiM04wTFhKbFlXTjBhVzl1SW4wLjg1T25wSjh2YW82S1dmb2kxZWFQMnJGNW50Qm1GUjVKTEotWmp1QTdmdEEiLCJwIjoxNDgwNzIzNTksInMiOjI0MzExMjksImYiOnRydWUsInUiOjExMTYwMDMxLCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTAiLCJzdWIiOiJsaW5rLXJlZGlyZWN0In0.y_ysg6ed95CdRAJClcmn2N6PD7w0mLLhwAfivLrIWFA?> >> Schedules in QuantLib >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=post-email-title&utm_campaign=email-post-title&isFreemail=true&r=6n74v&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTI0MzExMjkiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.85OnpJ8vao6KWfoi1eaP2rF5ntBmFR5JLJ-ZjuA7ftA> >> >> Luigi Ballabio <https://substack.com/@lballabio> >> Aug 29 >> <https://substack.com/@lballabio> >> >> >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&isFreemail=true&submitLike=true&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJyZWFjdGlvbiI6IuKdpCIsImlhdCI6MTcyNDkwOTQ2MCwiZXhwIjoxNzI3NTAxNDYwLCJpc3MiOiJwdWItMjQzMTEyOSIsInN1YiI6InJlYWN0aW9uIn0.sB6gVgVEMo4ZBZA44fsZmp_c6EBYvRc-tBHyN762xG8&utm_medium=email&utm_campaign=email-reaction&r=6n74v> >> >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&utm_medium=email&isFreemail=true&comments=true&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTI0MzExMjkiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.85OnpJ8vao6KWfoi1eaP2rF5ntBmFR5JLJ-ZjuA7ftA&r=6n74v&utm_campaign=email-half-magic-comments&action=post-comment&utm_source=substack&utm_medium=email> >> >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&utm_medium=email&utm_content=share&utm_campaign=email-share&action=share&triggerShare=true&isFreemail=true&r=6n74v&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTI0MzExMjkiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.85OnpJ8vao6KWfoi1eaP2rF5ntBmFR5JLJ-ZjuA7ftA> >> >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9vcGVuLnN1YnN0YWNrLmNvbS9wdWIvaW1wbGVtZW50aW5ncXVhbnRsaWIvcC9zY2hlZHVsZXMtaW4tcXVhbnRsaWI_dXRtX3NvdXJjZT1zdWJzdGFjayZ1dG1fbWVkaXVtPWVtYWlsJnV0bV9jYW1wYWlnbj1lbWFpbC1yZXN0YWNrLWNvbW1lbnQmYWN0aW9uPXJlc3RhY2stY29tbWVudCZyPTZuNzR2JnRva2VuPWV5SjFjMlZ5WDJsa0lqb3hNVEUyTURBek1Td2ljRzl6ZEY5cFpDSTZNVFE0TURjeU16VTVMQ0pwWVhRaU9qRTNNalE1TURrME5qQXNJbVY0Y0NJNk1UY3lOelV3TVRRMk1Dd2lhWE56SWpvaWNIVmlMVEkwTXpFeE1qa2lMQ0p6ZFdJaU9pSndiM04wTFhKbFlXTjBhVzl1SW4wLjg1T25wSjh2YW82S1dmb2kxZWFQMnJGNW50Qm1GUjVKTEotWmp1QTdmdEEiLCJwIjoxNDgwNzIzNTksInMiOjI0MzExMjksImYiOnRydWUsInUiOjExMTYwMDMxLCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTAiLCJzdWIiOiJsaW5rLXJlZGlyZWN0In0.E93_m7YsoFZzpil4XdpBCcvzhGiQOxaCifb9BX4qVyU?&utm_source=substack&utm_medium=email> >> >> READ IN APP >> <https://open.substack.com/pub/implementingquantlib/p/schedules-in-quantlib?utm_source=email&redirect=app-store> >> >> >> Hello again! This post was originally published in the March 2024 issue >> of Wilmott Magazine. The full source code is available on my Tutorial >> page >> <https://substack.com/redirect/a0e37dcd-d154-4ed3-aeaa-4f3550905f1c?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg>, >> together with code from other articles and, when available, either the >> articles themselves or corresponding blog posts like this one. >> Schedules in QuantLib >> >> For this article, I thought I’d try something new: I won’t completely >> change the subject from what I covered in the last issue, that is, calendars >> and holidays >> <https://substack.com/redirect/685b5a65-f9e1-45e7-9d95-57986f55d8fd?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg>. >> This month, I’ll start from there and show how to use QuantLib to generate >> schedules, i.e., regular sequences of dates, choosing from a number of >> market conventions. In turn, those can be used to create sequences of >> coupons; but that’s something for another time. What I will also show, >> instead, is a C++ technique that can come useful at times. Off we go. >> Some examples >> >> We can build a schedule with as little information as a start date, an >> end date, and a frequency. Here is the corresponding call: >> >> Schedule s = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, May, 2025)) >> .withFrequency(Semiannual); >> >> If you then write something like >> >> for (auto date : s) >> std::cout << date << std::endl; >> >> you’ll see the dates listed in the table below. Unsurprisingly, it is a >> sequence of alternating May 11th and November 11th from the start date to >> the end date; they are both included. >> >> <https://substack.com/redirect/37472cb9-17d8-4c0c-adaf-e956754aa0eb?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> When building coupons from this schedule, the understanding is that the >> first date in the schedule is the start of the first coupon; the second >> date is both the end of the first coupon and the start of the second; the >> third date is the end of the second coupon and the start of the third; >> until we get to the last date, which is the end of the last coupon. >> Adjusting for holidays >> >> The above schedule didn’t make a distinction between holidays and >> business days. If we want holidays to be adjusted, we need to choose a >> calendar: >> >> Schedule s = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, May, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()); >> >> The above generates the schedule in the next table. As you can see, a few >> dates are no longer the 11th of the month and were replaced with the next >> business day. In this case, those dates fell on Saturdays or Sundays, but >> of course the adjustment would also be performed if they were mid-week >> holidays. >> >> <https://substack.com/redirect/ae8057c5-7ee5-420c-af4f-cb7978fa34c3?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> For convenience, it’s possible to pass a calendar and at the same time >> specify that dates should be unadjusted; here is the corresponding call: >> >> Schedule s = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, May, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .withConvention(Unadjusted); >> >> The result is the same as the one we got when we didn’t pass a calendar. >> As I said, this is a convenience; when reading data from a file or a DB, it >> makes it unnecessary to write logic that chooses whether or not to pass a >> calendar. >> Short and long coupons >> >> If the start and end dates don’t bracket a whole number of periods, it >> becomes important to specify whether the dates should be generated forwards >> from the start date or backwards from the end date; the default is to >> generate them backwards, but it’s probably better to be explicit. The >> corresponding calls are as follows: >> >> Schedule s1 = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, February, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .forwards(); >> >> Schedule s2 = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, February, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .backwards(); >> >> The results are shown in the table below. In the first case, we ended up >> with a short last coupon; in the second, with a short first coupon. >> >> <https://substack.com/redirect/79b2a55d-55e3-4ef7-b18a-f815310c4b21?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> It’s also possible to specify a long coupon by passing an explicit stub: >> >> Schedule s = MakeSchedule() >> .from(Date(11, February, 2021)) >> .to(Date(11, May, 2025)) >> .withFirstDate(Date(11, November, 2021)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .forwards(); >> >> The result is shown below. In case of a long last coupon, you can use the >> withNextToLastDate method instead of withFirstDate; the two can also be >> used together. >> >> <https://substack.com/redirect/9c91b185-1084-427d-9240-b6ccdaf3ced1?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> End of month >> >> When the dates are close to the end of their month, other conventions can >> come into play. The default behavior is to generate dates as usual; the call >> >> Schedule s = MakeSchedule() >> .from(Date(28, February, 2019)) >> .to(Date(28, February, 2023)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .forwards(); >> >> results in the dates shown in the next table, where for instance February >> 28th 2021, a Sunday, is adjusted to March 1st according to the “following” >> convention. >> >> <https://substack.com/redirect/bb5d3306-b554-4057-a7ac-852c9da94366?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> However, if another convention such as “modified following” needs to be >> used, it can be passed to the call: >> >> Schedule s = MakeSchedule() >> .from(Date(28, February, 2019)) >> .to(Date(28, February, 2023)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .withConvention(ModifiedFollowing) >> .forwards(); >> >> The result is displayed below and shows that February 28th 2021 is >> adjusted back to February 26th so that it doesn’t change month. >> >> <https://substack.com/redirect/eba5b21f-42f4-49ab-b7d4-3a339fd9a827?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> Also, in some cases, the terms of an instrument might stipulate that >> coupons reset on the last business day of the month; in that case, the >> schedule can be generated with: >> >> Schedule s = MakeSchedule() >> .from(Date(28, February, 2019)) >> .to(Date(28, February, 2023)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .forwards() >> .endOfMonth(); >> >> The result is shown next; by comparing it with the tables above, you can >> see the difference of behavior for the dates at the end of August. >> >> <https://substack.com/redirect/5d65c482-eda7-47a4-98e7-70c6b2f0bee2?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> Specialized rules >> >> The forwards and backwards methods shown above are shorthand for calls >> to a more general method withRule that allows to specify a generation >> rule (“forwards” and “backwards” being two such rules.) Other, more >> specialized rules are available; for instance, if you needed to generate >> the schedule for the payments of a standard 5-years credit default swap, >> you would do it as follows: >> >> auto tradeDate = Date(11, March, 2021); >> auto tenor = Period(5, Years); >> auto maturityDate = >> cdsMaturity(tradeDate, tenor, >> DateGeneration::CDS2015); >> >> Schedule s = MakeSchedule() >> .from(tradeDate) >> .to(maturityDate) >> .withFrequency(Quarterly) >> .withCalendar(TARGET()) >> .withRule(DateGeneration::CDS2015); >> >> First, the cdsMaturity function returns the standardized maturity date >> for the passed trade date; for March 11th 2021, that would be December 20th >> 2025 (it would roll to June 2025 only later in March.) Then, we pass the >> calculated maturity date to MakeSchedule while also specifying a CDS2015 >> date-generation rule; this recalculates the start date of the CDS and also >> adjusts all the dates in the schedule to the twentieth of their months or >> the next business day. The result is shown below. >> >> <https://substack.com/redirect/39ba32d3-8058-4b41-983a-e7f7b19eef80?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg> >> >> This covers most of the functionality of schedules in QuantLib. However, >> you might still be curious about one thing. What about the syntax of >> MakeSchedule? Why aren’t we using a constructor like all decent folks, >> and what happens when we chain all those method calls? >> The Named Parameter idiom >> >> The Schedule class does have a constructor, of course, but it’s a bit >> awkward to use. As the time of this writing, corresponding to QuantLib >> 1.32, its signature is: >> >> Schedule(Date effectiveDate, >> const Date& terminationDate, >> const Period& tenor, >> Calendar calendar, >> BusinessDayConvention convention, >> BusinessDayConvention >> terminationDateConvention, >> DateGeneration::Rule rule, >> bool endOfMonth, >> const Date& firstDate, >> const Date& nextToLastDate); >> >> This means it requires a whole lot of parameters, even in the simplest >> case. Reasonable defaults exist for some of them (a null calendar, >> following for the conventions, backwards for the generation rule, false for >> the end of month, and no first or next-to-last date) but if we added them, >> we’d run into another problem. When we’re good with most of the default >> parameters but want to change one of the last ones (say, firstDate), >> there’s no easy syntax we can use for the call. In Python, which supports >> named parameters, we’d say >> >> s = Schedule( >> Date(11, February, 2021), >> Date(11, May, 2025), >> Period(6, Months), >> firstDate = Date(11, November, 2021), >> ) >> >> but in C++, we’d have to pass all the parameters before firstDate, even >> if they all equal the defaults. >> >> The solution? The Named Parameter idiom (a.k.a Fluent Interface). We >> write a helper class, MakeSchedule in our case, which contains the >> parameters needed to build a schedule and gives them sensible default >> values: >> >> class MakeSchedule { >> ... >> private: >> Calendar calendar_; >> Date effectiveDate_; >> Date terminationDate_; >> Period tenor_; >> BusinessDayConvention convention_ = Following; >> DateGeneration::Rule rule_ = >> DateGeneration::Backward; >> bool endOfMonth_ = false; >> Date firstDate_ = Date(); >> Date nextToLastDate_ = Date(); >> }; >> >> Settings the parameters >> >> To set the values of the parameters, we give MakeSchedule a number of >> setter methods; the twist here is that each of these methods returns the >> object itself, making it possible to chain them. >> >> class MakeSchedule { >> public: >> MakeSchedule& from(const Date& effectiveDate) { >> effectiveDate_ = effectiveDate; >> return *this; >> } >> >> MakeSchedule& to(const Date& terminationDate) { >> terminationDate_ = terminationDate; >> return *this; >> } >> >> MakeSchedule& withTenor(const Period& tenor) { >> tenor_ = tenor; >> return *this; >> } >> >> MakeSchedule& forwards() { >> rule_ = DateGeneration::Forward; >> return *this; >> } >> >> ... >> }; >> >> Getting our schedule >> >> At this point, we’re able to write >> >> MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, February, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()) >> .forwards() >> >> but the result is still a MakeSchedule instance, not a schedule. In >> order to build the latter, we could add an explicit to_schedule() method >> that calls the Schedule constructor and returns the result. However, we >> went for a fancier solution. >> >> A little-used feature of C++ are user-defined conversion functions. You >> can google them for details, but the gist is that, if A and B are two >> unrelated classes, you can give B a method which returns an instance of A, >> declared as >> >> class B { >> public: >> operator A() const; >> ... >> }; >> >> and if you then write >> >> B b; >> A a = b; >> >> the compiler will look first for an A constructor taking a B instance, >> and then (after seeing it isn’t there) it will look into B, find the >> conversion method, invoke it, and assign to a the instance of A returned >> by it. >> >> In our case, the conversion function will be declared in MakeSchedule as >> >> class MakeSchedule { >> public: >> ... >> >> operator Schedule() const; >> }; >> >> and its implementation will call the Schedule constructor with the >> required parameters and return the resulting schedule. Putting everything >> together, we get the syntax >> >> Schedule s = MakeSchedule() >> .from(Date(11, May, 2021)) >> .to(Date(11, May, 2025)) >> .withFrequency(Semiannual) >> .withCalendar(TARGET()); >> >> used in the examples. And in case you were wondering why I didn’t use the >> shorter syntax, note that using auto s above would not trigger the >> assignment operator; it would assign to s the MakeSchedule instance. >> >> And with this, we can bring this article to a close. See you next time! >> >> >> Share >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&utm_medium=email&utm_content=share&utm_campaign=email-share&action=share&triggerShare=true&isFreemail=true&r=6n74v&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTI0MzExMjkiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.85OnpJ8vao6KWfoi1eaP2rF5ntBmFR5JLJ-ZjuA7ftA> >> >> >> Like >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&isFreemail=true&submitLike=true&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJyZWFjdGlvbiI6IuKdpCIsImlhdCI6MTcyNDkwOTQ2MCwiZXhwIjoxNzI3NTAxNDYwLCJpc3MiOiJwdWItMjQzMTEyOSIsInN1YiI6InJlYWN0aW9uIn0.sB6gVgVEMo4ZBZA44fsZmp_c6EBYvRc-tBHyN762xG8&utm_medium=email&utm_campaign=email-reaction&r=6n74v> >> Comment >> <https://substack.com/app-link/post?publication_id=2431129&post_id=148072359&utm_source=substack&utm_medium=email&isFreemail=true&comments=true&token=eyJ1c2VyX2lkIjoxMTE2MDAzMSwicG9zdF9pZCI6MTQ4MDcyMzU5LCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTI0MzExMjkiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.85OnpJ8vao6KWfoi1eaP2rF5ntBmFR5JLJ-ZjuA7ftA&r=6n74v&utm_campaign=email-half-magic-comments&action=post-comment&utm_source=substack&utm_medium=email> >> Restack >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9vcGVuLnN1YnN0YWNrLmNvbS9wdWIvaW1wbGVtZW50aW5ncXVhbnRsaWIvcC9zY2hlZHVsZXMtaW4tcXVhbnRsaWI_dXRtX3NvdXJjZT1zdWJzdGFjayZ1dG1fbWVkaXVtPWVtYWlsJnV0bV9jYW1wYWlnbj1lbWFpbC1yZXN0YWNrLWNvbW1lbnQmYWN0aW9uPXJlc3RhY2stY29tbWVudCZyPTZuNzR2JnRva2VuPWV5SjFjMlZ5WDJsa0lqb3hNVEUyTURBek1Td2ljRzl6ZEY5cFpDSTZNVFE0TURjeU16VTVMQ0pwWVhRaU9qRTNNalE1TURrME5qQXNJbVY0Y0NJNk1UY3lOelV3TVRRMk1Dd2lhWE56SWpvaWNIVmlMVEkwTXpFeE1qa2lMQ0p6ZFdJaU9pSndiM04wTFhKbFlXTjBhVzl1SW4wLjg1T25wSjh2YW82S1dmb2kxZWFQMnJGNW50Qm1GUjVKTEotWmp1QTdmdEEiLCJwIjoxNDgwNzIzNTksInMiOjI0MzExMjksImYiOnRydWUsInUiOjExMTYwMDMxLCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTAiLCJzdWIiOiJsaW5rLXJlZGlyZWN0In0.E93_m7YsoFZzpil4XdpBCcvzhGiQOxaCifb9BX4qVyU?&utm_source=substack&utm_medium=email> >> >> >> © 2024 Luigi Ballabio >> Unsubscribe >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9pbXBsZW1lbnRpbmdxdWFudGxpYi5zdWJzdGFjay5jb20vYWN0aW9uL2Rpc2FibGVfZW1haWw_dG9rZW49ZXlKMWMyVnlYMmxrSWpveE1URTJNREF6TVN3aWNHOXpkRjlwWkNJNk1UUTRNRGN5TXpVNUxDSnBZWFFpT2pFM01qUTVNRGswTmpBc0ltVjRjQ0k2TVRjMU5qUTBOVFEyTUN3aWFYTnpJam9pY0hWaUxUSTBNekV4TWpraUxDSnpkV0lpT2lKa2FYTmhZbXhsWDJWdFlXbHNJbjAuSGhMSEJmRXlZWDZMLVJkV3p0X21WcGw5cElfU0lqV0FQZ3VuZDhCRllNNCIsInAiOjE0ODA3MjM1OSwicyI6MjQzMTEyOSwiZiI6dHJ1ZSwidSI6MTExNjAwMzEsImlhdCI6MTcyNDkwOTQ2MCwiZXhwIjoxNzI3NTAxNDYwLCJpc3MiOiJwdWItMCIsInN1YiI6ImxpbmstcmVkaXJlY3QifQ.7hYEpbmfPteAplYUa0TsI3ghXcX5gGEedAA-BrI5yoY?> >> >> [image: Get the app] >> <https://substack.com/redirect/6aaa26eb-860b-40a4-aaca-148a2fcbcd99?j=eyJ1IjoiNm43NHYifQ.2BvNVSYTXVj4Jl36nKPPVi0V9dvSTHmeQ67a-Xs1HCg>[image: >> Start writing] >> <https://substack.com/redirect/2/eyJlIjoiaHR0cHM6Ly9zdWJzdGFjay5jb20vc2lnbnVwP3V0bV9zb3VyY2U9c3Vic3RhY2smdXRtX21lZGl1bT1lbWFpbCZ1dG1fY29udGVudD1mb290ZXImdXRtX2NhbXBhaWduPWF1dG9maWxsZWQtZm9vdGVyJmZyZWVTaWdudXBFbWFpbD1pZ2l0dXJAZ21haWwuY29tJnI9Nm43NHYiLCJwIjoxNDgwNzIzNTksInMiOjI0MzExMjksImYiOnRydWUsInUiOjExMTYwMDMxLCJpYXQiOjE3MjQ5MDk0NjAsImV4cCI6MTcyNzUwMTQ2MCwiaXNzIjoicHViLTAiLCJzdWIiOiJsaW5rLXJlZGlyZWN0In0.IRAhmOitvOwB23-qSnqo2ANBKQmkWzs-PEHFPPaNWpc?> >> > _______________________________________________ > QuantLib-dev mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-dev > |