New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DividendVanillaOption #72

Closed
hfty opened this Issue Oct 19, 2016 · 21 comments

Comments

Projects
None yet
4 participants
@hfty
Contributor

hfty commented Oct 19, 2016

I would like to get prices and Greeks for American options with discrete dividends, which seems to be implemented in QuantLib in DividendVanillaOption.

It is my understanding that this is not currently part of the code covered by RQuantLib. Is there any way I could easily interface that code from R? My C++ is fairly limited, and the QuantLib codebase looks like a beast.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 19, 2016

Owner

The QuantLib codebase is a beast! But there is some hope -- by studying the examples and particularly the (very extensive) unit tests you can often come up with something simple. Get that working standalone, and from there interfacing from R is pretty easy thanks to Rcpp.

Sounds like a plan? I can help here and there...

Owner

eddelbuettel commented Oct 19, 2016

The QuantLib codebase is a beast! But there is some hope -- by studying the examples and particularly the (very extensive) unit tests you can often come up with something simple. Get that working standalone, and from there interfacing from R is pretty easy thanks to Rcpp.

Sounds like a plan? I can help here and there...

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 19, 2016

Contributor

Thanks, I can try and follow that route. On the RQuantLib side, what is the type of interface that would be most appropriate? Should I go with a DividendAmericanOption function alongside AmericanOption, or modify AmericanOption to include optional parameters?

Contributor

hfty commented Oct 19, 2016

Thanks, I can try and follow that route. On the RQuantLib side, what is the type of interface that would be most appropriate? Should I go with a DividendAmericanOption function alongside AmericanOption, or modify AmericanOption to include optional parameters?

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 20, 2016

Owner

If DividendAmericanOption is different (enough) from AmericanOption then it may make the most sense to make it a different function.

Owner

eddelbuettel commented Oct 20, 2016

If DividendAmericanOption is different (enough) from AmericanOption then it may make the most sense to make it a different function.

@tleitch

This comment has been minimized.

Show comment
Hide comment
@tleitch

tleitch Oct 21, 2016

Contributor

If it were me, I'd do an AmericanOption and have an optional dividend argument with a default of 0 and have a single interface.

Contributor

tleitch commented Oct 21, 2016

If it were me, I'd do an AmericanOption and have an optional dividend argument with a default of 0 and have a single interface.

@student-t

This comment has been minimized.

Show comment
Hide comment
@student-t

student-t Oct 21, 2016

@eddelbuettel Thus sounds like an easy problem for you. Why wouldn't you just do it?

student-t commented Oct 21, 2016

@eddelbuettel Thus sounds like an easy problem for you. Why wouldn't you just do it?

@tleitch

This comment has been minimized.

Show comment
Hide comment
@tleitch

tleitch Oct 21, 2016

Contributor

I'm working on a swap interface and a FRA interface. I just found unexpected behavior in the FRA results that I'm trying address. Also yield curve perturbations and then there are my 3 other clients. Sorry, another interface outside of fixed income is outside my ability to resource. Happy to advise. There's already an AmericanOption with a dividend yield, just add dividends and fork on non-zero dividend to call other quantlib dividend based method.

Contributor

tleitch commented Oct 21, 2016

I'm working on a swap interface and a FRA interface. I just found unexpected behavior in the FRA results that I'm trying address. Also yield curve perturbations and then there are my 3 other clients. Sorry, another interface outside of fixed income is outside my ability to resource. Happy to advise. There's already an AmericanOption with a dividend yield, just add dividends and fork on non-zero dividend to call other quantlib dividend based method.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 21, 2016

Owner

@student-t Let's see: maybe because I have a day job, over two dozen other CRAN packages several of which I released in the last few days, well over 100 CRAN packages I maintain for Debian where I currently prep for tomorrow's first beta of R 3.3.2, and maybe also because I occasionally sleep. So, your turn: Why don't you?

Jokes aside: easily contained and well-defined problems are the best to start so a case can be made that these should in fact be left as training ground for new contributors.

@tleitch Point taken. I haven't looked at the class interfaces but generalizing to 'with dividend' defaulting to a value of zero and giving old behaviour sounds good to me too.

Owner

eddelbuettel commented Oct 21, 2016

@student-t Let's see: maybe because I have a day job, over two dozen other CRAN packages several of which I released in the last few days, well over 100 CRAN packages I maintain for Debian where I currently prep for tomorrow's first beta of R 3.3.2, and maybe also because I occasionally sleep. So, your turn: Why don't you?

