├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE.txt ├── NOTICE.txt ├── READ ME.txt ├── README.md ├── build.xml ├── docs ├── algorithmicdifferentiation-dependencyinjection │ ├── experiment-05.jpg │ ├── experiment-05.svg │ └── index.html ├── algorithmicdifferentiation-forwardsensitivities │ └── index.html ├── black-scholes-hedge-simulator │ ├── experiment-01.png │ └── index.html ├── factor-reduction │ ├── experiment-01.png │ └── index.html ├── finmathnet-style.css ├── getting-started │ └── index.html ├── index.html ├── mathematical-finance-laboratory.png ├── montecarlo-bermudan │ ├── BermudanExerciseAdmissible.svg │ ├── BermudanExerciseForesight.svg │ └── index.html ├── montecarlo-blackscholes │ ├── experiment-01.jpg │ ├── experiment-01.svg │ ├── experiment-02.jpg │ ├── experiment-02.svg │ ├── experiment-03.jpg │ ├── experiment-03.svg │ └── index.html ├── parallel-computing-animation │ ├── ParallelComputingAnimation5b.png │ └── index.html ├── random-numbers │ ├── experiment-01a.svg │ ├── experiment-01b.svg │ ├── experiment-02a.svg │ ├── experiment-02b.svg │ └── index.html └── risk-neutral-density │ ├── experiment-01.svg │ ├── experiment-02.jpg │ ├── experiment-02.svg │ └── index.html ├── finmath-checkstyle.xml ├── lib ├── LICENSE for commons-lang3-3.4 │ ├── LICENSE.txt │ ├── NOTICE.txt │ └── RELEASE-NOTES.txt ├── LICENSE for commons-math3-3.6 │ ├── LICENSE.txt │ ├── NOTICE.txt │ └── RELEASE-NOTES.txt ├── colt-1.2.0.jar ├── commons-lang3-3.4.jar ├── commons-math3-3.6.1.jar ├── finmath-lib-1.3.0.jar ├── finmath-lib-2.4.2-java6.jar ├── finmath-lib-3.2.10.jar ├── jblas-1.2.4.jar └── joda-time-2.9.jar ├── logging.properties ├── mvnw ├── mvnw.cmd ├── notebooks ├── Black Scholes Model Monte-Carlo Simulation.json └── Regression of Continuation Value.json ├── pom.xml ├── spreadsheets └── Pseudo Random and Low Discrepancy Sequences │ ├── DISCLAIMER.txt │ ├── Halton Sequence 2 (wrong).ods │ ├── Halton Sequence 2 (wrong).xls │ ├── Halton Sequence.ods │ ├── Halton Sequence.xls │ ├── RandomNumbers.ods │ └── RandomNumbers.xls └── src ├── main ├── java │ ├── module-info.java │ └── net │ │ └── finmath │ │ └── experiments │ │ ├── blackscholes │ │ ├── AnalyticOptionValuation.java │ │ ├── BlackScholesOptionCalculator.java │ │ ├── DisplaceLognormalImpliedVolExperiment.java │ │ └── package-info.java │ │ ├── computation │ │ ├── ComputerArithmeticExperiment.java │ │ ├── ComputerArithmeticSolverQuadraticEquationExperiment.java │ │ ├── RoundingExperiment.java │ │ └── package-info.java │ │ ├── concurrency │ │ ├── ForkJoinPoolTest.java │ │ ├── NestedParallelForEachAndSynchronization.java │ │ ├── NestedParallelForEachBenchmark.java │ │ ├── NestedParallelForEachTest.java │ │ └── package-info.java │ │ ├── dice │ │ ├── DICEModelExperiment.java │ │ └── package-info.java │ │ ├── factorreduction │ │ ├── FactorMatrixExperiment.java │ │ ├── FactorReduction.java │ │ ├── FactorReductionApp.java │ │ ├── FactorReductionPanel.java │ │ └── package-info.java │ │ ├── hedgesimulator │ │ ├── HedgeSimulator.java │ │ ├── HedgeSimulatorApp.java │ │ ├── HedgeSimulatorPanel.java │ │ └── package-info.java │ │ ├── liboverview │ │ ├── MonteCarloBlackScholesEuropeanOptionDeltaAAD.java │ │ ├── MonteCarloBlackScholesEuropeanOptionValuation.java │ │ ├── MonteCarloLIBORMarketModelValuation.java │ │ ├── MonteCarloModelEuropeanOptionValuation.java │ │ └── RandomVariableDependencyInjection.java │ │ ├── marketdata │ │ └── curves │ │ │ └── CurveExperiments.java │ │ ├── montecarlo │ │ ├── BrownianMotionTests.java │ │ ├── MonteCarloIntegrationExperiment.java │ │ ├── MonteCarloIntegrationParallelizedExperiment.java │ │ ├── MonteCarloIntegrationWithQuasiRandomNumbersExperiment.java │ │ ├── assetderivativevaluation │ │ │ ├── BachelierModelPathsPlot.java │ │ │ ├── BlackScholesModelNumerairePlot.java │ │ │ ├── BlackScholesModelPathsPlot.java │ │ │ ├── BlackScholesMonteCarloValuationTest.java │ │ │ ├── DeltaHedgeSimulation.java │ │ │ ├── MonteCarloValuationExperiments.java │ │ │ ├── MonteCarloValuationUsingOpenCL.java │ │ │ ├── SimpleBlackScholesMonteCarloValuation.java │ │ │ ├── package-info.java │ │ │ └── products │ │ │ │ ├── BermudanOptionExerciseInMonteCarloBlackScholesPlot.java │ │ │ │ ├── BermudanOptionExerciseInMonteCarloPrimalDualMethodExperiments.java │ │ │ │ ├── BermudanOptionExperiments.java │ │ │ │ ├── EuropeanOption2.java │ │ │ │ ├── EuropeanOptionDeltaLikelihood.java │ │ │ │ ├── EuropeanOptionDeltaPathwise.java │ │ │ │ ├── EuropeanOptionGammaLikelihood.java │ │ │ │ ├── EuropeanOptionGammaPathwise.java │ │ │ │ ├── EuropeanOptionRhoLikelihood.java │ │ │ │ ├── EuropeanOptionRhoPathwise.java │ │ │ │ ├── EuropeanOptionVegaLikelihood.java │ │ │ │ ├── EuropeanOptionVegaPathwise.java │ │ │ │ └── package-info.java │ │ ├── automaticdifferentiation │ │ │ ├── MonteCarloBlackScholesModelDigitalOptionAADRegressionSensitivitiesLMM.java │ │ │ └── package-info.java │ │ ├── eulerscheme │ │ │ ├── BrownianMotionCoarseTimeDiscretization.java │ │ │ └── EulerSchemeIllustrationPlot.java │ │ ├── interestrates │ │ │ ├── ForwardRate.java │ │ │ ├── LIBORMarketModelBermudanValuationTest.java │ │ │ ├── LIBORMarketModelCalibrationATMTest.java │ │ │ ├── ModelFactory.java │ │ │ ├── NonlinearDiscounting.java │ │ │ ├── TermStructureMonteCarloSimulationExperiments.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── process │ │ │ └── MonteCarloProcessObjectsExperiments.java │ │ ├── randomnumbers │ │ │ ├── HaltonSequence.java │ │ │ ├── PseudoRandomNumberSequence.java │ │ │ └── package-info.java │ │ └── schemes │ │ │ ├── LogProcessEulerScheme.java │ │ │ ├── LogProcessLogEulerScheme.java │ │ │ ├── LogProcessMilsteinScheme.java │ │ │ ├── LognormalProcess.java │ │ │ ├── MonteCarloSchemeTests.java │ │ │ └── package-info.java │ │ ├── optimizer │ │ └── LevenbergMarquardtTest.java │ │ ├── optionvalueinterpolation │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── performance │ │ └── package-info.java │ │ ├── randomnumbers │ │ └── NormalViaICDFPlot.java │ │ ├── reproduction │ │ ├── BackProjection.java │ │ ├── BackProjectionAnalysis.java │ │ ├── DiscretizedLognormalDistribution.java │ │ ├── ReproductionSimulationExperiment.java │ │ └── package-info.java │ │ ├── shortrate │ │ ├── CIRSimulation.java │ │ └── package-info.java │ │ └── timeseries │ │ └── backcasting │ │ ├── BackcastExperiment.java │ │ └── CorrelationBasedBackcast.java └── resources │ └── experiment.jsh └── test └── java └── net └── finmath └── experiments └── reproduction └── BackProjectionTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /results/ 3 | /.settings 4 | release.properties 5 | /.project 6 | /.classpath 7 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | 2 | NOTICE for finmath lib 3 | --------------------------- 4 | 5 | Copyright (c) 2008-2019 Christian Fries, http://www.christianfries.com/finmath 6 | For updates on finmath lib see http://www.finmath.net 7 | Permission to use and/or redistribute this work is granted under the terms of the Apache License Version 2.0, with the exception that any usage related to military applications is expressly forbidden. The software and documentation made available under the terms of this license are provided with no warranty. 8 | 9 | 10 | NOTICE for Colt Library 11 | --------------------------- 12 | 13 | Packages cern.colt* , cern.jet*, cern.clhep: 14 | 15 | Copyright (c) 1999 CERN - European Organization for Nuclear Research. 16 | Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. CERN makes no representations about the suitability of this software for any purpose. It is provided "as is" without expressed or implied warranty. 17 | 18 | Packages hep.aida.*: 19 | 20 | Written by Pavel Binko, Dino Ferrero Merlino, Wolfgang Hoschek, Tony Johnson, Andreas Pfeiffer, and others. Check the FreeHEP home page for more info. Permission to use and/or redistribute this work is granted under the terms of the LGPL License, with the exception that any usage related to military applications is expressly forbidden. The software and documentation made available under the terms of this license are provided with no warranty. 21 | 22 | 23 | NOTICE for Apache Software 24 | --------------------------- 25 | 26 | This product includes software developed by 27 | The Apache Software Foundation (http://www.apache.org/). 28 | 29 | -------------------------------------------------------------------------------- /READ ME.txt: -------------------------------------------------------------------------------- 1 | finmath experiments 2 | =================== 3 | 4 | Experiments and demos based on finmath lib. 5 | 6 | NOTE: 7 | ----- 8 | 9 | For updates check http://www.finmath.net/finmath-lib 10 | 11 | 12 | DOCUMENTATION: 13 | -------------- 14 | 15 | For API documentation see http://www.finmath.net/finmath-lib 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | finmath experiments 2 | =================== 3 | 4 | Experiments and demos based on finmath lib. 5 | 6 | See also http://finmath.github.io/finmath-experiments/ 7 | 8 | Projects 9 | -------- 10 | 11 | **finmath lib** 12 | Java library providing implementations of methodologies related to 13 | mathematical finance, but applicable to other fields (e.g., the 14 | Monte-Carlo simulation of SDEs and the estimation of conditional 15 | expectations in Monte-Carlo). 16 | See http://finmath.net/finmath-lib 17 | 18 | **finmath spreadsheets** 19 | A collection of spreadsheets building upon *finmath lib* and 20 | providing end user solutions (e.g, interest rate curve calibration 21 | or calibration of a forward rate model, aka LIBOR market model). 22 | See http://finmath.net/spreadsheets/ 23 | 24 | **finmath experiments** 25 | Small experiments, illustrating some aspects of mathematical 26 | finance. Also illustrates how to use the finmath lib. 27 | 28 | **finmath lib plot extensions** 29 | Convenient abstractions of some plotting libraries and example usages of finmath lib. 30 | See http://finmath.net/finmath-lib-plot-extensions/ 31 | 32 | 33 | Documentation 34 | ------------- 35 | 36 | - [finmath lib API documentation][] 37 | provides the documentation of the library api. 38 | - [finmath.net special topics][] 39 | cover some selected topics with demo spreadsheets and uml diagrams. 40 | Some topics come with additional documentations (technical papers). 41 | 42 | 43 | License 44 | ------- 45 | 46 | The code of "finmath lib" and "finmath experiments" (packages 47 | `net.finmath.*`) are distributed under the [Apache License version 48 | 2.0][], unless otherwise explicitly stated. 49 | 50 | [finmath lib API documentation]: http://www.finmath.net/java/finmath-lib/doc/ 51 | [finmath.net special topics]: http://www.finmath.net/topics 52 | [Apache License version 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html 53 | 54 | 55 | Instruction for Contributors for Experiments 56 | ------- 57 | 58 | Here are a few remarks in case you like to create and contribute a web page with experiments, similar to the ones in the `docs` folder of this repo. 59 | 60 | - Used the same HTML header as in the example on Monte-Carlo simulation, see montecarlo-blackscholes (adjusting title and description). 61 | 62 | - Use the correct HTML tags for code blocks, i.e. the tag `
` and everything that is inside. Just change the title text, the id and the code inside. 63 | 64 | - If you like to use the Copy to clipboard button, make sure that value in data-clipboard-target corresponds to the id in the pre-tag. Like experiment1 in this example: 65 | 66 | 67 |

68 | 
69 | 			
70 | 71 | - Check your page on a mobile device (iPhone, iPad). Long package names or class names can lead to layout issues. 72 | 73 | - If you create plots, the best quality can be achieved by saving the plot as SVG. Use `plot.saveAsSVG(new File(filename), 800, 450))` 74 | 75 | - Use LaTeX with MathJax: you can write LaTeX inside the HTML using `\(` and `\)` to mark the start and the end. 76 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 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 | -------------------------------------------------------------------------------- /docs/algorithmicdifferentiation-dependencyinjection/experiment-05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/algorithmicdifferentiation-dependencyinjection/experiment-05.jpg -------------------------------------------------------------------------------- /docs/black-scholes-hedge-simulator/experiment-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/black-scholes-hedge-simulator/experiment-01.png -------------------------------------------------------------------------------- /docs/black-scholes-hedge-simulator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | finMath.net: Experiments: Black-Scholes Hedge Simulator for a European Call Option 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 | 48 |
49 | finMath.net 50 |
51 | 52 |

Black-Scholes Hedge Simulator for a European Call Option

53 | 54 | Getting Started 55 | 56 |

57 | Checkout finmath-experiments from git and run maven (mvn or mvnw) from 58 | its directory. This will start a JShell. 59 | See Getting Started for details. 60 |

61 | 62 |

Running the Hedge Simulator

63 | 64 |

65 | 66 | Note: due to a bug in Java 11.0.7 for macOS, the simulator does not run 67 | when launched with Java 11.0.7. Please use Java 11.0.8 or Java 14.0.1 or better. 68 | 69 |

70 |

71 | The Hedge Simulator is a GUI application. To run it just type the following in JShell: 72 |

73 | 74 |
75 | JShell: 76 | 77 |

78 | 				net.finmath.experiments.hedgesimulator.HedgeSimulator.run();
79 | 			
80 |
81 | 82 |
83 | 84 |
85 | 86 |

Where to continue

87 | 88 | You may continue with 89 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/factor-reduction/experiment-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/factor-reduction/experiment-01.png -------------------------------------------------------------------------------- /docs/finmathnet-style.css: -------------------------------------------------------------------------------- 1 | body { font-family: arial, sans-serif; color: #333; font-size: 14pt; line-height: 22pt; font-weight: normal; margin: 20px 20px 20px 20px; background: #fff; } header { font-size: 16pt; float: right; height: 34pt; } svg { width: 100%; } .logo-white { font-size: 14pt; background: #fff; color: #000; padding:10pt; padding-right:0pt; border: solid #999 1px; border-right: 0px; } .logo-red { font-size: 14pt; background: #900; color: #fff; padding: 10pt; padding-left:0pt; border: solid #999 1px; border-left: 0px; } author { font-style: italic; font-weight: bold; line-height: 10pt; font-size: 9pt; color: gray; position: relative; top: -10pt; } a:link { color: #a00; text-decoration: none; } a:visited { color: #800; text-decoration: none; } a:hover { color: #f00; text-decoration: underline; } code { color: #000; text-decoration: none; font-family: monospace; } .codeinline { font-size: 12pt; } .codeboxwithheader { background: gainsboro; border: solid 1px; margin-top: 20px; margin-bottom: 20px; font-size: 11pt; } .codebox { clear: both; } pre { margin-top: 0px; background: white; } pre > code { margin-top: 0px; background: white; font-family: "Lucida Console"; } .btn { font-family: "Arial"; font-size: 14pt; } dt { margin-top: 5pt; font-style: italic; } p { } h1 { font-size: 20pt; line-height: 22pt; font-style: normal; font-weight: normal; text-decoration: none; padding-top: 16pt; border-bottom: solid #333 1px; } h2 { font-size: 18pt; line-height: 20pt; font-style: normal; font-weight: normal; text-decoration: none; padding-top: 14pt; } h3 { font-size: 17pt; line-height: 18pt; font-style: normal; font-weight: normal; text-decoration: none; padding-top: 12pt; } h4 { font-size: 16pt; line-height: 17pt; font-style: normal; font-weight: normal; text-decoration: none; padding-top: 12pt; } h5 { font-size: 15pt; line-height: 16pt; font-style: normal; font-weight: normal; text-decoration: none; padding-top: 11pt; } ul { padding-bottom: 4pt; } table { background-color: transparent; } tr { } td.tocnumber { font-size: 9pt; line-height: 10pt; font-weight: normal; background-color: transparent; vertical-align: top; margin: 0px; padding-top: 3px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; border: dotted 0px; border-bottom: dotted 0px; } td.toctext { font-size: 9pt; line-height: 10pt; font-weight: normal; background-color: transparent; vertical-align: top; margin: 0px; padding-top: 3px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; border: dotted 0px; border-bottom: dotted 1px; } td.tocpage { font-size: 9pt; line-height: 10pt; font-weight: normal; background-color: transparent; vertical-align: bottom; text-align: right; margin: 0px; padding-top: 3px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; border: dotted 0px; border-bottom: dotted 1px; } td { font-size: 9pt; line-height: 12pt; font-weight: normal; background-color: transparent; vertical-align: top; margin: 0pt; padding: 3pt; border: dotted 0pt; } .bibliography .bibliographyAuthor { font-weight: bold; } .bibliography .bibliographyTitle { font-weight: bold; } table.tableWithBorder { background-color: transparent; border-collapse: collapse; border-spacing: 0px; margin-top: 16pt; border: solid 1px; } .tableWithBorder tr { background-color: transparent; } .tableWithBorder th { font-size: 9pt; line-height: 10pt; font-weight: bold; background-color: transparent; vertical-align: top; text-align: left; margin: 2px; padding-top: 0px; padding-bottom: 3px; padding-left: 2px; padding-right: 2px; border: dotted 1px; border-bottom: solid 1px; border-bottom: solid 1px; } .tableWithBorder td { font-size: 9pt; line-height: 10pt; font-weight: normal; background-color: transparent; vertical-align: top; text-align: left; margin: 2px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; padding-right: 10px; border: dotted 1px; border-top: solid 0px; } #navigation-header { display: table; width: 100%; background: #990000; margin-bottom: 20px; padding-top: 0px; padding-bottom: 0px; border: 1px solid #333; } #footer { text-align: center; color: #ddd; background-color: #fff; border-top: solid 1px #333; border-bottom: solid 1px #333; position: fixed; bottom: 0px; left: 0px; width: 100%; margin-bottom: 0px; } #navigation-header-left { background: transparent; float: left; } #navigation-header-right { background: transparent; float: right; } .navigation-header-item { background: #bbb; display: inline; height: 25px; font-size: 12px; font-weight: normal; padding-left: 15px; padding-right: 15px; padding-top: 0px; padding-bottom: 5px; border-top: 1px solid #333; border-left: 1px solid #333; border-right: 1px solid #333; margin-left: 7px; margin-right: 7px; margin-bottom: 0px; margin-top: 0px; } .navigation-header-item:hover { background: #eee; } .icon64 { float: left; margin-left: 2px; margin-right: 5px; margin-bottom: 5px; width: 64px; padding: 0px; border: #999 solid 1px; } .icon128 { float: left; margin-left: 2px; margin-right: 10px; margin-bottom: 10px; width: 128px; padding: 0px; border: #999 solid 1px; } .paragraph-block { border-left: solid 1px #900; padding-left: 5px; } -------------------------------------------------------------------------------- /docs/getting-started/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | finMath.net: Experiments: Getting Started 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 46 | 47 |
48 | finMath.net 49 |
50 | 51 |

Getting started

52 | 53 |

54 | Some experiments on this site use Java JShell started from a Maven project as a starting point. 55 |

56 | 57 |

58 | There are several options on how you can start that JShell. 59 |

60 | 61 |

Requirement

62 | 63 |

64 | To checkout the project you need git. 65 |

66 | 67 |

Running from a Command Shell (macOS: Terminal, Windows: Cmd.exe)

68 | 69 |

Checkout the finmath-experiments project from its Git repository and run it via Maven

70 | 71 | This assumes that you have Git installed on your machine. 72 | 73 |
    74 |
  1. Open a command shell
  2. 75 |
  3. Type mkdir git (to create a folder git, if you do not have one)
  4. 76 |
  5. Type cd git (to enter your git folder)
  6. 77 |
  7. Next, clone (i.e. download) the repository (git), change to the cloned directory (cd) and start jshell via Maven (mvn) by typing the following three commands:
  8. 78 |
79 | 80 |
81 | Terminal Window 82 | 83 |

 84 | 				git clone https://github.com/finmath/finmath-experiments        
 85 | 				cd finmath-experiments
 86 | 				mvnw
 87 | 			
88 |
89 | Note: If mvnw fails, try ./mvnw on Linux, macOS or .\mvnw on Windows. Alternatively, if you Maven installed run mvn. 90 | 91 |

Running from a Eclipse

92 | 93 | You may also directly run the JShell experiments from Ecplise. To do so: 94 | 95 | 116 | 117 |

Where to continue

118 | 119 | You may continue with 120 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | finMath.net: Experiments 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 28 |
29 | finMath.net 30 |
31 | 32 |

33 | 34 | Experiments 35 |

36 | 37 |

Risk Neutral Valuation

38 | 39 | Christian Fries, February 2020. 40 | 41 |

42 | Some experiments on risk neutral valuation. 43 |

44 | 45 |
    46 |
  1. 47 | Risk Neutral Density (Breeden-Litzenberger Theorem). 48 |
  2. 49 |
50 | 51 |

Random Numbers

52 | 53 | Christian Fries, June 2020. 54 | 55 |

56 | Small experiments related to the generation of normal distributed random numbers. 57 |

58 | 59 |
    60 |
  1. 61 | Quasi and pseudo random number sequences. 62 |
  2. 63 |
64 | 65 |

Black-Scholes Model Hedge Simulation GUI

66 | 67 |
    68 |
  1. 69 | Black-Scholes Model Hedge Simulation 70 |
  2. 71 |
72 | 73 |

Monte-Carlo Simulation, Bermudan Options, and Algorithmic Differentiation

74 | 75 | Christian Fries, February 2020, July 2020. 76 | 77 |

78 | Some experiments on Monte-Carlo simulation, Bermudan option valuation in a Monte-Carlo simulation and algorithmic differentiation. 79 |

80 | 81 |
    82 |
  1. 83 | Monte-Carlo Simulation 84 |
  2. 85 |
  3. 86 | Bermudan Option Valuation in a Monte-Carlo Simulation of Black-Scholes Model 87 |
  4. 88 |
  5. 89 | Algorithmic Differentiation and Dependency Injection: Basics with AAD 90 |
  6. 91 |
  7. 92 | Algorithmic Differentiation for Forward Sensitivities 93 |
  8. 94 |
95 | 96 |

Interest Rate Modelling

97 | 98 | Christian Fries, February 2021. 99 | 100 |

101 | Some experiments related to interest rate modelling. 102 |

103 | 104 |
    105 |
  1. 106 | Factor Reduction / Correlated Brownian Motion 107 |
  2. 108 |
  3. 109 |
  4. 110 |
111 | 112 |
113 | 114 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/mathematical-finance-laboratory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/mathematical-finance-laboratory.png -------------------------------------------------------------------------------- /docs/montecarlo-blackscholes/experiment-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/montecarlo-blackscholes/experiment-01.jpg -------------------------------------------------------------------------------- /docs/montecarlo-blackscholes/experiment-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/montecarlo-blackscholes/experiment-02.jpg -------------------------------------------------------------------------------- /docs/montecarlo-blackscholes/experiment-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/montecarlo-blackscholes/experiment-03.jpg -------------------------------------------------------------------------------- /docs/parallel-computing-animation/ParallelComputingAnimation5b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/parallel-computing-animation/ParallelComputingAnimation5b.png -------------------------------------------------------------------------------- /docs/parallel-computing-animation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | finMath.net: Experiments: Parallel Computing Animation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 | 48 |
49 | finMath.net 50 |
51 | 52 |

Parallel Computing Animation

53 | 54 |

55 | To run the animation checkout the project JavaGPUExperiments and launch 56 | com.christianfries.teaching.gpu.ParallelComputingAnimation via Maven exec. 57 |

58 | 59 |
60 | Terminal / Console: 61 | 62 |

63 | 				git clone https://github.com/cfries/JavaGPUExperiments
64 | 				cd JavaGPUExperiments
65 | 				mvn clean install exec:java -Dexec.mainClass=com.christianfries.teaching.gpu.ParallelComputingAnimation
66 | 			 
67 |
68 | 69 | Below you see a screenshot of the application. 70 |
71 | 72 |
73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/risk-neutral-density/experiment-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/docs/risk-neutral-density/experiment-02.jpg -------------------------------------------------------------------------------- /lib/LICENSE for commons-lang3-3.4/NOTICE.txt: -------------------------------------------------------------------------------- 1 | Apache Commons Lang 2 | Copyright 2001-2015 The Apache Software Foundation 3 | 4 | This product includes software developed at 5 | The Apache Software Foundation (http://www.apache.org/). 6 | 7 | This product includes software from the Spring Framework, 8 | under the Apache License 2.0 (see: StringUtils.containsWhitespace()) 9 | -------------------------------------------------------------------------------- /lib/LICENSE for commons-lang3-3.4/RELEASE-NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/LICENSE for commons-lang3-3.4/RELEASE-NOTES.txt -------------------------------------------------------------------------------- /lib/LICENSE for commons-math3-3.6/NOTICE.txt: -------------------------------------------------------------------------------- 1 | Apache Commons Math 2 | Copyright 2001-2016 The Apache Software Foundation 3 | 4 | This product includes software developed at 5 | The Apache Software Foundation (http://www.apache.org/). 6 | 7 | This product includes software developed for Orekit by 8 | CS Systèmes d'Information (http://www.c-s.fr/) 9 | Copyright 2010-2012 CS Systèmes d'Information 10 | -------------------------------------------------------------------------------- /lib/LICENSE for commons-math3-3.6/RELEASE-NOTES.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache Commons Math 3.6.1 RELEASE NOTES 3 | 4 | The Apache Commons Math team is pleased to announce the release of 5 | commons-math3-3.6.1 6 | 7 | The Apache Commons Math project is a library of lightweight, self-contained 8 | mathematics and statistics components addressing the most common practical 9 | problems not immediately available in the Java programming language or 10 | commons-lang. 11 | 12 | This is a minor bug fix release. It incorporates three bug fixes since version 13 | 3.6. The minimum version of the Java platform required to compile and use 14 | Commons Math 3.6.1 is Java 5. 15 | 16 | Changes in this version include: 17 | 18 | Fixed Bugs: 19 | o MATH-1316: Fix code example in User Guide > Statistics > Multiple linear regression. 20 | o MATH-1342: Fix ODE integrators when multiple events are nearly simultaneous. 21 | 22 | Changes: 23 | o MATH-1317: Add uniformity unit tests to "RandomGeneratorAbstractTest". 24 | 25 | 26 | For complete information on Apache Commons Math, including instructions on how 27 | to submit bug reports, patches, or suggestions for improvement, see the Apache 28 | Commons Math website: 29 | 30 | http://commons.apache.org/proper/commons-math/ 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/colt-1.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/colt-1.2.0.jar -------------------------------------------------------------------------------- /lib/commons-lang3-3.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/commons-lang3-3.4.jar -------------------------------------------------------------------------------- /lib/commons-math3-3.6.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/commons-math3-3.6.1.jar -------------------------------------------------------------------------------- /lib/finmath-lib-1.3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/finmath-lib-1.3.0.jar -------------------------------------------------------------------------------- /lib/finmath-lib-2.4.2-java6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/finmath-lib-2.4.2-java6.jar -------------------------------------------------------------------------------- /lib/finmath-lib-3.2.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/finmath-lib-3.2.10.jar -------------------------------------------------------------------------------- /lib/jblas-1.2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/jblas-1.2.4.jar -------------------------------------------------------------------------------- /lib/joda-time-2.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/lib/joda-time-2.9.jar -------------------------------------------------------------------------------- /logging.properties: -------------------------------------------------------------------------------- 1 | handlers = java.util.logging.ConsoleHandler, java.util.logging.SocketHandler 2 | 3 | # Enable this to show logging for all loggers 4 | #.level=FINE 5 | 6 | net.finmath.level=FINE 7 | 8 | # Logging messages to be send to the console 9 | java.util.logging.ConsoleHandler.level=FINE 10 | 11 | # Logging messages to be send to TCP/IP socket 12 | #java.util.logging.SocketHandler.level=FINE 13 | #java.util.logging.SocketHandler.host=127.0.0.1 14 | #java.util.logging.SocketHandler.port=50505 15 | #java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter 16 | 17 | -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | 2 | DISCLAIMER 3 | --------------------------- 4 | 5 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6 | -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence 2 (wrong).ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence 2 (wrong).ods -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence 2 (wrong).xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence 2 (wrong).xls -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence.ods -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/Halton Sequence.xls -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/RandomNumbers.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/RandomNumbers.ods -------------------------------------------------------------------------------- /spreadsheets/Pseudo Random and Low Discrepancy Sequences/RandomNumbers.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finmath/finmath-experiments/1a652ef083db4b6903b0eb06f43806f06b0e6a64/spreadsheets/Pseudo Random and Low Discrepancy Sequences/RandomNumbers.xls -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | 2 | module net.finmath.experiments { 3 | exports net.finmath.experiments.hedgesimulator; 4 | exports net.finmath.experiments.factorreduction; 5 | exports net.finmath.experiments.shortrate; 6 | exports net.finmath.experiments.montecarlo.assetderivativevaluation; 7 | exports net.finmath.experiments.montecarlo.automaticdifferentiation; 8 | exports net.finmath.experiments.montecarlo.interestrates; 9 | exports net.finmath.experiments.reproduction; 10 | 11 | requires transitive net.finmath.lib; 12 | requires transitive net.finmath.opencl; 13 | requires transitive net.finmath.plots; 14 | 15 | requires org.jfree.jfreechart; 16 | requires junit; 17 | 18 | requires javafx.controls; 19 | requires javafx.base; 20 | requires transitive javafx.graphics; 21 | requires javafx.swing; 22 | 23 | requires java.logging; 24 | requires java.management; 25 | requires java.sql; 26 | requires commons.csv; 27 | requires commons.math3; 28 | requires org.apache.commons.lang3; 29 | } -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/blackscholes/AnalyticOptionValuation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com. 3 | * 4 | * Created on 10.06.2014 5 | */ 6 | 7 | package net.finmath.experiments.blackscholes; 8 | 9 | import java.text.DecimalFormat; 10 | import java.text.NumberFormat; 11 | 12 | import net.finmath.functions.AnalyticFormulas; 13 | 14 | /** 15 | * @author Christian Fries 16 | */ 17 | public class AnalyticOptionValuation { 18 | 19 | static NumberFormat formatReal2 = new DecimalFormat("#0.00"); 20 | 21 | /** 22 | * @param args 23 | */ 24 | public static void main(String[] args) { 25 | final double spot1 = 100.0; 26 | final double spot2 = 100.0; 27 | final double volatility1 = 0.3; 28 | final double volatility2 = 0.2; 29 | final double riskFreeRate = 0.05; 30 | final double optionMaturity = 2.0; 31 | 32 | System.out.println("Value of exchange option for different correlation parameters:"); 33 | for(double rho = -1.0; rho <= 1.0; rho += 0.1) { 34 | final double value = AnalyticFormulas.margrabeExchangeOptionValue(spot1, spot2, volatility1, volatility2, rho, optionMaturity); 35 | System.out.println(formatReal2.format(rho) + "\t" + formatReal2.format(value)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/blackscholes/DisplaceLognormalImpliedVolExperiment.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.blackscholes; 2 | 3 | import java.util.List; 4 | import java.util.function.DoubleBinaryOperator; 5 | import java.util.function.DoubleUnaryOperator; 6 | 7 | import net.finmath.functions.AnalyticFormulas; 8 | import net.finmath.plots.Named; 9 | import net.finmath.plots.Plot; 10 | import net.finmath.plots.Plot2D; 11 | 12 | /** 13 | * Plot the shape of the implied log-normal volatility of values created from 14 | * displaced log-normal models. 15 | * 16 | * @author Christian Fries 17 | */ 18 | public class DisplaceLognormalImpliedVolExperiment { 19 | 20 | public static void main(String[] args) throws Exception { 21 | 22 | final double forward = 0.02; 23 | final double optionMaturity = 5.0; 24 | final double lognormalVolatility = 0.212; 25 | 26 | final double payoffUnit = 1.0; // does not matter in this conversion 27 | 28 | final DoubleBinaryOperator volCurveForDisplacement = (optionStrike, displacement) -> { 29 | final double optionValue = AnalyticFormulas.blackScholesGeneralizedOptionValue( 30 | forward+displacement, lognormalVolatility, optionMaturity, optionStrike+displacement, payoffUnit); 31 | final double impliedLognormalVolatility = AnalyticFormulas.blackScholesOptionImpliedVolatility(forward, optionMaturity, optionStrike, payoffUnit, optionValue); 32 | return impliedLognormalVolatility; 33 | }; 34 | 35 | final DoubleUnaryOperator volCurve0 = x -> volCurveForDisplacement.applyAsDouble(x, 0.00); 36 | final DoubleUnaryOperator volCurve1 = x -> volCurveForDisplacement.applyAsDouble(x, 0.01); 37 | final DoubleUnaryOperator volCurve2 = x -> volCurveForDisplacement.applyAsDouble(x, 0.02); 38 | 39 | final Plot plot = new Plot2D(0.01, 0.05, 100, List.of( 40 | new Named<>("0.00", volCurve0), 41 | new Named<>("0.01", volCurve1), 42 | new Named<>("0.02", volCurve2) 43 | )); 44 | plot.setXAxisLabel("strike"); 45 | plot.setYAxisLabel("implied lognormal vol"); 46 | plot.setIsLegendVisible(true); 47 | plot.setTitle("Displacement"); 48 | plot.show(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/blackscholes/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to the Black Scholes model. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.blackscholes; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/computation/ComputerArithmeticSolverQuadraticEquationExperiment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 18.10.2012 5 | */ 6 | package net.finmath.experiments.computation; 7 | 8 | /** 9 | * A simple class illustrating an aspect related to floating point arithmetic: 10 | * the loss of significance. 11 | * 12 | * @author Christian Fries 13 | */ 14 | public class ComputerArithmeticSolverQuadraticEquationExperiment { 15 | 16 | public static void main(String[] args) { 17 | 18 | /* 19 | * Test solution of quadratic equation 20 | */ 21 | final double p = 1000000.0; 22 | final double q = 1; 23 | System.out.println("\nLoss of significance: Solution of quadratic equation f(x) = 0 with"); 24 | System.out.println("f(x) = x^2 - 2px + q and p=" + p + " q="+q+""); 25 | System.out.println("__________________________________________________________________"); 26 | 27 | System.out.println("Method 1"); 28 | 29 | final double x1 = p - Math.sqrt(p * p - q); 30 | final double value1 = (x1 * x1 - 2 * p * x1 + q); 31 | 32 | System.out.println("Solution.: x = " + x1); 33 | System.out.println("Result: f(x) = " + value1); 34 | 35 | System.out.println(""); 36 | System.out.println("Method 2"); 37 | 38 | final double x2 = q / (p + Math.sqrt(p * p - q)); 39 | final double value2 = (x2 * x2 - 2 * p * x2 + q); 40 | 41 | System.out.println("Solution.: x = " + x2); 42 | System.out.print("Result: f(x) = " + value2); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/computation/RoundingExperiment.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.computation; 2 | 3 | /** 4 | * Simple experiment illustrating 1 + epsilon = 1 5 | * 6 | * @author Christian Fries 7 | */ 8 | public class RoundingExperiment { 9 | 10 | public static void main(String[] args) { 11 | 12 | System.out.println("Rounding: "); 13 | 14 | double x = 1.0; 15 | 16 | double epsilon = 1E-16; 17 | 18 | double y = x + epsilon; // 1 + 10^-16 = 1.0000000000000001 19 | 20 | System.out.println("x = " + x); 21 | System.out.println("𝜖 = " + epsilon); 22 | System.out.println("y = x + 𝜖 = " + y); 23 | 24 | System.out.println("x == y is " + (x==y)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/computation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to computer arithmetics. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.computation; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/concurrency/ForkJoinPoolTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 03.05.2014 5 | */ 6 | package net.finmath.experiments.concurrency; 7 | 8 | import java.util.concurrent.Semaphore; 9 | import java.util.stream.IntStream; 10 | 11 | /** 12 | * This is a test of Java 8 parallel streams. 13 | * 14 | * The idea behind this code is that the Semaphore concurrentExecutions 15 | * should limit the parallel executions of the outer forEach (which is an 16 | * IntStream.range(0,numberOfTasks).parallel().forEach (for example: 17 | * the parallel executions of the outer forEach should be limited due to a 18 | * memory constrain). 19 | * 20 | * Inside the execution block of the outer forEach we use another parallel stream 21 | * to create an inner forEach. The number of concurrent 22 | * executions of the inner forEach is not limited by us (it is however limited by a 23 | * system property "java.util.concurrent.ForkJoinPool.common.parallelism"). 24 | * 25 | * Problem: If the semaphore is used AND the inner forEach is active, then 26 | * the execution will be DEADLOCKED. 27 | * 28 | * @author Christian Fries 29 | */ 30 | public class ForkJoinPoolTest { 31 | 32 | // Any combination of the booleans works, except (true,true,false) 33 | private final boolean isUseSemaphore = true; 34 | private final boolean isUseInnerStream = true; 35 | private final boolean isWrappedInnerLoopThread = false; 36 | 37 | private final int numberOfTasksInOuterLoop = 20; // In real applications this can be a large number (e.g. > 1000). 38 | private final int numberOfTasksInInnerLoop = 100; // In real applications this can be a large number (e.g. > 1000). 39 | private final int concurrentExecusionsLimitInOuterLoop = 5; 40 | private final int concurrentExecutionsLimitForStreams = 10; 41 | 42 | private final Semaphore concurrentExecutions; 43 | 44 | public static void main(String[] args) { 45 | (new ForkJoinPoolTest()).testNestedLoops(); 46 | } 47 | 48 | public ForkJoinPoolTest() { 49 | super(); 50 | this.concurrentExecutions = new Semaphore(concurrentExecusionsLimitInOuterLoop); 51 | } 52 | 53 | public void testNestedLoops() { 54 | 55 | System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism",Integer.toString(concurrentExecutionsLimitForStreams)); 56 | System.out.println("java.util.concurrent.ForkJoinPool.common.parallelism = " + System.getProperty("java.util.concurrent.ForkJoinPool.common.parallelism")); 57 | 58 | // Outer loop 59 | IntStream.range(0,numberOfTasksInOuterLoop).parallel().forEach(i -> { 60 | 61 | if(isUseSemaphore) { 62 | concurrentExecutions.acquireUninterruptibly(); 63 | } 64 | 65 | try { 66 | System.out.println(i + "\t" + "-" + "\t" + concurrentExecutions.availablePermits() + "\t" + Thread.currentThread()); 67 | 68 | if(isUseInnerStream) { 69 | try { 70 | Thread.sleep(10*numberOfTasksInInnerLoop); 71 | } catch (final Exception e) { 72 | } 73 | runCodeWhichUsesParallelStream(i, Thread.currentThread().toString()); 74 | } 75 | else { 76 | try { 77 | Thread.sleep(10*numberOfTasksInInnerLoop); 78 | } catch (final Exception e) { 79 | } 80 | } 81 | } 82 | finally { 83 | if(isUseSemaphore) { 84 | concurrentExecutions.release(); 85 | } 86 | } 87 | }); 88 | 89 | System.out.println("D O N E"); 90 | } 91 | 92 | /** 93 | * Runs code in a parallel forEach using streams. 94 | * 95 | * @param numberOfTasksInInnerLoop Number of tasks to execute. 96 | */ 97 | private void runCodeWhichUsesParallelStream(int i, String callingThread) { 98 | 99 | final Runnable innerLoop = new Runnable() { 100 | @Override 101 | public void run() { 102 | // Inner loop 103 | IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> { 104 | try { 105 | System.out.println(i + "\t" + j + "\t" + concurrentExecutions.availablePermits() + "\t" + callingThread + "\t" + Thread.currentThread()); 106 | Thread.sleep(10); 107 | } catch (final Exception e) { 108 | } 109 | }); 110 | } 111 | }; 112 | 113 | if(isWrappedInnerLoopThread) { 114 | final Thread t = new Thread(innerLoop, "Wrapper Thread"); 115 | try { 116 | t.start(); 117 | t.join(); 118 | } catch (final InterruptedException e) { 119 | } 120 | } 121 | else { 122 | innerLoop.run(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/concurrency/NestedParallelForEachTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 06.05.2014 5 | */ 6 | package net.finmath.experiments.concurrency; 7 | 8 | import java.util.stream.IntStream; 9 | 10 | /** 11 | * This is a test of Java 8 parallel streams. 12 | * 13 | * We are testing nested parallel forEach loops, which appear to 14 | * have unexpected poor performance in Java 1.8.0u5. 15 | * 16 | * We have a nested stream.parallel().forEach(): 17 | * 18 | * The inner loop is independent (stateless, no interference, etc. - except of the use of a common pool) 19 | * and consumes 1 second in total in the worst case, namely if processed sequential. 20 | * Half of the tasks of the outer loop consume 10 seconds prior that loop. 21 | * Half consume 10 seconds after that loop. 22 | * We have a boolean which allows to switch the inner loop from parallel() to sequential(). 23 | * Hence every thread consumes 11 seconds (worst case) in total. 24 | * Now: submitting 24 outer-loop-tasks to a pool of 8 we would expect 24/8 * 11 = 33 seconds at best (on an 8 core or better machine). 25 | * 26 | * The result is: 27 | * - With inner sequential loop: 33 seconds. 28 | * - With inner parallel loop: >80 seconds (I had 92 seconds). 29 | * 30 | * Now, there is a funny workaround. The method 31 | * wraps every operation in its own thread. Use this to wrap the inner loop in its 32 | * own thread via 33 | * {@code 34 | * wrapInThread( () -> 35 | * IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> { 36 | * burnTime(10); 37 | * })); 38 | * } 39 | * And the performance issue is gone. Note that this does not introduce any new 40 | * parallelism and that the inner loop tasks are still submitted to the same 41 | * common fork-join pool. 42 | * 43 | * The reason, why this fix works, is because the inner loop is started form a Thread 44 | * and not from possible ForkJoinWorkerThread of the outer loop. In the latter case 45 | * the ForkJoinTask by mistake assumes that the starting thread is a worker of itself 46 | * and issues a join, effectively joining inner loop tasks with outer loop tasks. 47 | * 48 | * @author Christian Fries 49 | */ 50 | public class NestedParallelForEachTest { 51 | 52 | // The program uses 33 sec with this boolean to false and around 80+ with this boolean true: 53 | private final boolean isInnerStreamParallel = true; 54 | 55 | // Setup: Inner loop task 0.01 sec in worse case. Outer loop task: 10 sec + inner loop. This setup: (100 * 0.01 sec + 10 sec) * 24/8 = 33 sec. 56 | private final int numberOfTasksInOuterLoop = 24; // In real applications this can be a large number (e.g. > 1000). 57 | private final int numberOfTasksInInnerLoop = 100; // In real applications this can be a large number (e.g. > 1000). 58 | private final int concurrentExecutionsLimitForStreams = 8; // java.util.concurrent.ForkJoinPool.common.parallelism 59 | 60 | // For those, who do not trust the use of Thread.sleep(). 61 | private final boolean isCPUTimeBurned = false; // Set to true, if you like a true loop, and not Thread.sleep() 62 | private final long cpuTimeBurningCountPerMillis = 800000; // You might need to calibrate this for your machine 63 | 64 | public static void main(String[] args) { 65 | (new NestedParallelForEachTest()).testNestedLoops(); 66 | } 67 | 68 | public void testNestedLoops() { 69 | 70 | final long start = System.currentTimeMillis(); 71 | 72 | System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism",Integer.toString(concurrentExecutionsLimitForStreams)); 73 | System.out.println("java.util.concurrent.ForkJoinPool.common.parallelism = " + System.getProperty("java.util.concurrent.ForkJoinPool.common.parallelism")); 74 | 75 | // Outer loop 76 | IntStream.range(0,numberOfTasksInOuterLoop).parallel().forEach(i -> { 77 | 78 | try { 79 | if(i < 10) { 80 | burnTime(10 * 1000); 81 | } 82 | 83 | System.out.println(i + "\t" + Thread.currentThread()); 84 | 85 | if(isInnerStreamParallel) { 86 | // Inner loop as parallel: worst case (sequential) it takes 10 * numberOfTasksInInnerLoop millis 87 | IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> { 88 | burnTime(10); 89 | }); 90 | } 91 | else { 92 | // Inner loop as sequential 93 | IntStream.range(0,numberOfTasksInInnerLoop).sequential().forEach(j -> { 94 | burnTime(10); 95 | }); 96 | } 97 | 98 | if(i >= 10) { 99 | burnTime(10 * 1000); 100 | } 101 | } catch (final Exception e) { e.printStackTrace(); } 102 | 103 | }); 104 | 105 | final long end = System.currentTimeMillis(); 106 | 107 | System.out.println("Done in " + (end-start)/1000 + " sec."); 108 | } 109 | 110 | private double burnTime(long millis) { 111 | if(isCPUTimeBurned) { 112 | double x = 0; 113 | for(long i=0; i new FactorReductionApp().start(new Stage())); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/factorreduction/FactorReductionApp.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.factorreduction; 2 | 3 | import javafx.application.Application; 4 | import javafx.application.Platform; 5 | import javafx.embed.swing.SwingNode; 6 | import javafx.scene.Scene; 7 | import javafx.scene.layout.StackPane; 8 | import javafx.stage.Stage; 9 | 10 | public class FactorReductionApp extends Application { 11 | 12 | @Override 13 | public void start(Stage stage) { 14 | final SwingNode swingNode = new SwingNode(); 15 | createAndSetSwingContent(swingNode); 16 | swingNode.setVisible(true); 17 | 18 | final StackPane pane = new StackPane(); 19 | pane.getChildren().add(swingNode); 20 | 21 | final Scene scene = new Scene(pane, 1200, 800); 22 | 23 | stage.setScene(scene); 24 | // stage.setFullScreen(true); 25 | stage.show(); 26 | } 27 | 28 | @Override 29 | public void stop() { 30 | } 31 | 32 | private void createAndSetSwingContent(final SwingNode swingNode) { 33 | Platform.runLater(new Runnable() { 34 | @Override 35 | public void run() { 36 | final FactorReductionPanel panel = new FactorReductionPanel(); 37 | swingNode.setContent(panel); 38 | } 39 | }); 40 | } 41 | 42 | public static void main(String[] args) { 43 | launch(args); 44 | } 45 | 46 | public static void launch() { 47 | main(new String[0]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/factorreduction/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes to explore factor reduction. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.factorreduction; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/hedgesimulator/HedgeSimulator.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.hedgesimulator; 2 | 3 | import javafx.application.Platform; 4 | import javafx.embed.swing.JFXPanel; 5 | import javafx.stage.Stage; 6 | 7 | public class HedgeSimulator { 8 | 9 | public static void main(String[] args) { 10 | System.out.println("Starting HedgeSimulator..."); 11 | run(); 12 | } 13 | 14 | public static void run() { 15 | new JFXPanel(); // Hack to ensure that Java FX Platform is initialized 16 | Platform.runLater(() -> new HedgeSimulatorApp().start(new Stage())); 17 | Platform.setImplicitExit(false); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/hedgesimulator/HedgeSimulatorApp.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.hedgesimulator; 2 | 3 | import javafx.application.Application; 4 | import javafx.application.Platform; 5 | import javafx.embed.swing.SwingNode; 6 | import javafx.scene.Scene; 7 | import javafx.scene.layout.StackPane; 8 | import javafx.stage.Stage; 9 | 10 | public class HedgeSimulatorApp extends Application { 11 | 12 | @Override 13 | public void start(Stage stage) { 14 | final SwingNode swingNode = new SwingNode(); 15 | createAndSetSwingContent(swingNode); 16 | swingNode.setVisible(true); 17 | 18 | final StackPane pane = new StackPane(); 19 | pane.getChildren().add(swingNode); 20 | 21 | final Scene scene = new Scene(pane, 1200, 800); 22 | 23 | stage.setScene(scene); 24 | // stage.setFullScreen(true); 25 | stage.show(); 26 | } 27 | 28 | @Override 29 | public void stop() { 30 | } 31 | 32 | private void createAndSetSwingContent(final SwingNode swingNode) { 33 | Platform.runLater(new Runnable() { 34 | @Override 35 | public void run() { 36 | final HedgeSimulatorPanel panel = new HedgeSimulatorPanel(); 37 | swingNode.setContent(panel); 38 | } 39 | }); 40 | } 41 | 42 | public static void main(String[] args) { 43 | launch(args); 44 | } 45 | 46 | public static void launch() { 47 | main(new String[0]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/hedgesimulator/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes to explore hedging. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.hedgesimulator; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/liboverview/MonteCarloBlackScholesEuropeanOptionDeltaAAD.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.liboverview; 2 | 3 | import net.finmath.exception.CalculationException; 4 | import net.finmath.functions.AnalyticFormulas; 5 | import net.finmath.montecarlo.BrownianMotion; 6 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 7 | import net.finmath.montecarlo.MonteCarloProduct; 8 | import net.finmath.montecarlo.RandomVariableFactory; 9 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloAssetModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 12 | import net.finmath.montecarlo.automaticdifferentiation.RandomVariableDifferentiable; 13 | import net.finmath.montecarlo.automaticdifferentiation.backward.RandomVariableDifferentiableAADFactory; 14 | import net.finmath.montecarlo.model.ProcessModel; 15 | import net.finmath.montecarlo.process.EulerSchemeFromProcessModel; 16 | import net.finmath.montecarlo.process.MonteCarloProcess; 17 | import net.finmath.plots.DoubleToRandomVariableFunction; 18 | import net.finmath.plots.PlotProcess2D; 19 | import net.finmath.stochastic.RandomVariable; 20 | import net.finmath.time.TimeDiscretization; 21 | import net.finmath.time.TimeDiscretizationFromArray; 22 | 23 | public class MonteCarloBlackScholesEuropeanOptionDeltaAAD { 24 | 25 | public static void main(String[] args) throws CalculationException { 26 | testValuationUsingProduct(); 27 | } 28 | 29 | public static void testValuationUsingProduct() throws CalculationException { 30 | 31 | System.out.println("\n"); 32 | System.out.println("Valuation (using product):"); 33 | System.out.println("_".repeat(79)); 34 | 35 | RandomVariableFactory randomVariableFactory = new RandomVariableDifferentiableAADFactory(); 36 | 37 | // Model X - BlackScholesModel Parameters 38 | double initialValue = 100.0; // X(0) 39 | double riskFreeRate = 0.05; // r 40 | double sigma = 0.20; // σ 41 | ProcessModel processModel = new BlackScholesModel(initialValue, riskFreeRate, sigma, randomVariableFactory); 42 | 43 | // TimeDiscretization 44 | double initialTime = 0.0; 45 | int numberOfTimeSteps = 50; 46 | double dt = 0.5; 47 | TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray(initialTime, numberOfTimeSteps, dt); 48 | 49 | // BrownianMotion 50 | int numberOfFactors = 1; 51 | int numberOfPaths = 100000; 52 | int randomNumberSeed = 3216; 53 | BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers(timeDiscretization, numberOfFactors, numberOfPaths, randomNumberSeed); 54 | 55 | // Time discrete process (Euler Scheme) 56 | MonteCarloProcess process = new EulerSchemeFromProcessModel(processModel, brownianMotion); 57 | 58 | // Wrapped to AssetModel for valuation 59 | MonteCarloAssetModel model = new MonteCarloAssetModel(process); 60 | 61 | /* 62 | * Valuation of paying max(S(T)-K,0) in T 63 | */ 64 | double maturity = 10.0; // T 65 | double strike = 160.0; // K 66 | MonteCarloProduct product = new EuropeanOption(maturity, strike); 67 | 68 | RandomVariable value = product.getValue(initialTime, model); 69 | 70 | RandomVariable delta = ((RandomVariableDifferentiable)value).getGradient().get(((RandomVariableDifferentiable)((BlackScholesModel)processModel).getInitialValue(process)[0]).getID()); 71 | 72 | double valueAnalytic = AnalyticFormulas.blackScholesOptionValue(initialValue, riskFreeRate, sigma, maturity, strike); 73 | 74 | double deltaAnalytic = AnalyticFormulas.blackScholesOptionDelta(initialValue, riskFreeRate, sigma, maturity, strike); 75 | 76 | System.out.println("value...............: " + value.average().doubleValue()); 77 | System.out.println("value analytic......: " + valueAnalytic); 78 | System.out.println("delta...............: " + delta.average().doubleValue()); 79 | System.out.println("delta analytic......: " + deltaAnalytic); 80 | 81 | 82 | // Create a function, plotting paths t -> S(t) 83 | DoubleToRandomVariableFunction paths = time -> model.getAssetValue(timeDiscretization.getTimeIndex(time), 0 /* assetIndex: 0 is S(t) */); 84 | 85 | /* 86 | * Plot 87 | */ 88 | 89 | // Plot 100 of paths against the given time discretization. 90 | var plot = new PlotProcess2D(timeDiscretization, paths, 1000); 91 | plot.setTitle(processModel.getClass().getSimpleName() + " paths").setXAxisLabel("time").setYAxisLabel("value"); 92 | plot.show(); 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/liboverview/MonteCarloBlackScholesEuropeanOptionValuation.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.liboverview; 2 | 3 | import net.finmath.exception.CalculationException; 4 | import net.finmath.functions.AnalyticFormulas; 5 | import net.finmath.montecarlo.BrownianMotion; 6 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 7 | import net.finmath.montecarlo.MonteCarloProduct; 8 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloAssetModel; 9 | import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 11 | import net.finmath.montecarlo.model.ProcessModel; 12 | import net.finmath.montecarlo.process.EulerSchemeFromProcessModel; 13 | import net.finmath.montecarlo.process.MonteCarloProcess; 14 | import net.finmath.plots.DoubleToRandomVariableFunction; 15 | import net.finmath.plots.PlotProcess2D; 16 | import net.finmath.time.TimeDiscretization; 17 | import net.finmath.time.TimeDiscretizationFromArray; 18 | 19 | public class MonteCarloBlackScholesEuropeanOptionValuation { 20 | 21 | public static void main(String[] args) throws CalculationException { 22 | testValuationUsingProduct(); 23 | } 24 | 25 | public static void testValuationUsingProduct() throws CalculationException { 26 | 27 | System.out.println("\n"); 28 | System.out.println("Valuation (using product):"); 29 | System.out.println("_".repeat(79)); 30 | 31 | // Model X - BlackScholesModel Parameters 32 | double initialValue = 100.0; // X(0) 33 | double riskFreeRate = 0.05; // r 34 | double sigma = 0.20; // σ 35 | ProcessModel processModel = new BlackScholesModel(initialValue, riskFreeRate, sigma); 36 | 37 | // TimeDiscretization 38 | double initialTime = 0.0; 39 | int numberOfTimeSteps = 50; 40 | double dt = 0.5; 41 | TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray(initialTime, numberOfTimeSteps, dt); 42 | 43 | // BrownianMotion 44 | int numberOfFactors = 1; 45 | int numberOfPaths = 100000; 46 | int randomNumberSeed = 3216; 47 | BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers(timeDiscretization, numberOfFactors, numberOfPaths, randomNumberSeed); 48 | 49 | // Time discrete process (Euler Scheme) 50 | MonteCarloProcess process = new EulerSchemeFromProcessModel(processModel, brownianMotion); 51 | 52 | // Wrapped to AssetModel for valuation 53 | MonteCarloAssetModel model = new MonteCarloAssetModel(process); 54 | 55 | /* 56 | * Valuation of paying max(S(T)-K,0) in T 57 | */ 58 | double maturity = 10.0; // T 59 | double strike = 160.0; // K 60 | MonteCarloProduct product = new EuropeanOption(maturity, strike); 61 | 62 | double value = product.getValue(model); 63 | 64 | double valueAnalytic = AnalyticFormulas.blackScholesOptionValue(initialValue, riskFreeRate, sigma, maturity, strike); 65 | 66 | System.out.println("value...............: " + value); 67 | System.out.println("value analytic......: " + valueAnalytic); 68 | 69 | 70 | // Create a function, plotting paths t -> S(t) 71 | DoubleToRandomVariableFunction paths = time -> model.getAssetValue(timeDiscretization.getTimeIndex(time), 0 /* assetIndex: 0 is S(t) */); 72 | 73 | /* 74 | * Plot 75 | */ 76 | 77 | // Plot 100 of paths against the given time discretization. 78 | var plot = new PlotProcess2D(timeDiscretization, paths, 1000); 79 | plot.setTitle(processModel.getClass().getSimpleName() + " paths").setXAxisLabel("time").setYAxisLabel("value"); 80 | plot.show(); 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/liboverview/MonteCarloModelEuropeanOptionValuation.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.liboverview; 2 | 3 | import net.finmath.exception.CalculationException; 4 | import net.finmath.montecarlo.BrownianMotion; 5 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 6 | import net.finmath.montecarlo.MonteCarloProduct; 7 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloAssetModel; 8 | import net.finmath.montecarlo.assetderivativevaluation.models.BachelierModel; 9 | import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.models.HestonModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.models.HestonModel.Scheme; 12 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 13 | import net.finmath.montecarlo.model.ProcessModel; 14 | import net.finmath.montecarlo.process.EulerSchemeFromProcessModel; 15 | import net.finmath.montecarlo.process.MonteCarloProcess; 16 | import net.finmath.plots.DoubleToRandomVariableFunction; 17 | import net.finmath.plots.PlotProcess2D; 18 | import net.finmath.time.TimeDiscretization; 19 | import net.finmath.time.TimeDiscretizationFromArray; 20 | 21 | public class MonteCarloModelEuropeanOptionValuation { 22 | 23 | public static void main(String[] args) throws CalculationException { 24 | 25 | System.out.println("\n"); 26 | System.out.println("Valuation (using product):"); 27 | System.out.println("_".repeat(79)); 28 | 29 | // Model X - BlackScholesModel Parameters 30 | double initialValue = 100.0; // X(0) 31 | double riskFreeRate = 0.05; // r 32 | double sigma = 0.20; // σ 33 | 34 | ProcessModel blackScholesModel = new BlackScholesModel(initialValue, riskFreeRate, sigma); 35 | testValuationUsingProduct(blackScholesModel); 36 | 37 | ProcessModel bachelierModel = new BachelierModel(initialValue, riskFreeRate, sigma*100); 38 | testValuationUsingProduct(bachelierModel); 39 | 40 | final double theta = sigma*sigma; 41 | final double kappa = 0.1; 42 | final double xi = 0.1; 43 | final double rho = 0.1; 44 | ProcessModel hestonModel = new HestonModel(initialValue, riskFreeRate, sigma, theta, kappa, xi, rho, Scheme.FULL_TRUNCATION); 45 | testValuationUsingProduct(hestonModel); 46 | } 47 | 48 | public static void testValuationUsingProduct(ProcessModel processModel) throws CalculationException { 49 | 50 | // TimeDiscretization 51 | double initialTime = 0.0; 52 | int numberOfTimeSteps = 50; 53 | double dt = 0.5; 54 | TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray(initialTime, numberOfTimeSteps, dt); 55 | 56 | // BrownianMotion 57 | int numberOfFactors = 2; 58 | int numberOfPaths = 100000; 59 | int randomNumberSeed = 3216; 60 | BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers(timeDiscretization, numberOfFactors, numberOfPaths, randomNumberSeed); 61 | 62 | // Time discrete process (Euler Scheme) 63 | MonteCarloProcess process = new EulerSchemeFromProcessModel(processModel, brownianMotion); 64 | 65 | // Wrapped to AssetModel for valuation 66 | MonteCarloAssetModel model = new MonteCarloAssetModel(process); 67 | 68 | /* 69 | * Valuation of paying max(S(T)-K,0) in T 70 | */ 71 | double maturity = 10.0; // T 72 | double strike = 160.0; // K 73 | 74 | MonteCarloProduct product = new EuropeanOption(maturity, strike); 75 | double value = product.getValue(model); 76 | 77 | System.out.println(String.format("%-20s value.........: %8.4f", processModel.getClass().getSimpleName(), value)); 78 | 79 | 80 | // Create a function, plotting paths t -> S(t) 81 | DoubleToRandomVariableFunction paths = time -> model.getAssetValue(timeDiscretization.getTimeIndex(time), 0 /* assetIndex: 0 is S(t) */); 82 | 83 | /* 84 | * Plot 85 | */ 86 | 87 | // Plot 100 of paths against the given time discretization. 88 | var plot = new PlotProcess2D(timeDiscretization, paths, 1000); 89 | plot.setTitle(processModel.getClass().getSimpleName() + " paths").setXAxisLabel("time").setYAxisLabel("value"); 90 | plot.show(); 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/liboverview/RandomVariableDependencyInjection.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.liboverview; 2 | 3 | import net.finmath.montecarlo.RandomVariableFactory; 4 | import net.finmath.montecarlo.RandomVariableFromArrayFactory; 5 | import net.finmath.montecarlo.automaticdifferentiation.RandomVariableDifferentiable; 6 | import net.finmath.montecarlo.automaticdifferentiation.backward.RandomVariableDifferentiableAADFactory; 7 | import net.finmath.stochastic.RandomVariable; 8 | 9 | /** 10 | * Demonstrate RandomVariable and dependency injection via different implementations of RandomVariable operations. 11 | * 12 | * @author Christian Fries 13 | */ 14 | public class RandomVariableDependencyInjection { 15 | 16 | public static void main(String[] args) { 17 | 18 | testFiniteDifference(); 19 | 20 | testAAD(); 21 | } 22 | 23 | public static RandomVariable someFunction(RandomVariable x) { 24 | 25 | // y = exp(-0.5 * x * x) 26 | RandomVariable y = x.squared().mult(-0.5).exp(); 27 | 28 | return y; 29 | } 30 | 31 | private static void testFiniteDifference() { 32 | 33 | System.out.println("Injecting a standard random variable, calculating dy/dx via finite differences."); 34 | RandomVariableFactory randomVariableFactory = new RandomVariableFromArrayFactory(); 35 | 36 | RandomVariable x = randomVariableFactory.createRandomVariable(new double[] { -1, 0, 1, 2, 3 }); 37 | 38 | RandomVariable y = someFunction(x); 39 | 40 | System.out.println("x.............: " + x.getClass().getSimpleName()); 41 | System.out.println("f(x)..........: " + y.getClass().getSimpleName()); 42 | System.out.println("E(f(x)).......: " + y.average().doubleValue()); 43 | 44 | double epsilon = 1E-7; 45 | // (f(x+e)-f(x)) / e 46 | RandomVariable dydx = someFunction(x.add(epsilon)).sub(someFunction(x)).div(epsilon); 47 | 48 | System.out.println("d/dx E(f(x))..: " + dydx.average().doubleValue()); 49 | 50 | System.out.println("_".repeat(79) + "\n"); 51 | } 52 | 53 | private static void testAAD() { 54 | 55 | System.out.println("Injecting a random variable that perfoms AAD."); 56 | RandomVariableFactory randomVariableFactory = new RandomVariableDifferentiableAADFactory(); 57 | 58 | RandomVariableDifferentiable x = (RandomVariableDifferentiable) randomVariableFactory.createRandomVariable(new double[] { -1, 0, 1, 2, 3 }); 59 | 60 | RandomVariableDifferentiable y = (RandomVariableDifferentiable) someFunction(x); 61 | 62 | System.out.println("x.............: " + x.getClass().getSimpleName()); 63 | System.out.println("f(x)..........: " + y.getClass().getSimpleName()); 64 | System.out.println("E(f(x)).......: " + y.average().doubleValue()); 65 | 66 | RandomVariable dydx = y.getGradient().get(x.getID()); 67 | 68 | System.out.println("d/dx E(f(x))..: " + dydx.average().doubleValue()); 69 | 70 | System.out.println("_".repeat(79) + "\n"); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/BrownianMotionTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 10.02.2004 5 | */ 6 | package net.finmath.experiments.montecarlo; 7 | 8 | import java.text.DecimalFormat; 9 | 10 | import net.finmath.montecarlo.BrownianMotionLazyInit; 11 | import net.finmath.montecarlo.RandomVariableFromDoubleArray; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.time.TimeDiscretization; 14 | import net.finmath.time.TimeDiscretizationFromArray; 15 | 16 | /** 17 | * @author Christian Fries 18 | * 19 | */ 20 | public class BrownianMotionTests { 21 | 22 | static final DecimalFormat fromatterReal2 = new DecimalFormat("0.00"); 23 | static final DecimalFormat fromatterSci4 = new DecimalFormat(" 0.0000E00;-0.0000E00"); 24 | 25 | public static void main(String[] args) 26 | { 27 | // The parameters 28 | final int numberOfPaths = 10000; 29 | final int seed = 53252; 30 | 31 | final double lastTime = 4.0; 32 | final double dt = 0.1; 33 | 34 | // Create the time discretization 35 | final TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray(0.0, (int)(lastTime/dt), dt); 36 | 37 | // Test the quality of the Brownian motion 38 | final BrownianMotionLazyInit brownian = new BrownianMotionLazyInit( 39 | timeDiscretization, 40 | 1, 41 | numberOfPaths, 42 | seed 43 | ); 44 | 45 | System.out.println("Average, variance and other properties of a BrownianMotionLazyInit.\nTime step size (dt): " + dt + " Number of path: " + numberOfPaths + "\n"); 46 | 47 | System.out.println(" " + "\t" + " int dW " + "\t" + " " + "\t" + "int dW dW" + "\t" + " "); 48 | System.out.println("time " + "\t" + " mean " + "\t" + " var " + "\t" + " mean " + "\t" + " var "); 49 | 50 | final RandomVariable brownianMotionRealization = new RandomVariableFromDoubleArray(0.0); 51 | RandomVariable sumOfSquaredIncrements = new RandomVariableFromDoubleArray(0.0); 52 | for(int timeIndex=0; timeIndex> results = new ArrayList>(); 49 | for(int taskIndex=0; taskIndex value = executor.submit(new Callable() { 53 | @Override 54 | public Double call() { 55 | return getMonteCarloApproximationOfPi(startIndex, numberOfSimulationsPerTask); 56 | } 57 | }); 58 | 59 | results.add(value); 60 | } 61 | System.out.print("done.\n"); 62 | 63 | /* 64 | * Collect results 65 | */ 66 | System.out.print("Collecting results..."); 67 | double sumOfResults = 0.0; 68 | for(int taskIndex=0; taskIndex S(t) 35 | DoubleToRandomVariableFunction paths = time -> process.getProcessValue(td.getTimeIndex(time), 0 /* assetIndex: 0 is S(t) */); 36 | 37 | /* 38 | * Plot 39 | */ 40 | 41 | // Plot 100 of paths against the given time discretization. 42 | var plot = new PlotProcess2D(td, paths, 100); 43 | plot.setTitle("Bachelier model paths").setXAxisLabel("time").setYAxisLabel("value"); 44 | plot.show(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/BlackScholesModelNumerairePlot.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 2 | 3 | import java.awt.Color; 4 | import java.awt.Rectangle; 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.util.List; 10 | 11 | import net.finmath.plots.GraphStyle; 12 | import net.finmath.plots.Named; 13 | import net.finmath.plots.Plot2D; 14 | import net.finmath.plots.PlotableFunction2D; 15 | 16 | public class BlackScholesModelNumerairePlot { 17 | 18 | public static void main(String[] args) { 19 | double modelInitialValue = 100.0; // S(0) 20 | double modelRiskFreeRate = 0.08; // r 21 | double modelVolatility = 0.10; // σ 22 | 23 | var plot = new Plot2D(List.of(new PlotableFunction2D(0.0, 5.0, 500, new Named<>("Numeraire",t -> Math.exp(modelRiskFreeRate * t)), new GraphStyle(new Rectangle(-1,-1,3,3), null, new Color(0, 0.8f, 0))))); 24 | plot.setTitle("t -> N(t) = exp(r • t)").setXAxisLabel("time").setYAxisLabel("value"); 25 | plot.setYRange(0.7, 2.7); 26 | plot.show(); 27 | 28 | try { 29 | final Path path = Files.createDirectories(Path.of("images")); 30 | plot.saveAsPNG(new File(path + File.separator + "BlackScholeModelNumeraire.png"), 800, 400); 31 | } catch (IOException e) { e.printStackTrace(); } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/BlackScholesModelPathsPlot.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 2 | 3 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 4 | import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel; 5 | import net.finmath.montecarlo.process.EulerSchemeFromProcessModel; 6 | import net.finmath.plots.DoubleToRandomVariableFunction; 7 | import net.finmath.plots.PlotProcess2D; 8 | import net.finmath.time.TimeDiscretizationFromArray; 9 | 10 | public class BlackScholesModelPathsPlot { 11 | 12 | public static void main(String[] args) { 13 | double modelInitialValue = 100.0; // S(0) 14 | double modelRiskFreeRate = 0.08; // r 15 | double modelVolatility = 0.10; // σ 16 | 17 | // Create a model 18 | var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility); 19 | 20 | // Create a corresponding MC process from the model 21 | var timeDiscretization = new TimeDiscretizationFromArray(0.0, 500, 0.01); 22 | var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(timeDiscretization, 1, 10000, 3231); 23 | var process = new EulerSchemeFromProcessModel(model, brownianMotion); 24 | 25 | // Create a function, plotting paths t -> S(t) 26 | DoubleToRandomVariableFunction paths = time -> process.getProcessValue(timeDiscretization.getTimeIndex(time), 0 /* assetIndex */); 27 | 28 | // Plot 100 of paths against the given time discretization. 29 | var plot = new PlotProcess2D(timeDiscretization, paths, 100); 30 | plot.setTitle("Black Scholes model paths t -> S(t, \u03c9\u1D62)").setXAxisLabel("time").setYAxisLabel("value"); 31 | plot.show(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/DeltaHedgeSimulation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com. 3 | * 4 | * Created on 19.01.2014 5 | */ 6 | 7 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 8 | 9 | import net.finmath.exception.CalculationException; 10 | import net.finmath.montecarlo.BrownianMotion; 11 | import net.finmath.montecarlo.BrownianMotionLazyInit; 12 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 13 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 14 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 15 | import net.finmath.montecarlo.assetderivativevaluation.products.AssetMonteCarloProduct; 16 | import net.finmath.montecarlo.assetderivativevaluation.products.BlackScholesDeltaHedgedPortfolio; 17 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 18 | import net.finmath.stochastic.RandomVariable; 19 | import net.finmath.time.TimeDiscretizationFromArray; 20 | 21 | /** 22 | * @author Christian Fries 23 | * 24 | */ 25 | public class DeltaHedgeSimulation { 26 | 27 | /** 28 | * 29 | */ 30 | public DeltaHedgeSimulation() { 31 | // TODO Auto-generated constructor stub 32 | } 33 | 34 | /** 35 | * @param args 36 | * @throws CalculationException 37 | */ 38 | public static void main(String[] args) throws CalculationException { 39 | testHedge(); 40 | 41 | } 42 | 43 | private static void testHedge() throws CalculationException { 44 | System.out.println("\n\nT E S T o f C a l i b r a t i o n a n d H e d g e \n"); 45 | 46 | // Test parameters 47 | final double initialValue = 100; 48 | final double riskFreeRate = 0.05; 49 | final double volatility = 0.32; 50 | final int numberOfPaths = 1000; 51 | final int numberOfTimeSteps = 100; 52 | final TimeDiscretizationFromArray simulationTimeDiscretization = new TimeDiscretizationFromArray(0.0, numberOfTimeSteps, 2.0 / numberOfTimeSteps); 53 | final BrownianMotion brownianMotion = new BrownianMotionLazyInit(simulationTimeDiscretization, 1, numberOfPaths, 3141); 54 | final AssetModelMonteCarloSimulationModel model = new MonteCarloBlackScholesModel(simulationTimeDiscretization, numberOfPaths, initialValue, riskFreeRate, volatility); 55 | 56 | final TimeDiscretizationFromArray simulationTimeDiscretization2 = new TimeDiscretizationFromArray(0.0, numberOfTimeSteps/100, 2.0 / numberOfTimeSteps * 100); 57 | final AssetModelMonteCarloSimulationModel model2 = new MonteCarloBlackScholesModel(simulationTimeDiscretization2, numberOfPaths, initialValue, riskFreeRate, volatility); 58 | 59 | // Calibration products 60 | final double maturity = 2.0; 61 | 62 | final int[] testProductGroup = { 6, 5, 2, 7, 1, 4, 3, 8 }; 63 | final double[] testProductStrikes = { 100, 102, 105, 108, 110, 112, 115, 118 }; 64 | final double[] testProductTargetValues = { 22.215, 21.329, 20.060, 18.859, 18.094, 17.358, 16.305, 15.312 }; 65 | 66 | for(int testProductIndex = 0; testProductIndex models = List.of( 58 | new BlackScholesModel(initialValue, riskFreeRate, sigma), 59 | new BachelierModel(initialValue, riskFreeRate, sigma * initialValue), 60 | new HestonModel(initialValue, riskFreeRate, sigma, theta, kappa, xi, rho, Scheme.FULL_TRUNCATION) 61 | ); 62 | 63 | List products = List.of( 64 | new EuropeanOption(optionMaturity, optionStrike), 65 | new AsianOption(optionMaturity, optionStrike, new TimeDiscretizationFromArray(1.0, optionMaturity, 1.0)), 66 | new BermudanOption(new double[] { 3.0, 5.0 } , new double[] { 1.0, 1.0 }, new double[] { 110, optionStrike }) 67 | ); 68 | 69 | printValuations(models, products); 70 | } 71 | 72 | /** 73 | * Print the values of product for all models. 74 | * @param models List of the models. 75 | * @param products List of the products. 76 | * @throws CalculationException 77 | */ 78 | public void printValuations(List models, List products) throws CalculationException { 79 | 80 | // Value all product with all models 81 | for(ProcessModel model : models) { 82 | 83 | System.out.println(String.format(model.getClass().getSimpleName()) + ":"); 84 | MonteCarloAssetModel monteCarloAssetModel = getMonteCarloAssetModel(model); 85 | 86 | for(AssetMonteCarloProduct product : products) { 87 | 88 | double value = product.getValue(initialTime, monteCarloAssetModel).expectation().doubleValue(); 89 | 90 | System.out.println(String.format("\t%15s: %f", product.getClass().getSimpleName(), value)); 91 | } 92 | System.out.println(); 93 | } 94 | } 95 | 96 | /** 97 | * Create the Monte-Carlo simulation of the Euler-Scheme approximation for a given model. 98 | * 99 | * @param model A {@link ProcessModel} 100 | * @return The corresponding {@link MonteCarloAssetModel} 101 | * @throws CalculationException 102 | */ 103 | MonteCarloAssetModel getMonteCarloAssetModel(ProcessModel model) throws CalculationException { 104 | 105 | TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray(initialTime, numberOfTimeSteps, optionMaturity/numberOfTimeSteps); 106 | 107 | BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers(timeDiscretization, numberOfFactors, (int)numberOfSamples, (int)seed); 108 | 109 | MonteCarloProcess process = new EulerSchemeFromProcessModel(model, brownianMotion); 110 | 111 | MonteCarloAssetModel monteCarloAssetModel = new MonteCarloAssetModel(process); 112 | 113 | return monteCarloAssetModel; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/MonteCarloValuationUsingOpenCL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com. 3 | * 4 | * Created on 04.03.2021 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 7 | 8 | import java.util.List; 9 | 10 | import net.finmath.exception.CalculationException; 11 | import net.finmath.montecarlo.BrownianMotion; 12 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 13 | import net.finmath.montecarlo.RandomVariableFactory; 14 | import net.finmath.montecarlo.RandomVariableFromArrayFactory; 15 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloAssetModel; 16 | import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel; 17 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 18 | import net.finmath.montecarlo.process.EulerSchemeFromProcessModel; 19 | import net.finmath.opencl.montecarlo.RandomVariableOpenCLFactory; 20 | import net.finmath.stochastic.RandomVariable; 21 | import net.finmath.time.TimeDiscretizationFromArray; 22 | 23 | public class MonteCarloValuationUsingOpenCL { 24 | 25 | public static void main(String[] args) { 26 | 27 | /** 28 | * Factories to test - these are the implementations we inject. 29 | * On some machines some tests may fail, e.g. if you do not have a Cuda enabled 30 | */ 31 | final var randomVariableFactories = List.of( 32 | new RandomVariableFromArrayFactory(false), 33 | // new RandomVariableCudaFactory(), 34 | new RandomVariableOpenCLFactory() 35 | ); 36 | 37 | for(final RandomVariableFactory randomVariableFactory : randomVariableFactories) { 38 | try { 39 | testWithRandomVariableFactory(randomVariableFactory); 40 | } 41 | catch(final Exception e) {} 42 | } 43 | 44 | System.exit(0); 45 | } 46 | 47 | private static void testWithRandomVariableFactory(RandomVariableFactory randomVariableFactory) { 48 | 49 | System.out.println("Using " + randomVariableFactory.getClass().getSimpleName()); 50 | 51 | /* 52 | * First run 53 | */ 54 | 55 | final var run1Start = System.currentTimeMillis(); 56 | 57 | // Create Brownian motion 58 | final int numberOfPaths = 800000; 59 | final var td = new TimeDiscretizationFromArray(0.0, 200, 0.01); 60 | final var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(td, 1, numberOfPaths, 3231, randomVariableFactory); 61 | 62 | final var value1 = performValuation(randomVariableFactory, brownianMotion); 63 | 64 | final var run1End = System.currentTimeMillis(); 65 | final var run1Time = (run1End-run1Start)/1000.0; 66 | 67 | System.out.printf("\t (1st run) value = %12.8f \t computation time = %6.3f seconds.\n", value1, run1Time); 68 | 69 | /* 70 | * Second run - reusing brownianMotion 71 | */ 72 | final var run2Start = System.currentTimeMillis(); 73 | 74 | final var value2 = performValuation(randomVariableFactory, brownianMotion); 75 | 76 | final var run2End = System.currentTimeMillis(); 77 | final var run2Time = (run2End-run2Start)/1000.0; 78 | 79 | System.out.printf("\t (2nd run) value = %12.8f \t computation time = %6.3f seconds.\n", value2, run2Time); 80 | } 81 | 82 | private static double performValuation(RandomVariableFactory randomVariableFactory, BrownianMotion brownianMotion) { 83 | // Create a model 84 | final double modelInitialValue = 100.0; 85 | final double modelRiskFreeRate = 0.05; 86 | final double modelVolatility = 0.20; 87 | final var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility, randomVariableFactory); 88 | 89 | // Create a corresponding MC process 90 | final var process = new EulerSchemeFromProcessModel(model, brownianMotion); 91 | 92 | // Using the process (Euler scheme), create an MC simulation of a Black-Scholes model 93 | final var simulation = new MonteCarloAssetModel(process); 94 | 95 | final double maturity = 2.0; 96 | final double strike = 106.0; 97 | 98 | final var europeanOption = new EuropeanOption(maturity, strike); 99 | 100 | double value = 0.0; 101 | try { 102 | final RandomVariable valueOfEuropeanOption = europeanOption.getValue(0.0, simulation).average(); 103 | value = valueOfEuropeanOption.doubleValue(); 104 | } catch (final CalculationException e) { 105 | System.out.println("Calculation failed with exception: " + e.getCause().getMessage()); 106 | } 107 | 108 | return value; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/SimpleBlackScholesMonteCarloValuation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com. 3 | * 4 | * Created on 05.12.2013 5 | */ 6 | 7 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 8 | 9 | import net.finmath.exception.CalculationException; 10 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 12 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 13 | import net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption; 14 | import net.finmath.time.TimeDiscretizationFromArray; 15 | 16 | /** 17 | * A simple demo on how to value a financial product with a given model. 18 | * 19 | * This relates to the "separation of model and product". The only assumptions 20 | * made by the valuation code in the product is that the model implements 21 | * the interface {@code AssetModelMonteCarloSimulationModel}. 22 | * 23 | * @author Christian Fries 24 | */ 25 | public class SimpleBlackScholesMonteCarloValuation { 26 | 27 | /** 28 | * Demo program. 29 | * 30 | * @param args Arguments. Not used. 31 | * @throws CalculationException 32 | */ 33 | public static void main(String[] args) throws CalculationException { 34 | 35 | final AssetModelMonteCarloSimulationModel model = new MonteCarloBlackScholesModel(new TimeDiscretizationFromArray(0, 10, 0.5), 10000, 100, 0.05, 0.20); 36 | 37 | final AbstractAssetMonteCarloProduct product = new EuropeanOption(2.0, 110); 38 | 39 | final double value = product.getValue(model); 40 | 41 | System.out.println("The value is " + value); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Monte Carlo methods for single stock models. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOption2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 21.01.2004 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 11 | import net.finmath.stochastic.RandomVariable; 12 | import net.finmath.stochastic.RandomVariableAccumulator; 13 | 14 | /** 15 | * Implements valuation of a European stock option. 16 | * The code is equivalent to the code in net.finmath.montecarlo.assetderivativevaluation.products.EuropeanOption. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOption2 extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | /** 27 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 28 | * 29 | * @param strike The strike K in the option payoff max(S(T)-K,0). 30 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 31 | */ 32 | public EuropeanOption2(double maturity, double strike) { 33 | super(); 34 | this.maturity = maturity; 35 | this.strike = strike; 36 | } 37 | 38 | /** 39 | * Calculates the value of the option under a given model. 40 | * 41 | * @param model A reference to a model 42 | * @return the value 43 | * @throws CalculationException 44 | */ 45 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 46 | { 47 | // Get underlying and numeraire 48 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 49 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 50 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 51 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 52 | 53 | /* 54 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 55 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 56 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 57 | */ 58 | double average = 0.0; 59 | for(int path=0; path strike) 63 | { 64 | average += (underlyingAtMaturity.get(path) - strike) / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) 65 | * numeraireAtToday.get(path); 66 | } 67 | } 68 | 69 | return average; 70 | } 71 | 72 | @Override 73 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 74 | throw new RuntimeException("Method not supported."); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionDeltaLikelihood.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionDeltaLikelihood extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | private final boolean isLikelihoodByFiniteDifference = false; 27 | 28 | /** 29 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 30 | * 31 | * @param strike The strike K in the option payoff max(S(T)-K,0). 32 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 33 | */ 34 | public EuropeanOptionDeltaLikelihood(double maturity, double strike) { 35 | super(); 36 | this.maturity = maturity; 37 | this.strike = strike; 38 | } 39 | 40 | /** 41 | * Calculates the value of the option under a given model. 42 | * 43 | * @param model A reference to a model 44 | * @return the value 45 | * @throws CalculationException 46 | */ 47 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 48 | { 49 | MonteCarloBlackScholesModel blackScholesModel = null; 50 | try { 51 | blackScholesModel = (MonteCarloBlackScholesModel)model; 52 | } 53 | catch(final Exception e) { 54 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 55 | } 56 | 57 | // Get underlying and numeraire 58 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 59 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 60 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 61 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 62 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 63 | 64 | /* 65 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 66 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 67 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 68 | */ 69 | double average = 0.0; 70 | for(int path=0; path strike) 73 | { 74 | // Get some model parameters 75 | final double T = maturity; 76 | final double S0 = underlyingAtToday.get(path); 77 | final double r = blackScholesModel.getModel().getRiskFreeRate().doubleValue(); 78 | final double sigma = blackScholesModel.getModel().getVolatility().doubleValue(); 79 | 80 | final double ST = underlyingAtMaturity.get(path); 81 | 82 | final double x = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 83 | 84 | double lr; 85 | if(isLikelihoodByFiniteDifference) { 86 | final double h = 1E-6; 87 | 88 | final double x1 = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 89 | final double logPhi1 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x1*x1/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 90 | 91 | final double x2 = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0+h))); 92 | final double logPhi2 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x2*x2/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 93 | 94 | lr = (logPhi2 - logPhi1) / h; 95 | } 96 | else { 97 | lr = x / (sigma * Math.sqrt(T)) / S0; 98 | } 99 | 100 | final double payOff = (underlyingAtMaturity.get(path) - strike); 101 | final double modifiedPayoff = payOff * lr; 102 | 103 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 104 | } 105 | } 106 | 107 | return average; 108 | } 109 | 110 | @Override 111 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 112 | throw new RuntimeException("Method not supported."); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionDeltaPathwise.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import java.util.logging.Logger; 9 | 10 | import net.finmath.exception.CalculationException; 11 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 12 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 13 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 14 | import net.finmath.stochastic.RandomVariable; 15 | import net.finmath.stochastic.Scalar; 16 | 17 | /** 18 | * Implements calculation of the delta of a European option using the path-wise method, 19 | * assuming that the underlying follows a model where d S(T)/d S(0) = S(T)/S(0), 20 | * e.g., Black-Scholes. 21 | * 22 | * @author Christian Fries 23 | * @version 1.1 24 | */ 25 | public class EuropeanOptionDeltaPathwise extends AbstractAssetMonteCarloProduct { 26 | 27 | private final double maturity; 28 | private final double strike; 29 | 30 | /** 31 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 32 | * 33 | * @param strike The strike K in the option payoff max(S(T)-K,0). 34 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 35 | */ 36 | public EuropeanOptionDeltaPathwise(double maturity, double strike) { 37 | super(); 38 | this.maturity = maturity; 39 | this.strike = strike; 40 | } 41 | 42 | /** 43 | * This method returns the value random variable of the product within the specified model, evaluated at a given evalutationTime. 44 | * Note: For a lattice this is often the value conditional to evalutationTime, for a Monte-Carlo simulation this is the (sum of) value discounted to evaluation time. 45 | * Cashflows prior evaluationTime are not considered. 46 | * 47 | * @param evaluationTime The time on which this products value should be observed. 48 | * @param model The model used to price the product. 49 | * @return The random variable representing the value of the product discounted to evaluation time 50 | * @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method. 51 | */ 52 | @Override 53 | public RandomVariable getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) throws CalculationException { 54 | if(!MonteCarloBlackScholesModel.class.isInstance(model)) { 55 | Logger.getLogger("net.finmath").warning("This method assumes a Black-Scholes type model (MonteCarloBlackScholesModel)."); 56 | } 57 | 58 | // Get S(T), S(0) 59 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 60 | final RandomVariable underlyingAtEvalTime = model.getAssetValue(evaluationTime,0); 61 | 62 | // The "payoff": values = indicator(S(T)-K) * S(T)/S(0) 63 | final RandomVariable trigger = underlyingAtMaturity.sub(strike); 64 | RandomVariable values = trigger.choose(underlyingAtMaturity, new Scalar(0.0)).div(underlyingAtEvalTime); 65 | 66 | // Discounting... 67 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 68 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 69 | values = values.div(numeraireAtMaturity).mult(monteCarloWeights); 70 | 71 | // ...to evaluation time. 72 | final RandomVariable numeraireAtEvalTime = model.getNumeraire(evaluationTime); 73 | final RandomVariable monteCarloProbabilitiesAtEvalTime = model.getMonteCarloWeights(evaluationTime); 74 | values = values.mult(numeraireAtEvalTime).div(monteCarloProbabilitiesAtEvalTime); 75 | 76 | return values; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionGammaLikelihood.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionGammaLikelihood extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | private final boolean isLikelihoodByFiniteDifference = false; 27 | 28 | /** 29 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 30 | * 31 | * @param strike The strike K in the option payoff max(S(T)-K,0). 32 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 33 | */ 34 | public EuropeanOptionGammaLikelihood(double maturity, double strike) { 35 | super(); 36 | this.maturity = maturity; 37 | this.strike = strike; 38 | } 39 | 40 | /** 41 | * Calculates the value of the option under a given model. 42 | * 43 | * @param model A reference to a model 44 | * @return the value 45 | * @throws CalculationException 46 | */ 47 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 48 | { 49 | MonteCarloBlackScholesModel blackScholesModel = null; 50 | try { 51 | blackScholesModel = (MonteCarloBlackScholesModel)model; 52 | } 53 | catch(final Exception e) { 54 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 55 | } 56 | 57 | // Get underlying and numeraire 58 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 59 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 60 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 61 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 62 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 63 | 64 | /* 65 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 66 | * assumptions on the internals of the RandomVariable. Instead you should use 67 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 68 | */ 69 | double average = 0.0; 70 | for(int path=0; path strike) 73 | { 74 | // Get some model parameters 75 | final double T = maturity; 76 | final double S0 = underlyingAtToday.get(path); 77 | final double r = blackScholesModel.getModel().getRiskFreeRate().doubleValue(); 78 | final double sigma = blackScholesModel.getModel().getVolatility().doubleValue(); 79 | 80 | final double ST = underlyingAtMaturity.get(path); 81 | 82 | double lr; 83 | if(isLikelihoodByFiniteDifference) { 84 | final double h = 1E-2; 85 | 86 | final double x = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 87 | final double phi = (1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x*x/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 88 | 89 | final double xDown = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0-h))); 90 | final double phiDown = (1.0/Math.sqrt(2 * Math.PI) * Math.exp(-xDown*xDown/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 91 | 92 | final double xUp = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0+h))); 93 | final double phiUp = (1.0/Math.sqrt(2 * Math.PI) * Math.exp(-xUp*xUp/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 94 | 95 | lr = (phiUp - 2 * phi + phiDown) / (h * h) / phi; 96 | } 97 | else { 98 | final double x = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 99 | final double phi = (1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x*x/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 100 | final double dPhidS0 = x / (sigma * Math.sqrt(T)) / S0 * phi; 101 | final double d2PhidS02 = -1 / (sigma * Math.sqrt(T)) / (sigma * Math.sqrt(T)) / S0 / S0 * phi - x / (sigma * Math.sqrt(T)) / S0 / S0 * phi 102 | + x / (sigma * Math.sqrt(T)) / S0 * dPhidS0; 103 | lr = d2PhidS02 / phi; 104 | } 105 | 106 | final double payOff = (underlyingAtMaturity.get(path) - strike); 107 | final double modifiedPayoff = payOff * lr; 108 | 109 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 110 | } 111 | } 112 | 113 | return average; 114 | } 115 | 116 | @Override 117 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 118 | throw new RuntimeException("Method not supported."); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionGammaPathwise.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option using the pathwise method. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionGammaPathwise extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | /** 27 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 28 | * 29 | * @param strike The strike K in the option payoff max(S(T)-K,0). 30 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 31 | */ 32 | public EuropeanOptionGammaPathwise(double maturity, double strike) { 33 | super(); 34 | this.maturity = maturity; 35 | this.strike = strike; 36 | } 37 | 38 | /** 39 | * Calculates the value of the option under a given model. 40 | * 41 | * @param model A reference to a model 42 | * @return the value 43 | * @throws CalculationException 44 | */ 45 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 46 | { 47 | MonteCarloBlackScholesModel blackScholesModel = null; 48 | try { 49 | blackScholesModel = (MonteCarloBlackScholesModel)model; 50 | } 51 | catch(final Exception e) { 52 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 53 | } 54 | 55 | // Get underlying and numeraire 56 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 57 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 58 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 59 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 60 | 61 | /* 62 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 63 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 64 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 65 | */ 66 | double average = 0.0; 67 | for(int path=0; pathRandomVariableAccumulator. Instead you should use 67 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 68 | */ 69 | double average = 0.0; 70 | for(int path=0; path strike) 73 | { 74 | // Get some model parameters 75 | final double T = maturity; 76 | final double S0 = underlyingAtToday.get(path); 77 | final double r = blackScholesModel.getModel().getRiskFreeRate().doubleValue(); 78 | final double sigma = blackScholesModel.getModel().getVolatility().doubleValue(); 79 | 80 | final double ST = underlyingAtMaturity.get(path); 81 | 82 | final double x = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 83 | 84 | double lr; 85 | if(isLikelihoodByFiniteDifference) { 86 | final double h = 1E-6; 87 | 88 | final double x1 = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 89 | final double logPhi1 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x1*x1/2.0) / (ST * sigma * Math.sqrt(T)) ); 90 | 91 | final double x2 = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - ((r+h) * T - 0.5 * sigma*sigma * T + Math.log(S0))); 92 | final double logPhi2 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x2*x2/2.0) / (ST * sigma * Math.sqrt(T)) ); 93 | 94 | lr = (logPhi2 - logPhi1) / h; 95 | } 96 | else { 97 | final double dxdr = -1.0 / (sigma * Math.sqrt(T)); 98 | 99 | lr = - x * dxdr; 100 | } 101 | 102 | final double payOff = (underlyingAtMaturity.get(path) - strike); 103 | final double modifiedPayoff = payOff * (lr-T); 104 | 105 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 106 | } 107 | } 108 | 109 | return average; 110 | } 111 | 112 | @Override 113 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 114 | throw new RuntimeException("Method not supported."); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionRhoPathwise.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option using the pathwise method. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionRhoPathwise extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | /** 27 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 28 | * 29 | * @param strike The strike K in the option payoff max(S(T)-K,0). 30 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 31 | */ 32 | public EuropeanOptionRhoPathwise(double maturity, double strike) { 33 | super(); 34 | this.maturity = maturity; 35 | this.strike = strike; 36 | } 37 | 38 | /** 39 | * Calculates the value of the option under a given model. 40 | * 41 | * @param model A reference to a model 42 | * @return the value 43 | * @throws CalculationException 44 | */ 45 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 46 | { 47 | MonteCarloBlackScholesModel blackScholesModel = null; 48 | try { 49 | blackScholesModel = (MonteCarloBlackScholesModel)model; 50 | } 51 | catch(final Exception e) { 52 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 53 | } 54 | 55 | // Get underlying and numeraire 56 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 57 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 58 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 59 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 60 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 61 | 62 | /* 63 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 64 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 65 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 66 | */ 67 | double average = 0.0; 68 | for(int path=0; path strike) 71 | { 72 | // Get some model parameters 73 | final double T = maturity; 74 | final double ST = underlyingAtMaturity.get(path); 75 | 76 | final double payOff = 1; 77 | final double modifiedPayoff = payOff * ST * T - (ST-strike) * T; 78 | 79 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 80 | } 81 | } 82 | 83 | return average; 84 | } 85 | 86 | @Override 87 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 88 | throw new RuntimeException("Method not supported."); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionVegaLikelihood.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionVegaLikelihood extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | private final boolean isLikelihoodByFiniteDifference = false; 27 | 28 | /** 29 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 30 | * 31 | * @param strike The strike K in the option payoff max(S(T)-K,0). 32 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 33 | */ 34 | public EuropeanOptionVegaLikelihood(double maturity, double strike) { 35 | super(); 36 | this.maturity = maturity; 37 | this.strike = strike; 38 | } 39 | 40 | /** 41 | * Calculates the value of the option under a given model. 42 | * 43 | * @param model A reference to a model 44 | * @return the value 45 | * @throws CalculationException 46 | */ 47 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 48 | { 49 | MonteCarloBlackScholesModel blackScholesModel = null; 50 | try { 51 | blackScholesModel = (MonteCarloBlackScholesModel)model; 52 | } 53 | catch(final Exception e) { 54 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 55 | } 56 | 57 | // Get underlying and numeraire 58 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 59 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 60 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 61 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 62 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 63 | 64 | /* 65 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 66 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 67 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 68 | */ 69 | double average = 0.0; 70 | for(int path=0; path strike) 73 | { 74 | // Get some model parameters 75 | final double T = maturity; 76 | final double S0 = underlyingAtToday.get(path); 77 | final double r = blackScholesModel.getModel().getRiskFreeRate().doubleValue(); 78 | final double sigma = blackScholesModel.getModel().getVolatility().doubleValue(); 79 | 80 | final double ST = underlyingAtMaturity.get(path); 81 | 82 | final double x = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 83 | 84 | double lr; 85 | if(isLikelihoodByFiniteDifference) { 86 | final double h = 1E-6; 87 | 88 | final double x1 = 1.0 / (sigma * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * sigma*sigma * T + Math.log(S0))); 89 | final double logPhi1 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x1*x1/2.0) / (ST * (sigma) * Math.sqrt(T)) ); 90 | 91 | final double x2 = 1.0 / ((sigma+h) * Math.sqrt(T)) * (Math.log(ST) - (r * T - 0.5 * (sigma+h)*(sigma+h) * T + Math.log(S0))); 92 | final double logPhi2 = Math.log(1.0/Math.sqrt(2 * Math.PI) * Math.exp(-x2*x2/2.0) / (ST * (sigma+h) * Math.sqrt(T)) ); 93 | 94 | lr = (logPhi2 - logPhi1) / h; 95 | } 96 | else { 97 | final double dxdsigma = -x / sigma + Math.sqrt(T); 98 | 99 | lr = - x * dxdsigma - 1/sigma; 100 | } 101 | 102 | final double payOff = (underlyingAtMaturity.get(path) - strike); 103 | final double modifiedPayoff = payOff * lr; 104 | 105 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 106 | } 107 | } 108 | 109 | return average; 110 | } 111 | 112 | @Override 113 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 114 | throw new RuntimeException("Method not supported."); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/EuropeanOptionVegaPathwise.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 12.02.2013 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | 8 | import net.finmath.exception.CalculationException; 9 | import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel; 10 | import net.finmath.montecarlo.assetderivativevaluation.MonteCarloBlackScholesModel; 11 | import net.finmath.montecarlo.assetderivativevaluation.products.AbstractAssetMonteCarloProduct; 12 | import net.finmath.stochastic.RandomVariable; 13 | import net.finmath.stochastic.RandomVariableAccumulator; 14 | 15 | /** 16 | * Implements calculation of the delta of a European option using the pathwise method. 17 | * 18 | * @author Christian Fries 19 | * @version 1.0 20 | */ 21 | public class EuropeanOptionVegaPathwise extends AbstractAssetMonteCarloProduct { 22 | 23 | private final double maturity; 24 | private final double strike; 25 | 26 | /** 27 | * Construct a product representing an European option on an asset S (where S the asset with index 0 from the model - single asset case). 28 | * 29 | * @param strike The strike K in the option payoff max(S(T)-K,0). 30 | * @param maturity The maturity T in the option payoff max(S(T)-K,0) 31 | */ 32 | public EuropeanOptionVegaPathwise(double maturity, double strike) { 33 | super(); 34 | this.maturity = maturity; 35 | this.strike = strike; 36 | } 37 | 38 | /** 39 | * Calculates the value of the option under a given model. 40 | * 41 | * @param model A reference to a model 42 | * @return the value 43 | * @throws CalculationException 44 | */ 45 | public double getValue(AssetModelMonteCarloSimulationModel model) throws CalculationException 46 | { 47 | MonteCarloBlackScholesModel blackScholesModel = null; 48 | try { 49 | blackScholesModel = (MonteCarloBlackScholesModel)model; 50 | } 51 | catch(final Exception e) { 52 | throw new ClassCastException("This method requires a Black-Scholes type model (MonteCarloBlackScholesModel)."); 53 | } 54 | 55 | // Get underlying and numeraire 56 | final RandomVariable underlyingAtMaturity = model.getAssetValue(maturity,0); 57 | final RandomVariable numeraireAtMaturity = model.getNumeraire(maturity); 58 | final RandomVariable underlyingAtToday = model.getAssetValue(0.0,0); 59 | final RandomVariable numeraireAtToday = model.getNumeraire(0); 60 | final RandomVariable monteCarloWeights = model.getMonteCarloWeights(maturity); 61 | 62 | /* 63 | * The following way of calculating the expected value (average) is discouraged since it makes too strong 64 | * assumptions on the internals of the RandomVariableAccumulator. Instead you should use 65 | * the mutators sub, div, mult and the getter getAverage. This code is provided for illustrative purposes. 66 | */ 67 | double average = 0.0; 68 | for(int path=0; path strike) 71 | { 72 | // Get some model parameters 73 | final double T = maturity; 74 | final double S0 = underlyingAtToday.get(path); 75 | final double r = blackScholesModel.getModel().getRiskFreeRate().doubleValue(); 76 | final double sigma = blackScholesModel.getModel().getVolatility().doubleValue(); 77 | 78 | final double ST = underlyingAtMaturity.get(path); 79 | final double WT = (Math.log(ST/S0) - r * T + 0.5 * sigma * sigma * T)/sigma; 80 | 81 | final double payOff = 1; 82 | final double modifiedPayoff = payOff * ST * (-sigma * T + WT); 83 | 84 | average += modifiedPayoff / numeraireAtMaturity.get(path) * monteCarloWeights.get(path) * numeraireAtToday.get(path); 85 | } 86 | } 87 | 88 | return average; 89 | } 90 | 91 | @Override 92 | public RandomVariableAccumulator getValue(double evaluationTime, AssetModelMonteCarloSimulationModel model) { 93 | throw new RuntimeException("Method not supported."); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/assetderivativevaluation/products/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Monte Carlo methods for single stock models: product implementations. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo.assetderivativevaluation.products; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/automaticdifferentiation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to automatic differentiation 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo.automaticdifferentiation; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/eulerscheme/BrownianMotionCoarseTimeDiscretization.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.montecarlo.eulerscheme; 2 | 3 | import net.finmath.montecarlo.BrownianMotion; 4 | import net.finmath.stochastic.RandomVariable; 5 | import net.finmath.time.TimeDiscretization; 6 | 7 | public final class BrownianMotionCoarseTimeDiscretization implements BrownianMotion { 8 | private final BrownianMotion brownianMotion; 9 | private final TimeDiscretization timeDiscretizationCoarse; 10 | 11 | public BrownianMotionCoarseTimeDiscretization(TimeDiscretization timeDiscretizationCoarse, BrownianMotion brownianMotion) { 12 | this.timeDiscretizationCoarse = timeDiscretizationCoarse; 13 | this.brownianMotion = brownianMotion; 14 | } 15 | 16 | @Override 17 | public RandomVariable getIncrement(int timeIndex, int factor) { 18 | double startTime = timeDiscretizationCoarse.getTime(timeIndex); 19 | double endTime = timeDiscretizationCoarse.getTime(timeIndex+1); 20 | int startTimeIndexOnFineDiscretization = brownianMotion.getTimeDiscretization().getTimeIndex(startTime); 21 | int endTimeIndexOnFineDiscretization = brownianMotion.getTimeDiscretization().getTimeIndex(endTime); 22 | 23 | RandomVariable brownianIncrement = getRandomVariableForConstant(0.0); 24 | for(int indexOnFineDiscretization = startTimeIndexOnFineDiscretization; indexOnFineDiscretizationTermStructureMonteCarloSimulationModel. 15 | * 16 | * @author Christian Fries 17 | * @version 1.0 18 | */ 19 | public class ForwardRate extends AbstractTermStructureMonteCarloProduct { 20 | 21 | private final double fixingTime; 22 | private final double periodStartTime; 23 | private final double periodEndTime; 24 | private final double paymentTime; 25 | private final double daycountFraction; 26 | 27 | /** 28 | * Create a payment of a forward rate. 29 | * 30 | * The product pays \( L(T_{1},T_{2};T^{f}) \cdot daycountFraction \) at \( T^{p} \) 31 | * where L denotes the forward rate. 32 | * 33 | * @param fixingTime The fixing date \( T^{f} \) given as double. 34 | * @param periodStartTime The period start time \( T_{1} \) of the forward rate period. 35 | * @param periodEndTime The period end time \( T_{2} \) of the forward rate period. 36 | * @param paymentTime The payment date \( T^{p} \) given as double. 37 | * @param daycountFraction The daycount fraction used in the payout function. 38 | */ 39 | public ForwardRate(final double fixingTime, final double periodStartTime, final double periodEndTime, final double paymentTime, final double daycountFraction) { 40 | super(); 41 | this.fixingTime = fixingTime; 42 | this.periodStartTime = periodStartTime; 43 | this.periodEndTime = periodEndTime; 44 | this.paymentTime = paymentTime; 45 | this.daycountFraction = daycountFraction; 46 | } 47 | 48 | /** 49 | * Create a payment of a forward rate. 50 | * 51 | * The product pays \( L(T_{1},T_{2};T^{f}) \cdot daycountFraction \) at \( T^{p} \). 52 | * where L denotes the forward rate. 53 | * 54 | * This constructor assumes that \( T^{f} = T_{1} \) and \( T^{p} = T_{2} \). 55 | * 56 | * @param fixingTime The fixing date \( T^{f} \) given as double. 57 | * @param periodLength The period length \( T_{2}-T_{1} \) of the forward rate period. 58 | * @param daycountFraction The daycount fraction used in the payout function. 59 | */ 60 | public ForwardRate(final double fixingTime, final double periodLength, final double daycountFraction) { 61 | super(); 62 | this.fixingTime = fixingTime; 63 | this.periodStartTime = fixingTime; 64 | this.periodEndTime = fixingTime+periodLength; 65 | this.paymentTime = fixingTime+periodLength; 66 | this.daycountFraction = daycountFraction; 67 | } 68 | 69 | public ForwardRate(String currency, final double fixingTime, final double periodStartTime, final double periodEndTime, final double paymentTime, final double daycountFraction) { 70 | super(currency); 71 | this.fixingTime = fixingTime; 72 | this.periodStartTime = periodStartTime; 73 | this.periodEndTime = periodEndTime; 74 | this.paymentTime = paymentTime; 75 | this.daycountFraction = daycountFraction; 76 | } 77 | 78 | /** 79 | * This method returns the value random variable of the product within the specified model, evaluated at a given evalutationTime. 80 | * Note: For a lattice this is often the value conditional to evalutationTime, for a Monte-Carlo simulation this is the (sum of) value discounted to evaluation time. 81 | * Cashflows prior evaluationTime are not considered. 82 | * 83 | * @param evaluationTime The time on which this products value should be observed. 84 | * @param model The model used to price the product. 85 | * @return The random variable representing the value of the product discounted to evaluation time 86 | * @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method. 87 | */ 88 | @Override 89 | public RandomVariable getValue(final double evaluationTime, final TermStructureMonteCarloSimulationModel model) throws CalculationException { 90 | 91 | // Get random variables 92 | final RandomVariable forwardRate = model.getForwardRate(fixingTime, periodStartTime, periodEndTime); 93 | final RandomVariable numeraire = model.getNumeraire(paymentTime); 94 | final RandomVariable monteCarloProbabilities = model.getMonteCarloWeights(periodStartTime); 95 | 96 | RandomVariable values = forwardRate.mult(daycountFraction); 97 | 98 | values = values.div(numeraire).mult(monteCarloProbabilities); 99 | 100 | final RandomVariable numeraireAtValuationTime = model.getNumeraire(evaluationTime); 101 | final RandomVariable monteCarloProbabilitiesAtValuationTime = model.getMonteCarloWeights(evaluationTime); 102 | values = values.mult(numeraireAtValuationTime).div(monteCarloProbabilitiesAtValuationTime); 103 | 104 | return values; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/interestrates/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Monte Carlo methods for interest rate products 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo.interestrates; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to Monte Carlo methods. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/randomnumbers/HaltonSequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 18.10.2012 5 | */ 6 | package net.finmath.experiments.montecarlo.randomnumbers; 7 | 8 | /** 9 | * This class represents a Halton sequence (a low discrepancy sequence), or equivalently a vector of 10 | * Van der Corput sequences. For a given base b the van der Corput sequence is given by 11 | *
12 | * 13 | * xi = Σx1 ≤ j ≤ i ai,j b-j 14 | * 15 | *
16 | * where ai,j is such that 17 | *
18 | * 19 | * i = Σx1 ≤ j ≤ i ai,j bj-1 20 | * 21 | * 22 | * 23 | * @author Christian Fries 24 | */ 25 | public class HaltonSequence { 26 | 27 | private final int[] baseVector; 28 | 29 | /** 30 | * Construct a Halton sequence with d = base.length dimensions where the i-th component 31 | * uses base[i] as base of the corresponding van der Corput sequence. 32 | * 33 | * @param baseVector Vector of base integers for each component. 34 | */ 35 | public HaltonSequence(int[] baseVector) { 36 | // Check base 37 | for(final int base : baseVector) { 38 | if(base < 2) { 39 | throw new RuntimeException("Cannot create Halton sequence with base less than two."); 40 | } 41 | } 42 | 43 | this.baseVector = baseVector; 44 | } 45 | 46 | /** 47 | * Construct a one dimensional Halton sequence (Van der Corput sequence) with given base. 48 | * 49 | * @param base Base of the sequence. 50 | */ 51 | public HaltonSequence(int base) { 52 | // Check base 53 | if(base < 2) { 54 | throw new RuntimeException("Cannot create Halton sequence with base less than two."); 55 | } 56 | 57 | this.baseVector = new int[] { base }; 58 | } 59 | 60 | /** 61 | * Print the first 1000 Halton numbers for base b = (2,3). 62 | * 63 | * @param args 64 | */ 65 | public static void main(String[] args) { 66 | System.out.println("Halton sequence (base b = (2,3)):"); 67 | for(int i=0; i<1000; i++) { 68 | System.out.println("" + getHaltonNumber(i, 2) + "\t" + getHaltonNumber(i, 3)); 69 | } 70 | } 71 | 72 | /** 73 | * Get Halton number for given index. 74 | * 75 | * @param index Index of the Halton number. 76 | * @return Halton number (vector). 77 | */ 78 | public double[] getHaltonNumber(long index) { 79 | final double[] x = new double[baseVector.length]; 80 | for(int baseIndex=0; baseIndex < baseVector.length; baseIndex++) { 81 | x[baseIndex] = getHaltonNumber(index, baseVector[baseIndex]); 82 | } 83 | return x; 84 | } 85 | 86 | /** 87 | * Get Halton number for given index and base. 88 | * 89 | * @param index Index of the Halton number (starting at 0). 90 | * @param base Base of the Halton number. 91 | * @return Halton number. 92 | */ 93 | public static double getHaltonNumber(long index, int base) { 94 | // Check base 95 | if(base < 2) { 96 | throw new RuntimeException("Cannot create Halton number with base less than two."); 97 | } 98 | if(index < 0) { 99 | throw new RuntimeException("Cannot create Halton number with index less than zero."); 100 | } 101 | 102 | // Index shift: counting of the function starts at 0, algorithm below starts at 1. 103 | index++; 104 | 105 | // Calculate Halton number x 106 | double x = 0; 107 | double factor = 1.0/base; 108 | while(index > 0) { 109 | x += (index % base) * factor; 110 | factor /= base; 111 | index /= base; 112 | } 113 | return x; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/randomnumbers/PseudoRandomNumberSequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 25.10.2012 5 | */ 6 | package net.finmath.experiments.montecarlo.randomnumbers; 7 | 8 | import java.util.Random; 9 | 10 | import net.finmath.randomnumbers.MersenneTwister; 11 | 12 | /** 13 | * @author Christian Fries 14 | */ 15 | public class PseudoRandomNumberSequence { 16 | 17 | enum RandomNumberGeneratorType { 18 | LCG_JAVA, 19 | MERSENNE_TWISTER 20 | } 21 | 22 | private final RandomNumberGeneratorType type; 23 | private final long seed; 24 | private final int length; 25 | private double[] randomNumbers; 26 | 27 | 28 | /** 29 | * Create a random number sequence using a specified generator, seed and length. 30 | * Note: The sequence is pre-calculated and stored in memory to allow random access. 31 | * 32 | * @param type Random number generator to use. 33 | * @param seed Seed of the generator. 34 | * @param length Length of the sequence. 35 | */ 36 | public PseudoRandomNumberSequence(RandomNumberGeneratorType type, long seed, int length) { 37 | super(); 38 | this.type = type; 39 | this.seed = seed; 40 | this.length = length; 41 | } 42 | 43 | /** 44 | * Create a random number sequence using a specified generator, seed and length. 45 | * Note: The sequence is pre-calculated and stored in memory to allow random access. 46 | * Using a Mersenne Twister as default. 47 | * 48 | * @param seed Seed of the generator. 49 | * @param length Length of the sequence. 50 | */ 51 | public PseudoRandomNumberSequence(long seed, int length) { 52 | super(); 53 | this.type = RandomNumberGeneratorType.MERSENNE_TWISTER; 54 | this.seed = seed; 55 | this.length = length; 56 | } 57 | 58 | public double getRandomNumber(int index) { 59 | if(randomNumbers == null || randomNumbers.length < length) { 60 | initRandomNumbers(); 61 | } 62 | return randomNumbers[index]; 63 | } 64 | 65 | private void initRandomNumbers() { 66 | randomNumbers = new double[length]; 67 | 68 | // Create random number sequence 69 | switch(type) { 70 | case LCG_JAVA: 71 | final Random lcgJava = new Random(seed); 72 | for(int numberIndex=0; numberIndex < length; numberIndex++) { 73 | randomNumbers[numberIndex] = lcgJava.nextDouble(); 74 | } 75 | break; 76 | case MERSENNE_TWISTER: 77 | default: 78 | final MersenneTwister mersenneTwister = new MersenneTwister(seed); 79 | for(int numberIndex=0; numberIndex < length; numberIndex++) { 80 | randomNumbers[numberIndex] = mersenneTwister.nextDouble(); 81 | } 82 | break; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/randomnumbers/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to random number generation. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.montecarlo.randomnumbers; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/LogProcessEulerScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 20.12.2003 5 | */ 6 | package net.finmath.experiments.montecarlo.schemes; 7 | 8 | import net.finmath.montecarlo.BrownianMotion; 9 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 10 | import net.finmath.montecarlo.RandomVariableFromDoubleArray; 11 | import net.finmath.stochastic.RandomVariable; 12 | import net.finmath.time.TimeDiscretization; 13 | import net.finmath.time.TimeDiscretizationFromArray; 14 | 15 | /** 16 | * Monte-Carlo simulation of a time-discrete process. 17 | * Time discretization of a log-normal process using the Euler scheme. 18 | * 19 | * Note: We do not use RandomVariable for the arithmetics. This is just for didactical reasons. 20 | * 21 | * @author Christian Fries 22 | */ 23 | public class LogProcessEulerScheme implements LognormalProcess 24 | { 25 | private final int numberOfTimeSteps; 26 | private final double deltaT; 27 | private final int numberOfPaths; 28 | private final double initialValue; 29 | private final double mu; 30 | private final double sigma; 31 | 32 | private RandomVariable[] discreteProcess = null; 33 | 34 | /** 35 | * Create a Euler scheme on X. 36 | * 37 | * @param numberOfTimeSteps The number of time steps. 38 | * @param deltaT The time step size. 39 | * @param numberOfPaths The number of Monte-Carlo paths. 40 | * @param initialValue The initial value. 41 | * @param mu The parameter mu (the drift). 42 | * @param sigma The parameter sigma. 43 | */ 44 | public LogProcessEulerScheme( 45 | int numberOfTimeSteps, 46 | double deltaT, 47 | int numberOfPaths, 48 | double initialValue, 49 | double mu, 50 | double sigma) { 51 | super(); 52 | this.numberOfTimeSteps = numberOfTimeSteps; 53 | this.deltaT = deltaT; 54 | this.numberOfPaths = numberOfPaths; 55 | this.initialValue = initialValue; 56 | this.mu = mu; 57 | this.sigma = sigma; 58 | } 59 | 60 | @Override 61 | public RandomVariable getProcessValue(int timeIndex) 62 | { 63 | if(discreteProcess == null) 64 | { 65 | doPrecalculateProcess(); 66 | } 67 | 68 | // Return value of process 69 | return discreteProcess[timeIndex]; 70 | } 71 | 72 | /** 73 | * Calculates the whole (discrete) process. 74 | */ 75 | private void doPrecalculateProcess() { 76 | 77 | final TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray( 78 | 0.0 /* initial */, getNumberOfTimeSteps(), getDeltaT()); 79 | 80 | final BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers( 81 | timeDiscretization, 1 /* numberOfFactors */, getNumberOfPaths(), 31415 /* seed */); 82 | 83 | // Allocate Memory 84 | discreteProcess = new RandomVariable[getNumberOfTimeSteps()+1]; 85 | 86 | for(int timeIndex = 0; timeIndex < getNumberOfTimeSteps()+1; timeIndex++) 87 | { 88 | final double[] newRealization = new double[numberOfPaths]; 89 | 90 | // Generate process at timeIndex 91 | if(timeIndex == 0) 92 | { 93 | // Set initial value 94 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 95 | { 96 | newRealization[iPath] = initialValue; 97 | } 98 | } 99 | else 100 | { 101 | // The numerical scheme 102 | final RandomVariable previouseRealization = discreteProcess[timeIndex-1]; 103 | final RandomVariable deltaW = brownianMotion.getBrownianIncrement(timeIndex-1, 0); 104 | 105 | // Generate values 106 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 107 | { 108 | // Drift 109 | final double drift = mu * deltaT; 110 | 111 | // Diffusion 112 | final double diffusion = sigma * deltaW.get(iPath); 113 | 114 | // Previous value 115 | final double previousValue = previouseRealization.get(iPath); 116 | 117 | // Numerical scheme 118 | final double newValue = previousValue + previousValue * drift + previousValue * diffusion; 119 | 120 | // Store new value 121 | newRealization[iPath] = newValue; 122 | } 123 | } 124 | 125 | // Store values 126 | discreteProcess[timeIndex] = new RandomVariableFromDoubleArray(timeIndex, newRealization); 127 | } 128 | } 129 | 130 | /** 131 | * Returns the time step size deltaT. 132 | * 133 | * @return the time step size deltaT. 134 | */ 135 | @Override 136 | public double getDeltaT() { 137 | return deltaT; 138 | } 139 | 140 | /** 141 | * Returns the initial value. 142 | * 143 | * @return the initial value. 144 | */ 145 | @Override 146 | public double getInitialValue() { 147 | return initialValue; 148 | } 149 | 150 | /** 151 | * Returns the number of paths. 152 | * 153 | * @return the number of paths. 154 | */ 155 | @Override 156 | public int getNumberOfPaths() { 157 | return numberOfPaths; 158 | } 159 | 160 | /** 161 | * Returns the number of time steps. 162 | * 163 | * @return the number of time steps. 164 | */ 165 | @Override 166 | public int getNumberOfTimeSteps() { 167 | return numberOfTimeSteps; 168 | } 169 | 170 | /** 171 | * Returns the log-normal drift μ. 172 | * 173 | * @return the log-normal drift μ. 174 | */ 175 | @Override 176 | public double getDrift() { 177 | return mu; 178 | } 179 | 180 | /** 181 | * Returns the log-normal volatiltiy σ. 182 | * 183 | * @return the log-normal volatiltiy σ. 184 | */ 185 | @Override 186 | public double getSigma() { 187 | return sigma; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/LogProcessLogEulerScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 16.01.2004 5 | */ 6 | package net.finmath.experiments.montecarlo.schemes; 7 | 8 | import net.finmath.montecarlo.BrownianMotion; 9 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 10 | import net.finmath.montecarlo.RandomVariableFromDoubleArray; 11 | import net.finmath.stochastic.RandomVariable; 12 | import net.finmath.time.TimeDiscretization; 13 | import net.finmath.time.TimeDiscretizationFromArray; 14 | 15 | /** 16 | * Monte-Carlo simulation of a time-discrete process. 17 | * Time discretization of a log-normal process using the Log-Euler scheme. 18 | * 19 | * Note: We do not use RandomVariable for the arithmetics. This is just for didactical reasons. 20 | * 21 | * @author Christian Fries 22 | */ 23 | public class LogProcessLogEulerScheme implements LognormalProcess 24 | { 25 | private final int numberOfTimeSteps; 26 | private final double deltaT; 27 | private final int numberOfPaths; 28 | private final double initialValue; 29 | private final double mu; 30 | private final double sigma; 31 | 32 | private RandomVariable[] discreteProcess = null; 33 | 34 | /** 35 | * Create a Euler scheme on log(X). 36 | * 37 | * @param numberOfTimeSteps The number of time steps. 38 | * @param deltaT The time step size. 39 | * @param numberOfPaths The number of Monte-Carlo paths. 40 | * @param initialValue The initial value. 41 | * @param mu The parameter mu (the drift). 42 | * @param sigma The parameter sigma. 43 | */ 44 | public LogProcessLogEulerScheme( 45 | int numberOfTimeSteps, 46 | double deltaT, 47 | int numberOfPaths, 48 | double initialValue, 49 | double mu, 50 | double sigma) { 51 | super(); 52 | this.numberOfTimeSteps = numberOfTimeSteps; 53 | this.deltaT = deltaT; 54 | this.numberOfPaths = numberOfPaths; 55 | this.initialValue = initialValue; 56 | this.mu = mu; 57 | this.sigma = sigma; 58 | } 59 | 60 | @Override 61 | public RandomVariable getProcessValue(int timeIndex) 62 | { 63 | if(discreteProcess == null) 64 | { 65 | doPrecalculateProcess(); 66 | } 67 | 68 | // Return value of process 69 | return discreteProcess[timeIndex]; 70 | } 71 | 72 | /** 73 | * Calculates the whole (discrete) process. 74 | */ 75 | private void doPrecalculateProcess() { 76 | 77 | final TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray( 78 | 0.0 /* initial */, getNumberOfTimeSteps(), getDeltaT()); 79 | 80 | final BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers( 81 | timeDiscretization, 1 /* numberOfFactors */, getNumberOfPaths(), 31415 /* seed */); 82 | 83 | // Allocate Memory 84 | discreteProcess = new RandomVariable[getNumberOfTimeSteps()+1]; 85 | 86 | for(int timeIndex = 0; timeIndex < getNumberOfTimeSteps()+1; timeIndex++) 87 | { 88 | final double[] newRealization = new double[numberOfPaths]; 89 | 90 | // Generate process at timeIndex 91 | if(timeIndex == 0) 92 | { 93 | // Set initial value 94 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 95 | { 96 | newRealization[iPath] = initialValue; 97 | } 98 | } 99 | else 100 | { 101 | // Euler Scheme 102 | final RandomVariable previouseRealization = discreteProcess[timeIndex-1]; 103 | final RandomVariable deltaW = brownianMotion.getBrownianIncrement(timeIndex-1, 0); 104 | 105 | // Generate values 106 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 107 | { 108 | // Drift 109 | final double drift = mu * deltaT; 110 | 111 | // Diffusion 112 | final double diffusion = sigma * deltaW.get(iPath); 113 | 114 | // Previous value 115 | final double previousValue = previouseRealization.get(iPath); 116 | 117 | // Numerical scheme 118 | final double newValue = previousValue * Math.exp(drift - 0.5 * sigma * sigma * deltaT + diffusion); 119 | 120 | // Store new value 121 | newRealization[iPath] = newValue; 122 | } 123 | } 124 | 125 | // Store values 126 | discreteProcess[timeIndex] = new RandomVariableFromDoubleArray(timeIndex, newRealization); 127 | } 128 | } 129 | 130 | /** 131 | * Returns the time step size deltaT. 132 | * 133 | * @return the time step size deltaT. 134 | */ 135 | @Override 136 | public double getDeltaT() { 137 | return deltaT; 138 | } 139 | 140 | /** 141 | * Returns the initial value. 142 | * 143 | * @return the initial value. 144 | */ 145 | @Override 146 | public double getInitialValue() { 147 | return initialValue; 148 | } 149 | 150 | /** 151 | * Returns the number of paths. 152 | * 153 | * @return the number of paths. 154 | */ 155 | @Override 156 | public int getNumberOfPaths() { 157 | return numberOfPaths; 158 | } 159 | 160 | /** 161 | * Returns the number of time steps. 162 | * 163 | * @return the number of time steps. 164 | */ 165 | @Override 166 | public int getNumberOfTimeSteps() { 167 | return numberOfTimeSteps; 168 | } 169 | 170 | /** 171 | * Returns the log-normal drift μ. 172 | * 173 | * @return the log-normal drift μ. 174 | */ 175 | @Override 176 | public double getDrift() { 177 | return mu; 178 | } 179 | 180 | /** 181 | * Returns the log-normal volatiltiy σ. 182 | * 183 | * @return the log-normal volatiltiy σ. 184 | */ 185 | @Override 186 | public double getSigma() { 187 | return sigma; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/LogProcessMilsteinScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 16.01.2004 5 | */ 6 | package net.finmath.experiments.montecarlo.schemes; 7 | 8 | import net.finmath.montecarlo.BrownianMotion; 9 | import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers; 10 | import net.finmath.montecarlo.RandomVariableFromDoubleArray; 11 | import net.finmath.stochastic.RandomVariable; 12 | import net.finmath.time.TimeDiscretization; 13 | import net.finmath.time.TimeDiscretizationFromArray; 14 | 15 | /** 16 | * Monte-Carlo simulation of a time-discrete process. 17 | * Time discretization of a log-normal process using the Milstein scheme. 18 | * 19 | * Note: We do not use RandomVariable for the arithmetics. This is just for didactical reasons. 20 | * 21 | * @author Christian Fries 22 | */ 23 | public class LogProcessMilsteinScheme implements LognormalProcess 24 | { 25 | private final int numberOfTimeSteps; 26 | private final double deltaT; 27 | private final int numberOfPaths; 28 | private final double initialValue; 29 | private final double mu; 30 | private final double sigma; 31 | 32 | private RandomVariable[] discreteProcess = null; 33 | 34 | /** 35 | * Create a Milstein scheme on X. 36 | * 37 | * @param numberOfTimeSteps The number of time steps. 38 | * @param deltaT The time step size. 39 | * @param numberOfPaths The number of Monte-Carlo paths. 40 | * @param initialValue The initial value. 41 | * @param mu The parameter mu (the drift). 42 | * @param sigma The parameter sigma. 43 | */ 44 | public LogProcessMilsteinScheme( 45 | int numberOfTimeSteps, 46 | double deltaT, 47 | int numberOfPaths, 48 | double initialValue, 49 | double mu, 50 | double sigma) { 51 | super(); 52 | this.numberOfTimeSteps = numberOfTimeSteps; 53 | this.deltaT = deltaT; 54 | this.numberOfPaths = numberOfPaths; 55 | this.initialValue = initialValue; 56 | this.mu = mu; 57 | this.sigma = sigma; 58 | } 59 | 60 | @Override 61 | public RandomVariable getProcessValue(int timeIndex) 62 | { 63 | if(discreteProcess == null) 64 | { 65 | doPrecalculateProcess(); 66 | } 67 | 68 | // Return value of process 69 | return discreteProcess[timeIndex]; 70 | } 71 | 72 | /** 73 | * Calculates the whole (discrete) process. 74 | */ 75 | private void doPrecalculateProcess() { 76 | 77 | final TimeDiscretization timeDiscretization = new TimeDiscretizationFromArray( 78 | 0.0 /* initial */, getNumberOfTimeSteps(), getDeltaT()); 79 | 80 | final BrownianMotion brownianMotion = new BrownianMotionFromMersenneRandomNumbers( 81 | timeDiscretization, 1 /* numberOfFactors */, getNumberOfPaths(), 31415 /* seed */); 82 | 83 | // Allocate Memory 84 | discreteProcess = new RandomVariable[getNumberOfTimeSteps()+1]; 85 | 86 | for(int timeIndex = 0; timeIndex < getNumberOfTimeSteps()+1; timeIndex++) 87 | { 88 | final double[] newRealization = new double[numberOfPaths]; 89 | 90 | // Generate process at timeIndex 91 | if(timeIndex == 0) 92 | { 93 | // Set initial value 94 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 95 | { 96 | newRealization[iPath] = initialValue; 97 | } 98 | } 99 | else 100 | { 101 | // Milstein Scheme 102 | final RandomVariable previouseRealization = discreteProcess[timeIndex-1]; 103 | final RandomVariable deltaW = brownianMotion.getBrownianIncrement(timeIndex-1, 0); 104 | 105 | // Generate values 106 | for (int iPath = 0; iPath < numberOfPaths; iPath++ ) 107 | { 108 | // Drift 109 | final double drift = mu * deltaT; 110 | 111 | // Diffusion 112 | final double diffusion = sigma * deltaW.get(iPath); 113 | 114 | // Previous value 115 | final double previousValue = previouseRealization.get(iPath); 116 | 117 | // Numerical scheme 118 | final double newValue = previousValue + previousValue * drift + previousValue * diffusion // Euler step 119 | + 1.0/2.0 * previousValue * sigma * sigma * (deltaW.get(iPath) * deltaW.get(iPath) - deltaT); // Milstein correction 120 | 121 | // Store new value 122 | newRealization[iPath] = newValue; 123 | } 124 | } 125 | 126 | // Store values 127 | discreteProcess[timeIndex] = new RandomVariableFromDoubleArray(timeIndex, newRealization); 128 | } 129 | } 130 | 131 | /** 132 | * Returns the time step size deltaT. 133 | * 134 | * @return the time step size deltaT. 135 | */ 136 | @Override 137 | public double getDeltaT() { 138 | return deltaT; 139 | } 140 | 141 | /** 142 | * Returns the initial value. 143 | * 144 | * @return the initial value. 145 | */ 146 | @Override 147 | public double getInitialValue() { 148 | return initialValue; 149 | } 150 | 151 | /** 152 | * Returns the number of paths. 153 | * 154 | * @return the number of paths. 155 | */ 156 | @Override 157 | public int getNumberOfPaths() { 158 | return numberOfPaths; 159 | } 160 | 161 | /** 162 | * Returns the number of time steps. 163 | * 164 | * @return the number of time steps. 165 | */ 166 | @Override 167 | public int getNumberOfTimeSteps() { 168 | return numberOfTimeSteps; 169 | } 170 | 171 | /** 172 | * Returns the log-normal drift μ. 173 | * 174 | * @return the log-normal drift μ. 175 | */ 176 | @Override 177 | public double getDrift() { 178 | return mu; 179 | } 180 | 181 | /** 182 | * Returns the log-normal volatiltiy σ. 183 | * 184 | * @return the log-normal volatiltiy σ. 185 | */ 186 | @Override 187 | public double getSigma() { 188 | return sigma; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/LognormalProcess.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.montecarlo.schemes; 2 | 3 | import net.finmath.stochastic.RandomVariable; 4 | 5 | /** 6 | * Interface for classes that implement different time discrete approximations 7 | * \[ 8 | * i \mapsto \tilde{X}(t_{i}) 9 | * \] 10 | * of the lognormal process 11 | * \[ 12 | * dX(t) = mu X(t) dt + sigma X(t) dW(t), X(0) = X_0 13 | * \] 14 | * with a given time discretization 15 | * \[ 16 | * 0 = t_{0} < t_{1} < ... < t_{n} 17 | * \] 18 | * 19 | * @author Christian Fries 20 | * 21 | */ 22 | public interface LognormalProcess { 23 | 24 | /** 25 | * Returns the approximation \tilde{X}(t_{i}) as a sample vector. 26 | * 27 | * @param timeIndex The time index i 28 | * @return The RandomVariable \tilde{X}(t_{i}) 29 | */ 30 | RandomVariable getProcessValue(int timeIndex); 31 | 32 | /** 33 | * Returns E(X(t_i)) - the average of the random variable given by the process at the given time index. 34 | * 35 | * @param timeIndex The time index 36 | * @return The average 37 | */ 38 | default double getExpectation(int timeIndex) { 39 | return getProcessValue(timeIndex).getAverage(); 40 | } 41 | 42 | /** 43 | * Returns E(log(X(t_i))) 44 | * 45 | * @param timeIndex The time index 46 | * @return The average of log(X) 47 | */ 48 | default double getExpectationOfLog(int timeIndex) { 49 | return getProcessValue(timeIndex).log().getAverage(); 50 | } 51 | 52 | /** 53 | * Returns Variance(log(X(t_i))) 54 | * 55 | * @param timeIndex The time index 56 | * @return The variance of log(X) 57 | */ 58 | default double getVarianceOfLog(int timeIndex) { 59 | return getProcessValue(timeIndex).log().getVariance(); 60 | } 61 | 62 | /** 63 | * @return Returns the nPaths. 64 | */ 65 | int getNumberOfPaths(); 66 | 67 | /** 68 | * @return Returns the numberOfTimeSteps. 69 | */ 70 | int getNumberOfTimeSteps(); 71 | 72 | /** 73 | * @return Returns the deltaT. 74 | */ 75 | double getDeltaT(); 76 | 77 | /** 78 | * @return Returns the initialValue. 79 | */ 80 | double getInitialValue(); 81 | 82 | /** 83 | * @return Returns the mu. 84 | */ 85 | double getDrift(); 86 | 87 | /** 88 | * @return Returns the sigma. 89 | */ 90 | double getSigma(); 91 | } -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/MonteCarloSchemeTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. 3 | * 4 | * Created on 15.01.2004 5 | */ 6 | 7 | package net.finmath.experiments.montecarlo.schemes; 8 | 9 | import java.text.DecimalFormat; 10 | 11 | /** 12 | * Testing the behaviour of some time discretization schemes w.r.t. time step size. 13 | * 14 | * @author Christian Fries 15 | */ 16 | public class MonteCarloSchemeTests { 17 | 18 | public static void main(String[] args) 19 | { 20 | System.out.println("Checking the mean (m) and the variance (V) of the terminal distribution of log(S(T)).\n" 21 | +"Generated using different numerical scheme for S (comparing to the analytic values).\n" 22 | + "\n" 23 | + "Output shows the error \u0394m (error on mean) and \u0394V (error on variance) comparing to theoretical mean and variance at time T.\n"); 24 | 25 | final double initialValue = 1.0; 26 | final double mu = 0.0; 27 | final double sigma = 0.5; // Note: Try different sigmas: 0.2, 0.5, 0.7, 0.9 28 | final int numberOfPath = 100000; // Note: Try different number of path. For 10000000 you need around 6 GB (parameter is -mx6G) 29 | final double lastTime = 10.0; 30 | 31 | for(int numberOfTimeSteps=1; numberOfTimeSteps<=1001; numberOfTimeSteps+=10) 32 | { 33 | final double deltaT = lastTime/numberOfTimeSteps; 34 | 35 | // Create an instance of the Euler scheme class 36 | final LognormalProcess eulerScheme = new LogProcessEulerScheme( 37 | numberOfTimeSteps, // numberOfTimeSteps 38 | deltaT, // deltaT 39 | numberOfPath, // numberOfPaths 40 | initialValue, // initialValue 41 | mu, // mu (drift) 42 | sigma); // sigma (volatility) 43 | 44 | // Create an instance of the Milstein scheme class 45 | final LognormalProcess milsteinScheme = new LogProcessMilsteinScheme( 46 | numberOfTimeSteps, // numberOfTimeSteps 47 | deltaT, // deltaT 48 | numberOfPath, // numberOfPaths 49 | initialValue, // initialValue 50 | mu, // mu (drift) 51 | sigma); // sigma (volatility) 52 | 53 | // Create an instance of the Log-Euler scheme class 54 | final LognormalProcess logEulerScheme = new LogProcessLogEulerScheme( 55 | numberOfTimeSteps, // numberOfTimeSteps 56 | deltaT, // deltaT 57 | numberOfPath, // numberOfPaths 58 | initialValue, // initialValue 59 | mu, // mu (drift) 60 | sigma); // sigma (volatility) 61 | 62 | // Get start time of calculation 63 | final double startMillis = System.currentTimeMillis(); 64 | 65 | final int lastTimeIndex = eulerScheme.getNumberOfTimeSteps(); 66 | 67 | final double averageEuler = eulerScheme.getExpectationOfLog( lastTimeIndex ); 68 | final double averageMilstein = milsteinScheme.getExpectationOfLog( lastTimeIndex ); 69 | final double averageLogEuler = logEulerScheme.getExpectationOfLog( lastTimeIndex ); 70 | final double averageAnalytic = Math.log(initialValue) + (mu - 0.5 * sigma * sigma) * (lastTimeIndex * deltaT); 71 | 72 | final double varianceEuler = eulerScheme.getVarianceOfLog( lastTimeIndex ); 73 | final double varianceMilstein = milsteinScheme.getVarianceOfLog( lastTimeIndex ); 74 | final double varianceLogEuler = logEulerScheme.getVarianceOfLog( lastTimeIndex ); 75 | final double varianceAnalytic = sigma * sigma * (lastTimeIndex * deltaT); 76 | 77 | // Get end time of calculation 78 | final double endMillis = System.currentTimeMillis(); 79 | 80 | final double calculationTimeInSeconds = ((float)( endMillis - startMillis )) / 1000.0; 81 | 82 | // Print result 83 | final DecimalFormat decimalFormatInteger = new DecimalFormat("000"); 84 | final double errorAverageEuler = Math.abs(averageEuler - averageAnalytic); 85 | final double errorVarianceEuler = Math.abs(varianceEuler - varianceAnalytic); 86 | final double errorAverageMilstein = Math.abs(averageMilstein - averageAnalytic); 87 | final double errorVarianceMilstein = Math.abs(varianceMilstein- varianceAnalytic); 88 | final double errorAverageLogEuler = Math.abs(averageLogEuler - averageAnalytic); 89 | final double errorVarianceLogEuler = Math.abs(varianceLogEuler- varianceAnalytic); 90 | 91 | System.out.print("nPath = " + numberOfPath); 92 | System.out.print("\tnSteps = " + decimalFormatInteger.format(numberOfTimeSteps)); 93 | System.out.print("\tEuler...: \u0394m=" + formatPercent(errorAverageEuler) + " \u0394V=" + formatPercent(errorVarianceEuler)); 94 | System.out.print("\tMilstein: \u0394m=" + formatPercent(errorAverageMilstein) + " \u0394V=" + formatPercent(errorVarianceMilstein)); 95 | System.out.print("\tLogEuler: \u0394m=" + formatPercent(errorAverageLogEuler) + " \u0394V=" + formatPercent(errorVarianceLogEuler)); 96 | System.out.println("\t(Time=" + calculationTimeInSeconds + " sec)." ); 97 | } 98 | } 99 | 100 | /* 101 | * Small helper to create nice output string. 102 | */ 103 | private static String formatInteger(int value) { 104 | return String.format("%4d", value); 105 | } 106 | 107 | /* 108 | * Small helper to create nice output string. 109 | */ 110 | private static String formatPercent(double value) { 111 | if(Double.isNaN(value)) { 112 | return "--NaN--"; 113 | } else { 114 | return String.format("%6.3f%%", value * 100); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/montecarlo/schemes/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to time discretizations of SDEs. 3 | * These are used for illustration in a lecture. 4 | * 5 | * @author Christian Fries 6 | */ 7 | package net.finmath.experiments.montecarlo.schemes; 8 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/optionvalueinterpolation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to option value interpolation 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.optionvalueinterpolation; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments illustrating numerical methods, mathematics and the use of finmath lib 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/performance/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Experiments related to performance of algorithms. 3 | * 4 | * @author Christian Fries 5 | */ 6 | package net.finmath.experiments.performance; 7 | -------------------------------------------------------------------------------- /src/main/java/net/finmath/experiments/randomnumbers/NormalViaICDFPlot.java: -------------------------------------------------------------------------------- 1 | package net.finmath.experiments.randomnumbers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import net.finmath.functions.NormalDistribution; 7 | import net.finmath.plots.Plots; 8 | import net.finmath.randomnumbers.MersenneTwister; 9 | import net.finmath.randomnumbers.RandomNumberGenerator1D; 10 | 11 | public class NormalViaICDFPlot { 12 | 13 | public static void main(String[] args) throws Exception { 14 | 15 | final int numberOfSamples = 100000; 16 | 17 | RandomNumberGenerator1D randomNumberGenerator = new MersenneTwister(3636); 18 | 19 | List valuesUniform = new ArrayList<>(); 20 | List valuesNormal = new ArrayList<>(); 21 | for(int i = 0; i series1 = new ArrayList(); 71 | final List series2 = new ArrayList(); 72 | for(int i=0; i t -> X_{i+1}(t) 50 | * @param correlation The correlation matrix. 51 | * @param brownianForResidual The Brownian motion t -> W(t) 52 | * @return The process t -> X_{1}(t) 53 | */ 54 | DoubleToRandomVariableFunction buildReconstruction(Function marketProcesses, double[][] correlation, DoubleToRandomVariableFunction brownianForResidual) { 55 | 56 | double[] generatorVector = getGeneratorVector(correlation); 57 | double generatorNormSquared = Arrays.stream(generatorVector).map(x -> x*x).sum(); 58 | 59 | DoubleToRandomVariableFunction reconstruction = time -> { 60 | RandomVariable value = new Scalar(0.0); 61 | for(int i=0; i series1 = new ArrayList(); 46 | final List series2 = new ArrayList(); 47 | for(int i=0; i