info.financialecology.finance.utilities.datastruct.DoubleTimeSeries.java Source code

Java tutorial

Introduction

Here is the source code for info.financialecology.finance.utilities.datastruct.DoubleTimeSeries.java

Source

/*
 * Copyright (c) 2011-2014 Gilbert Peffer, Barbara Llacay
 * 
 * The source code and software releases are available at http://code.google.com/p/systemic-risk/
 * 
 * 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 info.financialecology.finance.utilities.datastruct;

import info.financialecology.finance.utilities.Assertion;
import info.financialecology.finance.utilities.Assertion.Level;

import java.text.DecimalFormat;
import java.util.ArrayList;

import org.apache.commons.math3.stat.StatUtils;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import cern.colt.list.*;
import cern.jet.stat.Descriptive;

/**
 * A time series class that holds doubles. Based on the {@code DoubleArrayList} from {@literal cern.colt.list }
 * 
 * @author Gilbert Peffer
 *
 */
@SuppressWarnings("serial")
public class DoubleTimeSeries extends AbstractDoubleList {
    /**
     * TODO Add a toString method to debug the time series 
     * TODO Remove 'ticks' since gaps are not allowed. Introduce a boolean to indicate where gaps are, 
     * if needed (filling up the values with zeros where no value is provided can be problematic) 
     */
    private final int MAX_OUPUT_HEAD = 180; // TODO move output formatting to elsewhere
    private final int MAX_OUPUT_TAIL = 20; // TODO move output formatting to elsewhere
    private static DecimalFormat formatter = new DecimalFormat();

    private IntArrayList ticks;
    private DoubleArrayList values;
    private String id;
    private int size = 0;

    public DoubleTimeSeries() {
        this.id = "anonymous_double_time_series";

        this.ticks = new IntArrayList();
        this.values = new DoubleArrayList();
    }

    public DoubleTimeSeries(String id) {
        this();
        this.id = id;
    }

    public DoubleTimeSeries(DoubleArrayList dal) {
        this.id = "anonymous_double_time_series";

        this.ticks = new IntArrayList();
        this.values = new DoubleArrayList();

        for (int i = 0; i < dal.size(); i++)
            add(dal.get(i));
    }

    public DoubleTimeSeries(String id, DoubleArrayList dal) {
        this(dal);
        this.id = id;
    }