Jokes aside: easily contained and well-defined problems are the best to start so a case can be made that these should in fact be left as training ground for new contributors.

@tleitch Point taken. I haven't looked at the class interfaces but generalizing to 'with dividend' defaulting to a value of zero and giving old behaviour sounds good to me too.

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 21, 2016

Contributor

@eddelbuettel I'm well aware of your enormous contributions to the community (and very grateful for them), and would love to do my part if I can wrap my head around the C++ side of things. I'm starting, as you suggested, from the unit test DividendOptionTest::testEuropeanKnownValue (doesn't look like there's a test unit for American options with discrete dividends). I'll try to add optional dividend parameters for AmericanOption and EuropeanOption, as suggested by @tleitch.

Contributor

hfty commented Oct 21, 2016

@eddelbuettel I'm well aware of your enormous contributions to the community (and very grateful for them), and would love to do my part if I can wrap my head around the C++ side of things. I'm starting, as you suggested, from the unit test DividendOptionTest::testEuropeanKnownValue (doesn't look like there's a test unit for American options with discrete dividends). I'll try to add optional dividend parameters for AmericanOption and EuropeanOption, as suggested by @tleitch.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 21, 2016

Owner

@hfty What I try in a case like that is to first builds a small self-contained program depending only on QuantLib. Maybe with the fewest feature. And then build up from there. What is in RQuantLib can serve as a framework for adding to it. And if you're stuck, come here and ask for help. No point in spinning the wheels...

Owner

eddelbuettel commented Oct 21, 2016

@hfty What I try in a case like that is to first builds a small self-contained program depending only on QuantLib. Maybe with the fewest feature. And then build up from there. What is in RQuantLib can serve as a framework for adding to it. And if you're stuck, come here and ask for help. No point in spinning the wheels...

@tleitch

This comment has been minimized.

Show comment
Hide comment
@tleitch

tleitch Oct 21, 2016

Contributor

@hfty A great resource on the C++ side are the examples in Quantlib. Some of the RQuantlib functions are almost direct wraps of an example. If you know some C++ and compare an existing R/Rcpp wrap with it's matching example you can infer what your interface should look like. AmericanOption is a great start, you only need to figure out how to add the dividend input (it will be two data points, amount and time/date) and then figure out how to format that data for the method call that takes discrete dividends. The Module you want if FDDividendAmericanEngine which is related to FDAemeicanEngine. There is no example for the dividend version, but there is test suite code where it is called. I would hunt that down and compare it with the dividend yield version to help with design the call.

The outputs are the same, so no work needed there.

Best of luck. C++ is the easy part. Dirk is much harder to learn.

Contributor

tleitch commented Oct 21, 2016

@hfty A great resource on the C++ side are the examples in Quantlib. Some of the RQuantlib functions are almost direct wraps of an example. If you know some C++ and compare an existing R/Rcpp wrap with it's matching example you can infer what your interface should look like. AmericanOption is a great start, you only need to figure out how to add the dividend input (it will be two data points, amount and time/date) and then figure out how to format that data for the method call that takes discrete dividends. The Module you want if FDDividendAmericanEngine which is related to FDAemeicanEngine. There is no example for the dividend version, but there is test suite code where it is called. I would hunt that down and compare it with the dividend yield version to help with design the call.

The outputs are the same, so no work needed there.

Best of luck. C++ is the easy part. Dirk is much harder to learn.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 21, 2016

Owner

Dirk is easy.

Terry was referring to the fact that he also needed a crash course in how to deal with Git(Hub). 😀

Owner

eddelbuettel commented Oct 21, 2016

Dirk is easy.

Terry was referring to the fact that he also needed a crash course in how to deal with Git(Hub). 😀

@tleitch

This comment has been minimized.

Show comment
Hide comment
@tleitch

tleitch Oct 21, 2016

Contributor

Too many years in a C suite..... ;~)

Contributor

tleitch commented Oct 21, 2016

Too many years in a C suite..... ;~)

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 21, 2016

Contributor

Thanks for the advice, @eddelbuettel and @tleitch. I'm sluggishly making my way through the code.

The engine expects vectors for dividend dates and amounts, and I'm not sure what the best way to pass those as parameters with Rcpp.

From the test suite:

std::vector<Date> dividendDates;
std::vector<Real> dividends;

Does that mean I can just add a std::vector<Real> dividends argument to the americanOptionEngine function, or should it be e.g. a Rcpp::NumericVector? I want it to be able to handle the default case where it's just a zero...

