<repo_name>Glamopod/MVP<file_sep>/src/main/java/de/mvpdt/mvp_dt/controller/MainController.java
package de.mvpdt.mvp_dt.controller;

import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;

/**
 * https://openexchangerates.org/api/latest.json?app_id=da84d2fed1f34062af7e28694fc22e7f&base=USD&symbols=EUR
 * https://docs.openexchangerates.org/docs/latest-json
 * https://timestamp.online/
 * https://stackabuse.com/reading-and-writing-json-in-java/
 *
 */
@Controller
@RequestMapping(value = {"","/person"})
public class MainController {

    @GetMapping(value = {"/","index"})
    public String index(Model model) throws URISyntaxException {
        String str = "https://openexchangerates.org/api/latest.json?app_id=da84d2fed1f34062af7e28694fc22e7f&base=USD&symbols=GBP%2CEUR";
        RestTemplate rs = new RestTemplate();
        JSONObject forObject = rs.getForObject(new URI(str), JSONObject.class);
        Integer timestamp = (Integer) forObject.get("timestamp");
        String base = (String)forObject.get("base");
        LinkedHashMap rates = (LinkedHashMap) forObject.get("rates");
//        System.out.println(personService.findAll());

        Date currentDate = new Date ((long)timestamp * 1000);
        SimpleDateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        String date = dateFormat.format(currentDate);

        model.addAttribute("timestampAsInteger", timestamp);
        model.addAttribute("dataFromTimestamp", date);
        model.addAttribute("base_currency", base);
        model.addAttribute("rates", rates);

        return "index";
    }

    @PostMapping
    public String add(HttpServletRequest request, Model model) {
        //@RequestParam("zahl1") String zahl
        String zahl12 = request.getParameter("zahl1");
        model.addAttribute("result", zahl12);
        return "index";
    }
}
<file_sep>/src/main/java/de/mvpdt/mvp_dt/prediction/NeuralNetworkStockPredictor.java
package de.mvpdt.mvp_dt.prediction;

import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Stream;

import de.mvpdt.mvp_dt.exception.EmptyTokenException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.core.data.DataSetRow;
import org.neuroph.core.events.LearningEvent;
import org.neuroph.core.events.LearningEventListener;
import org.neuroph.core.learning.SupervisedLearning;
import org.neuroph.nnet.MultiLayerPerceptron;
import org.neuroph.nnet.learning.BackPropagation;


/**
 * https://technobium.com/stock-market-prediction-using-neuroph-neural-networks/
 */
public class NeuralNetworkStockPredictor {

    private int slidingWindowSize;
    private double max = 0;
    private double min = Double.MAX_VALUE;
    private String rawDataFilePath;

    private String learningDataFilePath = NeuralNetworkStockPredictor.class.getResource("/input/").getPath() + "learningData";
    private String predictedFilePath = NeuralNetworkStockPredictor.class.getResource("/input/").getPath() + "predicted.csv";
    private String neuralNetworkModelFilePath = "stockPredictor.nnet";

    private Date dateAndTimeForPrediction;
    private List<Double> normalizedValuesForPrediction = new LinkedList<>();
    //private Map<Integer, Double> predictedValuePerRow = new HashMap<>();
    private Map<Integer, LinkedList<Double>> lastSlidingWindowPerRowForPrediction = new HashMap<>();

    public NeuralNetworkStockPredictor(int slidingWindowSize,
                                       String rawDataFilePath) {
        this.rawDataFilePath = rawDataFilePath;
        this.slidingWindowSize = slidingWindowSize;
    }

    public void prepareData(final int ... elementIndex) {
        for(int index : elementIndex) {
            try {
                getMaxAndMinForNormalization(index);
                prepareDataAndWriteItIntoFile(index);
            } catch (EmptyTokenException e) {
                // ToDo: add log4j LOGGING
                e.printStackTrace();
            }
        }
    }

