TA_RetCode TA_HT_PHASOR( TA_Integer startIdx, TA_Integer endIdx, const TA_Real inReal_0[], TA_Integer *outBegIdx, TA_Integer *outNbElement, TA_Real outInPhase_0[], TA_Real outQuadrature_1[] ) /**** END GENCODE SECTION 2 - DO NOT DELETE THIS LINE ****/ { /* insert local variable here */ int outIdx, i; int lookbackTotal, today; TA_Real tempReal, tempReal2; TA_Real adjustedPrevPeriod, period; /* Variable used for the price smoother (a weighted moving average). */ unsigned int trailingWMAIdx; TA_Real periodWMASum, periodWMASub, trailingWMAValue; TA_Real smoothedValue; /* Variables used for the Hilbert Transormation */ const double a = 0.0962; const double b = 0.5769; TA_Real hilbertTempReal; int hilbertIdx; HILBERT_VARIABLES( detrender ); HILBERT_VARIABLES( Q1 ); HILBERT_VARIABLES( jI ); HILBERT_VARIABLES( jQ ); TA_Real Q2, I2, prevQ2, prevI2, Re, Im; TA_Real I1ForOddPrev2, I1ForOddPrev3; TA_Real I1ForEvenPrev2, I1ForEvenPrev3; TA_Real rad2Deg; TA_Real todayValue; /**** 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; if( outInPhase_0 == NULL ) return TA_BAD_PARAM; if( outQuadrature_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. */ /* Constant */ rad2Deg = 180.0 / (4.0 * atan(1)); /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = 32 + TA_Globals.unstablePeriod[TA_FUNC_UNST_HT_PHASOR]; /* 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; } *outBegIdx = startIdx; /* Initialize the price smoother, which is simply a weighted * moving average of the price. * To understand this algorithm, I strongly suggest to understand * first how TA_WMA is done. */ trailingWMAIdx = startIdx - lookbackTotal; today = trailingWMAIdx; /* Initialization is same as WMA, except loop is unrolled * for speed optimization. */ tempReal = inReal_0[today++]; periodWMASub = tempReal; periodWMASum = tempReal; tempReal = inReal_0[today++]; periodWMASub += tempReal; periodWMASum += tempReal*2.0; tempReal = inReal_0[today++]; periodWMASub += tempReal; periodWMASum += tempReal*3.0; trailingWMAValue = 0.0; /* Subsequent WMA value are evaluated by using * the DO_PRICE_WMA macro. */ #define DO_PRICE_WMA(varNewPrice,varToStoreSmoothedValue) { \ periodWMASub += varNewPrice; \ periodWMASub -= trailingWMAValue; \ periodWMASum += varNewPrice*4.0; \ trailingWMAValue = inReal_0[trailingWMAIdx++]; \ varToStoreSmoothedValue = periodWMASum*0.1; \ periodWMASum -= periodWMASub; \ } i = 9; do { tempReal = inReal_0[today++]; DO_PRICE_WMA(tempReal,smoothedValue); } while( --i != 0); /* Initialize the circular buffers used by the hilbert * transform logic. * A buffer is used for odd day and another for even days. * This minimize the number of memory access and floating point * operations needed (note also that by using static circular buffer, * no large dynamic memory allocation is needed for storing * intermediate calculation!). */ hilbertIdx = 0; INIT_HILBERT_VARIABLES(detrender); INIT_HILBERT_VARIABLES(Q1); INIT_HILBERT_VARIABLES(jI); INIT_HILBERT_VARIABLES(jQ); period = 0.0; outIdx = 0; prevI2 = prevQ2 = 0.0; Re = Im = 0.0; I1ForOddPrev3 = I1ForEvenPrev3 = 0.0; I1ForOddPrev2 = I1ForEvenPrev2 = 0.0; /* The code is speed optimized and is most likely very * hard to follow if you do not already know well the * original algorithm. * To understadn better, it is strongly suggested to look * first at the Excel implementation in "test_MAMA.xls" included * in this package. */ while( today <= endIdx ) { adjustedPrevPeriod = (0.075*period)+0.54; todayValue = inReal_0[today]; DO_PRICE_WMA(todayValue,smoothedValue); if( today & 1 ) { /* Do the Hilbert Transforms for even price bar */ DO_HILBERT_EVEN(detrender,smoothedValue); DO_HILBERT_EVEN(Q1,detrender); if( today >= startIdx ) { outQuadrature_1[outIdx] = Q1; outInPhase_0[outIdx++] = I1ForEvenPrev3; } DO_HILBERT_EVEN(jI,I1ForEvenPrev3); DO_HILBERT_EVEN(jQ,Q1); if( ++hilbertIdx == 3 ) hilbertIdx = 0; Q2 = (0.2*(Q1 + jI)) + (0.8*prevQ2); I2 = (0.2*(I1ForEvenPrev3 - jQ)) + (0.8*prevI2); /* The variable I1 is the detrender delayed for * 3 price bars. * * Save the current detrender value for being * used by the "odd" logic later. */ I1ForOddPrev3 = I1ForOddPrev2; I1ForOddPrev2 = detrender; } else { /* Do the Hilbert Transforms for odd price bar */ DO_HILBERT_ODD(detrender,smoothedValue); DO_HILBERT_ODD(Q1,detrender); if( today >= startIdx ) { outQuadrature_1[outIdx] = Q1; outInPhase_0[outIdx++] = I1ForOddPrev3; } DO_HILBERT_ODD(jI,I1ForOddPrev3); DO_HILBERT_ODD(jQ,Q1); Q2 = (0.2*(Q1 + jI)) + (0.8*prevQ2); I2 = (0.2*(I1ForOddPrev3 - jQ)) + (0.8*prevI2); /* The varaiable I1 is the detrender delayed for * 3 price bars. * * Save the current detrender value for being * used by the "odd" logic later. */ I1ForEvenPrev3 = I1ForEvenPrev2; I1ForEvenPrev2 = detrender; } /* Adjust the period for next price bar */ Re = (0.2*((I2*prevI2)+(Q2*prevQ2)))+(0.8*Re); Im = (0.2*((I2*prevQ2)-(Q2*prevI2)))+(0.8*Im); prevQ2 = Q2; prevI2 = I2; tempReal = period; if( (Im != 0.0) && (Re != 0.0) ) period = 360.0 / (atan(Im/Re)*rad2Deg); tempReal2 = 1.5*tempReal; if( period > tempReal2) period = tempReal2; tempReal2 = 0.67*tempReal; if( period < tempReal2 ) period = tempReal2; if( period < 6 ) period = 6; else if( period > 50 ) period = 50; period = (0.2*period) + (0.8 * tempReal); /* Ooof... let's do the next price bar now! */ today++; } /* Default return values */ *outNbElement = outIdx; return TA_SUCCESS; }
/* Generated */ TA_RetCode TA_S_MAMA( int startIdx, /* Generated */ int endIdx, /* Generated */ const float inReal_0[], /* Generated */ double optInFastLimit_0, /* From 0.01 to 0.99 */ /* Generated */ double optInSlowLimit_1, /* From 0.01 to 0.99 */ /* Generated */ int *outBegIdx, /* Generated */ int *outNbElement, /* Generated */ double outMAMA_0[], /* Generated */ double outFAMA_1[] ) /* Generated */ #endif /* Generated */ { /* Generated */ int outIdx, i; /* Generated */ int lookbackTotal, today; /* Generated */ double tempReal, tempReal2; /* Generated */ double adjustedPrevPeriod, period; /* Generated */ unsigned int trailingWMAIdx; /* Generated */ double periodWMASum, periodWMASub, trailingWMAValue; /* Generated */ double smoothedValue; /* Generated */ const double a = 0.0962; /* Generated */ const double b = 0.5769; /* Generated */ double hilbertTempReal; /* Generated */ int hilbertIdx; /* Generated */ HILBERT_VARIABLES( detrender ); /* Generated */ HILBERT_VARIABLES( Q1 ); /* Generated */ HILBERT_VARIABLES( jI ); /* Generated */ HILBERT_VARIABLES( jQ ); /* Generated */ double Q2, I2, prevQ2, prevI2, Re, Im; /* Generated */ double I1ForOddPrev2, I1ForOddPrev3; /* Generated */ double I1ForEvenPrev2, I1ForEvenPrev3; /* Generated */ double rad2Deg; /* Generated */ double mama,fama,todayValue,prevPhase; /* 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_0 ) return TA_BAD_PARAM; /* Generated */ if( optInFastLimit_0 == TA_REAL_DEFAULT ) /* Generated */ optInFastLimit_0 = 5.000000e-1; /* Generated */ else if( (optInFastLimit_0 < 1.000000e-2) || (optInFastLimit_0 > 9.900000e-1) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( optInSlowLimit_1 == TA_REAL_DEFAULT ) /* Generated */ optInSlowLimit_1 = 5.000000e-2; /* Generated */ else if( (optInSlowLimit_1 < 1.000000e-2) || (optInSlowLimit_1 > 9.900000e-1) ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( outMAMA_0 == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ if( outFAMA_1 == NULL ) /* Generated */ return TA_BAD_PARAM; /* Generated */ #endif /* Generated */ rad2Deg = 180.0 / (4.0 * atan(1)); /* Generated */ lookbackTotal = 32 + TA_Globals->unstablePeriod[TA_FUNC_UNST_MAMA]; /* Generated */ if( startIdx < lookbackTotal ) /* Generated */ startIdx = lookbackTotal; /* Generated */ if( startIdx > endIdx ) /* Generated */ { /* Generated */ *outBegIdx = 0; /* Generated */ *outNbElement = 0; /* Generated */ return TA_SUCCESS; /* Generated */ } /* Generated */ *outBegIdx = startIdx; /* Generated */ trailingWMAIdx = startIdx - lookbackTotal; /* Generated */ today = trailingWMAIdx; /* Generated */ tempReal = inReal_0[today++]; /* Generated */ periodWMASub = tempReal; /* Generated */ periodWMASum = tempReal; /* Generated */ tempReal = inReal_0[today++]; /* Generated */ periodWMASub += tempReal; /* Generated */ periodWMASum += tempReal*2.0; /* Generated */ tempReal = inReal_0[today++]; /* Generated */ periodWMASub += tempReal; /* Generated */ periodWMASum += tempReal*3.0; /* Generated */ trailingWMAValue = 0.0; /* Generated */ #define DO_PRICE_WMA(varNewPrice,varToStoreSmoothedValue) { \ /* Generated */ periodWMASub += varNewPrice; \ /* Generated */ periodWMASub -= trailingWMAValue; \ /* Generated */ periodWMASum += varNewPrice*4.0; \ /* Generated */ trailingWMAValue = inReal_0[trailingWMAIdx++]; \ /* Generated */ varToStoreSmoothedValue = periodWMASum*0.1; \ /* Generated */ periodWMASum -= periodWMASub; \ /* Generated */ } /* Generated */ i = 9; /* Generated */ do /* Generated */ { /* Generated */ tempReal = inReal_0[today++]; /* Generated */ DO_PRICE_WMA(tempReal,smoothedValue); /* Generated */ } while( --i != 0); /* Generated */ hilbertIdx = 0; /* Generated */ INIT_HILBERT_VARIABLES(detrender); /* Generated */ INIT_HILBERT_VARIABLES(Q1); /* Generated */ INIT_HILBERT_VARIABLES(jI); /* Generated */ INIT_HILBERT_VARIABLES(jQ); /* Generated */ period = 0.0; /* Generated */ outIdx = 0; /* Generated */ prevI2 = prevQ2 = 0.0; /* Generated */ Re = Im = 0.0; /* Generated */ mama = fama = 0.0; /* Generated */ I1ForOddPrev3 = I1ForEvenPrev3 = 0.0; /* Generated */ I1ForOddPrev2 = I1ForEvenPrev2 = 0.0; /* Generated */ prevPhase = 0.0; /* Generated */ while( today <= endIdx ) /* Generated */ { /* Generated */ adjustedPrevPeriod = (0.075*period)+0.54; /* Generated */ todayValue = inReal_0[today]; /* Generated */ DO_PRICE_WMA(todayValue,smoothedValue); /* Generated */ if( today & 1 ) /* Generated */ { /* Generated */ DO_HILBERT_EVEN(detrender,smoothedValue); /* Generated */ DO_HILBERT_EVEN(Q1,detrender); /* Generated */ DO_HILBERT_EVEN(jI,I1ForEvenPrev3); /* Generated */ DO_HILBERT_EVEN(jQ,Q1); /* Generated */ if( ++hilbertIdx == 3 ) /* Generated */ hilbertIdx = 0; /* Generated */ Q2 = (0.2*(Q1 + jI)) + (0.8*prevQ2); /* Generated */ I2 = (0.2*(I1ForEvenPrev3 - jQ)) + (0.8*prevI2); /* Generated */ I1ForOddPrev3 = I1ForOddPrev2; /* Generated */ I1ForOddPrev2 = detrender; /* Generated */ if( I1ForEvenPrev3 != 0.0 ) /* Generated */ tempReal2 = (atan(Q1/I1ForEvenPrev3)*rad2Deg); /* Generated */ else /* Generated */ tempReal2 = 0.0; /* Generated */ } /* Generated */ else /* Generated */ { /* Generated */ DO_HILBERT_ODD(detrender,smoothedValue); /* Generated */ DO_HILBERT_ODD(Q1,detrender); /* Generated */ DO_HILBERT_ODD(jI,I1ForOddPrev3); /* Generated */ DO_HILBERT_ODD(jQ,Q1); /* Generated */ Q2 = (0.2*(Q1 + jI)) + (0.8*prevQ2); /* Generated */ I2 = (0.2*(I1ForOddPrev3 - jQ)) + (0.8*prevI2); /* Generated */ I1ForEvenPrev3 = I1ForEvenPrev2; /* Generated */ I1ForEvenPrev2 = detrender; /* Generated */ if( I1ForOddPrev3 != 0.0 ) /* Generated */ tempReal2 = (atan(Q1/I1ForOddPrev3)*rad2Deg); /* Generated */ else /* Generated */ tempReal2 = 0.0; /* Generated */ } /* Generated */ tempReal = prevPhase - tempReal2; /* Generated */ prevPhase = tempReal2; /* Generated */ if( tempReal < 1.0 ) /* Generated */ tempReal = 1.0; /* Generated */ if( tempReal > 1.0 ) /* Generated */ { /* Generated */ tempReal = optInFastLimit_0/tempReal; /* Generated */ if( tempReal < optInSlowLimit_1 ) /* Generated */ tempReal = optInSlowLimit_1; /* Generated */ } /* Generated */ else /* Generated */ { /* Generated */ tempReal = optInFastLimit_0; /* Generated */ } /* Generated */ mama = (tempReal*todayValue)+((1-tempReal)*mama); /* Generated */ tempReal *= 0.5; /* Generated */ fama = (tempReal*mama)+((1-tempReal)*fama); /* Generated */ if( today >= startIdx ) /* Generated */ { /* Generated */ outMAMA_0[outIdx] = mama; /* Generated */ outFAMA_1[outIdx++] = fama; /* Generated */ } /* Generated */ Re = (0.2*((I2*prevI2)+(Q2*prevQ2)))+(0.8*Re); /* Generated */ Im = (0.2*((I2*prevQ2)-(Q2*prevI2)))+(0.8*Im); /* Generated */ prevQ2 = Q2; /* Generated */ prevI2 = I2; /* Generated */ tempReal = period; /* Generated */ if( (Im != 0.0) && (Re != 0.0) ) /* Generated */ period = 360.0 / (atan(Im/Re)*rad2Deg); /* Generated */ tempReal2 = 1.5*tempReal; /* Generated */ if( period > tempReal2) /* Generated */ period = tempReal2; /* Generated */ tempReal2 = 0.67*tempReal; /* Generated */ if( period < tempReal2 ) /* Generated */ period = tempReal2; /* Generated */ if( period < 6 ) /* Generated */ period = 6; /* Generated */ else if( period > 50 ) /* Generated */ period = 50; /* Generated */ period = (0.2*period) + (0.8 * tempReal); /* Generated */ today++; /* Generated */ } /* Generated */ *outNbElement = outIdx; /* Generated */ return TA_SUCCESS; /* Generated */ }