/* The gateway routine */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { /* ----------------- Variables ----------------- */ /* input variables */ /* mandatory input */ int startIdx; int endIdx; double * inReal; /* optional input */ double optInFastLimit; double optInSlowLimit; /* output variables */ int outBegIdx; int outNbElement; double* outMAMA; double* outFAMA; /* input dimentions */ int inSeriesRows; int inSeriesCols; /* error handling */ TA_RetCode retCode; /* ----------------- input/output count ----------------- */ /* Check for proper number of arguments. */ if (nrhs < 1 || nrhs > 3) mexErrMsgTxt("#3 inputs possible #2 optional."); if (nlhs != 2) mexErrMsgTxt("#2 output required."); /* ----------------- INPUT ----------------- */ /* Create a pointer to the input matrix inReal. */ inReal = mxGetPr(prhs[0]); /* Get the dimensions of the matrix input inReal. */ inSeriesCols = mxGetN(prhs[0]); if (inSeriesCols != 1) mexErrMsgTxt("inReal only vector alowed."); inSeriesRows = mxGetM(prhs[0]); endIdx = inSeriesRows - 1; startIdx = 0; /* Process optional arguments */ if (nrhs >= 1+1) { if (!mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]) || mxGetN(prhs[1])*mxGetM(prhs[1]) != 1) mexErrMsgTxt("Input optInFastLimit must be a scalar."); /* Get the scalar input optInTimePeriod. */ optInFastLimit = mxGetScalar(prhs[1]); } else { optInFastLimit = 5.000000e-1; } if (nrhs >= 2+1) { if (!mxIsDouble(prhs[2]) || mxIsComplex(prhs[2]) || mxGetN(prhs[2])*mxGetM(prhs[2]) != 1) mexErrMsgTxt("Input optInSlowLimit must be a scalar."); /* Get the scalar input optInTimePeriod. */ optInSlowLimit = mxGetScalar(prhs[2]); } else { optInSlowLimit = 5.000000e-2; } /* ----------------- OUTPUT ----------------- */ outMAMA = mxCalloc(inSeriesRows, sizeof(double)); outFAMA = mxCalloc(inSeriesRows, sizeof(double)); /* -------------- Invocation ---------------- */ retCode = TA_MAMA( startIdx, endIdx, inReal, optInFastLimit, optInSlowLimit, &outBegIdx, &outNbElement, outMAMA, outFAMA); /* -------------- Errors ---------------- */ if (retCode) { mxFree(outMAMA); mxFree(outFAMA); mexPrintf("%s%i","Return code=",retCode); mexErrMsgTxt(" Error!"); } // Populate Output plhs[0] = mxCreateDoubleMatrix(outBegIdx+outNbElement,1, mxREAL); memcpy(((double *) mxGetData(plhs[0]))+outBegIdx, outMAMA, outNbElement*mxGetElementSize(plhs[0])); mxFree(outMAMA); plhs[1] = mxCreateDoubleMatrix(outBegIdx+outNbElement,1, mxREAL); memcpy(((double *) mxGetData(plhs[1]))+outBegIdx, outFAMA, outNbElement*mxGetElementSize(plhs[1])); mxFree(outFAMA); } /* END mexFunction */
static ErrorNumber do_test_ma( const TA_History *history, const TA_Test *test ) { TA_RetCode retCode; ErrorNumber errNb; TA_Integer outBegIdx; TA_Integer outNbElement; TA_RangeTestParam testParam; TA_Integer temp, temp2; const TA_Real *referenceInput; TA_SetCompatibility( test->compatibility ); /* Set to NAN all the elements of the gBuffers. */ clearAllBuffers(); /* Build the input. */ setInputBuffer( 0, history->close, history->nbBars ); setInputBuffer( 1, history->close, history->nbBars ); /* Re-initialize all the unstable period to zero. */ TA_SetUnstablePeriod( TA_FUNC_UNST_ALL, 0 ); /* Set the unstable period requested for that test. */ switch( test->optInMAType_1 ) { case TA_MAType_TEMA: case TA_MAType_DEMA: case TA_MAType_EMA: retCode = TA_SetUnstablePeriod( TA_FUNC_UNST_EMA, test->unstablePeriod ); break; case TA_MAType_KAMA: retCode = TA_SetUnstablePeriod( TA_FUNC_UNST_KAMA, test->unstablePeriod ); break; case TA_MAType_MAMA: retCode = TA_SetUnstablePeriod( TA_FUNC_UNST_MAMA, test->unstablePeriod ); break; case TA_MAType_T3: retCode = TA_SetUnstablePeriod( TA_FUNC_UNST_T3, test->unstablePeriod ); break; default: retCode = TA_SUCCESS; break; } if( retCode != TA_SUCCESS ) return TA_TEST_TFRR_SETUNSTABLE_PERIOD_FAIL; /* Transform the inputs for MAMA (it is an AVGPRICE in John Ehlers book). */ if( test->optInMAType_1 == TA_MAType_MAMA ) { TA_MEDPRICE( 0, history->nbBars-1, history->high, history->low, &outBegIdx, &outNbElement, gBuffer[0].in ); TA_MEDPRICE( 0, history->nbBars-1, history->high, history->low, &outBegIdx, &outNbElement, gBuffer[1].in ); /* Will be use as reference */ TA_MEDPRICE( 0, history->nbBars-1, history->high, history->low, &outBegIdx, &outNbElement, gBuffer[2].in ); referenceInput = gBuffer[2].in; } else referenceInput = history->close; /* Make a simple first call. */ switch( test->id ) { case TA_ANY_MA_TEST: retCode = TA_MA( test->startIdx, test->endIdx, gBuffer[0].in, test->optInTimePeriod_0, test->optInMAType_1, &outBegIdx, &outNbElement, gBuffer[0].out0 ); break; case TA_MAMA_TEST: retCode = TA_MAMA( test->startIdx, test->endIdx, gBuffer[0].in, 0.5, 0.05, &outBegIdx, &outNbElement, gBuffer[0].out0, gBuffer[0].out2 ); break; case TA_FAMA_TEST: retCode = TA_MAMA( test->startIdx, test->endIdx, gBuffer[0].in, 0.5, 0.05, &outBegIdx, &outNbElement, gBuffer[0].out2, gBuffer[0].out0 ); break; } errNb = checkDataSame( gBuffer[0].in, referenceInput, history->nbBars ); if( errNb != TA_TEST_PASS ) return errNb; errNb = checkExpectedValue( gBuffer[0].out0, retCode, test->expectedRetCode, outBegIdx, test->expectedBegIdx, outNbElement, test->expectedNbElement, test->oneOfTheExpectedOutReal, test->oneOfTheExpectedOutRealIndex ); if( errNb != TA_TEST_PASS ) return errNb; outBegIdx = outNbElement = 0; /* Make another call where the input and the output are the * same buffer. */ switch( test->id ) { case TA_ANY_MA_TEST: retCode = TA_MA( test->startIdx, test->endIdx, gBuffer[1].in, test->optInTimePeriod_0, test->optInMAType_1, &outBegIdx, &outNbElement, gBuffer[1].in ); break; case TA_MAMA_TEST: retCode = TA_MAMA( test->startIdx, test->endIdx, gBuffer[1].in, 0.5, 0.05, &outBegIdx, &outNbElement, gBuffer[1].in, gBuffer[0].out2 ); break; case TA_FAMA_TEST: retCode = TA_MAMA( test->startIdx, test->endIdx, gBuffer[1].in, 0.5, 0.05, &outBegIdx, &outNbElement, gBuffer[0].out2, gBuffer[1].in ); break; } /* The previous call to TA_MA should have the same output * as this call. * * checkSameContent verify that all value different than NAN in * the first parameter is identical in the second parameter. */ errNb = checkSameContent( gBuffer[0].out0, gBuffer[1].in ); if( errNb != TA_TEST_PASS ) return errNb; errNb = checkExpectedValue( gBuffer[1].in, retCode, test->expectedRetCode, outBegIdx, test->expectedBegIdx, outNbElement, test->expectedNbElement, test->oneOfTheExpectedOutReal, test->oneOfTheExpectedOutRealIndex ); if( errNb != TA_TEST_PASS ) return errNb; /* Verify that the "all-purpose" TA_MA_Lookback is consistent * with the corresponding moving average lookback function. */ switch( test->optInMAType_1 ) { case TA_MAType_WMA: temp = TA_WMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_SMA: temp = TA_SMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_EMA: temp = TA_EMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_DEMA: temp = TA_DEMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_TEMA: temp = TA_TEMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_KAMA: temp = TA_KAMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_MAMA: temp = TA_MAMA_Lookback( 0.5, 0.05 ); break; case TA_MAType_TRIMA: temp = TA_TRIMA_Lookback( test->optInTimePeriod_0 ); break; case TA_MAType_T3: temp = TA_T3_Lookback( test->optInTimePeriod_0, 0.7 ); break; default: return TA_TEST_TFRR_BAD_MA_TYPE; } temp2 = TA_MA_Lookback( test->optInTimePeriod_0, test->optInMAType_1 ); if( temp != temp2 ) return TA_TEST_TFFR_BAD_MA_LOOKBACK; /* Do a systematic test of most of the * possible startIdx/endIdx range. */ testParam.test = test; testParam.close = referenceInput; if( test->doRangeTestFlag ) { switch( test->optInMAType_1 ) { case TA_MAType_TEMA: case TA_MAType_DEMA: case TA_MAType_EMA: errNb = doRangeTest( rangeTestFunction, TA_FUNC_UNST_EMA, (void *)&testParam, 1, 0 ); break; case TA_MAType_T3: errNb = doRangeTest( rangeTestFunction, TA_FUNC_UNST_T3, (void *)&testParam, 1, 0 ); break; case TA_MAType_KAMA: errNb = doRangeTest( rangeTestFunction, TA_FUNC_UNST_KAMA, (void *)&testParam, 1, 0 ); break; case TA_MAType_MAMA: errNb = doRangeTest( rangeTestFunction, TA_FUNC_UNST_MAMA, (void *)&testParam, 2, 0 ); break; default: errNb = doRangeTest( rangeTestFunction, TA_FUNC_UNST_NONE, (void *)&testParam, 1, 0 ); } if( errNb != TA_TEST_PASS ) return errNb; } return TA_TEST_PASS; }
TA_RetCode TA_MA( TA_Integer startIdx, TA_Integer endIdx, const TA_Real inReal_0[], TA_Integer optInTimePeriod_0, /* From 2 to TA_INTEGER_MAX */ TA_MAType optInMAType_1, TA_Integer *outBegIdx, TA_Integer *outNbElement, TA_Real outReal_0[] ) /**** END GENCODE SECTION 2 - DO NOT DELETE THIS LINE ****/ { /* Insert local variables here. */ TA_Real *dummyBuffer; TA_RetCode retCode; /**** START GENCODE SECTION 3 - DO NOT DELETE THIS LINE ****/ #ifndef TA_FUNC_NO_RANGE_CHECK /* Validate the requested output range. */ if( startIdx < 0 ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx < startIdx)) return TA_OUT_OF_RANGE_END_INDEX; /* Validate the parameters. */ if( !inReal_0 ) return TA_BAD_PARAM; /* min/max are checked for optInTimePeriod_0. */ if( (TA_Integer)optInTimePeriod_0 == TA_INTEGER_DEFAULT ) optInTimePeriod_0 = 30; else if( ((TA_Integer)optInTimePeriod_0 < 2) || ((TA_Integer)optInTimePeriod_0 > 2147483647) ) return TA_BAD_PARAM; if( (TA_Integer)optInMAType_1 == TA_INTEGER_DEFAULT ) optInMAType_1 = 0; else if( ((TA_Integer)optInMAType_1 < 0) || ((TA_Integer)optInMAType_1 > 8) ) return TA_BAD_PARAM; if( outReal_0 == NULL ) return TA_BAD_PARAM; #endif /* TA_FUNC_NO_RANGE_CHECK */ /**** END GENCODE SECTION 3 - DO NOT DELETE THIS LINE ****/ /* Simply call the internal implementation of the * requested moving average. */ switch( optInMAType_1 ) { case TA_MAType_SMA: return TA_INT_SMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_EMA: return TA_INT_EMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, PER_TO_K(optInTimePeriod_0), outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_WMA: return TA_INT_WMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_DEMA: return TA_DEMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_TEMA: return TA_TEMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_TRIMA: return TA_TRIMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_KAMA: return TA_KAMA( startIdx, endIdx, inReal_0, optInTimePeriod_0, outBegIdx, outNbElement, outReal_0 ); break; case TA_MAType_MAMA: /* The optInTimePeriod_0 is ignored and the FAMA output of the MAMA * is ignored. */ dummyBuffer = TA_Malloc( sizeof(TA_Real)*(endIdx-startIdx+1) ); if( !dummyBuffer ) return TA_ALLOC_ERR; retCode = TA_MAMA( startIdx, endIdx, inReal_0, 0.5, 0.05, outBegIdx, outNbElement, outReal_0, dummyBuffer ); TA_Free( dummyBuffer ); return retCode; break; case TA_MAType_T3: return TA_T3( startIdx, endIdx, inReal_0, optInTimePeriod_0, 0.7, outBegIdx, outNbElement, outReal_0 ); break; } *outBegIdx = 0; *outNbElement = 0; return TA_BAD_PARAM; }
/**** Local functions definitions. ****/ static TA_RetCode rangeTestFunction( TA_Integer startIdx, TA_Integer endIdx, TA_Real *outputBuffer, TA_Integer *outBegIdx, TA_Integer *outNbElement, TA_Integer *lookback, void *opaqueData, unsigned int outputNb ) { TA_RetCode retCode; TA_RangeTestParam *testParam; TA_Real *dummyBuffer; testParam = (TA_RangeTestParam *)opaqueData; switch( testParam->test->optInMAType_1 ) { case TA_MAType_MAMA: dummyBuffer = TA_Malloc( sizeof(TA_Real)*(endIdx-startIdx+600) ); if( outputNb == 0 ) { retCode = TA_MAMA( startIdx, endIdx, testParam->close, 0.5, 0.05, outBegIdx, outNbElement, outputBuffer, &dummyBuffer[300] ); } else { retCode = TA_MAMA( startIdx, endIdx, testParam->close, 0.5, 0.05, outBegIdx, outNbElement, &dummyBuffer[300], outputBuffer ); } TA_Free( dummyBuffer ); *lookback = TA_MAMA_Lookback( 0.5, 0.05 ); break; default: /* Test for the TA_MA function. All the MA can be done * through that function. */ retCode = TA_MA( startIdx, endIdx, testParam->close, testParam->test->optInTimePeriod_0, testParam->test->optInMAType_1, outBegIdx, outNbElement, outputBuffer ); *lookback = TA_MA_Lookback( testParam->test->optInTimePeriod_0, testParam->test->optInMAType_1 ); break; } return retCode; }