    private void getMaxAndMinForNormalization(final int elementIndex) throws EmptyTokenException {
        // Find the minimum and maximum values - needed for normalization
        try (final BufferedReader reader = new BufferedReader(new FileReader(rawDataFilePath));){
            String line;
            String lastToken = "";
            while ((line = reader.readLine()) != null) {
                if(!line.startsWith("<")) { // die Überschriftszeile soll nicht genommen werden
                    String[] tokens = line.split("\t");
                    String token = tokens[elementIndex];

                    // if the current token is null take the previous one (from the last day)
                    if (StringUtils.isEmpty(token)) {
                        token = lastToken;
                    } else {
                        lastToken = token;
                        if(StringUtils.isBlank(lastToken)) {
                            throw new EmptyTokenException("The first value cannot be null");
                        }
                    }

                    double currentValue = Double.parseDouble(token);
                    setMaxAndMin(currentValue);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void setMaxAndMin(double currentValue) {
        if (currentValue > max) {
            max = currentValue;
        }
        if (currentValue < min) {
            min = currentValue;
        }
    }

    private void getValuesForPrediction(final List<Double> allTokens) {
        final int size = allTokens.size();
        for(int i = 0; i < slidingWindowSize; i++) {
            final int index = size - (slidingWindowSize - i);
            final Double token = allTokens.get(index);
            System.out.println("token for prediction = " + token);
            normalizedValuesForPrediction.add(normalizeValue(token));
        }
    }

    private void calculateDateAndTimeForPrediction(final List<Date> allDates) {
        final Date lastDate = allDates.get(allDates.size() - 1);
        dateAndTimeForPrediction = DateUtils.addMinutes(lastDate, 1);
    }

    private void saveAllDates(final String[] tokens, final List<Date> allDates) {
        try {
            String date = tokens[0];
            String time = tokens[1];
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss", Locale.GERMAN);
            formatter.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
            Date dateAndTime = formatter.parse(date + ' ' + time);
            String formattedDateString = formatter.format(dateAndTime);
            allDates.add(dateAndTime);
        } catch(ParseException e) {
            e.printStackTrace();
        }
    }

    private void saveAllValues(final double currentValue, final List<Double> allTokens) {
        allTokens.add(currentValue);
    }

    /**
     * The method gets data from the file with currency rates (e.g. USDJPY_202003120000_202003132142.csv)
     * Each line of this file contains several tab separated elements, e.g.
     * 2020.03.12	00:00:00.094	104.429	104.469
     * This method get the element with an as a parameter passed index on each line,
     * normalizes it to a value between 0 and 1 and puts the number of such normalized values,
     * which is equals to the value of the slidingWindowSize variable as a new line into the file,
     * specified in the variable learningDataFilePath (e.g. learningData.csv).
     * An example for such a line:
     * 0.3010125632852059, 0.3028126757922377, 0.3029626851678222, 0.3010125632852059, 0.3023626476654797, 0.30191261953872184
     * According to the slide window principle
     * the first line contains elements from line 1 till 'slidingWindowsSize' + 1 of the currency rates file,
     * the second - lines from 2 till 'slidingWindowsSize' + 2
     * the third - lines from 3 till 'slidingWindowsSize' + 3
     * and so on.
     *
     * @param elementIndex row index for BID, ASK, LAST or VOLUME
     */
    private void prepareDataAndWriteItIntoFile(final int ... elementIndex) throws EmptyTokenException {
        for(int index : elementIndex) {
            // Keep a queue with slidingWindowSize + 1 values
            LinkedList<Double> valuesQueue = new LinkedList<Double>();
            try (BufferedReader reader = new BufferedReader(new FileReader(rawDataFilePath));
                 BufferedWriter writer = new BufferedWriter(new FileWriter(learningDataFilePath + index + ".csv"))) {
                String line;
                String lastBid = "";
                List<Date> allDates = new LinkedList<>();
                List<Double> allTokens = new LinkedList<>();
                while ((line = reader.readLine()) != null) {
                    if (!line.startsWith("<")) { // die Überschriftszeile soll nicht genommen werden
                        String[] tokens = line.split("\t");

                        // Datum und Zeit auslesen und in einer Instanzveriablen abspeichern
                        saveAllDates(tokens, allDates);

                        String bid = tokens[index];

//                    // if the current token is null take the previous one (from the last day)
                        if (StringUtils.isEmpty(bid)) {
                            bid = lastBid;
                        } else {
                            lastBid = bid;
                            if (StringUtils.isBlank(lastBid)) {
                                throw new EmptyTokenException("The first value cannot be null");
                            }
                        }

                        double crtValue = Double.parseDouble(bid);
                        // Normalize values and add it to the queue
                        double normalizedValue = normalizeValue(crtValue);
                        valuesQueue.add(normalizedValue);

                        createAndWriteSlidingWindowOfValues(valuesQueue, writer, index);

                        // saveAllValues(crtValue, allTokens);
                    }
                }
                calculateDateAndTimeForPrediction(allDates);
                // getValuesForPrediction(allTokens);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * For training
     * @param valuesQueue
     * @param writer
     * @param elementIndex
     * @throws IOException
     */
    private void createAndWriteSlidingWindowOfValues(LinkedList<Double> valuesQueue, BufferedWriter writer, int elementIndex) throws IOException {
        // ToDo: For loop for all indexes
        if (valuesQueue.size() == slidingWindowSize + 1) {
            String valueLine = valuesQueue.toString().replaceAll(
                    "\\[|\\]", "");
            writer.write(valueLine);
            writer.newLine();
            // put last sliding window of a file (last 5 values) with row index into this HashMap
            // to use it for prediction in the method #testNetwork()
            lastSlidingWindowPerRowForPrediction.put(elementIndex, valuesQueue);
            // Remove the first element in queue to make place for a new one
            valuesQueue.removeFirst();
        }
    }

    double normalizeValue(double input) {
        return (input - min) / (max - min) * 0.8 + 0.1;
    }

    double deNormalizeValue(double input) {
        return min + (input - 0.1) * (max - min) / 0.8;
    }

    public void trainNetwork(final int ... elementIndex) throws IOException {
        // ToDo: For loop for all indexes
        NeuralNetwork<BackPropagation> neuralNetwork = new MultiLayerPerceptron(
                slidingWindowSize, 2 * slidingWindowSize + 1, 1);

        int maxIterations = 1000;
        double learningRate = 0.5;
        double maxError = 0.00001;
        SupervisedLearning learningRule = neuralNetwork.getLearningRule();
        learningRule.setMaxError(maxError);
        learningRule.setLearningRate(learningRate);
        learningRule.setMaxIterations(maxIterations);
        learningRule.addListener(new LearningEventListener() {
            public void handleLearningEvent(LearningEvent learningEvent) {
                SupervisedLearning rule = (SupervisedLearning) learningEvent
                        .getSource();
                System.out.println("Network error for interation "
                        + rule.getCurrentIteration() + ": "
                        + rule.getTotalNetworkError());
            }
        });

        DataSet trainingSet = loadTraininigData(elementIndex);
        neuralNetwork.learn(trainingSet);
        neuralNetwork.save(neuralNetworkModelFilePath);
    }

    DataSet loadTraininigData(int ... elementIndex) throws IOException {
        DataSet trainingSet = new DataSet(slidingWindowSize, 1);
        for(int index : elementIndex) {
            BufferedReader reader = new BufferedReader(new FileReader(learningDataFilePath + index + ".csv"));

            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] tokens = line.split(",");

                    double trainValues[] = new double[slidingWindowSize];
                    for (int i = 0; i < slidingWindowSize; i++) {
                        trainValues[i] = Double.valueOf(tokens[i]);
                    }
                    double expectedValue[] = new double[]{Double
                            .valueOf(tokens[slidingWindowSize])};
                    trainingSet.addRow(new DataSetRow(trainValues, expectedValue));
                    System.out.println("Index: " + index + " Load Taining Expected Value: " + expectedValue[0] + "  trainValue:" + trainValues[0]);
                }
            } finally {
                reader.close();
            }
        }
        return trainingSet;
    }

    public void testNetwork(final int ... elementIndex) {
        NeuralNetwork neuralNetwork = NeuralNetwork
                .createFromFile(neuralNetworkModelFilePath);

        // max 4 values: <HIGH>	<LOW> <CLOSE> <TICKVOL>
        final Map<Integer, Double> result = new HashMap<>(4);

        for(int index : elementIndex) {
            LinkedList<Double> normalizedValuesForPrediction = lastSlidingWindowPerRowForPrediction.get(index);
            Double[] doubles = normalizedValuesForPrediction.toArray(new Double[this.normalizedValuesForPrediction.size()]);

            neuralNetwork.setInput(Stream.of(doubles).mapToDouble(value -> value.doubleValue()).toArray());

            neuralNetwork.calculate();
            double[] networkOutput = neuralNetwork.getOutput();
            // System.out.println("Expected value  : 2066.96");
            double predictedValue = deNormalizeValue(networkOutput[0]);
            System.out.println("Index: " + index + ", Predicted value : "
                    + predictedValue);

            result.put(index, predictedValue);
        }

        savePredictionResults(result);
    }

    private void savePredictionResults(Map<Integer, Double> result) {
        String pattern = "yyyy.MM.dd\tHH:mm:ss";
        // Create an instance of SimpleDateFormat used for formatting
        // the string representation of date according to the chosen pattern
        DateFormat df = new SimpleDateFormat(pattern);
        // Using DateFormat format method we can create a string
        // representation of a date with the defined format.
        String dateAsString = df.format(dateAndTimeForPrediction);
        final StringBuilder predicted = new StringBuilder(dateAsString);
        result.forEach((key, value) -> predicted.append("\t" + value));
        System.out.println("predicted = " + predicted);
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(predictedFilePath))) {
            writer.write(predicted.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}<file_sep>/build.gradle
buildscript {
    ext {
        springBootVersion = '2.0.0.RELEASE'
    }
    repositories {
        maven { url "http://repo.spring.io/libs-milestone" }
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE")
    }
}

//plugins {
//    id "io.spring.dependency-management" version "1.0.5.RELEASE"
//}

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'


war {
    baseName = 'springboot'
    version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-milestone" }
}

configurations {
    providedRuntime
}

dependencies {
//  compile("org.springframework.boot:spring-boot-starter-data-jpa")
//  compile("javax.servlet:jstl:1.2")
//  runtime("mysql:mysql-connector-java")
//  compile("org.springframework.boot:spring-boot-starter-jdbc")
    compile ("org.springframework.boot:spring-boot-starter-web")
    providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
    // Für JSP
    providedRuntime 'org.apache.tomcat.embed:tomcat-embed-jasper'
    // Für HTML
    // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf
//    compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.2.5.RELEASE'

}


//eclipse {
//    classpath {
//         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
//         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7'
//    }
//}

//task wrapper2(type: Wrapper) {
//    gradleVersion = '2.3'
//}




//plugins {
//    id 'org.springframework.boot' version '2.3.0.M2'
//    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
//    id 'java'
//}
//
//group = 'de.dsimon'
//version = '0.0.1-SNAPSHOT'
//sourceCompatibility = '11'
//
//configurations {
//    developmentOnly
//    runtimeClasspath {
//        extendsFrom developmentOnly
//    }
//    compileOnly {
//        extendsFrom annotationProcessor
//    }
//}
//
//repositories {
//    mavenCentral()
//    maven { url 'https://repo.spring.io/milestone' }
//}
//
//dependencies {
//    implementation 'org.springframework.boot:spring-boot-starter-security'
//    implementation 'org.springframework.boot:spring-boot-starter-web'
//    compileOnly 'org.projectlombok:lombok'
//    developmentOnly 'org.springframework.boot:spring-boot-devtools'
//    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
//    annotationProcessor 'org.projectlombok:lombok'
//    testImplementation('org.springframework.boot:spring-boot-starter-test') {
//        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
//    }
//    testImplementation 'org.springframework.security:spring-security-test'
//}
//
dependencies {
    // testCompile group: 'junit', name: 'junit', version: '4.12'
    // https://mvnrepository.com/artifact/org.tensorflow/tensorflow
    compile group: 'org.tensorflow', name: 'tensorflow', version: '1.15.0'
    // https://mvnrepository.com/artifact/org.beykery/neuroph
    compile group: 'org.beykery', name: 'neuroph', version: '2.92'
    // https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple
    compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
    // JUnit 5
    implementation 'org.junit.jupiter:junit-jupiter-api:5.5.1'
}
//
//test {
//    useJUnitPlatform()
//}
<file_sep>/src/main/test/de/mvpdt/mvp_dt/service/DataPreparationServiceTest.java
package de.mvpdt.mvp_dt.service;


import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

class DataPreparationServiceTest {

    @Test
    public void testGetRawDataFromFile() {
    }
}<file_sep>/src/main/java/de/mvpdt/mvp_dt/StandaloneApplication.java
package de.mvpdt.mvp_dt;

import de.mvpdt.mvp_dt.prediction.NeuralNetworkStockPredictor;
import de.mvpdt.mvp_dt.service.TimeStampService;

import javax.annotation.Resource;
import java.io.IOException;

public class StandaloneApplication {

    @Resource
    private TimeStampService timeStampService;

    public static void main(String[] args) throws IOException {

        NeuralNetworkStockPredictor predictor = new NeuralNetworkStockPredictor(
                5, StandaloneApplication.class
                .getResource("/input/USDJPY_M1_202003190000_202003192016.csv")
                .getPath());
        // 3 for HIGH
        // 4 for LOW
        // 5 for CLOSE
        // 6 for TICKVOL
        final int[] elements = new int[]{2, 3, 4, 5};

        predictor.prepareData(elements);

        System.out.println("Training starting");
        predictor.trainNetwork(elements);

        System.out.println("Testing network");
        predictor.testNetwork(elements);
    }
}
<file_sep>/src/main/java/de/mvpdt/mvp_dt/service/NetworkService.java
package de.mvpdt.mvp_dt.service;

import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.core.data.DataSetRow;
import org.neuroph.core.events.LearningEvent;
import org.neuroph.core.events.LearningEventListener;
import org.neuroph.core.learning.SupervisedLearning;
import org.neuroph.nnet.MultiLayerPerceptron;
import org.neuroph.nnet.learning.BackPropagation;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedList;

@Service
public class NetworkService {
    private String neuralNetworkModelFilePath = "stockPredictor.nnet";
    private int slidingWindowSize = 3;
    private double max = 0;
    private double min = Double.MAX_VALUE;

    public void trainNetwork(final LinkedList<Double> rawValuesList, int slidingWindowSize, final boolean createNewNN) throws IOException {
        this.slidingWindowSize = slidingWindowSize;
        NeuralNetwork<BackPropagation> neuralNetwork = createOrLoadNN(createNewNN);

        final DataSet trainingSet = createTrainingData(rawValuesList);
        System.out.println("Rows in the training set = " + trainingSet.getRows().size());
        System.out.println("Rows = " + trainingSet.getRows().toString());
        final int lastRowIndex = trainingSet.size() - 1;
        final DataSetRow lastRow = trainingSet.getRowAt(lastRowIndex);
        trainingSet.removeRowAt(lastRowIndex);
        neuralNetwork.learn(trainingSet);
        neuralNetwork.save(neuralNetworkModelFilePath);
        testNetwork(lastRow);

//      System.out.println(trainingSet.getRows().toString().replace(",", "\n"));
        System.out.println();
    }

    private NeuralNetwork<BackPropagation> createOrLoadNN(boolean createNewNN) {
        NeuralNetwork<BackPropagation> neuralNetwork = null;
        if (createNewNN) {
            try {
                Files.deleteIfExists(Paths.get(neuralNetworkModelFilePath));
            } catch (IOException e) {
                System.err.println("Error while removing existing NN");
                e.printStackTrace();
            }
            //The number of hidden neurons should be between the size of the input layer and the size of the output layer.
            // The number of hidden neurons should be 2/3 the size of the input layer, plus the size of the output layer.
            // The number of hidden neurons should be less than twice the size of the input layer.Jun 1, 2017
            neuralNetwork = new MultiLayerPerceptron( // new NN
                    slidingWindowSize,
                    2*(slidingWindowSize*(2/3)+1),
                    2*(slidingWindowSize*(3/3)+1),
                    1); // new NN

            int maxIterations = 10000;
            double learningRate =0.5;
            double maxError = 0.000000000001;
            SupervisedLearning learningRule = neuralNetwork.getLearningRule(); // new NN
            learningRule.setMaxError(maxError); // new NN
            learningRule.setLearningRate(learningRate); // new NN
            learningRule.setMaxIterations(maxIterations); // new NN
            learningRule.addListener(new LearningEventListener() { // new NN
                public void handleLearningEvent(LearningEvent learningEvent) { // new NN
                    SupervisedLearning rule = (SupervisedLearning) learningEvent // new NN
                            .getSource(); // new NN
// DO NOT USE                System.out.println("Network error for interation " // new NN
// DO NOT USE                        + rule.getCurrentIteration() + ": " // new NN
// DO NOT USE                        + rule.getTotalNetworkError()); // new NN
                } // new NN
            }); // new NN
        } else {
            neuralNetwork = NeuralNetwork // load existing NN
                    .createFromFile(neuralNetworkModelFilePath); // load existing NN
        }
        return neuralNetwork;
    }

    private void setMaxAndMin(final LinkedList<Double> rawValuesList) {
        max = rawValuesList.stream().mapToDouble(Double::doubleValue).max().getAsDouble();
        min = rawValuesList.stream().mapToDouble(Double::doubleValue).min().getAsDouble();
    }

    private DataSet createTrainingData(final LinkedList<Double> rawValuesList) {
        setMaxAndMin(rawValuesList);
        DataSet trainingSet = new DataSet(slidingWindowSize, 1);
        while (!rawValuesList.isEmpty()) {
            double trainValues[] = new double[slidingWindowSize];
            for (int counter = 0; counter < slidingWindowSize; counter++) {
                if (rawValuesList.size() > counter)
                    trainValues[counter] = normalizeValue(rawValuesList.get(counter));
            }
            if (rawValuesList.size() > slidingWindowSize) {
                double expectedValue[] = new double[]{normalizeValue(rawValuesList.get(slidingWindowSize))};
                trainingSet.addRow(new DataSetRow(trainValues, expectedValue));
            }
            rawValuesList.removeFirst();
        }
        return trainingSet;
    }

    public void testNetwork(final DataSetRow lastRow) {
        NeuralNetwork neuralNetwork = NeuralNetwork
                .createFromFile(neuralNetworkModelFilePath);

        neuralNetwork.setInput(lastRow.getInput());
        neuralNetwork.calculate();
        double[] networkOutput = neuralNetwork.getOutput();
        final double expectedValue = deNormalizeValue(lastRow.getDesiredOutput()[0]);
        System.out.println("Expected value = " + expectedValue);
        double predictedValue = deNormalizeValue(networkOutput[0]);
        System.out.println("Predicted value = " + predictedValue);
        System.out.println("Difference = " + (expectedValue - predictedValue));
        // result.put(index, predictedValue);


        //savePredictionResults(result);
    }

    double normalizeValue(double input) {
        return (input - min) / (max - min) * 0.8 + 0.1;
    }

    double deNormalizeValue(double input) {
        return min + (input - 0.1) * (max - min) / 0.8;
    }
}