For the dividendDates, it's a little trickier given I think we should pass a vector of time to dividends, rather than actual dates, just like what you've done for the maturity. I guess the easiest would be to have a std::vector<Real> dividendTimes parameter (not sure about the name...), and then loop over it to create the std::vector<Date>?

I thought of making it a unique dividend for simplicity, but given the QuantLib function expects a vector anyway... might as well.

Contributor

hfty commented Oct 21, 2016

Thanks for the advice, @eddelbuettel and @tleitch. I'm sluggishly making my way through the code.

The engine expects vectors for dividend dates and amounts, and I'm not sure what the best way to pass those as parameters with Rcpp.

From the test suite:

std::vector<Date> dividendDates;
std::vector<Real> dividends;

Does that mean I can just add a std::vector<Real> dividends argument to the americanOptionEngine function, or should it be e.g. a Rcpp::NumericVector? I want it to be able to handle the default case where it's just a zero...

For the dividendDates, it's a little trickier given I think we should pass a vector of time to dividends, rather than actual dates, just like what you've done for the maturity. I guess the easiest would be to have a std::vector<Real> dividendTimes parameter (not sure about the name...), and then loop over it to create the std::vector<Date>?

I thought of making it a unique dividend for simplicity, but given the QuantLib function expects a vector anyway... might as well.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 21, 2016

Owner

The fixed incomes should have similar things for coupon dates and payment. In essence you are correct: vectors of dates and values.

We do have Rcpp::Datevector, and that whole stack is a bit of mess in RQuantLib because it was all done before Rcpp had facilities for it. (For what it is worth I finally added something better; hopefully in the next Rcpp release.) But there should be plenty of working examples.

Owner

eddelbuettel commented Oct 21, 2016

The fixed incomes should have similar things for coupon dates and payment. In essence you are correct: vectors of dates and values.

We do have Rcpp::Datevector, and that whole stack is a bit of mess in RQuantLib because it was all done before Rcpp had facilities for it. (For what it is worth I finally added something better; hopefully in the next Rcpp release.) But there should be plenty of working examples.

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 21, 2016

Contributor

I see. I can use some of the syntax from the bonds file, thank you.

For dates, however, I guess it's a stylistic choice. Bond valuation uses actual dates, and then asks you for the effectiveDate at which to value the bond. The option functions in RQuantLib, however, abstract from that and ask you for a maturity (in years), then convert it to a Date from today. For consistency, I think it would be better to do the same for discrete dividends: ask for time (in years) to the dividend, then convert it into dates from today. I think I should be able to make that work.

Contributor

hfty commented Oct 21, 2016

I see. I can use some of the syntax from the bonds file, thank you.

For dates, however, I guess it's a stylistic choice. Bond valuation uses actual dates, and then asks you for the effectiveDate at which to value the bond. The option functions in RQuantLib, however, abstract from that and ask you for a maturity (in years), then convert it to a Date from today. For consistency, I think it would be better to do the same for discrete dividends: ask for time (in years) to the dividend, then convert it into dates from today. I think I should be able to make that work.

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 21, 2016

Owner

Yes -- real valued 'time until' as fractional years is common. But that can happen both ways: giving QL a vector of (dividend) dates as well as a current evaluation date (today is a default), and letting it compute the time steps, or giving it the time steps. I usually follow the example and test code and try to conform to the existing class interfaces.

Owner

eddelbuettel commented Oct 21, 2016

Yes -- real valued 'time until' as fractional years is common. But that can happen both ways: giving QL a vector of (dividend) dates as well as a current evaluation date (today is a default), and letting it compute the time steps, or giving it the time steps. I usually follow the example and test code and try to conform to the existing class interfaces.

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 21, 2016

Contributor

There is no example for this, but the unit test uses fractional years from today, so I'll try to go with that. Thanks!

Contributor

hfty commented Oct 21, 2016

There is no example for this, but the unit test uses fractional years from today, so I'll try to go with that. Thanks!

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 22, 2016

Contributor

Looks like I have a working prototype! Thank you again for your help. I did both the European and American version. However, a few questions before I submit a pull requests for your consideration:

  1. There is a test for the European DividendVanillaOption in QuantLib, testEuropeanKnownValue. The test, however, is commented out with the message "Doesn't quite work. Need to deal with date conventions". I do get 3.67123 vs 3.6719 in the Hull (example 12.8), where it's from. But it's an upstream issue.

However, no such test for the American version, and the issue is that I would need to compare to a Finite Difference benchmark. Haug uses a discrete dividend yield model (i.e. % of the spot at the ex-dividend date, if I understood that right); Hull uses a binomial tree. The values I obtain are close to Haug, but not exactly the same; they are fairly different from those of Hull, although the Greeks are very similar.

