C#: EquityOption.cs and date.i

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

C#: EquityOption.cs and date.i

Eric H Jensen
Hi,

This summer Mike Allen posted an initial C# translation of EquityOption.cpp (thank you!).  I made a few changes to try to replicate the EquityOption.cpp results and also some cosmetic changes to make it a little clearer in my own mind what these files were doing.   Thanks also to Tito Ingargiola for recently posting the java version of EquityOption.cpp.  I found it very helpful.

In addition to the change Tito posted re: Joshi4 SWIG support, I also made a small change to the SWIG date.i file to support the Date object's '+' and '-' operators for C# (renamed to 'Add' and 'Subtract'):

    #if defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGJAVA) || defined(SWIGR) || defined(SWIGCSHARP)
    #if defined(SWIGCSHARP)
    %rename(Add) operator+;
    %rename(Subtract) operator-;
    #endif
    Date operator+(BigInteger days) const;
    Date operator-(BigInteger days) const;
    Date operator+(const Period&) const;
    Date operator-(const Period&) const;
    #endif

I've included my edited version of EquityOption.cs below (my email with an attached zip file was rejected).

Two things to note:

1) FDBermudanEngine is not exposed in SWIG

2) MCAmericanEngine is not exposed in SWIG

EquityOption.cs appears to replicate all the numeric results (sans the two cases noted above) of EquityOption.cpp except the low discrepancy Monte Carlo.  Since the C++ file relies on default values for the unnamed parameters, I am note sure whether I set these correctly or not in C# (I am not very fluent in C++).

I hope this is helpful to others.  Perhaps these changes can be included in the next release of QuantLib SWIG.

Best regards,

eric


--- EquityOption.cs

/*
 * A C# version of EquityOption.cpp
 *
 * Don't forget to build and then copy NQuantLib.dll and NQuantLibc.dll into your Debug and Release directories.
 *
 * This file is part of QuantLib, a free-software/open-source library
 * for financial quantitative analysts and developers - http://quantlib.org/
 *
 * QuantLib is free software: you can redistribute it and/or modify it
 * under the terms of the QuantLib license.  You should have received a
 * copy of the license along with this program; if not, please email
 * <[hidden email]>. The license is also available online at
 * <http://quantlib.org/license.shtml>.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the license for more details.
 */

using System;
using System.Collections.Generic;
using System.Text;

using QuantLib;

namespace EquityOptionTest
{
    class EquityOption
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;

            Option.Type optionType = Option.Type.Put;
            double underlyingPrice = 36;
            double strikePrice = 40;
            double dividendYield = 0.0;
            double riskFreeRate = 0.06;
            double volatility = 0.2;

            Date todaysDate = new Date(15, Month.May, 1998);
            Settings.instance().setEvaluationDate(todaysDate);

            Date settlementDate = new Date(17, Month.May, 1998);
            Date maturityDate = new Date(17, Month.May, 1999);

            DateVector exerciseDates = new DateVector(4);
            for (int i = 1; i <= 4; i++) {
                Period forwardPeriod = new Period(3 * i, TimeUnit.Months);
                Date forwardDate = settlementDate.Add(forwardPeriod);
                exerciseDates.Add(forwardDate);
                //Console.WriteLine("Forward Date {0}: {1} {2} {3}", i, forwardDate.year(), forwardDate.month(), forwardDate.dayOfMonth());
            }

            EuropeanExercise europeanExercise = new EuropeanExercise(maturityDate);
            BermudanExercise bermudanExercise = new BermudanExercise(exerciseDates);
            AmericanExercise americanExercise = new AmericanExercise(settlementDate, maturityDate);

            // bootstrap the yield/dividend/vol curves and create a BlackScholesMerton stochastic process
            DayCounter dayCounter = new Actual365Fixed();
            YieldTermStructureHandle flatRateTSH = new YieldTermStructureHandle(new FlatForward(settlementDate, riskFreeRate, dayCounter));
            YieldTermStructureHandle flatDividendTSH = new YieldTermStructureHandle(new FlatForward(settlementDate, dividendYield, dayCounter));
            BlackVolTermStructureHandle flatVolTSH = new BlackVolTermStructureHandle(new BlackConstantVol(settlementDate, volatility, dayCounter));

