org.mot.common.math.TechnicalAnalysis.java Source code

Java tutorial

Introduction

Here is the source code for org.mot.common.math.TechnicalAnalysis.java

Source

/*
 * Copyright (C) 2015 Stephan Grotz - stephan@myopentrader.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package org.mot.common.math;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.PropertyConfigurator;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mot.common.annotation.Cacheable;
import org.mot.common.cache.CacheModule;
import org.mot.common.db.TickPriceDAO;
import org.mot.common.tools.PropertiesFactory;
import org.mot.common.util.DateBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

import eu.verdelhan.ta4j.Decimal;
import eu.verdelhan.ta4j.Tick;
import eu.verdelhan.ta4j.TimeSeries;
import eu.verdelhan.ta4j.indicators.oscillators.StochasticOscillatorDIndicator;
import eu.verdelhan.ta4j.indicators.oscillators.StochasticOscillatorKIndicator;
import eu.verdelhan.ta4j.indicators.simple.ClosePriceIndicator;
import eu.verdelhan.ta4j.indicators.trackers.SMAIndicator;

/**
 * This is an implementation class for the TA4J libraries. They are very useful for technical analysis and 
 * provides out of the box several good indicators.
 *  
 * @author stephan
 * @see https://github.com/mdeverdelhan/ta4j
 */
public class TechnicalAnalysis {

    private DateBuilder db = new DateBuilder();
    private TickPriceDAO tpd = new TickPriceDAO();
    private CalculatorFactory cf = new CalculatorFactory();
    private Logger logger = LoggerFactory.getLogger(getClass());
    private String pattern = "yyyy-MM-dd";

    private static TechnicalAnalysis instance;

    @Inject
    public TechnicalAnalysis() {

    }

    public static TechnicalAnalysis getInstance() {
        if (instance == null) {
            Injector injector = Guice.createInjector(new CacheModule());
            instance = injector.getInstance(TechnicalAnalysis.class);

            //instance = new TechnicalAnalysis();
        }
        return instance;
    }

    /**
     * This method is used to retrieve a timeseries from the database and convert it into a TA4J series, so that 
     * further technical analysis can be done. 
     * 
     * @param symbol - symbol to search for
     * @param startDate - start date (use pattern: yyyy-MM-dd)
     * @param endDate - end date (use pattern: yyyy-MM-dd)
     * @return a timeseries object
     */
    @Cacheable(name = "TechnicalAnalysis", ttl = 600)
    public TimeSeries getSeriesByDate(String symbol, String startDate, String endDate) {

        List<String> days = db.getDaysBetweenDates(startDate, endDate, pattern);
        List<Tick> taList = new ArrayList<Tick>();

        DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern);

        // Loop over all days
        Iterator<String> i = days.iterator();
        while (i.hasNext()) {

            String sd = i.next();
            String ed = db.addDaysToDate(sd, pattern, 1);
            logger.trace("Start: " + sd + " - End: " + ed);

            ArrayList<Double> ticks = tpd.getPriceForSymbolByDate(symbol, sd, ed, "BID");

            if (ticks.size() > 0) {

                Double[] values = new Double[ticks.size()];
                values = ticks.toArray(values);

                Decimal open = Decimal.valueOf(ticks.get(0));
                Decimal close = Decimal.valueOf(ticks.get(ticks.size() - 1));
                Decimal high = Decimal.valueOf(cf.getMax(values));
                Decimal low = Decimal.valueOf(cf.getMin(values));

                // Default the volume to 0 for now - we dont listen to volume indication today
                Decimal volume = Decimal.valueOf(0.0);

                DateTime dt = formatter.parseDateTime(sd);

                taList.add(new Tick(dt, open, high, low, close, volume));
            }
        }
        TimeSeries series = new TimeSeries(taList);

