Assembla home | Assembla project page
 

Changeset 160

Show
Ignore:
Timestamp:
05/10/08 11:07:16 (2 months ago)
Author:
snovik
Message:

Change: Update of American Options

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/QLNet/QLNet/Instruments/OneAssetOption.cs

    r131 r160  
    158158        } 
    159159 
    160         public class Engine : GenericEngine<OneAssetOption.Arguments, OneAssetOption.Results> {} 
     160        public class Engine : GenericEngine<OneAssetOption.Arguments, OneAssetOption.Results> { 
     161        } 
    161162    } 
    162163} 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/FDAmericanEngine.cs

    r159 r160  
    3030        - the correctness of the returned greeks is tested by reproducing numerical derivatives. 
    3131    */ 
    32     public class FDAmericanEngine : FDEngineAdapter<FDAmericanCondition<FDStepConditionEngine>, OneAssetOption.Engine> { 
     32    public class FDAmericanEngine : FDEngineAdapter<FDAmericanCondition<FDStepConditionEngine>, OneAssetOption.Engine,  
     33                                                    OneAssetOption.Arguments, OneAssetOption.Results> { 
     34        public FDAmericanEngine(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent)  
     35            : base(process, timeSteps, gridPoints, timeDependent) { } 
    3336    } 
    3437} 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/FDMultiPeriodEngine.cs

    r159 r160  
    2323 
    2424namespace QLNet { 
    25     public abstract class FDMultiPeriodEngine : FDVanillaEngine { 
     25    public class FDMultiPeriodEngine : FDVanillaEngine { 
    2626        protected List<Event> events_; 
    2727        protected List<double> stoppingTimes_; 
     
    3232        protected FiniteDifferenceModel<CrankNicolson<TridiagonalOperator>> model_; 
    3333 
    34          
     34        public FDMultiPeriodEngine() { }    // required for generics 
     35        public override IOptionPricingEngine factory(GeneralizedBlackScholesProcess process, 
     36                                                    int timeSteps, int gridPoints, bool timeDependent) { 
     37            return new FDMultiPeriodEngine(process, timeSteps, gridPoints, timeDependent); 
     38        } 
     39 
    3540        //protected FDMultiPeriodEngine(GeneralizedBlackScholesProcess process, 
    3641        //     int gridPoints = 100, int timeSteps = 100, bool timeDependent = false)     
     
    5055        } 
    5156 
    52         protected override void setupArguments(IPricingEngineArguments a) { 
     57        protected virtual void executeIntermediateStep(int step) { throw new NotSupportedException(); } 
     58 
     59        protected virtual void initializeStepCondition() { 
     60            stepCondition_ = new NullCondition<Vector>(); 
     61        } 
     62 
     63        protected virtual void initializeModel() { 
     64            model_ = new FiniteDifferenceModel<CrankNicolson<TridiagonalOperator>>(finiteDifferenceOperator_,BCs_); 
     65        } 
     66 
     67        protected double getDividendTime(int i)  { 
     68            return stoppingTimes_[i]; 
     69        } 
     70 
     71        #region IOptionPricingEngine 
     72        public override void setupArguments(IPricingEngineArguments a) { 
    5373            base.setupArguments(a); 
    5474            OneAssetOption.Arguments args = a as OneAssetOption.Arguments; 
     
    5878            int n = args.exercise.dates().Count; 
    5979            stoppingTimes_ = new List<double>(n); 
    60             for (int i=0; i<n; ++i) 
     80            for (int i = 0; i < n; ++i) 
    6181                stoppingTimes_[i] = process_.time(args.exercise.date(i)); 
    6282        } 
    6383 
    64         protected virtual void calculate(IPricingEngineResults r) { 
     84        public override void calculate(IPricingEngineResults r) { 
    6585            OneAssetOption.Results results = r as OneAssetOption.Results; 
    6686            if (results == null) throw new ApplicationException("incorrect results type"); 
     
    80100                if (!(getDividendTime(0) >= 0)) 
    81101                    throw new ApplicationException("first date (" + getDividendTime(0) + ") cannot be negative"); 
    82                 if(getDividendTime(0) < getResidualTime() * dateTolerance )
     102                if (getDividendTime(0) < getResidualTime() * dateTolerance)
    83103                    firstDateIsZero = true; 
    84104                    firstIndex = 0; 
    85                     if(dateNumber >= 2) 
     105                    if (dateNumber >= 2) 
    86106                        firstNonZeroDate = getDividendTime(1); 
    87107                } 
     
    97117                if (dateNumber >= 2) { 
    98118                    for (j = 1; j < dateNumber; j++) 
    99                         if (!(getDividendTime(j-1) < getDividendTime(j))) 
     119                        if (!(getDividendTime(j - 1) < getDividendTime(j))) 
    100120                            throw new ApplicationException("dates must be in increasing order: " 
    101                                    + getDividendTime(j-1) + " is not strictly smaller than " + getDividendTime(j)); 
     121                                   + getDividendTime(j - 1) + " is not strictly smaller than " + getDividendTime(j)); 
    102122                } 
    103123            } 
    104124 
    105             double dt = getResidualTime()/(timeStepPerPeriod_*(dateNumber+1)); 
     125            double dt = getResidualTime() / (timeStepPerPeriod_ * (dateNumber + 1)); 
    106126 
    107127            // Ensure that dt is always smaller than the first non-zero date 
    108128            if (firstNonZeroDate <= dt) 
    109                 dt = firstNonZeroDate/2.0; 
     129                dt = firstNonZeroDate / 2.0; 
    110130 
    111131            setGridLimits(); 
     
    117137 
    118138            prices_ = intrinsicValues_; 
    119             if(lastDateIsResTime) 
     139            if (lastDateIsResTime) 
    120140                executeIntermediateStep(dateNumber - 1); 
    121141 
     
    126146                    beginDate = getResidualTime(); 
    127147                else 
    128                     beginDate = getDividendTime(j+1); 
     148                    beginDate = getDividendTime(j + 1); 
    129149 
    130150                if (j >= 0) 
     
    136156                model_.rollback(ref temp, beginDate, endDate, timeStepPerPeriod_, stepCondition_); 
    137157                prices_.setValues((Vector)temp); 
    138                  
     158 
    139159                if (j >= 0) 
    140160                    executeIntermediateStep(j); 
     
    145165            prices_.setValues((Vector)temp); 
    146166 
    147             if(firstDateIsZero) 
     167            if (firstDateIsZero) 
    148168                executeIntermediateStep(0); 
    149169 
     
    154174        } 
    155175 
    156         protected abstract void executeIntermediateStep(int step); 
    157  
    158         protected virtual void initializeStepCondition() { 
    159             stepCondition_ = new NullCondition<Vector>(); 
    160         } 
    161  
    162         protected virtual void initializeModel() { 
    163             model_ = new FiniteDifferenceModel<CrankNicolson<TridiagonalOperator>>(finiteDifferenceOperator_,BCs_); 
    164         } 
    165  
    166         protected double getDividendTime(int i)  { 
    167             return stoppingTimes_[i]; 
    168         } 
     176        #endregion 
    169177    } 
    170178} 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/FDStepConditionEngine.cs

    r159 r160  
    3131        protected SampledCurve controlPrices_; 
    3232 
     33        // required for generics 
     34        public FDStepConditionEngine() { } 
     35        public override IOptionPricingEngine factory(GeneralizedBlackScholesProcess process, 
     36                                                     int timeSteps, int gridPoints, bool timeDependent) { 
     37            return new FDStepConditionEngine(process, timeSteps, gridPoints, timeDependent); 
     38        } 
     39 
     40 
    3341        //public FDStepConditionEngine(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, 
    3442        //     bool timeDependent = false) 
     
    4149        protected virtual void initializeStepCondition() { } 
    4250 
    43         protected virtual void calculate(IPricingEngineResults r) { 
     51        public override void calculate(IPricingEngineResults r) { 
    4452            OneAssetOption.Results results = r as OneAssetOption.Results; 
    4553            setGridLimits(); 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/FDVanillaEngine.cs

    r159 r160  
    2929        \ingroup vanillaengines 
    3030    */ 
    31     public class FDVanillaEngine
     31    public class FDVanillaEngine : IOptionPricingEngine
    3232        protected GeneralizedBlackScholesProcess process_; 
    3333        protected int timeSteps_, gridPoints_; 
     
    4848        const double safetyZoneFactor_ = 1.1; 
    4949 
     50        // required for generics 
     51        public FDVanillaEngine() { } 
     52        public virtual IOptionPricingEngine factory(GeneralizedBlackScholesProcess process, 
     53                                                    int timeSteps, int gridPoints, bool timeDependent) { 
     54            return new FDVanillaEngine(process, timeSteps, gridPoints, timeDependent); 
     55        } 
    5056 
    5157        //public FDVanillaEngine(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, 
     
    6066        } 
    6167 
     68 
    6269        public Vector grid() { return intrinsicValues_.grid(); } 
    6370 
    64         protected void setGridLimits() { 
     71        protected virtual void setGridLimits() { 
    6572            setGridLimits(process_.stateVariable().link.value(), getResidualTime()); 
    6673            ensureStrikeInGrid(); 
    67         } 
    68  
    69         protected virtual void setupArguments(IPricingEngineArguments a) { 
    70             OneAssetOption.Arguments args = a as OneAssetOption.Arguments; 
    71             if (args == null) throw new ApplicationException("incorrect argument type"); 
    72  
    73             exerciseDate_ = args.exercise.lastDate(); 
    74             payoff_ = args.payoff; 
    75             requiredGridValue_ = ((StrikedTypePayoff)payoff_).strike(); 
    7674        } 
    7775 
     
    142140                                : minGridPoints); 
    143141        } 
     142 
     143        #region IOptionPricingEngine 
     144        public virtual void setupArguments(IPricingEngineArguments a) { 
     145            OneAssetOption.Arguments args = a as OneAssetOption.Arguments; 
     146            if (args == null) throw new ApplicationException("incorrect argument type"); 
     147 
     148            exerciseDate_ = args.exercise.lastDate(); 
     149            payoff_ = args.payoff; 
     150            requiredGridValue_ = ((StrikedTypePayoff)payoff_).strike(); 
     151        } 
     152        public virtual void calculate(IPricingEngineResults r) { throw new NotSupportedException(); } 
     153        #endregion 
    144154    } 
    145155 
    146156 
    147     public class FDEngineAdapter<Base, Engine> { 
    148         //Base optionBase; 
    149  
    150         ////public FDEngineAdapter(GeneralizedBlackScholesProcess process, Size timeSteps=100, Size gridPoints=100, bool timeDependent = false) 
    151         //public FDEngineAdapter(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) 
    152         //    : base(process, timeSteps, gridPoints, timeDependent) { 
    153         //    process.registerWith(update); 
    154         //} 
    155  
    156         //protected void calculate() { 
    157         //    optionBase.setupArguments(arguments_); 
    158         //    optionBase.calculate(results_); 
    159         //} 
     157    public interface IOptionPricingEngine { 
     158        void calculate(IPricingEngineResults r); 
     159        void setupArguments(IPricingEngineArguments a); 
     160        IOptionPricingEngine factory(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent); 
     161    } 
     162 
     163    public class FDEngineAdapter<Base, Engine, ArgumentsType, ResultsType> : FDVanillaEngine 
     164        where Base : IOptionPricingEngine, new() 
     165        where Engine : IGenericEngine<ArgumentsType, ResultsType> 
     166        where ArgumentsType : IPricingEngineArguments, new() 
     167        where ResultsType : IPricingEngineResults, new() { 
     168 
     169        Base optionBase; 
     170 
     171        //public FDEngineAdapter(GeneralizedBlackScholesProcess process, Size timeSteps=100, Size gridPoints=100, bool timeDependent = false) 
     172        public FDEngineAdapter(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) { 
     173            optionBase = (Base)new Base().factory(process, timeSteps, gridPoints, timeDependent); 
     174            process.registerWith(update); 
     175        } 
     176 
     177        protected void calculate() { 
     178            optionBase.setupArguments(arguments_); 
     179            optionBase.calculate(results_); 
     180        } 
     181 
     182        #region IGenericEngine copy-cat 
     183        protected IPricingEngineArguments arguments_ = new ArgumentsType(); 
     184        protected IPricingEngineResults results_ = new ResultsType(); 
     185 
     186        public IPricingEngineArguments getArguments() { return arguments_; } 
     187        public IPricingEngineResults getResults() { return results_; } 
     188        public void reset() { results_.reset(); } 
     189 
     190        #region Observer & Observable 
     191        // observable interface 
     192        public event Callback notifyObserversEvent; 
     193        public void registerWith(Callback handler) { notifyObserversEvent += handler; } 
     194        public void unregisterWith(Callback handler) { notifyObserversEvent -= handler; } 
     195        protected void notifyObservers() { 
     196            Callback handler = notifyObserversEvent; 
     197            if (handler != null) { 
     198                handler(); 
     199            } 
     200        } 
     201 
     202        public void update() { notifyObservers(); } 
     203        #endregion 
     204        #endregion 
    160205    } 
    161206} 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/fdconditions.cs

    r159 r160  
    2323 
    2424namespace QLNet { 
    25     public class FDAmericanCondition<baseEngine> : FDVanillaEngine where baseEngine : FDVanillaEngine { 
     25    public class FDAmericanCondition<baseEngine> : FDVanillaEngine, IOptionPricingEngine  
     26            where baseEngine : IOptionPricingEngine, new() { 
     27        baseEngine engine_; 
     28 
     29        // required for generics 
     30        public FDAmericanCondition() { } 
     31        public override IOptionPricingEngine factory(GeneralizedBlackScholesProcess process, 
     32                                            int timeSteps, int gridPoints, bool timeDependent) { 
     33            engine_ = (baseEngine)new baseEngine().factory(process, timeSteps, gridPoints, timeDependent); 
     34            return engine_; 
     35        } 
     36 
    2637        //public FDAmericanCondition(GeneralizedBlackScholesProcess process, 
    2738        //     int timeSteps = 100, int gridPoints = 100, bool timeDependent = false) 
    28         public FDAmericanCondition(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) 
    29             : base(process, timeSteps, gridPoints, timeDependent) {
    30        
     39        public FDAmericanCondition(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) { 
     40       
     41 
    3142        protected void initializeStepCondition() { 
    32             // baseEngine::stepCondition_ = new AmericanCondition(baseEngine::intrinsicValues_.values()); 
     43            // stepCondition_ = new AmericanCondition(intrinsicValues_.values()); 
     44        } 
     45 
     46        public override void setupArguments(IPricingEngineArguments a) { 
     47            engine_.setupArguments(a); 
     48        } 
     49        public override void calculate(IPricingEngineResults r) { 
     50            engine_.calculate(r); 
    3351        } 
    3452    } 
  • trunk/QLNet/QLNet/Pricingengines/vanilla/fddividendengine.cs

    r159 r160  
    2929    */ 
    3030    public abstract class FDDividendEngineBase : FDMultiPeriodEngine { 
    31          
    3231        //public FDDividendEngineBase(GeneralizedBlackScholesProcess process, 
    3332        //    Size timeSteps = 100, Size gridPoints = 100, bool timeDependent = false) 
     
    3534            : base(process, timeSteps, gridPoints, timeDependent) {} 
    3635 
    37         protected override void setupArguments(IPricingEngineArguments a) { 
     36        public override void setupArguments(IPricingEngineArguments a) { 
    3837            DividendVanillaOption.Arguments args = a as DividendVanillaOption.Arguments; 
    3938            if (args == null) throw new ApplicationException("incorrect argument type"); 
     
    6059        } 
    6160    } 
     61 
     62 
     63    //! Finite-differences pricing engine for dividend options using 
     64    // escowed dividend model 
     65    /*! \ingroup vanillaengines */ 
     66    /* The merton 73 engine is the classic engine described in most 
     67       derivatives texts.  However, Haug, Haug, and Lewis in 
     68       "Back to Basics: a new approach to the discrete dividend 
     69       problem" argues that this scheme underprices call options. 
     70       This is set as the default engine, because it is consistent 
     71       with the analytic version. 
     72    */ 
     73    public class FDDividendEngineMerton73 : FDDividendEngineBase { 
     74        public FDDividendEngineMerton73(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) 
     75            : base(process, timeSteps, gridPoints, timeDependent) {} 
     76         
     77        // The value of the x axis is the NPV of the underlying minus the 
     78        // value of the paid dividends. 
     79 
     80        // Note that to get the PDE to work, I have to scale the values 
     81        // and not shift them.  This means that the price curve assumes 
     82        // that the dividends are scaled with the value of the underlying. 
     83        // 
     84        protected override void setGridLimits() { 
     85            double paidDividends = 0.0; 
     86            for (int i=0; i<events_.Count; i++) { 
     87                if (getDividendTime(i) >= 0.0) 
     88                    paidDividends += getDiscountedDividend(i); 
     89            } 
     90 
     91            base.setGridLimits(process_.stateVariable().link.value()-paidDividends, getResidualTime()); 
     92            ensureStrikeInGrid(); 
     93        } 
     94 
     95        // TODO:  Make this work for both fixed and scaled dividends 
     96        protected override void executeIntermediateStep(int step) { 
     97            double scaleFactor = getDiscountedDividend(step) / center_ + 1.0; 
     98            sMin_ *= scaleFactor; 
     99            sMax_ *= scaleFactor; 
     100            center_ *= scaleFactor; 
     101 
     102            intrinsicValues_.scaleGrid(scaleFactor); 
     103            initializeInitialCondition(); 
     104            prices_.scaleGrid(scaleFactor); 
     105            initializeOperator(); 
     106            initializeModel(); 
     107 
     108            initializeStepCondition(); 
     109            stepCondition_.applyTo(prices_.values(), getDividendTime(step)); 
     110        } 
     111    } 
     112 
     113 
     114    //! Finite-differences engine for dividend options using shifted dividends 
     115    /*! \ingroup vanillaengines */ 
     116    /* This engine uses the same algorithm that was used in quantlib 
     117       in versions 0.3.11 and earlier.  It produces results that 
     118       are different from the Merton 73 engine. 
     119 
     120       \todo Review literature to see whether this is described 
     121    */ 
     122    public class FDDividendEngineShiftScale : FDDividendEngineBase { 
     123        public FDDividendEngineShiftScale(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, bool timeDependent) 
     124            : base(process, timeSteps, gridPoints, timeDependent) {} 
     125       
     126        protected override void setGridLimits() { 
     127            double underlying = process_.stateVariable().link.value(); 
     128            for (int i=0; i<events_.Count; i++) { 
     129                Dividend dividend = events_[i] as Dividend; 
     130                if (dividend == null) continue; 
     131                if (getDividendTime(i) < 0.0) continue; 
     132                underlying -= dividend.amount(underlying); 
     133            } 
     134 
     135            base.setGridLimits(underlying, getResidualTime()); 
     136            ensureStrikeInGrid(); 
     137        } 
     138 
     139        protected override void executeIntermediateStep(int step) { 
     140            Dividend dividend = events_[step] as Dividend; 
     141            if (dividend == null) return; 
     142            DividendAdder adder = new DividendAdder(dividend); 
     143            sMin_ = adder.value(sMin_); 
     144            sMax_ = adder.value(sMax_); 
     145            center_ = adder.value(center_); 
     146            intrinsicValues_.transformGrid(adder.value); 
     147 
     148            initializeInitialCondition(); 
     149            prices_.transformGrid(adder.value); 
     150 
     151            initializeOperator(); 
     152            initializeModel(); 
     153 
     154            initializeStepCondition(); 
     155            stepCondition_.applyTo(prices_.values(), getDividendTime(step)); 
     156        } 
     157 
     158        class DividendAdder { 
     159            private Dividend dividend; 
     160             
     161            public DividendAdder(Dividend d) { 
     162                dividend = d; 
     163            } 
     164            public double value(double x) { 
     165                return x + dividend.amount(x); 
     166            } 
     167        } 
     168    } 
    62169}