PlotLine * TALIB::getMA (PlotLine *in, int type, int period) { PlotLine *ma = new PlotLine; TA_Real input[in->getSize()]; TA_Real out[in->getSize()]; TA_Integer outBeg; TA_Integer count; TA_RetCode rc = TA_SUCCESS; int loop; for (loop = 0; loop < in->getSize(); loop++) input[loop] = (TA_Real) in->getData(loop); switch (type) { case 0: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_SMA, &outBeg, &count, &out[0]); break; case 1: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_EMA, &outBeg, &count, &out[0]); break; case 2: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_WMA, &outBeg, &count, &out[0]); break; case 3: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_DEMA, &outBeg, &count, &out[0]); break; case 4: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_TEMA, &outBeg, &count, &out[0]); break; case 5: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_TRIMA, &outBeg, &count, &out[0]); break; case 6: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_KAMA, &outBeg, &count, &out[0]); break; case 7: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_MAMA, &outBeg, &count, &out[0]); break; case 8: rc = TA_MA(0, in->getSize()- 1, &input[0], period, TA_MAType_T3, &outBeg, &count, &out[0]); break; default: break; } if (rc != TA_SUCCESS) { qDebug("TALIB::getMA:error on TALIB function call"); return ma; } for (loop = 0; loop < count; loop++) ma->append((double) out[loop]); return ma; }
int RSI::getMA (QString inKey, QString outKey, int type, int period) { if (! g_symbol) return 0; TA_RetCode rc = TA_Initialize(); if (rc != TA_SUCCESS) qDebug() << "RSI::getMA: error on TA_Initialize"; QList<int> keys = g_symbol->keys(); TA_Real input[MAX_SIZE]; TA_Real out[MAX_SIZE]; TA_Integer outBeg; TA_Integer outNb; int dpos = 0; for (int kpos = 0; kpos < keys.size(); kpos++) { CBar *bar = g_symbol->bar(keys.at(kpos)); double v; if (! bar->get(inKey, v)) continue; input[dpos++] = (TA_Real) v; } rc = TA_MA(0, dpos - 1, &input[0], period, (TA_MAType) type, &outBeg, &outNb, &out[0]); if (rc != TA_SUCCESS) { qDebug() << "RSI::getMA: TA-Lib error" << rc; return 0; } int keyLoop = keys.size() - 1; int outLoop = outNb - 1; while (keyLoop > -1 && outLoop > -1) { CBar *bar = g_symbol->bar(keys.at(keyLoop)); bar->set(outKey, out[outLoop]); keyLoop--; outLoop--; } return 1; }
/* Generated */ TA_RetCode TA_S_STOCHF( int startIdx, /* Generated */ int endIdx, /* Generated */ const float inHigh_0[], /* Generated */ const float inLow_0[], /* Generated */ const float inClose_0[], /* Generated */ int optInFastK_Period_0, /* From 1 to 100000 */ /* Generated */ int optInFastD_Period_1, /* From 1 to 100000 */ /* Generated */ TA_MAType optInFastD_MAType_2, /* Generated */ int *outBegIdx, /* Generated */ int *outNbElement, /* Generated */ double outFastK_0[], /* Generated */ double outFastD_1[] ) /* Generated */ #endif /* Generated */ { /* Generated */ TA_RetCode retCode; /* Generated */ double lowest, highest, tmp, diff; /* Generated */ ARRAY_REF( tempBuffer ); /* Generated */ int outIdx, lowestIdx, highestIdx; /* Generated */ int lookbackTotal, lookbackK, lookbackFastD; /* Generated */ int trailingIdx, today, i; /* Generated */ #if !defined( _MANAGED ) && !defined(USE_SINGLE_PRECISION_INPUT) /* Generated */ int bufferIsAllocated; /* Generated */ #endif /* Generated */ #ifndef TA_FUNC_NO_RANGE_CHECK /* Generated */ if( startIdx < 0 ) /* Generated */ return TA_OUT_OF_RANGE_START_INDEX; /* Generated */ if( (endIdx < 0) || (endIdx < startIdx)) /* Generated */ return TA_OUT_OF_RANGE_END_INDEX; /* Generated */ if(!inHigh_0||!inLow_0||!inClose_0) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( (int)optInFastK_Period_0 == TA_INTEGER_DEFAULT ) /* Generated */ optInFastK_Period_0 = 5; /* Generated */ else if( ((int)optInFastK_Period_0 < 1) || ((int)optInFastK_Period_0 > 100000) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( (int)optInFastD_Period_1 == TA_INTEGER_DEFAULT ) /* Generated */ optInFastD_Period_1 = 3; /* Generated */ else if( ((int)optInFastD_Period_1 < 1) || ((int)optInFastD_Period_1 > 100000) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #if !defined(_MANAGED) /* Generated */ if( (int)optInFastD_MAType_2 == TA_INTEGER_DEFAULT ) /* Generated */ optInFastD_MAType_2 = 0; /* Generated */ else if( ((int)optInFastD_MAType_2 < 0) || ((int)optInFastD_MAType_2 > 8) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ if( outFastK_0 == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( outFastD_1 == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ lookbackK = optInFastK_Period_0-1; /* Generated */ lookbackFastD = TA_MA_Lookback( optInFastD_Period_1, optInFastD_MAType_2 ); /* Generated */ lookbackTotal = lookbackK + lookbackFastD; /* Generated */ if( startIdx < lookbackTotal ) /* Generated */ startIdx = lookbackTotal; /* Generated */ if( startIdx > endIdx ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return TA_SUCCESS; /* Generated */ } /* Generated */ outIdx = 0; /* Generated */ trailingIdx = startIdx-lookbackTotal; /* Generated */ today = trailingIdx+lookbackK; /* Generated */ lowestIdx = highestIdx = -1; /* Generated */ diff = highest = lowest = 0.0; /* Generated */ #if !defined( _MANAGED ) && !defined(USE_SINGLE_PRECISION_INPUT) /* Generated */ bufferIsAllocated = 0; /* Generated */ #endif /* Generated */ #if defined(USE_SINGLE_PRECISION_INPUT) /* Generated */ ARRAY_ALLOC( tempBuffer, endIdx-today+1 ); /* Generated */ #else /* Generated */ if( (outFastK_0 == inHigh_0) || /* Generated */ (outFastK_0 == inLow_0) || /* Generated */ (outFastK_0 == inClose_0) ) /* Generated */ { /* Generated */ tempBuffer = outFastK_0; /* Generated */ } /* Generated */ else if( (outFastD_1 == inHigh_0) || /* Generated */ (outFastD_1 == inLow_0) || /* Generated */ (outFastD_1 == inClose_0) ) /* Generated */ { /* Generated */ tempBuffer = outFastD_1; /* Generated */ } /* Generated */ else /* Generated */ { /* Generated */ #if !defined( _MANAGED ) /* Generated */ bufferIsAllocated = 1; /* Generated */ #endif /* Generated */ ARRAY_ALLOC(tempBuffer, endIdx-today+1 ); /* Generated */ } /* Generated */ #endif /* Generated */ while( today <= endIdx ) /* Generated */ { /* Generated */ tmp = inLow_0[today]; /* Generated */ if( lowestIdx < trailingIdx ) /* Generated */ { /* Generated */ lowestIdx = trailingIdx; /* Generated */ lowest = inLow_0[lowestIdx]; /* Generated */ i = lowestIdx; /* Generated */ while( ++i<=today ) /* Generated */ { /* Generated */ tmp = inLow_0[i]; /* Generated */ if( tmp < lowest ) /* Generated */ { /* Generated */ lowestIdx = i; /* Generated */ lowest = tmp; /* Generated */ } /* Generated */ } /* Generated */ diff = (highest - lowest)/100.0; /* Generated */ } /* Generated */ else if( tmp <= lowest ) /* Generated */ { /* Generated */ lowestIdx = today; /* Generated */ lowest = tmp; /* Generated */ diff = (highest - lowest)/100.0; /* Generated */ } /* Generated */ tmp = inHigh_0[today]; /* Generated */ if( highestIdx < trailingIdx ) /* Generated */ { /* Generated */ highestIdx = trailingIdx; /* Generated */ highest = inHigh_0[highestIdx]; /* Generated */ i = highestIdx; /* Generated */ while( ++i<=today ) /* Generated */ { /* Generated */ tmp = inHigh_0[i]; /* Generated */ if( tmp > highest ) /* Generated */ { /* Generated */ highestIdx = i; /* Generated */ highest = tmp; /* Generated */ } /* Generated */ } /* Generated */ diff = (highest - lowest)/100.0; /* Generated */ } /* Generated */ else if( tmp >= highest ) /* Generated */ { /* Generated */ highestIdx = today; /* Generated */ highest = tmp; /* Generated */ diff = (highest - lowest)/100.0; /* Generated */ } /* Generated */ if( diff != 0.0 ) /* Generated */ tempBuffer[outIdx++] = (inClose_0[today]-lowest)/diff; /* Generated */ else /* Generated */ tempBuffer[outIdx++] = 0.0; /* Generated */ trailingIdx++; /* Generated */ today++; /* Generated */ } /* Generated */ retCode = TA_MA( 0, outIdx-1, /* Generated */ tempBuffer, optInFastD_Period_1, /* Generated */ optInFastD_MAType_2, /* Generated */ outBegIdx, outNbElement, outFastD_1 ); /* Generated */ if( (retCode != TA_SUCCESS) || (*outNbElement == 0) ) /* Generated */ { /* Generated */ #if defined(USE_SINGLE_PRECISION_INPUT) /* Generated */ ARRAY_FREE( tempBuffer ); /* Generated */ #else /* Generated */ ARRAY_FREE_COND( bufferIsAllocated, tempBuffer ); /* Generated */ #endif /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return retCode; /* Generated */ } /* Generated */ ARRAY_MEMMOVE( outFastK_0, 0, tempBuffer, lookbackFastD, *outNbElement ); /* Generated */ #if defined(USE_SINGLE_PRECISION_INPUT) /* Generated */ ARRAY_FREE( tempBuffer ); /* Generated */ #else /* Generated */ ARRAY_FREE_COND( bufferIsAllocated, tempBuffer ); /* Generated */ #endif /* Generated */ if( retCode != TA_SUCCESS ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return retCode; /* Generated */ } /* Generated */ *outBegIdx = startIdx; /* Generated */ return TA_SUCCESS; /* Generated */ }
/* Generated */ TA_RetCode TA_S_MACDEXT( int startIdx, /* Generated */ int endIdx, /* Generated */ const float inReal[], /* Generated */ int optInFastPeriod, /* From 2 to 100000 */ /* Generated */ TA_MAType optInFastMAType, /* Generated */ int optInSlowPeriod, /* From 2 to 100000 */ /* Generated */ TA_MAType optInSlowMAType, /* Generated */ int optInSignalPeriod, /* From 1 to 100000 */ /* Generated */ TA_MAType optInSignalMAType, /* Generated */ int *outBegIdx, /* Generated */ int *outNbElement, /* Generated */ double outMACD[], /* Generated */ double outMACDSignal[], /* Generated */ double outMACDHist[] ) /* Generated */ #endif /* Generated */ { /* Generated */ ARRAY_REF( slowMABuffer ); /* Generated */ ARRAY_REF( fastMABuffer ); /* Generated */ TA_RetCode retCode; /* Generated */ int tempInteger, outBegIdx1, outNbElement1; /* Generated */ int outBegIdx2, outNbElement2; /* Generated */ int lookbackTotal, lookbackSignal, lookbackLargest; /* Generated */ int i; /* Generated */ TA_MAType tempMAType; /* Generated */ #ifndef TA_FUNC_NO_RANGE_CHECK /* Generated */ if( startIdx < 0 ) /* Generated */ return TA_OUT_OF_RANGE_START_INDEX; /* Generated */ if( (endIdx < 0) || (endIdx < startIdx)) /* Generated */ return TA_OUT_OF_RANGE_END_INDEX; /* Generated */ if( !inReal ) return TA_BAD_PARAM; /* Generated */ if( (int)optInFastPeriod == TA_INTEGER_DEFAULT ) /* Generated */ optInFastPeriod = 12; /* Generated */ else if( ((int)optInFastPeriod < 2) || ((int)optInFastPeriod > 100000) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #if !defined(_MANAGED) /* Generated */ if( (int)optInFastMAType == TA_INTEGER_DEFAULT ) /* Generated */ optInFastMAType = 0; /* Generated */ else if( ((int)optInFastMAType < 0) || ((int)optInFastMAType > 8) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ if( (int)optInSlowPeriod == TA_INTEGER_DEFAULT ) /* Generated */ optInSlowPeriod = 26; /* Generated */ else if( ((int)optInSlowPeriod < 2) || ((int)optInSlowPeriod > 100000) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #if !defined(_MANAGED) /* Generated */ if( (int)optInSlowMAType == TA_INTEGER_DEFAULT ) /* Generated */ optInSlowMAType = 0; /* Generated */ else if( ((int)optInSlowMAType < 0) || ((int)optInSlowMAType > 8) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ if( (int)optInSignalPeriod == TA_INTEGER_DEFAULT ) /* Generated */ optInSignalPeriod = 9; /* Generated */ else if( ((int)optInSignalPeriod < 1) || ((int)optInSignalPeriod > 100000) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #if !defined(_MANAGED) /* Generated */ if( (int)optInSignalMAType == TA_INTEGER_DEFAULT ) /* Generated */ optInSignalMAType = 0; /* Generated */ else if( ((int)optInSignalMAType < 0) || ((int)optInSignalMAType > 8) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ if( outMACD == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( outMACDSignal == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( outMACDHist == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ if( optInSlowPeriod < optInFastPeriod ) /* Generated */ { /* Generated */ tempInteger = optInSlowPeriod; /* Generated */ optInSlowPeriod = optInFastPeriod; /* Generated */ optInFastPeriod = tempInteger; /* Generated */ tempMAType = optInSlowMAType; /* Generated */ optInSlowMAType = optInFastMAType; /* Generated */ optInFastMAType = tempMAType; /* Generated */ } /* Generated */ lookbackLargest = TA_MA_Lookback( optInFastPeriod, optInFastMAType ); /* Generated */ tempInteger = TA_MA_Lookback( optInSlowPeriod, optInSlowMAType ); /* Generated */ if( tempInteger > lookbackLargest ) /* Generated */ lookbackLargest = tempInteger; /* Generated */ lookbackSignal = TA_MA_Lookback( optInSignalPeriod, optInSignalMAType ); /* Generated */ lookbackTotal = lookbackSignal+lookbackLargest; /* Generated */ if( startIdx < lookbackTotal ) /* Generated */ startIdx = lookbackTotal; /* Generated */ if( startIdx > endIdx ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return TA_SUCCESS; /* Generated */ } /* Generated */ tempInteger = (endIdx-startIdx)+1+lookbackSignal; /* Generated */ ARRAY_ALLOC( fastMABuffer, tempInteger ); /* Generated */ if( !fastMABuffer ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return TA_ALLOC_ERR; /* Generated */ } /* Generated */ ARRAY_ALLOC( slowMABuffer, tempInteger ); /* Generated */ if( !slowMABuffer ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ ARRAY_FREE( fastMABuffer ); /* Generated */ return TA_ALLOC_ERR; /* Generated */ } /* Generated */ tempInteger = startIdx-lookbackSignal; /* Generated */ retCode = TA_PREFIX(MA)( tempInteger, endIdx, /* Generated */ inReal, optInSlowPeriod, optInSlowMAType, /* Generated */ &outBegIdx1, &outNbElement1, slowMABuffer ); /* Generated */ if( retCode != TA_SUCCESS ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ ARRAY_FREE( fastMABuffer ); /* Generated */ ARRAY_FREE( slowMABuffer ); /* Generated */ return retCode; /* Generated */ } /* Generated */ retCode = TA_PREFIX(MA)( tempInteger, endIdx, /* Generated */ inReal, optInFastPeriod, optInFastMAType, /* Generated */ &outBegIdx2, &outNbElement2, fastMABuffer ); /* Generated */ if( retCode != TA_SUCCESS ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ ARRAY_FREE( fastMABuffer ); /* Generated */ ARRAY_FREE( slowMABuffer ); /* Generated */ return retCode; /* Generated */ } /* Generated */ if( (outBegIdx1 != tempInteger) || /* Generated */ (outBegIdx2 != tempInteger) || /* Generated */ (outNbElement1 != outNbElement2) || /* Generated */ (outNbElement1 != (endIdx-startIdx)+1+lookbackSignal) ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ ARRAY_FREE( fastMABuffer ); /* Generated */ ARRAY_FREE( slowMABuffer ); /* Generated */ return TA_INTERNAL_ERROR(119); /* Generated */ } /* Generated */ for( i=0; i < outNbElement1; i++ ) /* Generated */ fastMABuffer[i] = fastMABuffer[i] - slowMABuffer[i]; /* Generated */ ARRAY_MEMMOVE( outMACD, 0, fastMABuffer, lookbackSignal, (endIdx-startIdx)+1 ); /* Generated */ retCode = TA_MA( 0, outNbElement1-1, /* Generated */ fastMABuffer, optInSignalPeriod, optInSignalMAType, /* Generated */ &outBegIdx2, &outNbElement2, outMACDSignal ); /* Generated */ ARRAY_FREE( fastMABuffer ); /* Generated */ ARRAY_FREE( slowMABuffer ); /* Generated */ if( retCode != TA_SUCCESS ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return retCode; /* Generated */ } /* Generated */ for( i=0; i < outNbElement2; i++ ) /* Generated */ outMACDHist[i] = outMACD[i]-outMACDSignal[i]; /* Generated */ *outBegIdx = startIdx; /* Generated */ *outNbElement = outNbElement2; /* Generated */ return TA_SUCCESS; /* Generated */ }
TEST(TA_MA, test_ta_lib_for_ma) { int result = MQL4::mapRatesData.get_forex_data("/home/sean/projects/quants/gom/data"); EXPECT_EQ(result, 0); std::string symbol_name("USDJPY"); MQL4::RatesData *rd = MQL4::mapRatesData.getSymbol( MQL4::MARKET_FOREX_FURTURES, symbol_name, MQL4::PERIOD_M1); EXPECT_NE((void*)rd, (void*)0); double *outTrimaReal = new double[rd->rs.size * 4]; double *outSmaReal = outTrimaReal + rd->rs.size; double *outEmaReal = outSmaReal + rd->rs.size; double *outWmaReal = outEmaReal + rd->rs.size; int outBegIdx, outNBElement; int period = 60; TA_RetCode code = TA_MA( 0, (int)rd->rs.amount - 1, rd->rs.close, period, /* From 1 to 100000 */ TA_MAType_TRIMA, &outBegIdx, &outNBElement, outTrimaReal); EXPECT_EQ(code, 0); EXPECT_EQ(outBegIdx, period - 1); EXPECT_EQ(outNBElement, (int)rd->rs.amount - outBegIdx); code = TA_MA(0, (int)rd->rs.amount - 1, rd->rs.close, period, /* From 1 to 100000 */ TA_MAType_SMA, &outBegIdx, &outNBElement, outSmaReal); EXPECT_EQ(code, 0); EXPECT_EQ(outBegIdx, period - 1); EXPECT_EQ(outNBElement, (int)rd->rs.amount - outBegIdx); code = TA_MA(0, (int)rd->rs.amount - 1, rd->rs.close, period, /* From 1 to 100000 */ TA_MAType_EMA, &outBegIdx, &outNBElement, outEmaReal); EXPECT_EQ(code, 0); EXPECT_EQ(outBegIdx, period - 1); EXPECT_EQ(outNBElement, (int)rd->rs.amount - outBegIdx); code = TA_MA(0, (int)rd->rs.amount - 1, rd->rs.close, period, /* From 1 to 100000 */ TA_MAType_WMA, &outBegIdx, &outNBElement, outWmaReal); EXPECT_EQ(code, 0); EXPECT_EQ(outBegIdx, period - 1); EXPECT_EQ(outNBElement, (int)rd->rs.amount - outBegIdx); ofstream fout("test-ma.csv"); fout << "Close Price, TRIma, Sma, Ema, Wma\n"; for (int i = 0; i < outNBElement; ++i) { if (i < outBegIdx) fout << rd->rs.close[i] << ", " << ", " << ", " << ", " << endl; else fout << rd->rs.close[i] << ", " << outTrimaReal[i] << ", " << outSmaReal[i] << ", " << outEmaReal[i] << ", " << outWmaReal[i] << ", " << endl; } fout.close(); delete[] outTrimaReal; MQL4::mapRatesData.releaseRatesFromMap(); }
Datum ta_f( PG_FUNCTION_ARGS) { // Declare for TA TA_RetCode retCode; TA_Real *closePrice = NULL; TA_Real *out; TA_Integer outBeg; TA_Integer outNbElement; // Declare for postgres FuncCallContext *funcctx; int call_cntr; int max_calls; Datum *result = NULL; int dim; int z; ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); if (array_contains_nulls(ur)) { ereport(ERROR, ( errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cannot work with arrays containing NULLs") )); } dim = ARRNELEMS(ur); closePrice = ARRPTR(ur); if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* One-time setup code appears here: */ retCode = TA_Initialize(); if (retCode != TA_SUCCESS) { ereport(ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Cannot initialize TA-Lib (%d)!\n", retCode) )); } out = palloc(dim * sizeof(TA_Real)); retCode = TA_MA(0, dim - 1, &closePrice[0], 5, TA_MAType_SMA, &outBeg, &outNbElement, &out[0]); result = palloc(outNbElement * sizeof(Datum)); // Error log for debugging /* ereport(NOTICE, (errmsg("dims %d, outBeg: %d, outNbElement %d\n", dim, outBeg, outNbElement))); */ for (z = 0; z < dim; z++) { // Error log for debugging //ereport(NOTICE, (errmsg("z: %d, out[z]: %5.1f", z, out[z]))); if(z > outBeg-1) { result[z] = Float8GetDatum(out[z-outBeg]); continue; } result[z] = NULL; } TA_Shutdown(); funcctx->max_calls = dim; funcctx->user_fctx = result; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; if (call_cntr < max_calls) { if(((Datum *) funcctx->user_fctx)[call_cntr]) { SRF_RETURN_NEXT(funcctx, ((Datum *) funcctx->user_fctx)[call_cntr]); } SRF_RETURN_NEXT_NULL(funcctx); } SRF_RETURN_DONE(funcctx); }
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; }
/**** 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; }
TA_RetCode TA_STOCH( TA_Integer startIdx, TA_Integer endIdx, const TA_Real inHigh_0[], const TA_Real inLow_0[], const TA_Real inClose_0[], TA_Integer optInFastK_Period_0, /* From 1 to TA_INTEGER_MAX */ TA_Integer optInSlowK_Period_1, /* From 1 to TA_INTEGER_MAX */ TA_MAType optInSlowK_MAType_2, TA_Integer optInSlowD_Period_3, /* From 1 to TA_INTEGER_MAX */ TA_MAType optInSlowD_MAType_4, TA_Integer *outBegIdx, TA_Integer *outNbElement, TA_Real outSlowK_0[], TA_Real outSlowD_1[] ) /**** END GENCODE SECTION 2 - DO NOT DELETE THIS LINE ****/ { /* Insert local variables here. */ TA_RetCode retCode; TA_Real lowest, highest, tmp, diff; TA_Real *tempBuffer; TA_Integer outIdx, lowestIdx, highestIdx; TA_Integer lookbackTotal, lookbackK, lookbackKSlow, lookbackDSlow; TA_Integer trailingIdx, today, i, bufferIsAllocated; /**** 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. */ /* Verify required price component. */ if(!inHigh_0||!inLow_0||!inClose_0) return TA_BAD_PARAM; /* min/max are checked for optInFastK_Period_0. */ if( (TA_Integer)optInFastK_Period_0 == TA_INTEGER_DEFAULT ) optInFastK_Period_0 = 5; else if( ((TA_Integer)optInFastK_Period_0 < 1) || ((TA_Integer)optInFastK_Period_0 > 2147483647) ) return TA_BAD_PARAM; /* min/max are checked for optInSlowK_Period_1. */ if( (TA_Integer)optInSlowK_Period_1 == TA_INTEGER_DEFAULT ) optInSlowK_Period_1 = 3; else if( ((TA_Integer)optInSlowK_Period_1 < 1) || ((TA_Integer)optInSlowK_Period_1 > 2147483647) ) return TA_BAD_PARAM; if( (TA_Integer)optInSlowK_MAType_2 == TA_INTEGER_DEFAULT ) optInSlowK_MAType_2 = 0; else if( ((TA_Integer)optInSlowK_MAType_2 < 0) || ((TA_Integer)optInSlowK_MAType_2 > 8) ) return TA_BAD_PARAM; /* min/max are checked for optInSlowD_Period_3. */ if( (TA_Integer)optInSlowD_Period_3 == TA_INTEGER_DEFAULT ) optInSlowD_Period_3 = 3; else if( ((TA_Integer)optInSlowD_Period_3 < 1) || ((TA_Integer)optInSlowD_Period_3 > 2147483647) ) return TA_BAD_PARAM; if( (TA_Integer)optInSlowD_MAType_4 == TA_INTEGER_DEFAULT ) optInSlowD_MAType_4 = 0; else if( ((TA_Integer)optInSlowD_MAType_4 < 0) || ((TA_Integer)optInSlowD_MAType_4 > 8) ) return TA_BAD_PARAM; if( outSlowK_0 == NULL ) return TA_BAD_PARAM; if( outSlowD_1 == NULL ) return TA_BAD_PARAM; #endif /* TA_FUNC_NO_RANGE_CHECK */ /**** END GENCODE SECTION 3 - DO NOT DELETE THIS LINE ****/ /* Insert TA function code here. */ /* With stochastic, there is a total of 4 different lines that * are defined: FASTK, FASTD, SLOWK and SLOWD. * * The D is the signal line usually drawn over its * corresponding K function. * * (Today's Close - LowestLow) * FASTK(Kperiod) = --------------------------- * 100 * (HighestHigh - LowestLow) * * FASTD(FastDperiod, MA type) = MA Smoothed FASTK over FastDperiod * * SLOWK(SlowKperiod, MA type) = MA Smoothed FASTK over SlowKperiod * * SLOWD(SlowDperiod, MA Type) = MA Smoothed SLOWK over SlowDperiod * * The HighestHigh and LowestLow are the extreme values among the * last 'Kperiod'. * * SLOWK and FASTD are equivalent when using the same period. * * The following shows how these four lines are made available in TA-LIB: * * TA_STOCH : Returns the SLOWK and SLOWD * TA_STOCHF : Returns the FASTK and FASTD * * The TA_STOCH function correspond to the more widely implemented version * found in many software/charting package. The TA_STOCHF is more rarely * used because its higher volatility cause often whipsaws. */ /* Identify the lookback needed. */ lookbackK = optInFastK_Period_0-1; lookbackKSlow = TA_MA_Lookback( optInSlowK_Period_1, optInSlowK_MAType_2 ); lookbackDSlow = TA_MA_Lookback( optInSlowD_Period_3, optInSlowD_MAType_4 ); lookbackTotal = lookbackK + lookbackDSlow + lookbackKSlow; /* Move up the start index if there is not * enough initial data. */ if( startIdx < lookbackTotal ) startIdx = lookbackTotal; /* Make sure there is still something to evaluate. */ if( startIdx > endIdx ) { /* Succeed... but no data in the output. */ *outBegIdx = 0; *outNbElement = 0; return TA_SUCCESS; } /* Do the K calculation: * * Kt = 100 x ((Ct-Lt)/(Ht-Lt)) * * Kt is today stochastic * Ct is today closing price. * Lt is the lowest price of the last K Period (including today) * Ht is the highest price of the last K Period (including today) */ /* Proceed with the calculation for the requested range. * Note that this algorithm allows the input and * output to be the same buffer. */ outIdx = 0; /* Calculate just enough K for ending up with the caller * requested range. (The range of k must consider all * the lookback involve with the smoothing). */ trailingIdx = startIdx-lookbackTotal; today = trailingIdx+lookbackK; lowestIdx = highestIdx = -1; diff = highest = lowest = 0.0; /* Allocate a temporary buffer large enough to * store the K. * * If the output is the same as the input, great * we just save ourself one memory allocation. */ bufferIsAllocated = 0; if( (outSlowK_0 == inHigh_0) || (outSlowK_0 == inLow_0) || (outSlowK_0 == inClose_0) ) { tempBuffer = outSlowK_0; } else if( (outSlowD_1 == inHigh_0) || (outSlowD_1 == inLow_0) || (outSlowD_1 == inClose_0) ) { tempBuffer = outSlowD_1; } else { bufferIsAllocated = 1; tempBuffer = TA_Malloc( (endIdx-today+1)*sizeof(TA_Real) ); } /* Do the K calculation */ while( today <= endIdx ) { /* Set the lowest low */ tmp = inLow_0[today]; if( lowestIdx < trailingIdx ) { lowestIdx = trailingIdx; lowest = inLow_0[lowestIdx]; i = lowestIdx; while( ++i<=today ) { tmp = inLow_0[i]; if( tmp < lowest ) { lowestIdx = i; lowest = tmp; } } diff = (highest - lowest)/100.0; } else if( tmp <= lowest ) { lowestIdx = today; lowest = tmp; diff = (highest - lowest)/100.0; } /* Set the highest high */ tmp = inHigh_0[today]; if( highestIdx < trailingIdx ) { highestIdx = trailingIdx; highest = inHigh_0[highestIdx]; i = highestIdx; while( ++i<=today ) { tmp = inHigh_0[i]; if( tmp > highest ) { highestIdx = i; highest = tmp; } } diff = (highest - lowest)/100.0; } else if( tmp >= highest ) { highestIdx = today; highest = tmp; diff = (highest - lowest)/100.0; } /* Calculate stochastic. */ if( diff != 0.0 ) tempBuffer[outIdx++] = (inClose_0[today]-lowest)/diff; else tempBuffer[outIdx++] = 0.0; trailingIdx++; today++; } /* Un-smoothed K calculation completed. This K calculation is not returned * to the caller. It is always smoothed and then return. * Some documentation will refer to the smoothed version as being * "K-Slow", but often this end up to be shorten to "K". */ retCode = TA_MA( 0, outIdx-1, tempBuffer, optInSlowK_Period_1, optInSlowK_MAType_2, outBegIdx, outNbElement, tempBuffer ); if( (retCode != TA_SUCCESS) || (*outNbElement == 0) ) { if( bufferIsAllocated ) TA_Free( tempBuffer ); /* Something wrong happen? No further data? */ *outBegIdx = 0; *outNbElement = 0; return retCode; } /* Calculate the %D which is simply a moving average of * the already smoothed %K. */ retCode = TA_MA( 0, (*outNbElement)-1, tempBuffer, optInSlowD_Period_3, optInSlowD_MAType_4, outBegIdx, outNbElement, outSlowD_1 ); /* Copy tempBuffer into the caller buffer. * (Calculation could not be done directly in the * caller buffer because more input data then the * requested range was needed for doing %D). */ memmove( outSlowK_0, &tempBuffer[lookbackDSlow], (*outNbElement) * sizeof(TA_Real) ); /* Don't need K anymore, free it if it was allocated here. */ if( bufferIsAllocated ) TA_Free( tempBuffer ); if( retCode != TA_SUCCESS ) { /* Something wrong happen while processing %D? */ *outBegIdx = 0; *outNbElement = 0; return retCode; } /* Note: Keep the outBegIdx relative to the * caller input before returning. */ *outBegIdx = startIdx; return TA_SUCCESS; }
/* This is an un-optimized version of the STOCH function */ static TA_RetCode referenceStoch( TA_Integer startIdx, TA_Integer endIdx, const TA_Real inHigh_0[], const TA_Real inLow_0[], const TA_Real inClose_0[], TA_Integer optInFastK_Period_0, /* From 1 to TA_INTEGER_MAX */ TA_Integer optInSlowK_Period_1, /* From 1 to TA_INTEGER_MAX */ TA_Integer optInSlowK_MAType_2, TA_Integer optInSlowD_Period_3, /* From 1 to TA_INTEGER_MAX */ TA_Integer optInSlowD_MAType_4, TA_Integer *outBegIdx, TA_Integer *outNbElement, TA_Real outSlowK_0[], TA_Real outSlowD_1[] ) /**** END GENCODE SECTION 2 - DO NOT DELETE THIS LINE ****/ { /* Insert local variables here. */ TA_RetCode retCode; TA_Real Lt, Ht, tmp, *tempBuffer; TA_Integer outIdx; TA_Integer lookbackTotal, lookbackK, lookbackKSlow, lookbackDSlow; TA_Integer trailingIdx, today, i, bufferIsAllocated; /**** 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. */ /* Verify required price component. */ if(!inHigh_0||!inLow_0||!inClose_0) return TA_BAD_PARAM; /* min/max are checked for optInFastK_Period_0. */ if( optInFastK_Period_0 == TA_INTEGER_DEFAULT ) optInFastK_Period_0 = 5; else if( (optInFastK_Period_0 < 1) || (optInFastK_Period_0 > 2147483647) ) return TA_BAD_PARAM; /* min/max are checked for optInSlowK_Period_1. */ if( optInSlowK_Period_1 == TA_INTEGER_DEFAULT ) optInSlowK_Period_1 = 3; else if( (optInSlowK_Period_1 < 1) || (optInSlowK_Period_1 > 2147483647) ) return TA_BAD_PARAM; if( optInSlowK_MAType_2 == TA_INTEGER_DEFAULT ) optInSlowK_MAType_2 = 0; else if( (optInSlowK_MAType_2 < 0) || (optInSlowK_MAType_2 > 4) ) return TA_BAD_PARAM; /* min/max are checked for optInSlowD_Period_3. */ if( optInSlowD_Period_3 == TA_INTEGER_DEFAULT ) optInSlowD_Period_3 = 3; else if( (optInSlowD_Period_3 < 1) || (optInSlowD_Period_3 > 2147483647) ) return TA_BAD_PARAM; if( optInSlowD_MAType_4 == TA_INTEGER_DEFAULT ) optInSlowD_MAType_4 = 0; else if( (optInSlowD_MAType_4 < 0) || (optInSlowD_MAType_4 > 4) ) return TA_BAD_PARAM; if( outSlowK_0 == NULL ) return TA_BAD_PARAM; if( outSlowD_1 == NULL ) return TA_BAD_PARAM; #endif /* TA_FUNC_NO_RANGE_CHECK */ /**** END GENCODE SECTION 3 - DO NOT DELETE THIS LINE ****/ /* Insert TA function code here. */ /* Identify the lookback needed. */ lookbackK = optInFastK_Period_0-1; lookbackKSlow = TA_MA_Lookback( optInSlowK_Period_1, optInSlowK_MAType_2 ); lookbackDSlow = TA_MA_Lookback( optInSlowD_Period_3, optInSlowD_MAType_4 ); lookbackTotal = lookbackK + lookbackDSlow + lookbackKSlow; /* Move up the start index if there is not * enough initial data. */ if( startIdx < lookbackTotal ) startIdx = lookbackTotal; /* Make sure there is still something to evaluate. */ if( startIdx > endIdx ) { /* Succeed... but no data in the output. */ *outBegIdx = 0; *outNbElement = 0; return TA_SUCCESS; } /* Do the K calculation: * * Kt = 100 x ((Ct-Lt)/(Ht-Lt)) * * Kt is today stochastic * Ct is today closing price. * Lt is the lowest price of the last K Period (including today) * Ht is the highest price of the last K Period (including today) */ /* Proceed with the calculation for the requested range. * Note that this algorithm allows the input and * output to be the same buffer. */ outIdx = 0; /* Calculate just enough K for ending up with the caller * requested range. (The range of k must consider all * the lookback involve with the smoothing). */ trailingIdx = startIdx-lookbackTotal; today = trailingIdx+lookbackK; /* Allocate a temporary buffer large enough to * store the K. * * If the output is the same as the input, great * we just save ourself one memory allocation. */ bufferIsAllocated = 0; if( (outSlowK_0 == inHigh_0) || (outSlowK_0 == inLow_0) || (outSlowK_0 == inClose_0) ) { tempBuffer = outSlowK_0; } else if( (outSlowD_1 == inHigh_0) || (outSlowD_1 == inLow_0) || (outSlowD_1 == inClose_0) ) { tempBuffer = outSlowD_1; } else { bufferIsAllocated = 1; tempBuffer = TA_Malloc( (endIdx-today+1)*sizeof(TA_Real) ); } /* Do the K calculation */ while( today <= endIdx ) { /* Find Lt and Ht for the requested K period. */ Lt = inLow_0 [trailingIdx]; Ht = inHigh_0[trailingIdx]; trailingIdx++; for( i=trailingIdx; i <= today; i++ ) { tmp = inLow_0[i]; if( tmp < Lt ) Lt = tmp; tmp = inHigh_0[i]; if( tmp > Ht ) Ht = tmp; } /* Calculate stochastic. */ tmp = Ht-Lt; if( tmp > 0.0 ) tempBuffer[outIdx++] = 100.0*((inClose_0[today]-Lt)/tmp); else tempBuffer[outIdx++] = 100.0; today++; } /* Un-smoothed K calculation completed. This K calculation is not returned * to the caller. It is always smoothed and then return. * Some documentation will refer to the smoothed version as being * "K-Slow", but often this end up to be shorten to "K". */ retCode = TA_MA( 0, outIdx-1, tempBuffer, optInSlowK_Period_1, optInSlowK_MAType_2, outBegIdx, outNbElement, tempBuffer ); if( (retCode != TA_SUCCESS) || (*outNbElement == 0) ) { if( bufferIsAllocated ) TA_Free( tempBuffer ); /* Something wrong happen? No further data? */ *outBegIdx = 0; *outNbElement = 0; return retCode; } /* Calculate the %D which is simply a moving average of * the already smoothed %K. */ retCode = TA_MA( 0, (*outNbElement)-1, tempBuffer, optInSlowD_Period_3, optInSlowD_MAType_4, outBegIdx, outNbElement, outSlowD_1 ); /* Copy tempBuffer into the caller buffer. * (Calculation could not be done directly in the * caller buffer because more input data then the * requested range was needed for doing %D). */ memmove( outSlowK_0, &tempBuffer[lookbackDSlow], (*outNbElement) * sizeof(TA_Real) ); /* Don't need K anymore, free it if it was allocated here. */ if( bufferIsAllocated ) TA_Free( tempBuffer ); if( retCode != TA_SUCCESS ) { /* Something wrong happen while processing %D? */ *outBegIdx = 0; *outNbElement = 0; return retCode; } /* Note: Keep the outBegIdx relative to the * caller input before returning. */ *outBegIdx = startIdx; return TA_SUCCESS; }