I guess that it is not our job to check that the upstream results are correct, but I'd like the new functionality to be properly tested anyway...

  1. I've added the extra parameters as a discreteDividends and discreteDividendsTimeUntil, vectors of type double, at the end of the existing parameters for both engine. It may be more logical to add them after dividendYield, but I worry about backward compatibility for people who use unnamed parameters. Do you have a suggestion on either the names or the order?

  2. For American option, the "BaroneAdesiWhaley" does not handle discrete dividend, so if the engine is left on the default and not set to "CrankNicolson", I switch it and send a Rf_warning. Is that a good way to handle the case?

  3. Should I worry about europeanOptionArraysEngine at this stage? (I don't think there is an americanOptionArraysEngine yet. Maybe something for me to do next?)

Contributor

hfty commented Oct 22, 2016

Looks like I have a working prototype! Thank you again for your help. I did both the European and American version. However, a few questions before I submit a pull requests for your consideration:

  1. There is a test for the European DividendVanillaOption in QuantLib, testEuropeanKnownValue. The test, however, is commented out with the message "Doesn't quite work. Need to deal with date conventions". I do get 3.67123 vs 3.6719 in the Hull (example 12.8), where it's from. But it's an upstream issue.

However, no such test for the American version, and the issue is that I would need to compare to a Finite Difference benchmark. Haug uses a discrete dividend yield model (i.e. % of the spot at the ex-dividend date, if I understood that right); Hull uses a binomial tree. The values I obtain are close to Haug, but not exactly the same; they are fairly different from those of Hull, although the Greeks are very similar.

I guess that it is not our job to check that the upstream results are correct, but I'd like the new functionality to be properly tested anyway...

  1. I've added the extra parameters as a discreteDividends and discreteDividendsTimeUntil, vectors of type double, at the end of the existing parameters for both engine. It may be more logical to add them after dividendYield, but I worry about backward compatibility for people who use unnamed parameters. Do you have a suggestion on either the names or the order?

  2. For American option, the "BaroneAdesiWhaley" does not handle discrete dividend, so if the engine is left on the default and not set to "CrankNicolson", I switch it and send a Rf_warning. Is that a good way to handle the case?

  3. Should I worry about europeanOptionArraysEngine at this stage? (I don't think there is an americanOptionArraysEngine yet. Maybe something for me to do next?)

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 22, 2016

Owner

Sounds good! Now in order:

  1. That sounds fine. Sometimes we just have a few decimals of precision. Over the years I even had to adjust test result comparison for the same routine (because of subtle implementation details, things that can happen with numerical optimization and alike and so on). So we could compare the European for up to, say, 3.67. American Options are trickier as is known so we may skip this, or just test 'ballpark'.

  2. We have something new in Rcpp which can: a templated Nullable<> . I can update this once you have sent a pull request -- it is not something you need to do now. And yes, I would place them at the end as C++ cares about the order...

  3. Seems right.

  4. Naaa. That was an experiment a decade ago. Just leave as is.

Owner

eddelbuettel commented Oct 22, 2016

Sounds good! Now in order:

  1. That sounds fine. Sometimes we just have a few decimals of precision. Over the years I even had to adjust test result comparison for the same routine (because of subtle implementation details, things that can happen with numerical optimization and alike and so on). So we could compare the European for up to, say, 3.67. American Options are trickier as is known so we may skip this, or just test 'ballpark'.

  2. We have something new in Rcpp which can: a templated Nullable<> . I can update this once you have sent a pull request -- it is not something you need to do now. And yes, I would place them at the end as C++ cares about the order...

  3. Seems right.

  4. Naaa. That was an experiment a decade ago. Just leave as is.

@hfty

This comment has been minimized.

Show comment
Hide comment
@hfty

hfty Oct 26, 2016

Contributor

PR merged! Thanks for your help.

Contributor

hfty commented Oct 26, 2016

PR merged! Thanks for your help.

@hfty hfty closed this Oct 26, 2016

@eddelbuettel

This comment has been minimized.

Show comment
Hide comment
@eddelbuettel

eddelbuettel Oct 26, 2016

Owner

Ahh. Forgot we had an open issue. Will mark.

(Pro-tip: Having (Closes #72) in your commit message automates this.)

Owner

eddelbuettel commented Oct 26, 2016

Ahh. Forgot we had an open issue. Will mark.

(Pro-tip: Having (Closes #72) in your commit message automates this.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment