/*
* Copyright 2014-2015 JKOOL, LLC.
*
* Licensed 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 com.jkoolcloud.tnt4j.utils;
import java.util.Iterator;
import java.util.List;
/**
* Math utility methods.
*
* @version $Revision: 1 $
*/
public class MathUtils {
private MathUtils() {
}
/**
* Compute low Bollinger band value. Same as {@code getBBLow(List, 2, 20)}
*
* @param harray of numbers (measurements) sorted by time
* @return low Bollinger band value
*/
public static double getBBLow(List<Number> harray) {
return getBBLow(harray, 2, 20);
}
/**
* Compute high Bollinger band value. Same as {@code getBoHigh(List, 2, 20)}
*
* @param harray of numbers (measurements) sorted by time
* @return high Bollinger band value
*/
public static double getBBHigh(List<Number> harray) {
return getBBHigh(harray, 2, 20);
}
/**
* Compute low Bollinger band value. Typical values for N and K are 20 and 2, respectively.
*
* @param harray of numbers (measurements) sorted by time
* @param kTimes K times an N-period standard deviation above the EMA(nPeriod)
* @param nPeriod an N-period moving average (EMA)
* @return low Bollinger band value
*/
public static double getBBLow(List<Number> harray, int kTimes, int nPeriod) {
double low = 0;
if (harray != null && harray.size() >= nPeriod) {
double mean = getEMA(harray, nPeriod);
double dev = Math.sqrt(getHVariance(harray, mean));
low = mean - (kTimes * dev);
}
return low;
}
/**
* Compute high Bollinger band value. Typical values for N and K are 20 and 2, respectively.
*
* @param harray of numbers (measurements) sorted by time
* @param kTimes K times an N-period standard deviation above the EMA(nPeriod)
* @param nPeriod an N-period exponentially moving average (EMA)
* @return high Bollinger band value
*/
public static double getBBHigh(List<Number> harray, int kTimes, int nPeriod) {
double high = 0;
if (harray != null && harray.size() >= nPeriod) {
double mean = getEMA(harray, nPeriod);
double dev = Math.sqrt(getHVariance(harray, mean));
high = mean + (kTimes * dev);
}
return high;
}
/**
* Compute historical variance for a given set of measurements
*
* @param harray of numbers (measurements)
* @return variance
*/
public static double getHVariance(List<Number> harray) {
return getHVariance(harray, getHMean(harray));
}
/**
* Compute historical variance given a mean
*
* @param harray of numbers (measurements)
* @param mean computed for the given array of numbers
* @return variance
*/
public static double getHVariance(List<Number> harray, double mean) {
double vsum = 0, variance = 0;
if (harray != null && harray.size() > 1) {
Iterator<Number> it = harray.iterator();
while (it.hasNext()) {
Number vl = it.next();
double val = vl.doubleValue() - mean;
vsum += (val * val);
}
if (harray.size() > 1) {
variance = vsum / (harray.size() - 1);
}
}
return variance;
}
/**
* Compute mean for a given set of numbers
*
* @param harray of numbers (measurements)
* @return mean
*/
public static double getHMean(List<Number> harray) {
Iterator<Number> it = harray.iterator();
double vsum = 0, mean = 0;
int count = 0;
while (it.hasNext()) {
Number vl = it.next();
double val = vl.doubleValue();
vsum += val;
count++;
}
mean = count > 0 ? vsum / count : mean;
return mean;
}
/**
* Compute mean for a given set of numbers and number of elements
*
* @param harray of numbers (measurements)
* @param nPeriod an N-period for which to compute the mean
* @return mean
*/
public static double getHMean(List<Number> harray, int nPeriod) {
double vsum = 0, mean = 0;
int count = 0;
Iterator<Number> it = harray.iterator();
while (it.hasNext() && (count < nPeriod)) {
Number vl = it.next();
double val = vl.doubleValue();
vsum += val;
count++;
}
mean = count > 0 ? vsum / count : mean;
return mean;
}
/**
* Compute EMA for a given set of numbers
* and 20 N period moving average.
*
* @param harray of numbers (measurements)
* @return N-period exponentially moving average
*/
public static double getEMA(List<Number> harray) {
return getEMA(harray, 20);
}
/**
* Compute EMA for a given set of numbers
* and a given N-period moving average
*
* @param harray of numbers (measurements)
* @param nPeriod an N-period for which to compute the EMA
* @return N-period exponentially moving average
*/
public static double getEMA(List<Number> harray, int nPeriod) {
if (harray != null && harray.size() > 1) {
// calculate based EMA(nSamples) which is same as SMA(nPeriod)
double nEma = getHMean(harray, nPeriod);
float k = (float) 2 / (float) (nPeriod + 1);
int size = harray.size();
for (int i = nPeriod; i < size; i++) {
Number cVal = harray.get(i);
nEma = getKoEMA(cVal.doubleValue(), k, nEma);
}
return nEma;
}
return 0.0;
}
/**
* Compute EMA for a given number
* and a previous N-period moving average
*
* @param cVal measured number
* @param nPeriod an N-period for which to compute the EMA
* @param pEMA previous computed EMA
* @return N-period exponentially moving average
*/
public static double getEMA(double cVal, int nPeriod, double pEMA) {
float k = (float) 2 / (float) (nPeriod + 1);
return getKoEMA(cVal, k, pEMA);
}
/**
* Compute EMA for a given number, k
* and a given N-period moving average
*
* @param cVal measured number
* @param k weighting coefficient
* @param pEMA previous computed EMA
* @return N-period exponentially moving average
*/
public static double getKoEMA(double cVal, float k, double pEMA) {
return (k * (cVal - pEMA)) + pEMA;
}
}