/**
* 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.TimeSeriesReturnCalculator;
import com.opengamma.timeseries.DoubleTimeSeries;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.CalculationMode;
/**
* Calculates the historical volatility of a time series with a given return
* calculation method.
* <p>
* The historical volatility of a time series with close price data $x_i$ is
* given by:
* $$
* \begin{eqnarray*}
* \sigma = \sqrt{\frac{1}{n(n-1)}\sum\limits_{i=1}^n (r_i - \overline{r})^2}
* \end{eqnarray*}
* $$
* where $r_i$ is the $i^\text{th}$ period return of the time series and $n$ is
* the number of data points in the return series.
*/
public class HistoricalVolatilityCloseCalculator extends HistoricalVolatilityCalculator {
/** The logger */
private static final Logger s_logger = LoggerFactory.getLogger(HistoricalVolatilityCloseCalculator.class);
/** The return calculator */
private final TimeSeriesReturnCalculator _returnCalculator;
/**
* Creates a historical volatility calculator with the given return
* calculation method and default values for the calculation mode and
* allowable percentage of bad data points
* @param returnCalculator The return calculator, not null
*/
public HistoricalVolatilityCloseCalculator(final TimeSeriesReturnCalculator returnCalculator) {
super();
ArgumentChecker.notNull(returnCalculator, "return calculator");
_returnCalculator = returnCalculator;
}
/**
* Creates a historical volatility calculator with the given return
* calculation method and calculation mode and the default value for the
* allowable percentage of bad data points
* @param returnCalculator The return calculator, not null
* @param mode The calculation mode, not null
*/
public HistoricalVolatilityCloseCalculator(final TimeSeriesReturnCalculator returnCalculator, final CalculationMode mode) {
super(mode);
ArgumentChecker.notNull(returnCalculator, "return calculator");
_returnCalculator = returnCalculator;
}
/**
* Creates a historical volatility calculator with the given return
* calculation method, calculation mode and allowable percentage of bad data
* points
* @param returnCalculator The return calculator
* @param mode The calculation mode
* @param percentBadDataPoints The maximum allowable percentage of bad data points
* @throws IllegalArgumentException If the return calculator is null
*/
public HistoricalVolatilityCloseCalculator(final TimeSeriesReturnCalculator returnCalculator, final CalculationMode mode, final double percentBadDataPoints) {
super(mode, percentBadDataPoints);
ArgumentChecker.notNull(returnCalculator, "return calculator");
_returnCalculator = returnCalculator;
}
/**
* If more than one price time series is provided, the first element of the
* array is used.
* @param x The array of price time series
* @return The historical close volatility
* @throws IllegalArgumentException If the array is null or empty; if the first element of the array is null; if the price series does not contain at least two data points
*/
@Override
public Double evaluate(final LocalDateDoubleTimeSeries... x) {
testTimeSeries(x, 2);
if (x.length > 1) {
s_logger.info("Time series array contained more than one series; only using the first one");
}
testTimeSeries(x, 2);
final DoubleTimeSeries<?> returnTS = _returnCalculator.evaluate(x);
final Iterator<Double> iter = returnTS.valuesIterator();
Double value;
double sum = 0;
double sumSq = 0;
final int n = returnTS.size() - 1;
while (iter.hasNext()) {
value = iter.next();
sum += value;
sumSq += value * value;
}
return Math.sqrt((sumSq - sum * sum / (n + 1)) / n);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
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 HistoricalVolatilityCloseCalculator other = (HistoricalVolatilityCloseCalculator) obj;
return ObjectUtils.equals(_returnCalculator, other._returnCalculator);
}
}