/* TA-LIB Copyright (c) 1999-2026, 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. */ /* AUTO-GENERATED by ta_codegen — DO NOT EDIT. * Source of truth: ta_codegen/input// (regenerate: cd ta_codegen/generator && cargo run -- generate) */ #include #include #include "ta_func.h" #include "ta_utility.h" #include "ta_memory.h" #include "ta_func_unguarded.h" /* List of contributors: * * Initial Name/description * ------------------------------------------------------------------- * MF Mario Fortier * * * Change history: * * MMDDYY BY Description * ------------------------------------------------------------------- * 120802 MF Template creation. * 052603 MF Adapt code to compile with .NET Managed C++ * 062704 MF Fix limit case to avoid divid by zero (or by * a value close to zero induce by the imprecision * of floating points). * 070226 MF,CC Allow period of 1: output is a copy of the input, * consistent with TA_MA (issues #48, #59). The natural * KAMA math at period=1 would be a fixed-alpha EMA * (efficiency ratio is always 1), which would disagree * with TA_MA's period-1 copy, so identity is explicit. */ TA_LIB_API int TA_KAMA_Lookback( int optInTimePeriod ) { if( (int)optInTimePeriod == (int)0x80000000 ) optInTimePeriod = 30; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return -1; if( optInTimePeriod == 1 ) { return TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); } return optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); } TA_FMA_MULTIVERSION TA_LIB_API TA_RetCode TA_KAMA( int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { double constMax; double constDiff; double tempReal; double tempReal2; double sumROC1; double periodROC; double prevKAMA; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue; if( startIdx < 0 ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( !inReal ) return TA_BAD_PARAM; if( (int)optInTimePeriod == (int)0x80000000 ) optInTimePeriod = 30; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; if( !outReal ) return TA_BAD_PARAM; constMax = 2.0 / (30.0 + 1.0); constDiff = 2.0 / (2.0 + 1.0) - constMax; /* Default return values */ *outBegIdx= 0; *outNBElement= 0; /* No smoothing at period of 1: the output is a copy of the input * (same convention as TA_MA for every MAType). The unstable period * still delays the first output for API consistency. */ if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_SUCCESS; } *outBegIdx= startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { outReal[outIdx++] = inReal[today++]; } *outNBElement= outIdx; return TA_SUCCESS; } /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); /* 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 ) { *outBegIdx= 0; *outNBElement= 0; return TA_SUCCESS; } /* Initialize the variables by going through * the lookback period. */ sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = inReal[today++]; tempReal -= inReal[today]; sumROC1 += fabs(tempReal); } /* At this point sumROC1 represent the * summation of the 1-day price difference * over the (optInTimePeriod-1) */ /* Calculate the first KAMA */ /* The yesterday price is used here as the previous KAMA. */ prevKAMA = inReal[today - 1]; tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); /* 'today' keep track of where the processing is within the * input. */ /* Skip the unstable period. Do the whole processing * needed for KAMA, but do not write it in the output. */ while( today <= startIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); } /* Write the first value. */ outReal[0] = prevKAMA; outIdx = 1; *outBegIdx= today - 1; /* Do the KAMA calculation for the requested range. */ while( today <= endIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); outReal[outIdx++] = prevKAMA; } *outNBElement= outIdx; return TA_SUCCESS; } TA_FMA_MULTIVERSION TA_LIB_API TA_RetCode TA_KAMA_Unguarded( int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { double constMax; double constDiff; double tempReal; double tempReal2; double sumROC1; double periodROC; double prevKAMA; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue; constMax = 2.0 / (30.0 + 1.0); constDiff = 2.0 / (2.0 + 1.0) - constMax; *outBegIdx= 0; *outNBElement= 0; if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_SUCCESS; } *outBegIdx= startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { outReal[outIdx++] = inReal[today++]; } *outNBElement= outIdx; return TA_SUCCESS; } lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { *outBegIdx= 0; *outNBElement= 0; return TA_SUCCESS; } sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = inReal[today++]; tempReal -= inReal[today]; sumROC1 += fabs(tempReal); } prevKAMA = inReal[today - 1]; tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); while( today <= startIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); } outReal[0] = prevKAMA; outIdx = 1; *outBegIdx= today - 1; while( today <= endIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); outReal[outIdx++] = prevKAMA; } *outNBElement= outIdx; return TA_SUCCESS; } TA_FMA_MULTIVERSION TA_RetCode TA_S_KAMA( int startIdx, int endIdx, const float inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { double constMax; double constDiff; double tempReal; double tempReal2; double sumROC1; double periodROC; double prevKAMA; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue; if( startIdx < 0 ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( !inReal ) return TA_BAD_PARAM; if( (int)optInTimePeriod == (int)0x80000000 ) optInTimePeriod = 30; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; if( !outReal ) return TA_BAD_PARAM; constMax = 2.0 / (30.0 + 1.0); constDiff = 2.0 / (2.0 + 1.0) - constMax; *outBegIdx= 0; *outNBElement= 0; if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_SUCCESS; } *outBegIdx= startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { outReal[outIdx++] = (double)inReal[today++]; } *outNBElement= outIdx; return TA_SUCCESS; } lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { *outBegIdx= 0; *outNBElement= 0; return TA_SUCCESS; } sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = (double)inReal[today++]; tempReal -= (double)inReal[today]; sumROC1 += fabs(tempReal); } prevKAMA = (double)inReal[today - 1]; tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); while( today <= startIdx ) { tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - (double)inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); } outReal[0] = prevKAMA; outIdx = 1; *outBegIdx= today - 1; while( today <= endIdx ) { tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - (double)inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); outReal[outIdx++] = prevKAMA; } *outNBElement= outIdx; return TA_SUCCESS; } TA_FMA_MULTIVERSION TA_RetCode TA_S_KAMA_Unguarded( int startIdx, int endIdx, const float inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { double constMax; double constDiff; double tempReal; double tempReal2; double sumROC1; double periodROC; double prevKAMA; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue; constMax = 2.0 / (30.0 + 1.0); constDiff = 2.0 / (2.0 + 1.0) - constMax; *outBegIdx= 0; *outNBElement= 0; if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_SUCCESS; } *outBegIdx= startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { outReal[outIdx++] = (double)inReal[today++]; } *outNBElement= outIdx; return TA_SUCCESS; } lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { *outBegIdx= 0; *outNBElement= 0; return TA_SUCCESS; } sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = (double)inReal[today++]; tempReal -= (double)inReal[today]; sumROC1 += fabs(tempReal); } prevKAMA = (double)inReal[today - 1]; tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); while( today <= startIdx ) { tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - (double)inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); } outReal[0] = prevKAMA; outIdx = 1; *outBegIdx= today - 1; while( today <= endIdx ) { tempReal = (double)inReal[today]; tempReal2 = (double)inReal[trailingIdx++]; periodROC = tempReal - tempReal2; sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - (double)inReal[today - 1]); trailingValue = tempReal2; if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; prevKAMA = fma((double)inReal[today++] - prevKAMA, tempReal, prevKAMA); outReal[outIdx++] = prevKAMA; } *outNBElement= outIdx; return TA_SUCCESS; } /**** Streaming API *****/ struct TA_KAMA_Stream { int optInTimePeriod; double constMax; double constDiff; double sumROC1; double prevKAMA; double trailingValue; double lag1_inReal; int ringPos_trailingIdx; int ringCap_trailingIdx; double *ring_trailingIdx_inReal; double *ringMirror_trailingIdx_inReal; }; /* Private function, not in public API. */ static void TA_KAMA_ReleaseInternal( struct TA_KAMA_Stream *sp ) { if( !sp ) return; if( sp->ring_trailingIdx_inReal ) TA_Free( sp->ring_trailingIdx_inReal ); if( sp->ringMirror_trailingIdx_inReal ) TA_Free( sp->ringMirror_trailingIdx_inReal ); TA_Free( sp ); } /* Private function, not in public API. */ static void TA_KAMA_StepInternal( struct TA_KAMA_Stream *sp, double inReal, double *outReal ) { double tempReal; double tempReal2; double periodROC; if( sp->optInTimePeriod == 1 ) { *outReal= inReal; return; } if( sp->ringCap_trailingIdx == 0 ) { sp->ring_trailingIdx_inReal[0] = inReal; } tempReal = inReal; tempReal2 = sp->ring_trailingIdx_inReal[sp->ringPos_trailingIdx]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sp->sumROC1 -= fabs(sp->trailingValue - tempReal2); sp->sumROC1 += fabs(tempReal - sp->lag1_inReal); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ sp->trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sp->sumROC1 <= periodROC || TA_IS_ZERO(sp->sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sp->sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, sp->constDiff, sp->constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ sp->prevKAMA = fma(inReal - sp->prevKAMA, tempReal, sp->prevKAMA); *outReal= sp->prevKAMA; sp->lag1_inReal = inReal; sp->ring_trailingIdx_inReal[sp->ringPos_trailingIdx] = inReal; sp->ringPos_trailingIdx = sp->ringPos_trailingIdx + 1; if( sp->ringPos_trailingIdx >= sp->ringCap_trailingIdx ) { sp->ringPos_trailingIdx = 0; } } /* Private function, not in public API. */ TA_RetCode TA_KAMA_OpenInternal( struct TA_KAMA_Stream **stream, const double inReal[], int startIdx, int historyLen, int optInTimePeriod, double *outReal ) { struct TA_KAMA_Stream *sp; int endIdx; int dummyBegIdx; int dummyNBElement; double lastValue_outReal; if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( !inReal || !outReal ) return TA_BAD_PARAM; if( historyLen < 1 ) return TA_BAD_PARAM; if( (int)optInTimePeriod == (int)0x80000000 ) optInTimePeriod = 30; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; endIdx = historyLen - 1; dummyBegIdx = 0; dummyNBElement = 0; lastValue_outReal = 0.0; (void)startIdx; (void)dummyBegIdx; (void)dummyNBElement; if( optInTimePeriod == 1 ) { if( historyLen < TA_KAMA_Lookback( optInTimePeriod ) + 1 ) return TA_BAD_PARAM; sp = (struct TA_KAMA_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->optInTimePeriod = optInTimePeriod; sp->ringCap_trailingIdx = 0; { size_t allocN = (size_t)(sp->ringCap_trailingIdx > 0 ? sp->ringCap_trailingIdx : 1); sp->ring_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ring_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } sp->ringMirror_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ringMirror_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } memset( sp->ring_trailingIdx_inReal, 0, sizeof(double) * allocN ); } sp->ringPos_trailingIdx = 0; *outReal = inReal[historyLen - 1]; *stream = sp; return TA_SUCCESS; } { double constMax = 2.0 / (30.0 + 1.0); double constDiff = 2.0 / (2.0 + 1.0) - constMax; double tempReal; double tempReal2; double sumROC1 = 0.0; double periodROC; double prevKAMA = 0.0; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue = 0.0; /* Default return values */ dummyBegIdx = 0; dummyNBElement = 0; /* No smoothing at period of 1: the output is a copy of the input * (same convention as TA_MA for every MAType). The unstable period * still delays the first output for API consistency. */ if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_BAD_PARAM; } dummyBegIdx = startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { lastValue_outReal = inReal[today++]; } dummyNBElement = outIdx; return TA_BAD_PARAM; } /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); /* 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 ) { dummyBegIdx = 0; dummyNBElement = 0; return TA_BAD_PARAM; } /* Initialize the variables by going through * the lookback period. */ sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = inReal[today++]; tempReal -= inReal[today]; sumROC1 += fabs(tempReal); } /* At this point sumROC1 represent the * summation of the 1-day price difference * over the (optInTimePeriod-1) */ /* Calculate the first KAMA */ /* The yesterday price is used here as the previous KAMA. */ prevKAMA = inReal[today - 1]; tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); /* 'today' keep track of where the processing is within the * input. */ /* Skip the unstable period. Do the whole processing * needed for KAMA, but do not write it in the output. */ while( today <= startIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); } /* Write the first value. */ lastValue_outReal = prevKAMA; outIdx = 1; dummyBegIdx = today - 1; /* Do the KAMA calculation for the requested range. */ while( today <= endIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); lastValue_outReal = prevKAMA; } dummyNBElement = outIdx; /* Capture the live batch state into the handle. */ sp = (struct TA_KAMA_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->optInTimePeriod = optInTimePeriod; sp->constMax = constMax; sp->constDiff = constDiff; sp->sumROC1 = sumROC1; sp->prevKAMA = prevKAMA; sp->trailingValue = trailingValue; sp->ringCap_trailingIdx = (int)(today - trailingIdx); if( sp->ringCap_trailingIdx < 0 || sp->ringCap_trailingIdx > historyLen ) { TA_KAMA_ReleaseInternal( sp ); return TA_INTERNAL_ERROR; } { size_t allocN = (size_t)(sp->ringCap_trailingIdx > 0 ? sp->ringCap_trailingIdx : 1); sp->ring_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ring_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } sp->ringMirror_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ringMirror_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } memcpy( sp->ring_trailingIdx_inReal, inReal + (historyLen - sp->ringCap_trailingIdx), sizeof(double) * (size_t)sp->ringCap_trailingIdx ); } sp->ringPos_trailingIdx = 0; sp->lag1_inReal = inReal[historyLen - 1]; *outReal = lastValue_outReal; *stream = sp; return TA_SUCCESS; } } TA_LIB_API TA_RetCode TA_KAMA_Open( TA_KAMA_Stream **stream, const double inReal[], int historyLen, int optInTimePeriod, double *outReal ) { return TA_KAMA_OpenInternal( stream, inReal, 0, historyLen, optInTimePeriod, outReal ); } TA_LIB_API TA_RetCode TA_KAMA_OpenAndFill( TA_KAMA_Stream **stream, const double inReal[], int historyLen, int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { struct TA_KAMA_Stream *sp; int endIdx; int startIdx; int dummyBegIdx; int dummyNBElement; if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( !inReal || !outReal || !outBegIdx || !outNBElement ) return TA_BAD_PARAM; if( historyLen < 1 ) return TA_BAD_PARAM; if( (const void *)outReal == (const void *)inReal ) return TA_BAD_PARAM; if( (int)optInTimePeriod == (int)0x80000000 ) optInTimePeriod = 30; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; endIdx = historyLen - 1; startIdx = 0; dummyBegIdx = 0; dummyNBElement = 0; (void)startIdx; (void)dummyBegIdx; (void)dummyNBElement; if( optInTimePeriod == 1 ) { if( historyLen < TA_KAMA_Lookback( optInTimePeriod ) + 1 ) return TA_BAD_PARAM; sp = (struct TA_KAMA_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->optInTimePeriod = optInTimePeriod; sp->ringCap_trailingIdx = 0; { size_t allocN = (size_t)(sp->ringCap_trailingIdx > 0 ? sp->ringCap_trailingIdx : 1); sp->ring_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ring_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } sp->ringMirror_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ringMirror_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } memset( sp->ring_trailingIdx_inReal, 0, sizeof(double) * allocN ); } sp->ringPos_trailingIdx = 0; { int fillLb = TA_KAMA_Lookback( optInTimePeriod ); int fillIdx; *outBegIdx = fillLb; *outNBElement = historyLen - fillLb; for( fillIdx = 0; fillIdx < historyLen - fillLb; fillIdx++ ) { outReal[fillIdx] = inReal[fillLb + fillIdx]; } } *stream = sp; return TA_SUCCESS; } { double constMax = 2.0 / (30.0 + 1.0); double constDiff = 2.0 / (2.0 + 1.0) - constMax; double tempReal; double tempReal2; double sumROC1 = 0.0; double periodROC; double prevKAMA = 0.0; int i; int today; int outIdx; int lookbackTotal; int trailingIdx; double trailingValue = 0.0; /* Default return values */ *outBegIdx= 0; *outNBElement= 0; /* No smoothing at period of 1: the output is a copy of the input * (same convention as TA_MA for every MAType). The unstable period * still delays the first output for API consistency. */ if( optInTimePeriod == 1 ) { lookbackTotal = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_BAD_PARAM; } *outBegIdx= startIdx; outIdx = 0; today = startIdx; while( today <= endIdx ) { outReal[outIdx++] = inReal[today++]; } *outNBElement= outIdx; return TA_BAD_PARAM; } /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_KAMA,Kama); /* 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 ) { *outBegIdx= 0; *outNBElement= 0; return TA_BAD_PARAM; } /* Initialize the variables by going through * the lookback period. */ sumROC1 = 0.0; today = startIdx - lookbackTotal; trailingIdx = today; i = optInTimePeriod; while( i-- > 0 ) { tempReal = inReal[today++]; tempReal -= inReal[today]; sumROC1 += fabs(tempReal); } /* At this point sumROC1 represent the * summation of the 1-day price difference * over the (optInTimePeriod-1) */ /* Calculate the first KAMA */ /* The yesterday price is used here as the previous KAMA. */ prevKAMA = inReal[today - 1]; tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); /* 'today' keep track of where the processing is within the * input. */ /* Skip the unstable period. Do the whole processing * needed for KAMA, but do not write it in the output. */ while( today <= startIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); } /* Write the first value. */ outReal[0] = prevKAMA; outIdx = 1; *outBegIdx= today - 1; /* Do the KAMA calculation for the requested range. */ while( today <= endIdx ) { tempReal = inReal[today]; tempReal2 = inReal[trailingIdx++]; periodROC = tempReal - tempReal2; /* Adjust sumROC1: * - Remove trailing ROC1 * - Add new ROC1 */ sumROC1 -= fabs(trailingValue - tempReal2); sumROC1 += fabs(tempReal - inReal[today - 1]); /* Save the trailing value. Do this because inReal * and outReal can be pointers to the same buffer. */ trailingValue = tempReal2; /* Calculate the efficiency ratio */ if( sumROC1 <= periodROC || TA_IS_ZERO(sumROC1) ) { tempReal = 1.0; } else { tempReal = fabs(periodROC / sumROC1); } /* Calculate the smoothing constant */ tempReal = fma(tempReal, constDiff, constMax); tempReal *= tempReal; /* Calculate the KAMA like an EMA, using the * smoothing constant as the adaptive factor. */ prevKAMA = fma(inReal[today++] - prevKAMA, tempReal, prevKAMA); outReal[outIdx++] = prevKAMA; } *outNBElement= outIdx; /* Capture the live batch state into the handle. */ sp = (struct TA_KAMA_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->optInTimePeriod = optInTimePeriod; sp->constMax = constMax; sp->constDiff = constDiff; sp->sumROC1 = sumROC1; sp->prevKAMA = prevKAMA; sp->trailingValue = trailingValue; sp->ringCap_trailingIdx = (int)(today - trailingIdx); if( sp->ringCap_trailingIdx < 0 || sp->ringCap_trailingIdx > historyLen ) { TA_KAMA_ReleaseInternal( sp ); return TA_INTERNAL_ERROR; } { size_t allocN = (size_t)(sp->ringCap_trailingIdx > 0 ? sp->ringCap_trailingIdx : 1); sp->ring_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ring_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } sp->ringMirror_trailingIdx_inReal = (double *)TA_Malloc( sizeof(double) * allocN ); if( !sp->ringMirror_trailingIdx_inReal ) { TA_KAMA_ReleaseInternal( sp ); return TA_ALLOC_ERR; } memcpy( sp->ring_trailingIdx_inReal, inReal + (historyLen - sp->ringCap_trailingIdx), sizeof(double) * (size_t)sp->ringCap_trailingIdx ); } sp->ringPos_trailingIdx = 0; sp->lag1_inReal = inReal[historyLen - 1]; *stream = sp; return TA_SUCCESS; } } TA_LIB_API TA_RetCode TA_KAMA_Update( TA_KAMA_Stream *stream, double inReal, double *outReal ) { if( !stream || !outReal ) return TA_BAD_PARAM; TA_KAMA_StepInternal( stream, inReal, outReal ); return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_KAMA_Peek( const TA_KAMA_Stream *stream, double inReal, double *outReal ) { struct TA_KAMA_Stream scratch; if( !stream || !outReal ) return TA_BAD_PARAM; scratch = *stream; scratch.ring_trailingIdx_inReal = stream->ringMirror_trailingIdx_inReal; memcpy( scratch.ring_trailingIdx_inReal, stream->ring_trailingIdx_inReal, sizeof(double) * (size_t)(stream->ringCap_trailingIdx > 0 ? stream->ringCap_trailingIdx : 1) ); TA_KAMA_StepInternal( &scratch, inReal, outReal ); return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_KAMA_Close( TA_KAMA_Stream *stream ) { TA_KAMA_ReleaseInternal( stream ); return TA_SUCCESS; }