        return series;
    }

    /**
     * This method returns a time series with data from the last x days. 
     * 
     * @param days - how many days to include in the series
     * @param enforce - boolean value, if set to true, it ensures that at least x days are returned. (Useful to exclude weekends etc).
     * @return a timeseries object
     */

    public TimeSeries getSeriesByDays(String symbol, int days, boolean enforce) {

        long start = System.currentTimeMillis();
        String today = db.getTimeStampWithPattern(pattern);
        TimeSeries series = null;

        // Default seriesSize and iteration to 0
        int seriesSize = 0;
        int iteration = 0;

        // Loop until the seriesSize matches the requested amount of days or until we have done 30 iterations (otherwise we end up in infinite loop!)
        while ((seriesSize < days) && (iteration < 30)) {
            String startDate = db.subtractDaysFromDate(today, pattern, days + iteration);

            series = this.getSeriesByDate(symbol, startDate, today);
            seriesSize = series.getTickCount();

            // Increase the iteration by the difference between days and current seriesSize
            iteration = iteration + (days - seriesSize);
        }

        System.out.println("getSeriesByDays for " + symbol + "," + days + " took: "
                + (System.currentTimeMillis() - start) + " msecs");
        return series;

    }

    @Cacheable(name = "TechnicalAnalysis_getSeriesByDays", ttl = 600)
    public TimeSeries getSeriesByDays(String symbol, String startDate, int days, boolean enforce) {

        String today = db.getTimestampFromDate(startDate, pattern).toString();
        TimeSeries series = null;

        // Default seriesSize and iteration to 0
        int seriesSize = 0;
        int iteration = 0;

        // Loop until the seriesSize matches the requested amount of days or until we have done 30 iterations (otherwise we end up in infinite loop!)
        while ((seriesSize < days) && (iteration < 30)) {
            String sd = db.subtractDaysFromDate(today, pattern, days + iteration);

            series = this.getSeriesByDate(symbol, sd, today);
            if (series != null) {
                seriesSize = series.getTickCount();
            }

            // Increase the iteration by the difference between days and current seriesSize
            iteration = iteration + (days - seriesSize);
        }

        return series;

    }

    /**
     * Calculates the stochastic oscillator K indicator for the past 3 days.
     * 
     * @param days - how many days to go back (today minus x days)
     * @param startDate - the date when to beginn looking for data
     * @param symbol - which symbol to look for
     * @return Double value
     */
    //@CacheResult ()
    public Double getStochasticOscillatorKIndicator(String symbol, String startDate, int days) {

        long start = System.currentTimeMillis();
        Double ret = 0.0;
        int tickCount = 0;

        logger.debug("Running stochastic oscillator calculation for " + symbol + " the last " + days + " days!");

        // Create the time series
        TimeSeries series = this.getSeriesByDays(symbol, startDate, days, true);

        if (series != null) {
            // Get the tick count or size of the series
            tickCount = series.getTickCount();
        }
        if (tickCount > 0) {
            // Create a new stochasic oscillator indicator
            StochasticOscillatorKIndicator soki = new StochasticOscillatorKIndicator(series, tickCount);

            // Return the last value
            ret = soki.getValue(tickCount - 1).toDouble();
        }

        long end = System.currentTimeMillis();
        //System.out.println("getStochasticOscillatorKIndicator - Processing symbol " + symbol + "(" + startDate + ", " + days + ") took " + (end - start) + " msecs...");

        return ret;
    }

    public static void main(String[] args) {

        PropertiesFactory pf = PropertiesFactory.getInstance();
        pf.setConfigDir(args[0]);

        System.setProperty("PathToConfigDir", pf.getConfigDir());
        PropertyConfigurator.configure(pf.getConfigDir() + "/log4j.properties");

        TechnicalAnalysis ta = TechnicalAnalysis.getInstance();

        // create a new series
        //TimeSeries series = ta.getSeriesByDate("AAPL", "2014-11-17", "2014-12-25");
        TimeSeries series = ta.getSeriesByDays("AAPL", 5, true);
        System.out.println("Series contains " + series.getTickCount() + " ticks");

        int lastTick = series.getTickCount() - 1;

        // Create a close price indicator
        ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
        System.out
                .println("First value: " + series.getFirstTick().getClosePrice() + " - " + closePrice.getValue(0));
        System.out.println(
                "Last value: " + series.getLastTick().getClosePrice() + " - " + closePrice.getValue(lastTick));

        SMAIndicator shortSma = new SMAIndicator(closePrice, 5);
        System.out.println("5-ticks-SMA value at the last (" + lastTick + ") index: "
                + shortSma.getValue(lastTick).toDouble());

        StochasticOscillatorKIndicator soki = new StochasticOscillatorKIndicator(series, 3);
        System.out.println("StochasticOscillatorKIndicator value at the last (" + lastTick + ") index: "
                + soki.getValue(lastTick));
        StochasticOscillatorDIndicator sodi = new StochasticOscillatorDIndicator(soki);
        System.out.println("StochasticOscillatorDIndicator value at the last (" + lastTick + ") index: "
                + sodi.getValue(lastTick));
        //System.out.println(sodi.size());

        System.exit(0);
    }

}