/* 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; import java.lang.annotation.Annotation; import java.lang.annotation.IncompleteAnnotationException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import com.tictactec.ta.lib.CoreAnnotated; import com.tictactec.ta.lib.MAType; import com.tictactec.ta.lib.MInteger; import com.tictactec.ta.lib.RetCode; 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.OptInputParameterType; 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; /** * CoreMetaData provides low level RTTI (Run Time Type Information) for TA functions. It also provides methods * for those willing to call a certain TA function using late binding techniques. These two functionalities let you * call TA functions dinamically. Even if more TA functions are added by the time, your application code will be able * to call all added functions by querying TA-Lib package about: * * <li>TA functions available; * <li>function groups the TA functions belong to; * <li>input arguments of TA functions and also their run time type information; * <li>output arguments of TA functions and also their run time type information; * <li>optional input arguments of TA functions and also their run time type information; * * CoreMetaData is mostly intended for API developers and mimic as accurately as possible the functionality exposed by * <i>ta_abstract.h</i> "C" header file. * @see com.tictactec.ta.lib.meta.helpers.SimpleHelper is a simple API level helper class based on CoreMetaData * @see com.tictactec.ta.lib.meta.CoreMetaDataCompatibility for a "C" style interface, mostly intended for those traslating "C" code to Java. * * @author Richard Gomes */ public class CoreMetaData implements Comparable<CoreMetaData> { private static transient final String CONTACT_DEVELOPERS = "Contact developers"; private static transient final String INDEX_OUT_OF_BOUNDS = "Index out of bounds"; private static transient final String ILLEGAL_NUMBER_OF_ARGUMENTS = "Illegal number of arguments"; private static transient final String ARRAY_IS_NULL = "Array is null"; private static transient final String INT_ARRAY_EXPECTED = "int[] expected"; private static transient final String DOUBLE_ARRAY_EXPECTED = "double[] expected"; private static transient final String PRICE_EXPECTED = "PriceInputParameter object expected"; private static transient final Class<CoreAnnotated> coreClass = CoreAnnotated.class; private static transient final String LOOKBACK_SUFFIX = "Lookback"; private static transient CoreAnnotated taCore = null; private String name = null; private Method function = null; private Method lookback = null; private static transient Map<String, CoreMetaData> taFuncMap = null; private static transient Map<String, Set<CoreMetaData> > taGrpMap = null; private transient Object callInputParams[] = null; private transient Object callOutputParams[] = null; private transient Object callOptInputParams[] = null; protected CoreMetaData() { synchronized (coreClass) { if (taCore==null) { taCore = new CoreAnnotated(); } } } public int compareTo(CoreMetaData arg) { return this.name.compareTo(arg.name); } static private Map<String, CoreMetaData> getAllFuncs() { synchronized (coreClass) { if (taFuncMap == null) { taFuncMap = getTaFuncMetaInfoMap(); } } return taFuncMap; } static private Map<String, Set<CoreMetaData> > getAllGrps() { synchronized (coreClass) { if (taGrpMap == null) { taGrpMap = getTaGrpMetaInfoMap(); } } return taGrpMap; } static private Map<String, Method> getLookbackMethodMap() { Map<String, Method> map = new HashMap<String, Method>(); Method[] ms = coreClass.getDeclaredMethods(); for (Method m : ms) { if (m.getName().endsWith(LOOKBACK_SUFFIX)) { map.put(m.getName(), m); // System.out.println("lookback="+m.getName()); } } return map; } static private Map<String, CoreMetaData> getTaFuncMetaInfoMap() { Map<String, CoreMetaData> result = new TreeMap<String, CoreMetaData>(); Method[] ms = coreClass.getDeclaredMethods(); Map<String, Method> lookbackMap = getLookbackMethodMap(); for (Method funcMethod : ms) { String fn = funcMethod.getName(); if (funcMethod.getReturnType().equals(RetCode.class)) // && !fn.startsWith(INT_PREFIX)) { String lookbackName = fn + LOOKBACK_SUFFIX; Method lookbackMethod = lookbackMap.get(lookbackName); if (lookbackMethod != null) { FuncInfo info = getFuncInfo(funcMethod); String funcName = info.name(); CoreMetaData mi = new CoreMetaData(); mi.name = funcName; mi.function = funcMethod; mi.lookback = lookbackMethod; result.put(funcName, mi); } } } return result; } static private Map<String, Set<CoreMetaData> > getTaGrpMetaInfoMap() { if (taFuncMap==null) getAllFuncs(); Map<String, Set<CoreMetaData> > result = new TreeMap<String, Set<CoreMetaData> >(); for (String func : taFuncMap.keySet()) { CoreMetaData mi = taFuncMap.get(func); String group = mi.getFuncInfo().group(); Set<CoreMetaData> set = result.get(group); if (set==null) { set = new TreeSet<CoreMetaData>(); result.put(group, set); } set.add(mi); } return result; } static private FuncInfo getFuncInfo(Method method) throws IncompleteAnnotationException { FuncInfo annotation = method.getAnnotation(FuncInfo.class); if (annotation != null) return annotation; throw new IncompleteAnnotationException(FuncInfo.class, "Method " + method.getName()); } static CoreMetaData getFuncHandle(final String name) throws NoSuchMethodException { CoreMetaData mi = getAllFuncs().get(name.toUpperCase()); if (mi == null) throw new NoSuchMethodException(name.toUpperCase()); mi.callInputParams = null; mi.callOutputParams = null; mi.callOptInputParams = null; if (mi != null) return mi; throw new NoSuchMethodException("Function " + name); } /** * Returns the instance which describes a TA function. This is a * convenience method that simply adopts the standard "getInstance" * convention. This method simply calls getFuncHandle. * * @param name * @return an instance of CoreMetaData * @throws NoSuchMethodException */ static public CoreMetaData getInstance(final String name) throws NoSuchMethodException { return getFuncHandle(name); } /** * Returns an annotation which describes this TA function. * * @return an @interface FuncInfo * @throws IncompleteAnnotationException */ public FuncInfo getFuncInfo() throws IncompleteAnnotationException { return getFuncInfo(function); } private Annotation getParameterInfo(final int paramIndex, Class<? extends Object> paramAnnotation) { if (paramIndex < 0) throw new IllegalArgumentException(INDEX_OUT_OF_BOUNDS); int i = 0; for (Annotation[] annArray : function.getParameterAnnotations()) { for (Annotation ann : annArray) { if ((ann.annotationType() == paramAnnotation) && (paramIndex == i++)) { return ann; } } } return null; } private Annotation getParameterInfo(final int paramIndex, Class<? extends Object> paramAnnotation, Class<? extends Object> paramExtraAnnotation) { if (paramIndex < 0) throw new IllegalArgumentException(INDEX_OUT_OF_BOUNDS); int i = 0; for (Annotation[] annArray : function.getParameterAnnotations()) { for (Annotation ann : annArray) { if ((ann.annotationType() == paramAnnotation) && (paramIndex == i++)) { for (Annotation annExt : annArray) { if (annExt.annotationType() == paramExtraAnnotation) { return annExt; } } } } } return null; } /** * Returns an annotation which describes the n-th input parameter requested, if any. * * @param paramIndex is the n-th input parameter * @return an @interface InputParameterInfo * @throws IllegalArgumentException */ public InputParameterInfo getInputParameterInfo(final int paramIndex) throws IllegalArgumentException { return (InputParameterInfo) getParameterInfo(paramIndex, InputParameterInfo.class); } /** * Returns an annotation which describes the n-th output parameter requested, if any. * * @param paramIndex is the n-th output parameter * @return an @interface OutputParameterInfo * @throws IllegalArgumentException */ public OutputParameterInfo getOutputParameterInfo(final int paramIndex) throws IllegalArgumentException { return (OutputParameterInfo) getParameterInfo(paramIndex, OutputParameterInfo.class); } /** * Returns an annotation which describes the n-th optional input parameter requested, if any. * * @param paramIndex is the n-th optional input parameter * @return an @interface OptInputParameterInfo * @throws IllegalArgumentException */ public OptInputParameterInfo getOptInputParameterInfo(final int paramIndex) throws IllegalArgumentException { return (OptInputParameterInfo) getParameterInfo(paramIndex, OptInputParameterInfo.class); } /** * Returns an annotation describing an optional input parameter which type * is expected to be an IntegerList * * @param paramIndex is the n-th optional input parameter * @return an @interface IntegerList * @throws IllegalArgumentException */ public IntegerList getOptInputIntegerList(final int paramIndex) throws IllegalArgumentException { return (IntegerList) getParameterInfo(paramIndex, OptInputParameterInfo.class, IntegerList.class); } /** * Returns an annotation describing an optional input parameter which type * is expected to be an IntegerRange * * @param paramIndex is the n-th optional input parameter * @return an @interface IntegerRange * @throws IllegalArgumentException */ public IntegerRange getOptInputIntegerRange(final int paramIndex) throws IllegalArgumentException { return (IntegerRange) getParameterInfo(paramIndex, OptInputParameterInfo.class, IntegerRange.class); } /** * Returns an annotation describing an optional input parameter which type * is expected to be an RealList * * @param paramIndex is the n-th optional input parameter * @return an @interface RealList * @throws IllegalArgumentException */ public RealList getOptInputRealList(final int paramIndex) throws IllegalArgumentException { return (RealList) getParameterInfo(paramIndex, OptInputParameterInfo.class, RealList.class); } /** * Returns an annotation describing an optional input parameter which type * is expected to be an RealRange * * @param paramIndex is the n-th optional input parameter * @return an @interface RealRange * @throws IllegalArgumentException */ public RealRange getOptInputRealRange(final int paramIndex) throws IllegalArgumentException { return (RealRange) getParameterInfo(paramIndex, OptInputParameterInfo.class, RealRange.class); } /** * Assigns an <b>int</b> value to an optional input parameter * which is expected to be assignment compatible to <b>int</b>. * * @param paramIndex is the n-th optional input parameter * @param value is the <b>int</b> value * @throws IllegalArgumentException */ public void setOptInputParamInteger(final int paramIndex, final int value) throws IllegalArgumentException { OptInputParameterInfo param = getOptInputParameterInfo(paramIndex); if (param==null) throw new InternalError(CONTACT_DEVELOPERS); if (param.type()==OptInputParameterType.TA_OptInput_IntegerList) { IntegerList list = getOptInputIntegerList(paramIndex); for (int entry : list.value()) { if (value==entry) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; callOptInputParams[paramIndex] = value; return; } } } else if (param.type()==OptInputParameterType.TA_OptInput_IntegerRange) { IntegerRange range = getOptInputIntegerRange(paramIndex); if ((value >= range.min())&&(value <= range.max())) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; callOptInputParams[paramIndex] = value; return; } } throw new InternalError(CONTACT_DEVELOPERS); } /** * Assigns an <b>int</b> value obtained from a <b>String</b> to an optional input parameter * which is expected to be assignment compatible to <b>int</b>. * * @param paramIndex is the n-th optional input parameter * @param string is the <b>String</b> which must hold an <b>int</b> value * @throws IllegalArgumentException */ public void setOptInputParamInteger(final int paramIndex, final String string) throws IllegalArgumentException { try { Integer v = new Integer(string); setOptInputParamInteger(paramIndex, v.intValue()); } catch (NumberFormatException e) { OptInputParameterInfo param = getOptInputParameterInfo(paramIndex); if (param==null) throw new InternalError(CONTACT_DEVELOPERS); if (param.type()!=OptInputParameterType.TA_OptInput_IntegerList) throw new InternalError(CONTACT_DEVELOPERS); // FIXME: The correct implementation should ... // expose a field in @IntegerList informing // which Class should be taken for introspection. // Currently, all IntegerList instances implicitly depend on MAType class // but it may change some day. MAType[] fields = MAType.values(); for (MAType value : fields) { if (value.name().toUpperCase().equals(string.toUpperCase())) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; callOptInputParams[paramIndex] = value; return; } } throw new InternalError(CONTACT_DEVELOPERS); } } /** * Assigns an <b>double</b> value to an optional input parameter * which is expected to be assignment compatible to <b>double</b>. * * @param paramIndex is the n-th optional input parameter * @param value is the <b>double</b> value * @throws IllegalArgumentException */ public void setOptInputParamReal(final int paramIndex, final double value) throws IllegalArgumentException { OptInputParameterInfo param = getOptInputParameterInfo(paramIndex); if (param.type()==OptInputParameterType.TA_OptInput_RealList) { RealList list = getOptInputRealList(paramIndex); for (double entry : list.value()) { if (value==entry) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; callOptInputParams[paramIndex] = value; return; } } } else if (param.type()==OptInputParameterType.TA_OptInput_RealRange) { RealRange range = getOptInputRealRange(paramIndex); if ((value >= range.min())&&(value <= range.max())) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; callOptInputParams[paramIndex] = value; return; } } throw new InternalError(CONTACT_DEVELOPERS); } /** * Assigns an <b>double</b> value obtained from a <b>String</b> to an optional input parameter * which is expected to be assignment compatible to <b>double</b>. * * @param paramIndex is the n-th optional input parameter * @param string is the <b>String</b> which must hold an <b>double</b> value * @throws IllegalArgumentException */ public void setOptInputParamReal(final int paramIndex, final String string) throws IllegalArgumentException { try { Double v = new Double(string); setOptInputParamReal(paramIndex, v.doubleValue()); } catch (NumberFormatException e) { OptInputParameterInfo param = getOptInputParameterInfo(paramIndex); if (param==null) throw new InternalError(CONTACT_DEVELOPERS); if (param.type()==OptInputParameterType.TA_OptInput_RealList) { RealList list = getOptInputRealList(paramIndex); for (int i=0; i<list.string().length; i++) { if (string.toUpperCase().equals(list.string()[i])) { if (callOptInputParams==null) callOptInputParams = new Object[getFuncInfo().nbOptInput()]; double value = list.value()[i]; callOptInputParams[paramIndex] = value; return; } } } throw new InternalError(CONTACT_DEVELOPERS); } } /** * Assigns an Object which is expected to be assignment compatible of <b>double[]</b> to * an input parameter which is expected to be assignment compatible of <b>double[]</b>. * * @param paramIndex is the n-th input parameter * @param array is an Object expected to be assignment compatible to <b>double[]</b> * @throws IllegalArgumentException * @throws NullPointerException */ public void setInputParamReal(final int paramIndex, final Object array) throws IllegalArgumentException, NullPointerException { if (array==null) throw new NullPointerException(ARRAY_IS_NULL); InputParameterInfo param = getInputParameterInfo(paramIndex); if ((param==null) || (param.type()!=InputParameterType.TA_Input_Real)) throw new InternalError(CONTACT_DEVELOPERS); if (! (array instanceof double[]) ) throw new IllegalArgumentException(DOUBLE_ARRAY_EXPECTED); if (callInputParams==null) callInputParams = new Object[getFuncInfo().nbInput()]; callInputParams[paramIndex] = array; } /** * Assigns an Object which is expected to be assignment compatible of <b>int[]</b> to * an input parameter which is expected to be assignment compatible of <b>int[]</b>. * * @param paramIndex is the n-th input parameter * @param array is an Object expected to be assignment compatible to <b>int[]</b> * @throws IllegalArgumentException * @throws NullPointerException */ public void setInputParamInteger(final int paramIndex, final Object array) throws IllegalArgumentException, NullPointerException { if (array==null) throw new NullPointerException(ARRAY_IS_NULL); InputParameterInfo param = getInputParameterInfo(paramIndex); if ((param==null) || (param.type()!=InputParameterType.TA_Input_Integer)) throw new InternalError(CONTACT_DEVELOPERS); if (! (array instanceof int[]) ) throw new IllegalArgumentException(INT_ARRAY_EXPECTED); if (callInputParams==null) callInputParams = new Object[getFuncInfo().nbInput()]; callInputParams[paramIndex] = array; } /** * Assigns Objects which are expected to be assignment compatible of <b>double[]</b> to * an input parameter which is expected to be assignment compatible of <b>PriceInputParameter</b>. * * <p>You only need to pass those parameters strictly needed by the n-th input parameter of a certain TA function. * * @param paramIndex is the n-th input parameter * @param open represents the open prices. This Object expected to be assignment compatible to <b>double[]</b> * @param high represents the high prices. This Object expected to be assignment compatible to <b>double[]</b> * @param low represents the low prices. This Object expected to be assignment compatible to <b>double[]</b> * @param close represents the close prices. This Object expected to be assignment compatible to <b>double[]</b> * @param volume represents the volume. This Object expected to be assignment compatible to <b>double[]</b> * @param openInterest represents the open interest. This Object expected to be assignment compatible to <b>double[]</b> * @throws IllegalArgumentException * @throws NullPointerException */ public void setInputParamPrice(final int paramIndex, final double[] open, final double[] high, final double[] low, final double[] close, final double[] volume, final double[] openInterest) throws IllegalArgumentException, NullPointerException { InputParameterInfo param = getInputParameterInfo(paramIndex); if ((param==null) || (param.type()!=InputParameterType.TA_Input_Price)) throw new InternalError(CONTACT_DEVELOPERS); if (callInputParams==null) callInputParams = new Object[getFuncInfo().nbInput()]; callInputParams[paramIndex] = new PriceInputParameter(param.flags(), open, high, low, close, volume, openInterest); } /** * Assigns an Object which are expected to be assignment compatible of <b>PriceInputParameter</b> to * an input parameter which is expected to be assignment compatible of <b>PriceInputParameter</b>. * * @param paramIndex is the n-th input parameter * @param array is an Object expected to be assignment compatible to <b>PriceInputParameter</b> * @throws IllegalArgumentException * @throws NullPointerException */ public void setInputParamPrice(final int paramIndex, final Object array) throws IllegalArgumentException, NullPointerException { if (array==null) throw new NullPointerException(ARRAY_IS_NULL); InputParameterInfo param = getInputParameterInfo(paramIndex); if ((param==null) || (param.type()!=InputParameterType.TA_Input_Price)) throw new InternalError(CONTACT_DEVELOPERS); if (! (array instanceof PriceInputParameter) ) throw new IllegalArgumentException(PRICE_EXPECTED); if (callInputParams==null) callInputParams = new Object[getFuncInfo().nbInput()]; callInputParams[paramIndex] = array; } /** * Assigns an Object which are expected to be assignment compatible of <b>double[]</b> to * an output parameter which is expected to be assignment compatible of <b>double[]</b>. * * @param paramIndex is the n-th output parameter * @param array is an Object expected to be assignment compatible to <b>double[]</b> * @throws IllegalArgumentException * @throws NullPointerException * @throws ClassCastException */ public void setOutputParamReal(final int paramIndex, Object array) throws IllegalArgumentException, NullPointerException, ClassCastException { if (array==null) throw new NullPointerException(ARRAY_IS_NULL); OutputParameterInfo param = getOutputParameterInfo(paramIndex); if ((param==null)||(param.type()!=OutputParameterType.TA_Output_Real)) throw new InternalError(CONTACT_DEVELOPERS); if (! (array instanceof double[]) ) throw new IllegalArgumentException(DOUBLE_ARRAY_EXPECTED); if (callOutputParams==null) callOutputParams = new Object[getFuncInfo().nbOutput()]; callOutputParams[paramIndex] = array; } /** * Assigns an Object which are expected to be assignment compatible of <b>int[]</b> to * an output parameter which is expected to be assignment compatible of <b>int[]</b>. * * @param paramIndex is the n-th output parameter * @param array is an Object expected to be assignment compatible to <b>int[]</b> * @throws IllegalArgumentException * @throws NullPointerException * @throws ClassCastException */ public void setOutputParamInteger(final int paramIndex, Object array) throws IllegalArgumentException, NullPointerException, ClassCastException { if (array==null) throw new NullPointerException(ARRAY_IS_NULL); OutputParameterInfo param = getOutputParameterInfo(paramIndex); if ((param==null)||(param.type()!=OutputParameterType.TA_Output_Integer)) throw new InternalError(CONTACT_DEVELOPERS); if (! (array instanceof int[]) ) throw new IllegalArgumentException(INT_ARRAY_EXPECTED); if (callOutputParams==null) callOutputParams = new Object[getFuncInfo().nbOutput()]; callOutputParams[paramIndex] = array; } /** * For each defined TA function executes the <b>TaFuncService.execute()</b> interface method of the implementation * class passed ar argument. * * @param service is a <b>TaFuncService</b> implementation class * @throws Exception */ static public void forEachFunc(TaFuncService service) throws Exception { for (CoreMetaData mi : getAllFuncs().values()) { service.execute(mi); } } /** * For each defined group of TA functions executes the <b>TaFuncService.execute()</b> interface method of the implementation * class passed ar argument. * * @param service * @throws Exception */ static public void forEachGrp(TaGrpService service) throws Exception { for (String group : getAllGrps().keySet()) { service.execute(group, taGrpMap.get(group)); } } private Object[] getOptInputParameters() { int size = getFuncInfo().nbOptInput(); if (callOptInputParams==null) callOptInputParams = new Object[size]; for (int i=0; i<size; i++) { if (callOptInputParams[i]==null) { OptInputParameterInfo param = getOptInputParameterInfo(i); if (param==null) throw new InternalError(CONTACT_DEVELOPERS); if (param.type()==OptInputParameterType.TA_OptInput_IntegerList) { IntegerList list = getOptInputIntegerList(i); callOptInputParams[i] = list.defaultValue(); } else if (param.type()==OptInputParameterType.TA_OptInput_IntegerRange) { IntegerRange range = getOptInputIntegerRange(i); callOptInputParams[i] = range.defaultValue(); } else if (param.type()==OptInputParameterType.TA_OptInput_RealList) { RealList list = getOptInputRealList(i); callOptInputParams[i] = list.defaultValue(); } else if (param.type()==OptInputParameterType.TA_OptInput_RealRange) { RealRange range = getOptInputRealRange(i); callOptInputParams[i] = range.defaultValue(); } else { throw new InternalError(CONTACT_DEVELOPERS); } } } return callOptInputParams; } /** * 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 IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public int getLookback() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Object[] params = getOptInputParameters(); return (Integer) lookback.invoke(taCore, params); } /** * 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. * * @see com.tictactec.ta.lib.meta.helpers.SimpleHelper class for an example of use. * * @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 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 IllegalAccessException * @throws InvocationTargetException */ public void callFunc(final int startIndex, final int endIndex, MInteger outBegIdx, MInteger outNbElement) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int count = 0; for (Object item : callInputParams) { if (PriceInputParameter.class.isAssignableFrom(item.getClass())) { count += ((PriceInputParameter)item).getCount(); } else { count++; } } count += callOutputParams.length; count += callOptInputParams.length; Object[] params = new Object[count+4]; count = 0; params[count++] = startIndex; params[count++] = endIndex; for (Object item : callInputParams) { if (PriceInputParameter.class.isAssignableFrom(item.getClass())) { Object objs[] = ((PriceInputParameter)item).toArrays(); for (int i=0; i<objs.length; i++) { params[count++] = objs[i]; } } else { params[count++] = item; } } for (Object item : callOptInputParams) { params[count++] = item; } params[count++] = outBegIdx; params[count++] = outNbElement; for (Object item : callOutputParams) { params[count++] = item; } Type[] types = function.getGenericParameterTypes(); if (types.length != params.length) throw new IllegalArgumentException(ILLEGAL_NUMBER_OF_ARGUMENTS); //for (int i=0; i<types.length; i++) { // if (! (params[i].getClass().isAssignableFrom(types[i])) ) { // throw new IllegalArgumentException("Type mismatch on argument "+i+": "+types[i]); // } //} function.invoke(taCore, params); } }