/* This file is part of jTotus. jTotus 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. jTotus 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 jTotus. If not, see <http://www.gnu.org/licenses/>. */ /* https://www.nordnet.fi/mux/page/hjalp/ordHjalp.html?ord=diagram%20momentum momentum Momentum toimii hyvin markkinoilla, joilla on havaittavissa joko nousevia tai laskevia trendejä. Momentum kertoo sen, kuinka paljon osakkeen kurssi on muuttunut valitulla aikavälillä. Se antaa seuraavat signaalit: - Osta, kun indikaattori käy pohjalla ja kääntyy ylös - Myy, kun indikaattori käy huipulla ja kääntyy alas */ package org.jtotus.methods; import org.jlucrum.realtime.eventtypes.MarketData; import org.jtotus.common.MethodResults; import com.tictactec.ta.lib.Core; import com.tictactec.ta.lib.MInteger; import com.tictactec.ta.lib.RetCode; import java.io.File; import java.util.Date; import org.jtotus.common.DateIterator; import org.jtotus.common.NumberRangeIter; import org.jtotus.config.ConfTaLibMOM; import org.jtotus.config.ConfigLoader; import org.jtotus.gui.graph.GraphSender; import org.jtotus.methods.utils.Normalizer; /** * * @author Evgeni Kappinen */ public class TaLibMOM extends TaLibAbstract implements MethodEntry { private double avgSuccessRate = 0.0f; private int totalStocksAnalyzed = 0; public ConfTaLibMOM config = null; public ConfigLoader<ConfTaLibMOM> configFile = null; //INPUTS TO METHOD: private int inputParam_Period = 10; public TaLibMOM() { super(); } public void loadInputs(String configStock) { configFile = new ConfigLoader<ConfTaLibMOM>(super.portfolioConfig.portfolioName + File.separator + configStock + File.separator + this.getMethName()); if (configFile.getConfig() == null) { //Load default values config = new ConfTaLibMOM(); configFile.storeConfig(config); } else { config = (ConfTaLibMOM) configFile.getConfig(); } configFile.applyInputsToObject(this); } //MOM public MethodResults performMOM(String stockName, double []input) { double[] output = null; MInteger outBegIdx = null; MInteger outNbElement = null; int period = 0; this.loadInputs(stockName); final Core core = new Core(); period = input.length - 1; final int allocationSize = period - core.momLookback(config.inputMOMPeriod); if (allocationSize <= 0) { System.err.printf("No data for period (%d)\n", allocationSize); return null; } output = new double[allocationSize]; outBegIdx = new MInteger(); outNbElement = new MInteger(); RetCode code = core.mom(0, period - 1, input, config.inputMOMPeriod, outBegIdx, outNbElement, output); if (code.compareTo(RetCode.Success) != 0) { //Error return empty method results System.err.printf("SMI failed!\n"); return new MethodResults(this.getMethName()); } methodResults.putResult(stockName, output[output.length - 1]); if (config.inputPrintResults) { sender = new GraphSender(stockName); sender.setSeriesName(this.getMethName()); DateIterator dateIterator = new DateIterator(portfolioConfig.inputStartingDate, portfolioConfig.inputEndingDate); dateIterator.move(outBegIdx.value); for (int i = 0; i < outNbElement.value && dateIterator.hasNext(); i++) { Date stockDate = dateIterator.next(); //System.out.printf("Date:"+stockDate+" Time:"+inputEndingDate.getTime()+"Time2:"+inputStartingDate.getTime()+"\n"); sender.addForSending(stockDate, output[i]); } sender.sendAllStored(); } //************* DECISION TEST *************// if (config.inputPerfomDecision) { double amoutOfStocks = 0; double bestAssumedBudjet = 0; double bestPeriod = 0; double assumedBudjet = 0.0f; int decMOMPeriod = 0; NumberRangeIter numberIter = new NumberRangeIter("MOMRange"); numberIter.setRange(config.inputMOMDecisionPeriod); while (numberIter.hasNext()) { amoutOfStocks = 0; assumedBudjet = portfolioConfig.inputAssumedBudjet; decMOMPeriod = numberIter.next().intValue(); final int allocationSizeDecision = period - core.momLookback(decMOMPeriod); if (allocationSizeDecision <= 0) { System.err.printf("No data for period (%d)\n", allocationSizeDecision); return null; } double[] outputDec = new double[allocationSizeDecision]; MInteger outBegIdxDec = new MInteger(); MInteger outNbElementDec = new MInteger(); RetCode decCode = core.mom(0, period - 1, input, decMOMPeriod, outBegIdxDec, outNbElementDec, outputDec); if (decCode.compareTo(RetCode.Success) != 0) { //Error return empty method results throw new java.lang.IllegalStateException("MOM failed"); } //TODO: Evaluate and store best config int direction = 0; boolean changed = true; for (int elem = 1; elem < outNbElementDec.value; elem++) { // [elem-1] > [elem] => ln([elem-1]/[elem]) > 0) if (outputDec[elem - 1] > outputDec[elem]) { //stock is falling if (direction == 1 && amoutOfStocks != 0) { //selling, Price went to the top and starts to fall changed = true; //Price is going down assumedBudjet = amoutOfStocks * input[elem + outBegIdxDec.value]; amoutOfStocks = 0; System.out.printf("%s selling for:" + input[elem + outBegIdxDec.value] + " budjet:%f per:%d bestper:%f\n", stockName, assumedBudjet, decMOMPeriod, bestPeriod); if (bestAssumedBudjet < assumedBudjet) { bestAssumedBudjet = assumedBudjet; bestPeriod = decMOMPeriod; } } direction = -1; } else { //buying, Price went to the buttom and raising if (direction == -1 && amoutOfStocks == 0) { changed = true; //Price is going up amoutOfStocks = assumedBudjet / input[elem + outBegIdxDec.value]; System.out.printf("%s buying for:" + input[elem + outBegIdxDec.value] + " budjet:%f period:%d bestper:%f\n", stockName, assumedBudjet, decMOMPeriod, bestPeriod); } direction = 1; } if (changed) { if (config.inputPrintResults && decMOMPeriod == config.inputMOMPeriod) { DateIterator dateIterator = new DateIterator(portfolioConfig.inputStartingDate, portfolioConfig.inputEndingDate); dateIterator.move(elem + outBegIdxDec.value); sender.setSeriesName("Sell/Buy signals"); sender.addForSending(dateIterator.getCurrent(), input[elem + outBegIdxDec.value] + 0.1); } } } } double successRate = ((bestAssumedBudjet / portfolioConfig.inputAssumedBudjet) - 1) * 100; System.out.printf("%s:The best period:%f best budjet:%f pros:%f\n", stockName, bestPeriod, bestAssumedBudjet, successRate); totalStocksAnalyzed++; this.avgSuccessRate += successRate; this.config.outputSuccessRate = successRate; this.config.inputMOMPeriod = (int) bestPeriod; this.configFile.storeConfig(config); } methodResults.setAvrSuccessRate(avgSuccessRate / totalStocksAnalyzed); System.out.printf("%s has %d successrate\n", this.getMethName(), methodResults.getAvrSuccessRate().intValue()); return methodResults; } @Override public MethodResults performMethod(String stockName, double []input) { MethodResults results = this.performMOM(stockName, input); System.out.printf("Normilizer:%s\n", config.inputNormilizerType); if (config.inputNormilizerType != null) { Normalizer norm = new Normalizer(); return norm.perform(config.inputNormilizerType, results); } return results; } public MethodResults runCalculation() { throw new UnsupportedOperationException("Not supported yet."); } public MethodResults runCalculation(MarketData data) { throw new UnsupportedOperationException("Not supported yet."); } }