    public void fillWithConstants(int length, double constant) {
        ticks.clear();
        values.clear();
        size = 0;

        for (int i = 0; i < length; i++)
            add(constant);
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Override
    public void add(double value) {
        add(size, value);
    }

    @Override
    public double get(int index) {
        return values.get(index);
    }

    /**
     * Add a value at location tick. Handles the three cases where the
     * value is appended, where it replaces an existing value, and where
     * it adds a value beyond the bounds of the array and the missing 
     * intermediate values are set to zero.
     * 
     * @param tick
     * @param value
     */
    public void add(int tick, double value) {

        if (tick == size) { // tick is the next in sequence -> append to array
            ticks.add(tick);
            values.add(value);
            size++;
        } else if (tick < size) { // tick already exists in the sequence -> replace value
            values.set(tick, value);
        } else { // tick skips ahead of end of sequence -> insert zeros for the skipped values but emit warning
            Assertion.assertStrict(false, Level.INFO,
                    "Inserting value beyond end of array in DoubleTimeSeries '" + id);

            for (int i = size; i < tick; i++) {
                ticks.add(i);
                values.add(0);
            }

            ticks.add(tick);
            values.add(value);

            size = tick + 1;
        }
    }

    public void addToValue(int tick, double value) {
        double v = this.values.get(tick);
        this.values.set(tick, v + value);
    }

    public void set(int tick, double element) {
        values.set(tick, element);
    }

    public int[] ticks() {
        return ticks.elements();
    }

    public double[] values() {
        return values.elements();
    }

    public String ticksToString() {
        String ts = "[";
        int nTicks = ticks.size();
        int headLength = nTicks < MAX_OUPUT_HEAD ? nTicks : MAX_OUPUT_HEAD;
        int tailLength = nTicks < MAX_OUPUT_HEAD ? 0 : nTicks - MAX_OUPUT_HEAD;
        tailLength = tailLength < MAX_OUPUT_TAIL ? tailLength : MAX_OUPUT_TAIL;

        for (int i = 0; i < headLength; i++) {
            ts += String.format("%11d", ticks.get(i));
        }

        if (tailLength > 0)
            ts += "     ... ";

        for (int i = nTicks - tailLength; i < nTicks; i++) {
            ts += String.format("%11d", ticks.get(i)); // TODO create a settings xml file for the formatting and other settings
        }

        return ts + "]";
    }

    public int size() {
        return values.size();
    }

    public static void setFormatter(DecimalFormat df) {
        formatter = df;
    }

    /* (non-Javadoc)
     * @see cern.colt.list.AbstractDoubleList#ensureCapacity(int)
     */
    @Override
    public void ensureCapacity(int minCapacity) {
        ticks.ensureCapacity(minCapacity);
        values.ensureCapacity(minCapacity);
    }

    public int getTick(int index) {
        return ticks.get(index);
    }

    /**
     * Return the last tick of the time series
     * 
     * @param index
     * @return
     */
    public int getLastTick() {
        return ticks.get(ticks.size() - 1);
    }

    public double getValue(int index) {
        return values.get(index);
    }

    /* (non-Javadoc)
     * @see cern.colt.list.AbstractDoubleList#getQuick(int)
     */
    @Override
    protected double getQuick(int index) {
        return values.getQuick(index);
    }

    /* (non-Javadoc)
     * @see cern.colt.list.AbstractDoubleList#setQuick(int, double)
     */
    @Override
    protected void setQuick(int index, double element) {
        //      throw IllegalArgumentException("Not implemented");
    }

    /**
     * Compares the following characteristics of two time series:
     * <ul>
     * <li> size of the time series (=number of ticks stored)
     * <li> first tick
     * <li> last tick
     * </ul> 
     * 
     * @return true, if the characteristics of both time series are the same
     */
    public Boolean quickCompare(DoubleTimeSeries ts) {
        if ((this.size() != ts.size()) || (this.getTick(0) != ts.getTick(0))
                || (this.getTick(this.size() - 1) != ts.getTick(ts.size() - 1)))
            return false;

        return true;
    }

    /**
     * First order difference of the time series
     * 
     * @return
     */
    public DoubleTimeSeries getFirstDiff() {

        Assertion.assertOrKill(this.size() > 1,
                "Method getFirstDiff() requires the time series to contain more than one data point");

        DoubleTimeSeries firstDiff = new DoubleTimeSeries();

        for (int t = 1; t < this.size(); t++)
            firstDiff.add(this.get(t) - this.get(t - 1));

        return firstDiff;
    }

    public double mean() {
        DescriptiveStatistics stats = new DescriptiveStatistics();

        for (int i = 0; i < this.values.size(); i++)
            stats.addValue(this.values.get(i));

        return stats.getMean();
    }

    public double stdev() {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (int i = 0; i < this.values.size(); i++)
            stats.addValue(this.values.get(i));

        return stats.getStandardDeviation();
    }

    public double skewness() {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (int i = 0; i < this.values.size(); i++)
            stats.addValue(this.values.get(i));

        return stats.getSkewness();
    }

    public double unbiasedExcessKurtosis() {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (int i = 0; i < this.values.size(); i++)
            stats.addValue(this.values.get(i));

        return stats.getKurtosis();
    }

    public double excessKurtosis() {
        double s2 = 0, s4 = 0, mean = 0, n = this.values.size();

        for (int i = 0; i < n; i++)
            mean += this.values.get(i);

        mean /= n;

        for (int i = 0; i < n; i++) {
            s2 += Math.pow(this.values.get(i) - mean, 2);
            s4 += Math.pow(this.values.get(i) - mean, 4);
        }

        double m2 = s2 / n;
        double m4 = s4 / n;

        return m4 / Math.pow(m2, 2) - 3;
    }

    public double unbiasedExcessKurtosisOverInterval(int start, int length) {
        DescriptiveStatistics stats = new DescriptiveStatistics();

        for (int i = start; i < start + length; i++)
            stats.addValue(this.values.get(i));

        return stats.getKurtosis();
    }

    public double normalisedVolatility() {
        DescriptiveStatistics stats = new DescriptiveStatistics();

        for (int i = 0; i < this.values.size(); i++)
            stats.addValue(this.values.get(i));

        return stats.getStandardDeviation() / Math.sqrt(this.values.size());
    }

    public DoubleArrayList acf(int maxLag) {

        DoubleArrayList acfValues = new DoubleArrayList();

        double mean = Descriptive.mean(values);
        double var = Descriptive.variance(values.size(), Descriptive.sum(values), Descriptive.sumOfSquares(values));

        for (int lag = 0; lag <= maxLag; lag++)
            acfValues.add(Descriptive.autoCorrelation(values, lag, mean, var));

        return acfValues;
    }

    public DoubleArrayList acfAbs(int maxLag) {

        DoubleArrayList acfValues = new DoubleArrayList();
        DoubleArrayList absValues = new DoubleArrayList();

        for (int i = 0; i < values.size(); i++)
            absValues.add(Math.abs(values.get(i)));

        double mean = Descriptive.mean(absValues);
        double var = Descriptive.variance(absValues.size(), Descriptive.sum(absValues),
                Descriptive.sumOfSquares(absValues));

        for (int lag = 0; lag <= maxLag; lag++)
            acfValues.add(Descriptive.autoCorrelation(absValues, lag, mean, var));

        return acfValues;
    }

    public DoubleArrayList acfSquared(int maxLag) {

        DoubleArrayList acfValues = new DoubleArrayList();
        DoubleArrayList squareValues = new DoubleArrayList();

        for (int i = 0; i < values.size(); i++)
            squareValues.add(Math.pow(values.get(i), 2));

        double mean = Descriptive.mean(squareValues);
        double var = Descriptive.variance(squareValues.size(), Descriptive.sum(squareValues),
                Descriptive.sumOfSquares(squareValues));

        for (int lag = 0; lag <= maxLag; lag++)
            acfValues.add(Descriptive.autoCorrelation(squareValues, lag, mean, var));

        return acfValues;
    }

    public double percentile(int percentile, int window) {

        Assertion.assertStrict(window <= this.values.size(), Level.ERR,
                "percentile(): Length of time series must be larger than the window (" + window + ").");

        DescriptiveStatistics stats = new DescriptiveStatistics();
        int tsLength = this.values.size();

        for (int i = 0; i < window; i++) {
            stats.addValue(this.values.get(tsLength - i - 1));
        }

        return stats.getPercentile(percentile);
    }

    @Override
    public String toString() {
        String ts = "[";
        int nTicks = ticks.size();
        int headLength = nTicks < MAX_OUPUT_HEAD ? nTicks : MAX_OUPUT_HEAD;
        int tailLength = nTicks < MAX_OUPUT_HEAD ? 0 : nTicks - MAX_OUPUT_HEAD;
        tailLength = tailLength < MAX_OUPUT_TAIL ? tailLength : MAX_OUPUT_TAIL;

        for (int i = 0; i < headLength; i++) {
            ts += String.format("%11.5g", values.get(i));
        }

        if (tailLength > 0)
            ts += "     ... ";

        for (int i = nTicks - tailLength; i < nTicks; i++) {
            ts += String.format("%11.5g", values.get(i)); // TODO create a settings xml file for the formatting and other settings
        }

        return ts + "]";
    }

}