Changeset 160
- Timestamp:
- 05/10/08 11:07:16 (2 months ago)
- Files:
-
- trunk/QLNet/QLNet/Instruments/OneAssetOption.cs (modified) (1 diff)
- trunk/QLNet/QLNet/Pricingengines/vanilla/FDAmericanEngine.cs (modified) (1 diff)
- trunk/QLNet/QLNet/Pricingengines/vanilla/FDMultiPeriodEngine.cs (modified) (11 diffs)
- trunk/QLNet/QLNet/Pricingengines/vanilla/FDStepConditionEngine.cs (modified) (2 diffs)
- trunk/QLNet/QLNet/Pricingengines/vanilla/FDVanillaEngine.cs (modified) (4 diffs)
- trunk/QLNet/QLNet/Pricingengines/vanilla/fdconditions.cs (modified) (1 diff)
- trunk/QLNet/QLNet/Pricingengines/vanilla/fddividendengine.cs (modified) (3 diffs)
- trunk/QLNet/QLNet1.vsmdi (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/QLNet/QLNet/Instruments/OneAssetOption.cs
r131 r160 158 158 } 159 159 160 public class Engine : GenericEngine<OneAssetOption.Arguments, OneAssetOption.Results> {} 160 public class Engine : GenericEngine<OneAssetOption.Arguments, OneAssetOption.Results> { 161 } 161 162 } 162 163 } trunk/QLNet/QLNet/Pricingengines/vanilla/FDAmericanEngine.cs
r159 r160 30 30 - the correctness of the returned greeks is tested by reproducing numerical derivatives. 31 31 */ 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) { } 33 36 } 34 37 } trunk/QLNet/QLNet/Pricingengines/vanilla/FDMultiPeriodEngine.cs
r159 r160 23 23 24 24 namespace QLNet { 25 public abstractclass FDMultiPeriodEngine : FDVanillaEngine {25 public class FDMultiPeriodEngine : FDVanillaEngine { 26 26 protected List<Event> events_; 27 27 protected List<double> stoppingTimes_; … … 32 32 protected FiniteDifferenceModel<CrankNicolson<TridiagonalOperator>> model_; 33 33 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 35 40 //protected FDMultiPeriodEngine(GeneralizedBlackScholesProcess process, 36 41 // int gridPoints = 100, int timeSteps = 100, bool timeDependent = false) … … 50 55 } 51 56 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) { 53 73 base.setupArguments(a); 54 74 OneAssetOption.Arguments args = a as OneAssetOption.Arguments; … … 58 78 int n = args.exercise.dates().Count; 59 79 stoppingTimes_ = new List<double>(n); 60 for (int i =0; i<n; ++i)80 for (int i = 0; i < n; ++i) 61 81 stoppingTimes_[i] = process_.time(args.exercise.date(i)); 62 82 } 63 83 64 p rotected virtualvoid calculate(IPricingEngineResults r) {84 public override void calculate(IPricingEngineResults r) { 65 85 OneAssetOption.Results results = r as OneAssetOption.Results; 66 86 if (results == null) throw new ApplicationException("incorrect results type"); … … 80 100 if (!(getDividendTime(0) >= 0)) 81 101 throw new ApplicationException("first date (" + getDividendTime(0) + ") cannot be negative"); 82 if (getDividendTime(0) < getResidualTime() * dateTolerance ){102 if (getDividendTime(0) < getResidualTime() * dateTolerance) { 83 103 firstDateIsZero = true; 84 104 firstIndex = 0; 85 if (dateNumber >= 2)105 if (dateNumber >= 2) 86 106 firstNonZeroDate = getDividendTime(1); 87 107 } … … 97 117 if (dateNumber >= 2) { 98 118 for (j = 1; j < dateNumber; j++) 99 if (!(getDividendTime(j -1) < getDividendTime(j)))119 if (!(getDividendTime(j - 1) < getDividendTime(j))) 100 120 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)); 102 122 } 103 123 } 104 124 105 double dt = getResidualTime() /(timeStepPerPeriod_*(dateNumber+1));125 double dt = getResidualTime() / (timeStepPerPeriod_ * (dateNumber + 1)); 106 126 107 127 // Ensure that dt is always smaller than the first non-zero date 108 128 if (firstNonZeroDate <= dt) 109 dt = firstNonZeroDate /2.0;129 dt = firstNonZeroDate / 2.0; 110 130 111 131 setGridLimits(); … … 117 137 118 138 prices_ = intrinsicValues_; 119 if (lastDateIsResTime)139 if (lastDateIsResTime) 120 140 executeIntermediateStep(dateNumber - 1); 121 141 … … 126 146 beginDate = getResidualTime(); 127 147 else 128 beginDate = getDividendTime(j +1);148 beginDate = getDividendTime(j + 1); 129 149 130 150 if (j >= 0) … … 136 156 model_.rollback(ref temp, beginDate, endDate, timeStepPerPeriod_, stepCondition_); 137 157 prices_.setValues((Vector)temp); 138 158 139 159 if (j >= 0) 140 160 executeIntermediateStep(j); … … 145 165 prices_.setValues((Vector)temp); 146 166 147 if (firstDateIsZero)167 if (firstDateIsZero) 148 168 executeIntermediateStep(0); 149 169 … … 154 174 } 155 175 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 169 177 } 170 178 } trunk/QLNet/QLNet/Pricingengines/vanilla/FDStepConditionEngine.cs
r159 r160 31 31 protected SampledCurve controlPrices_; 32 32 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 33 41 //public FDStepConditionEngine(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, 34 42 // bool timeDependent = false) … … 41 49 protected virtual void initializeStepCondition() { } 42 50 43 p rotected virtualvoid calculate(IPricingEngineResults r) {51 public override void calculate(IPricingEngineResults r) { 44 52 OneAssetOption.Results results = r as OneAssetOption.Results; 45 53 setGridLimits(); trunk/QLNet/QLNet/Pricingengines/vanilla/FDVanillaEngine.cs
r159 r160 29 29 \ingroup vanillaengines 30 30 */ 31 public class FDVanillaEngine {31 public class FDVanillaEngine : IOptionPricingEngine { 32 32 protected GeneralizedBlackScholesProcess process_; 33 33 protected int timeSteps_, gridPoints_; … … 48 48 const double safetyZoneFactor_ = 1.1; 49 49 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 } 50 56 51 57 //public FDVanillaEngine(GeneralizedBlackScholesProcess process, int timeSteps, int gridPoints, … … 60 66 } 61 67 68 62 69 public Vector grid() { return intrinsicValues_.grid(); } 63 70 64 protected v oid setGridLimits() {71 protected virtual void setGridLimits() { 65 72 setGridLimits(process_.stateVariable().link.value(), getResidualTime()); 66 73 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();76 74 } 77 75 … … 142 140 : minGridPoints); 143 141 } 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 144 154 } 145 155 146 156 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 160 205 } 161 206 } trunk/QLNet/QLNet/Pricingengines/vanilla/fdconditions.cs
r159 r160 23 23 24 24 namespace 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 26 37 //public FDAmericanCondition(GeneralizedBlackScholesProcess process, 27 38 // 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 31 42 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); 33 51 } 34 52 } trunk/QLNet/QLNet/Pricingengines/vanilla/fddividendengine.cs
r159 r160 29 29 */ 30 30 public abstract class FDDividendEngineBase : FDMultiPeriodEngine { 31 32 31 //public FDDividendEngineBase(GeneralizedBlackScholesProcess process, 33 32 // Size timeSteps = 100, Size gridPoints = 100, bool timeDependent = false) … … 35 34 : base(process, timeSteps, gridPoints, timeDependent) {} 36 35 37 p rotectedoverride void setupArguments(IPricingEngineArguments a) {36 public override void setupArguments(IPricingEngineArguments a) { 38 37 DividendVanillaOption.Arguments args = a as DividendVanillaOption.Arguments; 39 38 if (args == null) throw new ApplicationException("incorrect argument type"); … … 60 59 } 61 60 } 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 } 62 169 }