Wednesday, November 7, 2018

A Double Moving Average QLearning Program - Java


package QLearning;

import java.io.IOException;
import java.sql.SQLException;
import java.util.TreeMap;

import com.americancoders.TopAndBottomList;
import com.americancoders.dataGetAndSet.GetStockDataUsingSQL;
import com.tictactec.ta.lib.Core;
import com.tictactec.ta.lib.MInteger;

import util.Realign;

/**
 * @author joe mcverry usacoder@gmail.com
 * @since 10-10-2018
 * @version 0.0.10
 *
 *          abstract class QLearner is runnable so we can run multiple tests
 *          concurrently using threads.
 */



/**
 * calls QLearningAlgorithm
 * source code posted https://usacoder.blogspot.com/2018/10/a-java-based-qlearning-algorithm-for.html
 */

public class DoubleMovingAverage extends QLearner {

    TreeMap> maFastTree;
    TreeMap> maSlowTree;

    @Override
    public String getIntervalKey() {
        /**
         * method use to find price, trend and moving average data stored in
         * tree maps
         */
        String key = intervals[0] + ";" + intervals[1];
        return key;
    }

    @Override
    public double getTrend(String symbol, String[] intervals, int i) {
        /**
         * get the trend (5 days), its overridden because some interval keys can
         * be be different
         */
        String key = intervals[1];
        return trendTree.get(symbol).get(key)[i];
    }

    @Override
    public boolean dataHere(String symbol, String intervals[], int position) {
        /**
         * skip overdata from position 0 to moving average period, its
         * overridden becaus some interval keys can be be different
         */
        String key = intervals[1];
        return maSlowTree.get(symbol).get(key)[position] != 0;
    }

    @Override
    public String getAttributeValue(String symbol, String[] intervals, int pos) {

        /**
         * this returns the attribute strings for the simple moving average
         * qlearner price at this position greater Fast MA at same position or
         * price less Fast MA price greater Slow MA or less Slow MA fast MA
         * greater Slow MA or below Slow MA
         */

        String ret = "";
        if (getPrice(symbol, pos) > maFastTree.get(symbol).get(intervals[0])[pos])
            ret += "priceAboveFast";
        else
            ret += "priceBelowFast";
        if (getPrice(symbol, pos) > maSlowTree.get(symbol).get(intervals[1])[pos])
            ret += "-priceAboveSlow";
        else
            ret += "-priceBelowSlow";
        if (maFastTree.get(symbol).get(intervals[0])[pos] > maSlowTree.get(symbol).get(intervals[1])[pos])
            ret += "-fastAboveSlow";
        else
            ret += "-fastBelowSlow";

        return ret;
    }

    /**
     * @param args
     * @throws SQLException
     * @throws IOException
     * @throws NumberFormatException
     */
    public static void main(String[] args) throws NumberFormatException, IOException, SQLException {

        DoubleMovingAverage smas = new DoubleMovingAverage();
        smas.run();
    }

    @Override
    public void run() {

        for (String symbol : QLearner.symbols) {
            /**
             * I use a list of ETFs based on the SP100 and 500 best for symbol
             * is a table with the symbol as key and the data is the best
             * returned value along with the fast and slow parameters
             */
            bestForSymbol.put(symbol, new TopAndBottomList());
            // first load up the run tables for testing
            for (int fast = 4; fast <= 10; fast++) {
                for (int slow = fast + 3; slow <= 20; slow++) {
                    try {
                        add(symbol, fast, slow);
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        for (int fast = 4; fast <= 10; fast++) {
            intervals[0] = fast + "";
            for (int slow = fast + 3; slow <= 20; slow++) {
                intervals[1] = slow + "";
                /**
                 * test and run calls the qlearner algorithm building training
                 * data up to a previous date - I use data upto 6 months ago.
                 * the method then runs a simulator using data after the
                 * trainging data stops It will populat the best for symbol
                 * table mentioned above.
                 */
                testAndRun();
            }
        }
        try {
            /**
             * after all is said and don take the best returned value for each
             * symbol and update database with the fast & slow values so the
             * same parameters can be used when making buy sell calls based on
             * the double moving averages
             */
            updateTables("DoubleMA");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public DoubleMovingAverage() {
        priceTree = new TreeMap<>();
        dateTree = new TreeMap<>();
        maFastTree = new TreeMap<>();
        maSlowTree = new TreeMap<>();
    }

    public void add(String sym, int fast, int slow) throws NumberFormatException, IOException, SQLException {

        double price[];
        String dates[];
        double maFast[];
        double maSlow[];

        intervals = new String[2];

        GetStockDataUsingSQL gsd = GetStockDataUsingSQL.getInstance(sym);
        price = gsd.inClose;
        priceTree.put(sym, price);
        dates = gsd.inDate;
        dateTree.put(sym, dates);

        Core core = new Core();

        maFast = new double[gsd.inClose.length];
        TreeMap fastTreeMap = maFastTree.get(sym);
        if (fastTreeMap == null) {
            fastTreeMap = new TreeMap<>();
            maFastTree.put(sym, fastTreeMap);
        }
        fastTreeMap.put(fast + "", maFast);
        MInteger outBegIdx = new MInteger();
        MInteger outNBElement = new MInteger();
        core.sma(0, gsd.inClose.length - 1, gsd.inClose, fast, outBegIdx, outNBElement, maFast);
        Realign.realign(maFast, outBegIdx.value);

        maSlow = new double[gsd.inClose.length];
        TreeMap slowTreeMap = maSlowTree.get(sym);
        if (slowTreeMap == null) {
            slowTreeMap = new TreeMap<>();
            maSlowTree.put(sym, slowTreeMap);
        }
        slowTreeMap.put(slow + "", maSlow);
        outBegIdx = new MInteger();
        outNBElement = new MInteger();
        core.sma(0, gsd.inClose.length - 1, gsd.inClose, slow, outBegIdx, outNBElement, maSlow);
        Realign.realign(maSlow, outBegIdx.value);

        buildTrend(sym, slow + "", gsd.inClose, trendTree);

    }

}

No comments:

Post a Comment