            QuoteHandle underlyingQuoteH = new QuoteHandle(new SimpleQuote(underlyingPrice));
            BlackScholesMertonProcess stochasticProcess = new BlackScholesMertonProcess(underlyingQuoteH, flatDividendTSH, flatRateTSH, flatVolTSH);

            PlainVanillaPayoff payoff = new PlainVanillaPayoff(optionType, strikePrice);

            // options
            VanillaOption europeanOption = new VanillaOption(stochasticProcess, payoff, europeanExercise);
            VanillaOption bermudanOption = new VanillaOption(stochasticProcess, payoff, bermudanExercise);
            VanillaOption americanOption = new VanillaOption(stochasticProcess, payoff, americanExercise);

            // report the parameters we are using
            ReportParameters(optionType, underlyingPrice, strikePrice, dividendYield, riskFreeRate, volatility, maturityDate);

            // write out the column headings
            ReportHeadings();

            #region Analytic Formulas

            // Black-Scholes for European
            try {
                europeanOption.setPricingEngine(new AnalyticEuropeanEngine());
                ReportResults("Black-Scholes", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Barone-Adesi and Whaley approximation for American
            try {
                americanOption.setPricingEngine(new BaroneAdesiWhaleyEngine());
                ReportResults("Barone-Adesi/Whaley", null, null, americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Bjerksund and Stensland approximation for American
            try {
                americanOption.setPricingEngine(new BjerksundStenslandEngine());
                ReportResults("Bjerksund/Stensland", null, null, americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Integral
            try {
                europeanOption.setPricingEngine(new IntegralEngine());
                ReportResults("Integral", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            uint timeSteps = 801;

            // Finite differences
            try {
                europeanOption.setPricingEngine(new FDEuropeanEngine(timeSteps, timeSteps - 1));
                // FDBermudanEngine is not currently exposed in SWIG
                //bermudanOption.setPricingEngine(new FDBermudanEngine(timeSteps, timeSteps - 1));
                americanOption.setPricingEngine(new FDAmericanEngine(timeSteps, timeSteps - 1));
                ReportResults("Finite differences", europeanOption.NPV(), null, americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            #endregion Analytic Formulas

            #region Binomial Methods

            // Binomial Jarrow-Rudd
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("jarrowrudd", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("jarrowrudd", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("jarrowrudd", timeSteps));
                ReportResults("Binomial Jarrow-Rudd", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Cox-Ross-Rubinstein
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("coxrossrubinstein", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("coxrossrubinstein", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("coxrossrubinstein", timeSteps));
                ReportResults("Binomial Cox-Ross-Rubinstein", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Additive Equiprobabilities
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("eqp", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("eqp", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("eqp", timeSteps));
                ReportResults("Additive Equiprobabilities", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Trigeorgis
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("trigeorgis", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("trigeorgis", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("trigeorgis", timeSteps));
                ReportResults("Binomial Trigeorgis", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Tian
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("tian", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("tian", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("tian", timeSteps));
                ReportResults("Binomial Tian", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Leisen-Reimer
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("leisenreimer", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("leisenreimer", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("leisenreimer", timeSteps));
                ReportResults("Binomial Leisen-Reimer", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Joshi
            try {
                europeanOption.setPricingEngine(new BinomialVanillaEngine("joshi4", timeSteps));
                bermudanOption.setPricingEngine(new BinomialVanillaEngine("joshi4", timeSteps));
                americanOption.setPricingEngine(new BinomialVanillaEngine("joshi4", timeSteps));
                ReportResults("Binomial Joshi", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            #endregion Binomial Methods

            #region Monte Carlo Methods

            // quantlib appears to use max numeric (int and real) values to test for 'null' (or rather 'default') values

            // MC (crude)
            try {
                string traits = "pseudorandom";
                int mcTimeSteps = 1;
                int timeStepsPerYear = int.MaxValue;
                bool brownianBridge = false;
                bool antitheticVariate = false;
                bool controlVariate = false;
                int requiredSamples = int.MaxValue;
                double requiredTolerance = 0.02;
                int maxSamples = int.MaxValue;
                int seed = 42;
                europeanOption.setPricingEngine(new MCEuropeanEngine(traits, mcTimeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed));
                ReportResults("MC (crude)", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // MC (Sobol)
            try {
                string traits = "lowdiscrepancy";
                int mcTimeSteps = 1;
                int timeStepsPerYear = int.MaxValue;
                bool brownianBridge = false;
                bool antitheticVariate = false;
                bool controlVariate = false;
                int requiredSamples = 32768;  // 2^15
                double requiredTolerance = double.MaxValue;
                int maxSamples = int.MaxValue;
                int seed = 0;
                europeanOption.setPricingEngine(new MCEuropeanEngine(traits, mcTimeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed));
                ReportResults("MC (Sobol)", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // MC (Longstaff Schwartz)
            try {
                // MCAmericanEngine is not currently exposed in SWIG
                //americanOption.setPricingEngine(new MCAmericanEngine());
                ReportResults("MC (Longstaff Schwartz)", null, null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            #endregion Monte Carlo Methods

            DateTime endTime = DateTime.Now;
            TimeSpan delta = endTime - startTime;
            Console.WriteLine();
            Console.WriteLine("Run completed in {0} s", delta.TotalSeconds);
        }

        private static void ReportParameters(Option.Type optionType, double underlyingPrice, double strikePrice, double dividendYield, double riskFreeRate, double volatility, Date maturityDate)
        {
            Console.WriteLine();
            Console.WriteLine("Option type = {0}", optionType);
            Console.WriteLine("Maturity = {0} {1} {2}", maturityDate.year(), maturityDate.month(), maturityDate.dayOfMonth());
            Console.WriteLine("Underlying price = ${0}", underlyingPrice);
            Console.WriteLine("Strike = ${0}", strikePrice);
            Console.WriteLine("Risk-free interest rate = {0}%", riskFreeRate * 100.0);
            Console.WriteLine("Dividend yield = {0}%", dividendYield * 100.0);
            Console.WriteLine("Volatility = {0}%", volatility * 100);
            Console.WriteLine();

        }

        private static int[] columnWidths = { 35, 14, 14, 14 };

        private static void ReportHeadings()
        {
            Console.Write("Method".PadRight(columnWidths[0]));
            Console.Write("European".PadRight(columnWidths[1]));
            Console.Write("Bermudan".PadRight(columnWidths[2]));
            Console.Write("American".PadRight(columnWidths[3]));
            Console.WriteLine();
        }

        private static void ReportResults(string methodName, double? european, double? bermudan, double? american)
        {
            string strNA = "N/A";
            string format = "{0:N6}";
            Console.Write(methodName.PadRight(columnWidths[0]));
            Console.Write(String.Format((european == null) ? strNA : format, european).PadRight(columnWidths[1]));
            Console.Write(String.Format((bermudan == null) ? strNA : format, bermudan).PadRight(columnWidths[2]));
            Console.Write(String.Format((american == null) ? strNA : format, american).PadRight(columnWidths[3]));
            Console.WriteLine();
        }
    }
}




-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: C#: EquityOption.cs and date.i

Luigi Ballabio
On Wed, 2007-09-19 at 10:00 -0400, Eric H Jensen wrote:
> This summer Mike Allen posted an initial C# translation of
> EquityOption.cpp (thank you!).  I made a few changes to try to
> replicate the EquityOption.cpp results and also some cosmetic changes
> to make it a little clearer in my own mind what these files were
> doing.   Thanks also to Tito Ingargiola for recently posting the java
> version of EquityOption.cpp.  I found it very helpful.

Hi Eric,
        thanks---I'll add your files to the repository as soon as I get some
time.

Later,
        Luigi


--

The young man knows the rules, but the old man knows the exceptions.
-- O. W. Holmes



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: C#: EquityOption.cs and date.i

Luigi Ballabio
In reply to this post by Eric H Jensen
On Wed, 2007-09-19 at 10:00 -0400, Eric H Jensen wrote:
> This summer Mike Allen posted an initial C# translation of EquityOption.cpp (thank you!).  I made a few changes to try to replicate the EquityOption.cpp results and also some cosmetic changes to make it a little clearer in my own mind what these files were doing.

Hi Eric,
        I've just added your example to the repository. Thanks for the
contribution.

Luigi


--

A debugged program is one for which you have not yet found the
conditions that make it fail.
-- Jerry Ogdin



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users