com.opengamma.analytics.financial.covariance.ExponentialWeightedMovingAverageHistoricalVolatilityCalculator.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.covariance.ExponentialWeightedMovingAverageHistoricalVolatilityCalculator.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.covariance;

import java.util.Iterator;

import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.analytics.financial.timeseries.returns.ContinuouslyCompoundedTimeSeriesReturnCalculator;
import com.opengamma.analytics.financial.timeseries.returns.TimeSeriesReturnCalculator;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.CalculationMode;

/**
 *
 * Exponentially weighted moving average (EWMA) volatility calculations put
 * variable weight on the values in a time series. The weight is controlled by
 * a parameter $\lambda$ which can take any positive value: in most markets,
 * the most suitable range is between 0.75 and 1.
 * <p>
 * The exponential moving average of a time series is given by:
 * $$
 * \begin{eqnarray*}
 * \frac{x_{t-1} + \lambda x_{t-2} + \lambda^2 x_{t-3} + \dots + \lambda^{n-1} x_{t-n}}{1 + \lambda + \lambda^2 + \dots + \lambda^{n-1}}
 * \end{eqnarray*}
 * $$
 * where $x_i$ is the $i^\text{th}$ value in the time series and $\lambda$ is
 * the weight.
 * <p>
 * The exponential weighted volatility is:
 * $$
 * \begin{eqnarray*}
 * \sigma_t = \sqrt{\lambda \sigma_{t-1}^2 + (1 - \lambda)r_t^2}
 * \end{eqnarray*}
 * $$
 * where $\sigma_{t-1}$ is the previous volatility calculation and $r_t$ is the
 * continuously compounded return over a single period.  As with other
 * historical volatility calculations, the volatility can be annualized by
 * scaling by the square root of the number of periods in a year.
 */
public class ExponentialWeightedMovingAverageHistoricalVolatilityCalculator extends HistoricalVolatilityCalculator {
    /** The logger */
    private static final Logger s_logger = LoggerFactory
            .getLogger(ExponentialWeightedMovingAverageHistoricalVolatilityCalculator.class);
    /** The return calculator */
    private final TimeSeriesReturnCalculator _returnCalculator;
    /** Lambda, the volatility weighting parameter */
    private final double _lambda;
    /** Lambda minus one */
    private final double _lambdaM1;

    /**
     * Although the return calculator can be any {@link TimeSeriesReturnCalculator}, to obtain correct results a {@link ContinuouslyCompoundedTimeSeriesReturnCalculator} should be
     * used. The calculation mode is set to be the default (strict). Although the weight parameter can take any positive value, for most use the range should be $\lambda < 1$;
     * if a value higher outside of this range is used then greater weight will be placed on older return values.
     * @param lambda The weight parameter, not negative
     * @param returnCalculator The return calculator, not null
     */
    public ExponentialWeightedMovingAverageHistoricalVolatilityCalculator(final double lambda,
            final TimeSeriesReturnCalculator returnCalculator) {
        this(lambda, returnCalculator, getDefaultCalculationMode());
    }

    /**
     * Although the return calculator can be any {@link TimeSeriesReturnCalculator}, to obtain correct results a {@link ContinuouslyCompoundedTimeSeriesReturnCalculator} should be
     * used. Although the weight parameter can take any positive value, for most use the range should be $\lambda < 1$; if a value higher outside of this range is used then
     * greater weight will be placed on older return values.
     * @param lambda The weight parameter, not negative
     * @param returnCalculator The return calculator, not null
     * @param mode The calculation mode, not null
     */
    public ExponentialWeightedMovingAverageHistoricalVolatilityCalculator(final double lambda,
            final TimeSeriesReturnCalculator returnCalculator, final CalculationMode mode) {
        super(mode);
        ArgumentChecker.notNull(returnCalculator, "return calculator");
        ArgumentChecker.notNull(mode, "calculation mode");
        ArgumentChecker.notNegative(lambda, "lambda");
        if (lambda > 1) {
            s_logger.warn("Weight for EWMA series is greater than one: this is probably not what was intended");
        }
        _lambda = lambda;
        _lambdaM1 = 1 - lambda;
        _returnCalculator = returnCalculator;
    }

    /**
     * @param x The array of price time series. The first time series should be the price; any other arrays are assumed to be a timeseries of dividend payments.
     * @return The exponential weighted historical volatility
     * @throws IllegalArgumentException If x is null, empty or if the first element of the array is null; if the number of values in the time series is less than three; if the
     * dates in the different time series do not coincide
     */
    @Override
    public Double evaluate(final LocalDateDoubleTimeSeries... x) {
        testTimeSeries(x, 3);
        final LocalDateDoubleTimeSeries returnTS = _returnCalculator.evaluate(x);
        final Iterator<Double> iter = returnTS.valuesIterator();
        double returnValue = iter.next();
        double variance = returnValue * returnValue;
        while (iter.hasNext()) {
            returnValue = iter.next();
            variance = _lambda * variance + _lambdaM1 * returnValue * returnValue;
        }
        return Math.sqrt(variance);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        long temp;
        temp = Double.doubleToLongBits(_lambda);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        result = prime * result + ((_returnCalculator == null) ? 0 : _returnCalculator.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!super.equals(obj)) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ExponentialWeightedMovingAverageHistoricalVolatilityCalculator other = (ExponentialWeightedMovingAverageHistoricalVolatilityCalculator) obj;
        if (Double.doubleToLongBits(_lambda) != Double.doubleToLongBits(other._lambda)) {
            return false;
        }
        return ObjectUtils.equals(_returnCalculator, other._returnCalculator);
    }
}