1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
Copyright (C) 2020 Klaus Spanderen
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
<quantlib-dev@lists.sf.net>. The license is also available online at
<https://www.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 QuantLib;
using static QuantLib.NQuantLibc;
namespace FiniteDifferenceMethods
{
class FdmDemo
{
// test class for the operator delegate and proxy
public class FdmBSDelegate : FdmLinearOpCompositeDelegate
{
private readonly FdmLinearOpComposite op;
public FdmBSDelegate(FdmLinearOpComposite op)
{
this.op = op;
}
override public uint size()
{
return op.size();
}
override public void setTime(double t1, double t2)
{
op.setTime(t1, t2);
}
override public QlArray apply(QlArray r)
{
return op.apply(r);
}
override public QlArray apply_direction(uint i, QlArray r)
{
return op.apply_direction(i, r);
}
override public QlArray solve_splitting(uint i, QlArray r, double s)
{
return op.solve_splitting(i, r, s);
}
};
static void Main(string[] args)
{
const int xSteps = 100;
const int tSteps = 25;
const int dampingSteps = 0;
Date today = new Date(15, Month.January, 2020);
Settings.instance().setEvaluationDate(today);
DayCounter dc = new Actual365Fixed();
YieldTermStructureHandle rTS = new YieldTermStructureHandle(
new FlatForward(today, 0.06, dc));
YieldTermStructureHandle qTS = new YieldTermStructureHandle(
new FlatForward(today, 0.02, dc));
const double strike = 110.0;
StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, strike);
Date maturityDate = today.Add(new Period(1, TimeUnit.Years));
double maturity = dc.yearFraction(today, maturityDate);
Exercise exercise = new AmericanExercise(today, maturityDate);
Instrument vanillaOption = new VanillaOption(payoff, exercise);
QuoteHandle spot = new QuoteHandle(new SimpleQuote(100.0));
BlackVolTermStructureHandle volatility = new BlackVolTermStructureHandle(
new BlackConstantVol(today, new TARGET(), 0.20, dc));
BlackScholesMertonProcess process =
new BlackScholesMertonProcess(spot, qTS, rTS, volatility);
vanillaOption.setPricingEngine(new FdBlackScholesVanillaEngine(
process, tSteps, xSteps, dampingSteps));
double expected = vanillaOption.NPV();
// build an PDE engine from scratch
Fdm1dMesher equityMesher = new FdmBlackScholesMesher(
xSteps, process, maturity, strike,
nullDouble(), nullDouble(), 0.0001, 1.5,
new DoublePair(strike, 0.1));
FdmMesherComposite mesher = new FdmMesherComposite(equityMesher);
FdmLinearOpComposite op = new FdmBlackScholesOp(mesher, process, strike);
FdmInnerValueCalculator calc = new FdmLogInnerValue(payoff, mesher, 0);
QlArray x = new QlArray(equityMesher.size());
QlArray rhs = new QlArray(equityMesher.size());
FdmLinearOpIterator iter = mesher.layout().begin();
for (uint i = 0; i < rhs.size(); ++i, iter.increment())
{
x.set(i, mesher.location(iter, 0));
rhs.set(i, calc.avgInnerValue(iter, maturity));
}
FdmBoundaryConditionSet bcSet = new FdmBoundaryConditionSet();
FdmStepConditionComposite stepCondition =
FdmStepConditionComposite.vanillaComposite(
new DividendSchedule(), exercise, mesher, calc, today, dc);
FdmLinearOpComposite proxyOp = new FdmLinearOpCompositeProxy(
new FdmBSDelegate(op));
FdmBackwardSolver solver = new FdmBackwardSolver(
proxyOp, bcSet, stepCondition, FdmSchemeDesc.Douglas());
solver.rollback(rhs, maturity, 0.0, tSteps, dampingSteps);
double logS = Math.Log(spot.value());
double calculated = new CubicNaturalSpline(x, rhs).call(logS);
Console.WriteLine("Homebrew PDE engine : {0:0.0000}", calculated);
Console.WriteLine("FdBlackScholesVanillaEngine: {0:0.0000}", expected);
}
}
}
|