/* 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.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.gui.graph.GraphSender; import org.jtotus.config.ConfTaLibRSI; import org.jtotus.common.StateIterator; import org.jtotus.config.ConfigLoader; import org.jtotus.methods.evaluators.EvaluateMethodSignals; /** * * @author Evgeni Kappinen */ public class TaLibRSI extends TaLibAbstract implements MethodEntry { /*Stock list */ private boolean debug = false; protected ConfTaLibRSI config = null; public ConfigLoader<ConfTaLibRSI> configFile = null; public void loadInputs(String configStock) { configFile = new ConfigLoader<ConfTaLibRSI>(super.portfolioConfig.portfolioName + File.separator + configStock + File.separator + this.getMethName()); if (configFile.getConfig() == null) { //Load default values config = new ConfTaLibRSI(); configFile.storeConfig(config); } else { config = configFile.getConfig(); } super.child_config = config; configFile.applyInputsToObject(this); } /************* DECISION TEST ************* * @param evaluator Evaluation object * @param stockName ReviewTarget of the method * @param input closing price for period * @return void * */ public void performDecisionTest(EvaluateMethodSignals evaluator, String stockName, double[] input, int decRSIPeriod, int lowestThreshold, int highestThreshold) { boolean change=false; MInteger outBegIdx = new MInteger(); MInteger outNbElement = new MInteger(); double[] output = this.actionRSI(input, outBegIdx, outNbElement, decRSIPeriod); if (config.inputPrintResults) { DateIterator dateIterator = new DateIterator(portfolioConfig.inputStartingDate, portfolioConfig.inputEndingDate); dateIterator.move(outBegIdx.value); for (int elem = 0; elem < outNbElement.value && dateIterator.hasNext(); elem++) { Date date = dateIterator.next(); if (output[elem] < lowestThreshold && change == false) { evaluator.buy(input[elem + outBegIdx.value], -1, date); change = true; } else if (output[elem] > highestThreshold && change == true) { evaluator.sell(input[elem + outBegIdx.value], -1, date); change = false; } } } else { for (int elem = 0; elem < outNbElement.value; elem++) { if (output[elem] < lowestThreshold && change == false) { evaluator.buy(input[elem + outBegIdx.value], -1); change = true; } else if (output[elem] > highestThreshold && change == true) { evaluator.sell(input[elem + outBegIdx.value], -1); change = false; } } } } public double[] actionRSI(double[] input, MInteger outBegIdxDec, MInteger outNbElementDec, int decRSIPeriod) { int intput_size = input.length - 1; final Core core = new Core(); final int allocationSizeDecision = intput_size - core.rsiLookback(decRSIPeriod); if (allocationSizeDecision <= 0) { System.err.printf("No data for period (%d)\n", allocationSizeDecision); return null; } double[] outputDec = new double[allocationSizeDecision]; RetCode decCode = core.rsi(0, intput_size - 1, input, decRSIPeriod, outBegIdxDec, outNbElementDec, outputDec); if (decCode.compareTo(RetCode.Success) != 0) { //Error return empty method results throw new java.lang.IllegalStateException("RSI failed:" + decRSIPeriod + " Begin:" + outBegIdxDec.value + " NumElem:" + outNbElementDec.value + "\n"); } return outputDec; } public MethodResults performRSI(String stockName, double[] input) { this.loadInputs(stockName); if (debug) { System.out.printf("RSI period:%d\n", config.inputRSIPeriod); } //************* DECISION TEST *************// MInteger outBegIdx = new MInteger(); MInteger outNbElement = new MInteger(); double[] output = this.actionRSI(input, outBegIdx, outNbElement, config.inputRSIPeriod); methodResults.putResult(stockName, output[output.length - 1]); if (config.inputPrintResults) { sender = new GraphSender(stockName); sender.setPlotName("RSI"); 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(); } if (debug) { System.out.printf("%s (%s) has %d successrate\n", this.getMethName(), stockName, methodResults.getSuccessRate().intValue()); } return methodResults; } @Override public MethodResults performMethod(String stockName, double [] input) { //Load config for a stock this.loadInputs(stockName); //Perform testing if it is asked if (config.inputPerfomDecision) { EvaluateMethodSignals budjetCounter = new EvaluateMethodSignals(); for (StateIterator iter = new StateIterator() .addParam("RSIpriod", config.inputRSIDecisionPeriod) .addParam("LowestThreshold", config.inputRSILowestThreshold) .addParam("HigestThreshold", config.inputRSIHigestThreshold); iter.hasNext() != StateIterator.END_STATE; iter.nextState()) { budjetCounter.initialize(stockName, "DecisionRSI", portfolioConfig.inputAssumedBudjet); this.performDecisionTest(budjetCounter, stockName, input, iter.nextInt("RSIpriod"), iter.nextInt("LowestThreshold"), iter.nextInt("HigestThreshold")); if(budjetCounter.newBest()) { config.inputRSIPeriod = iter.nextInt("RSIpriod"); } } this.config.outputSuccessRate = budjetCounter.getProfitInProcents(); methodResults.putSuccessRate(stockName, budjetCounter.getProfitInProcents()); this.configFile.storeConfig(config); if (debug) { budjetCounter.printBestResults(); budjetCounter.dumpResults(); } } //Perform method return this.performRSI(stockName, input); } }