/* TA-LIB Copyright (c) 1999-2007, Mario Fortier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither name of author nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* List of contributors:
*
* Initial Name/description
* -------------------------------------------------------------------
* RG Richard Gomes
*
* Change history:
*
* YYYYMMDD BY Description
* -------------------------------------------------------------------
* 20070311 RG First Version
*/
package com.tictactec.ta.lib.meta.helpers;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import com.tictactec.ta.lib.MInteger;
import com.tictactec.ta.lib.meta.CoreMetaData;
import com.tictactec.ta.lib.meta.annotation.FuncInfo;
import com.tictactec.ta.lib.meta.annotation.InputParameterInfo;
import com.tictactec.ta.lib.meta.annotation.InputParameterType;
import com.tictactec.ta.lib.meta.annotation.IntegerList;
import com.tictactec.ta.lib.meta.annotation.IntegerRange;
import com.tictactec.ta.lib.meta.annotation.OptInputParameterInfo;
import com.tictactec.ta.lib.meta.annotation.OutputParameterInfo;
import com.tictactec.ta.lib.meta.annotation.OutputParameterType;
import com.tictactec.ta.lib.meta.annotation.RealList;
import com.tictactec.ta.lib.meta.annotation.RealRange;
/**
* This is a simple API level helper class based on CoreMetaData.
*
* <p>This class provides the very simple functionality of calling dinamically a TA function once you already know beforehand:
*
* <li>the TA function name;
* <li>its input argument types;
* <li>its output argument types;
* <li>its optional input arguments types and domain values;
*
* It means this class is mostly intended for test purposes and provided as example of how to obtain RTTI
* (run time type information) from CoreMetaData.
*
* @see com.tictactec.ta.lib.meta.CoreMetaData
*
* @author Richard Gomes
*/
public class SimpleHelper {
private String func = null;
private String[] args = null;
private CoreMetaData calc = null;
/**
* Constructs a SimpleHelper class providing the TA function name and a list of optional parameters.
*
* @see SimpleHelper#calculate(int, int, Object[], Object[], MInteger, MInteger)
* @param func is the TA function name
* @param args is a list of optional input arguments
*/
public SimpleHelper(final String func, final List<String> args) {
if (func==null || func.length()==0) throw new NullPointerException(); //TODO: message
this.func = func;
if (args!=null && args.size()>0) {
this.args = (String[]) args.toArray(new String[0]);
for (int i=0; i<this.args.length; i++) { this.args[i] = this.args[i].toUpperCase(); }
}
}
/**
* This method returns the underlying CoreMetaData class.
*
* @return the underlying CoreMetaData class
* @throws NoSuchMethodException
* @throws IllegalArgumentException
*/
public CoreMetaData getMetaData() throws NoSuchMethodException, IllegalArgumentException {
if (this.calc!=null) return this.calc;
this.calc = CoreMetaData.getInstance(func);
FuncInfo finfo = calc.getFuncInfo();
if (args.length>finfo.nbOptInput()) throw new IllegalArgumentException(); //TODO: message
for (int i=0; i<args.length; i++) {
OptInputParameterInfo ppinfo = calc.getOptInputParameterInfo(i);
if (ppinfo.dataSet().isAssignableFrom(IntegerList.class) || ppinfo.dataSet().isAssignableFrom(IntegerRange.class)) {
calc.setOptInputParamInteger(i, args[i]);
} else if (ppinfo.dataSet().isAssignableFrom(RealList.class) || ppinfo.dataSet().isAssignableFrom(RealRange.class)) {
calc.setOptInputParamReal(i, args[i]);
} else {
throw new ClassCastException(); //TODO: message
}
}
return this.calc;
}
/**
* Returns the lookback.
*
* <p> Lookback is the number of input data points to be consumed in order to calculate the first output data point. This value
* is affected by the optional input arguments passed to this TA function.
*
* @return the lookback number of input points to be consumed before the first output data point is produced.
*
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public int getLookback() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return getMetaData().getLookback();
}
/**
* Executes the calculations defined by this TA function.
*
* <p>You need to provide input arguments where this TA function will obtain data from and output arguments where this
* TA function will write output data to. Optionally you can change default parameters used by this TA function in order
* to execute the calculations. The typical use case would be:
* <pre>
* func = "MAMA";
* params.clear();
* params.add("0.2");
* params.add("0.02");
* calc = new SimpleHelper(func, params);
* calc.calculate(0, 59, new Object[] { close }, new Object[] { output1, output2 }, lOutIdx, lOutSize);
* System.out.println("lookback="+calc.getLookback());
* System.out.println("outBegIdx = "+lOutIdx.value+ " outNbElement = "+lOutSize.value);
* for (int i=0; i<lOutSize.value; i++) {
* System.out.println("output1["+i+"]="+output1[i]+" "+"output2["+i+"]="+output2[i]);
* }
* </pre>
*
* @param startIndex is the initial position of input data to be considered for TA function calculations
* @param endIndex is the final position of input data to be considered for TA function calculations
* @param inputs is an array of input arguments
* @param outputs is an array of output arguments
* @param outBegIdx is returned by this method and represents the initial position of output data returned by this TA function
* @param outNbElement is returned by this method and represents the quantity of output data returned by this TA function
* @throws IllegalArgumentException
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public void calculate(final int startIndex, final int endIndex,
final Object[] inputs, Object[] outputs,
MInteger outBegIdx, MInteger outNbElement)
throws IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//for (int i=startIndex; i<startIndex+endIndex; i++) {
// System.err.println("input["+i+"]="+((double[])(inputs[0]))[i]);
//}
// parse function name and optional arguments
FuncInfo finfo = getMetaData().getFuncInfo();
// set input parameters
if (inputs==null || inputs.length!=finfo.nbInput()) throw new IllegalArgumentException(); //TODO: message
for (int i=0; i<inputs.length; i++) {
InputParameterInfo ipinfo = calc.getInputParameterInfo(i);
if (ipinfo.type()==InputParameterType.TA_Input_Price) {
calc.setInputParamPrice(i, inputs[i]);
} else if (ipinfo.type()==InputParameterType.TA_Input_Real) {
calc.setInputParamReal(i, inputs[i]);
} else if (ipinfo.type()==InputParameterType.TA_Input_Integer) {
calc.setInputParamInteger(i, inputs[i]);
} else {
throw new IllegalArgumentException(); //TODO: message
}
}
// set output parameters
if (outputs==null || outputs.length!=finfo.nbOutput()) throw new IllegalArgumentException(); //TODO: message
for (int i=0; i<outputs.length; i++) {
OutputParameterInfo opinfo = calc.getOutputParameterInfo(i);
if (opinfo.type()==OutputParameterType.TA_Output_Real) {
calc.setOutputParamReal(i, outputs[i]);
} else if (opinfo.type()==OutputParameterType.TA_Output_Integer) {
calc.setOutputParamInteger(i, outputs[i]);
} else {
throw new IllegalArgumentException(); //TODO: message
}
}
// call function
calc.callFunc(startIndex, endIndex, outBegIdx, outNbElement);
}
}