File: FiniteDifferenceMethods.cs

package info (click to toggle)
quantlib-swig 1.40-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,280 kB
  • sloc: python: 6,024; java: 1,552; cs: 774; makefile: 349; sh: 22
file content (146 lines) | stat: -rw-r--r-- 5,220 bytes parent folder | download
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);
        }
    }
}