org.wso2.extension.siddhi.execution.var.models.montecarlo.MonteCarloStandardSimulation.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.extension.siddhi.execution.var.models.montecarlo.MonteCarloStandardSimulation.java

Source

/*
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.extension.siddhi.execution.var.models.montecarlo;

import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class MonteCarloStandardSimulation {

    private NormalDistribution distribution = null;
    private DescriptiveStatistics stat = null;
    private double randomZValue = 0.0;
    public static double[] finalSimulatedValues;
    Random rnd = new Random(3);

    public MonteCarloStandardSimulation() {
    }

    public MonteCarloStandardSimulation(int numberOfTrials) {
        MonteCarloStandardSimulation.finalSimulatedValues = new double[numberOfTrials];
    }

    /**
     * return a random Z value from thr probability Distribution
     *
     * @return
     */
    private double getRandomZVal() {
        randomZValue = this.getDistribution().inverseCumulativeProbability(Math.random());
        return randomZValue;
    }

    private double getRandomZValThreadSafe() {
        randomZValue = this.getDistribution().inverseCumulativeProbability(rnd.nextDouble());
        return randomZValue;
    }

    /**
     * get the future stock price using Geomatric brownian motion
     *
     * @param parameters
     * @return
     */
    public double getBrownianMotionOutput(Map<String, Double> parameters) {

        double drift = (parameters.get("distributionMean")
                - (parameters.get("standardDeviation") * parameters.get("standardDeviation")) / 2)
                * parameters.get("timeSlice");
        double stochasticOffset = parameters.get("standardDeviation") * parameters.get("randomValue")
                * Math.sqrt(parameters.get("timeSlice"));
        return parameters.get("currentStockValue") * Math.exp(drift + stochasticOffset);
    }

    /**
     * perform monte carlo simulation and return array of terminal values
     *
     * @param numberOfTrials
     * @param calculationsPerDay
     * @param timeSlice
     * @param currentStockPrice
     * @return
     */
    public double[] simulation(double mean, double std, double timeSlice, double currentStockPrice,
            int numberOfTrials, int calculationsPerDay) {
        double terminalStockValues[] = new double[numberOfTrials];

        Map<String, Double> parameters;
        parameters = new HashMap<>();
        double tempStockValue = 0;

        parameters.put("distributionMean", mean);
        parameters.put("standardDeviation", std);
        parameters.put("timeSlice", timeSlice);
        parameters.put("randomValue", this.getRandomZVal());
        parameters.put("currentStockValue", currentStockPrice);

        for (int i = 0; i < numberOfTrials; i++) {
            parameters.put("currentStockValue", currentStockPrice);
            for (int j = 0; j < calculationsPerDay; j++) {
                tempStockValue = this.getBrownianMotionOutput(parameters);
                parameters.put("randomValue", this.getRandomZVal());
                parameters.put("currentStockValue", tempStockValue);
            }
            terminalStockValues[i] = tempStockValue;
        }
        return terminalStockValues;
    }

    /**
     * get instance of normal distribution
     *
     * @return
     */
    public NormalDistribution getDistribution() {
        if (!(distribution instanceof NormalDistribution)) {
            this.distribution = new NormalDistribution();
        }
        return this.distribution;
    }

    /**
     * Do the simulation in parallel
     *
     * @param numberOfTrials
     * @param calculationsPerDay
     * @param timeSlice
     * @param currentStockPrice
     * @return
     */
    public double[] parallelSimulation(double mean, double std, double timeSlice, double currentStockPrice,
            int numberOfTrials, int calculationsPerDay) {
        int cores = Runtime.getRuntime().availableProcessors();
        int taskForOneThread = numberOfTrials / cores;
        int remainingTask = numberOfTrials % cores;
        int startingPoint;

        Thread threads[] = new Thread[cores];

        for (int i = 0; i < threads.length; i++) {
            startingPoint = i * taskForOneThread;
            //assign remaining tasks for the last thread
            if (i == threads.length - 1) {
                taskForOneThread = taskForOneThread + remainingTask;
            }

            threads[i] = new Thread(new ParallelSimulation(taskForOneThread, calculationsPerDay, mean, std,
                    timeSlice, currentStockPrice, startingPoint), i + "");
            threads[i].start();
        }

        for (int i = 0; i < threads.length; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return MonteCarloStandardSimulation.finalSimulatedValues;
    }

    class ParallelSimulation implements Runnable {
        private int numberOfTrials;
        private int startingPoint;
        private int calculationsPerDay;
        Map<String, Double> parameters;
        private MonteCarloStandardSimulation simulationReference = new MonteCarloStandardSimulation();
        private double currentStockPrice;

        public ParallelSimulation(int numberOfTrials, int calculationsPerDay, double mean, double std,
                double timeSlice, double currentStockPrice, int startingPoint) {

            this.numberOfTrials = numberOfTrials;
            this.calculationsPerDay = calculationsPerDay;
            this.startingPoint = startingPoint;
            this.currentStockPrice = currentStockPrice;

            parameters = new HashMap<>();
            parameters.put("distributionMean", mean);
            parameters.put("standardDeviation", std);
            parameters.put("timeSlice", timeSlice);
            parameters.put("randomValue", simulationReference.getRandomZValThreadSafe());
            parameters.put("currentStockValue", currentStockPrice);
        }

        @Override
        public void run() {

            double tempStockValue = 0;
            for (int i = startingPoint; i < startingPoint + numberOfTrials; i++) {
                parameters.put("currentStockValue", currentStockPrice);
                for (int j = 0; j < calculationsPerDay; j++) {
                    tempStockValue = simulationReference.getBrownianMotionOutput(parameters);
                    parameters.put("randomValue", simulationReference.getRandomZValThreadSafe());
                    parameters.put("currentStockValue", tempStockValue);
                }
                MonteCarloStandardSimulation.finalSimulatedValues[i] = tempStockValue;
            }
        }
    }
}