/* 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%20rsi * RSI RSI on hintaa seuraava oskilaattori, joka saavuttaa 0-100 välisiä arvoja. Se vertaa viimeisten ylöspäin tapahtuneiden hintamuutosten voimakkuutta alaspäin suuntautuneisiin hintamuutoksiin. Suosituimmat tarkasteluvälit ovat 9, 14 ja 25 päivän RSI. Tulkinta: - RSI huipussa: korkea arvo (yli 70/noususuhdanteessa yleensä 80) indikoi yliostotilannetta - RSI pohjassa: matala arvo (alle 30/laskusuhdanteessa yleenäs 20) indikoi aliostotilannetta Signaalit: - Osta, kun RSI:n arvo leikkaa aliostorajan alapuolelta - Myy, kun RSI:n arvo leikkaa yliostorajan yläpuolelta Vaihtoehtoisesti: - Osta, kun RSI leikkaa keskilinjan (50) alapuolelta - Myy, kun RSI leikkaa keskilinjan (50) yläpuolelta */ 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.util.Calendar; import java.util.Date; import org.jtotus.common.DateIterator; import org.jtotus.config.ConfigLoader; import org.jtotus.gui.graph.GraphSender; import java.io.File; import org.jtotus.common.NumberRangeIter; import org.jtotus.config.ConfTaLibEMA; /** * * @author Evgeni Kappinen */ public class TaLibEMA extends TaLibAbstract implements MethodEntry { /*Stock list */ private double avgSuccessRate = 0.0f; private int totalStocksAnalyzed = 0; //INPUTS TO METHOD: public Calendar inputStartingDate = null; public ConfTaLibEMA config = null; ConfigLoader<ConfTaLibEMA> configFile = null; public void loadInputs(String configStock) { configFile = new ConfigLoader<ConfTaLibEMA>(super.portfolioConfig.portfolioName + File.separator + configStock + File.separator + this.getMethName()); // new ConfigLoader<ConfTaLibEMA>(portfolio+File.separator+this.getMethName()); if (configFile.getConfig() == null) { //Load default values config = new ConfTaLibEMA(); configFile.storeConfig(config); } else { config = configFile.getConfig(); } configFile.applyInputsToObject(this); } public MethodResults performEMA(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.emaLookback(config.inputEMAPeriod); 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.ema(0, period - 1, input, config.inputEMAPeriod, 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()); } //System.out.printf("The original size: (%d:%d) alloc:%d\n", outBegIdx.value,outNbElement.value,allocationSize); methodResults.putResult(stockName, output[output.length - 1]); if (config.inputPrintResults) { sender = new GraphSender(this.getMethName()); 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(); 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 decEMAPeriod = 0; NumberRangeIter numberIter = new NumberRangeIter("EMARange"); numberIter.setRange(config.inputEMADecisionPeriod); while (numberIter.hasNext()) { amoutOfStocks = 0; assumedBudjet = portfolioConfig.inputAssumedBudjet; decEMAPeriod = numberIter.next().intValue(); final int allocationSizeDecision = period - core.emaLookback(decEMAPeriod); 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.ema(0, period - 1, input, decEMAPeriod, outBegIdxDec, outNbElementDec, outputDec); if (decCode.compareTo(RetCode.Success) != 0) { //Error return empty method results System.err.printf("SMI failed in Decision!\n"); return new MethodResults(this.getMethName()); } //TODO: Evaluate and store best config int direction = 0; boolean changed = true; for (int elem = 1; elem < outNbElementDec.value; elem++) { double threshold = (outputDec[elem - 1] + outputDec[elem]) / 2; changed = false; if (input[outBegIdxDec.value + elem] > threshold) { //above the line if (direction == -1) { changed = true; //Price is going down if (amoutOfStocks != 0) { assumedBudjet = amoutOfStocks * input[elem + outBegIdxDec.value]; if (bestAssumedBudjet < assumedBudjet) { bestAssumedBudjet = assumedBudjet; bestPeriod = decEMAPeriod; } } } direction = 1; } else { if (direction == 1) { changed = true; //Price is going up amoutOfStocks = assumedBudjet / input[elem + outBegIdxDec.value]; } direction = -1; } if (changed) { if (config.inputPrintResults && decEMAPeriod == config.inputEMAPeriod) { DateIterator dateIterator = new DateIterator(portfolioConfig.inputStartingDate, portfolioConfig.inputEndingDate); dateIterator.move(elem + outBegIdxDec.value); sender.setSeriesName("CrossingPoint"); sender.addForSending(dateIterator.getCurrent(), input[elem + outBegIdxDec.value] + 0.1); sender.sendAllStored(); } } } } 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.inputEMAPeriod = (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) { return this.performEMA(stockName, input); } public MethodResults runCalculation() { throw new UnsupportedOperationException("Not supported yet."); } public MethodResults runCalculation(MarketData data) { throw new UnsupportedOperationException("Not supported yet."); } }