/* 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/>. */ package org.jlucrum.realtime.listeners; import org.jlucrum.realtime.BrokerWatcher; import org.jlucrum.realtime.eventtypes.EsperEventRsi; import org.jlucrum.realtime.eventtypes.IndicatorData; import org.jlucrum.realtime.eventtypes.StockTick; import com.espertech.esper.client.EPRuntime; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.UpdateListener; import com.tictactec.ta.lib.Core; import com.tictactec.ta.lib.MInteger; import com.tictactec.ta.lib.RetCode; import java.util.ArrayList; import java.util.HashMap; import org.apache.commons.lang.ArrayUtils; import org.jtotus.common.StateIterator; import org.jtotus.config.ConfTaLibRSI; import org.jtotus.config.ConfigLoader; import org.jtotus.methods.evaluators.EvaluateMethodSignals; /** * * @author Evgeni Kappinen */ public class ListenerRsiIndicator implements UpdateListener { //FIXME:read from somewhere else budjet. private double assumedBudjet = 7000; private HashMap<String, ArrayList<Double>> stockRsi = null; private HashMap<String, ConfTaLibRSI> configRsi = null; private HashMap<String, EvaluateMethodSignals> budjetCounter = null; private EPRuntime esperRuntime = null; private void initialize() { stockRsi = new HashMap<String, ArrayList<Double>>(); configRsi = new HashMap<String, ConfTaLibRSI>(); budjetCounter = new HashMap<String, EvaluateMethodSignals>(); } public ListenerRsiIndicator() { this.initialize(); configRsi = new HashMap<String, ConfTaLibRSI>(); } public ListenerRsiIndicator(EPRuntime esperRuntime) { this.initialize(); this.esperRuntime = esperRuntime; } private EvaluateMethodSignals getBudjetCounter(String stockName) { EvaluateMethodSignals eval = budjetCounter.get(stockName); if (eval == null) { eval = new EvaluateMethodSignals(); eval.initialize(stockName, "DecisionRSI", assumedBudjet); budjetCounter.put(stockName, eval); } return eval; } private EPRuntime getEngine() { if (esperRuntime == null) { esperRuntime = BrokerWatcher.getMainEngine().getEPRuntime(); } return esperRuntime; } //FIXME: see at original RSI implementation public ConfTaLibRSI getConfig(String stockName) { ConfTaLibRSI config = null; config = configRsi.get(stockName); if (config == null) { ConfigLoader<ConfTaLibRSI> loader = new ConfigLoader<ConfTaLibRSI>(stockName); config = loader.getConfig(); if (config == null) { config = new ConfTaLibRSI(); //FIXME: //loader.storeConfig(config); configRsi.put(stockName, config); } } return config; } 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 void update(EventBean[] ebs, EventBean[] ebs1) { //Update list of the price for (EventBean eb : ebs) { StockTick tick = (StockTick) eb.getUnderlying(); ArrayList<Double> list = stockRsi.get(tick.getStockName()); if (list == null) { list = new ArrayList<Double>(); stockRsi.put(tick.getStockName(), list); } list.add(tick.getLatestSell()); } for (EventBean eb : ebs) { StockTick tick = (StockTick) eb.getUnderlying(); ArrayList<Double> stockTicks = stockRsi.get(tick.getStockName()); if (stockTicks.size() > getConfig(tick.getStockName()).inputRSIPeriod + 1) { double[] input = ArrayUtils.toPrimitive(stockTicks.toArray(new Double[0])); makeTest(tick.getStockName(), input); MInteger outBegIdx = new MInteger(); MInteger outNbElement = new MInteger(); double[] output = this.actionRSI(input, outBegIdx, outNbElement, getConfig(tick.getStockName()).inputRSIPeriod); if (output[output.length - 1] < getConfig(tick.getStockName()).outputRSILowestThreshold) { // System.err.printf("[%s] buy for: %f rsi:%d\n",tick.getStockName(), tick.getLatestSell(), getConfig(tick.getStockName()).outputRSILowestThreshold); getBudjetCounter(tick.getStockName()).buy(tick.getLatestSell(), -1); } else if (output[output.length - 1] > getConfig(tick.getStockName()).outputRSIHigestThreshold) { getBudjetCounter(tick.getStockName()).buy(tick.getLatestBuy(), -1); } //System.out.printf("Size of output:%d rsi:%d\n", output.length, getConfig(tick.getStockName()).inputRSIPeriod); EsperEventRsi rsiEvent = new EsperEventRsi(); rsiEvent.setStockName(tick.getStockName()); rsiEvent.setRsi(output[output.length - 1]); this.getEngine().sendEvent(rsiEvent); //Sending Indicator Data IndicatorData data = new IndicatorData(); data.setStockName(tick.getStockName()); data.setIndicatorValue(output[output.length - 1]); data.setIndicatorName("RSI"); this.getEngine().sendEvent(data); getBudjetCounter(tick.getStockName()).dumpResults(); } } } public void makeTest(String stockName, double[] input) { EvaluateMethodSignals budjetCounter = new EvaluateMethodSignals(); for (StateIterator iter = new StateIterator() .addParam("RSIpriod", getConfig(stockName).inputRSIDecisionPeriod) .addParam("LowestThreshold", getConfig(stockName).inputRSILowestThreshold) .addParam("HigestThreshold", getConfig(stockName).inputRSIHigestThreshold); iter.hasNext() != StateIterator.END_STATE; iter.nextState()) { budjetCounter.initialize(stockName, "DecisionRSI", assumedBudjet); this.performDecisionTest(budjetCounter, input, iter.nextInt("RSIpriod"), iter.nextInt("LowestThreshold"), iter.nextInt("HigestThreshold")); if (budjetCounter.newBest()) { getConfig(stockName).inputRSIPeriod = iter.nextInt("RSIpriod"); getConfig(stockName).outputRSIHigestThreshold = iter.nextInt("LowestThreshold"); getConfig(stockName).outputRSILowestThreshold = iter.nextInt("HigestThreshold"); } } getConfig(stockName).outputSuccessRate = budjetCounter.getProfitInProcents(); //budjetCounter.dumpResults(); } /************* DECISION TEST ************* * @param evaluator Evaluation object * @param input closing price for period * * @return void */ public void performDecisionTest(EvaluateMethodSignals evaluator, double[] input, int decRSIPeriod, int lowestThreshold, int highestThreshold) { if (input.length < decRSIPeriod) { return; } boolean change=false; MInteger outBegIdx = new MInteger(); MInteger outNbElement = new MInteger(); double[] output = this.actionRSI(input, outBegIdx, outNbElement, decRSIPeriod); 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; } } } }