/* 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_stream_private.h" /* List of contributors: * * Initial Name/description * ------------------------------------------------------------------- * AC Angelo Ciceri * * * Change history: * * MMDDYY BY Description * ------------------------------------------------------------------- * 011605 AC Creation */ TA_LIB_API int TA_CDLXSIDEGAP3METHODS_Lookback( void ) { return 2; } TA_LIB_API int TA_CDLXSIDEGAP3METHODS_DisplayShift( int outputIdx ) { if( outputIdx < 0 || outputIdx >= 1 ) return INT_MIN; return 0; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS( int startIdx, int endIdx, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int *outBegIdx, int *outNBElement, int outInteger[] ) { int i; int outIdx; int lookbackTotal; if( (startIdx < 0) || (startIdx > TA_INDEX_MAX) ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx > TA_INDEX_MAX) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( !inOpen ) return TA_BAD_PARAM; if( !inHigh ) return TA_BAD_PARAM; if( !inLow ) return TA_BAD_PARAM; if( !inClose ) return TA_BAD_PARAM; if( !outBegIdx || !outNBElement ) return TA_BAD_PARAM; if( !outInteger ) return TA_BAD_PARAM; /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = TA_CDLXSIDEGAP3METHODS_Lookback(); /* 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; } /* Do the calculation using tight loops. */ /* Add-up the initial period, except for the last value. */ i = startIdx; /* Proceed with the calculation for the requested range. * Must have: * - first candle: white (black) candle * - second candle: white (black) candle * - upside (downside) gap between the first and the second real bodies * - third candle: black (white) candle that opens within the second real body and closes within the first real body * outInteger is positive (1 to 100) when bullish or negative (-1 to -100) when bearish; * the user should consider that up/downside gap 3 methods is significant when it appears in a trend, while this * function does not consider it */ outIdx = 0; do { if( ((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == ((inClose[i - 1] >= inOpen[i - 1]) ? 1 : -1) && /* 1st and 2nd of same color */ ((inClose[i - 1] >= inOpen[i - 1]) ? 1 : -1) == -((inClose[i] >= inOpen[i]) ? 1 : -1) && /* 3rd opposite color */ inOpen[i] < max(inClose[i - 1],inOpen[i - 1]) && /* 3rd opens within 2nd rb */ inOpen[i] > min(inClose[i - 1],inOpen[i - 1]) && inClose[i] < max(inClose[i - 2],inOpen[i - 2]) && /* 3rd closes within 1st rb */ inClose[i] > min(inClose[i - 2],inOpen[i - 2]) && ((((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == 1 && /* when 1st is white */ ((min(inOpen[i - 1],inClose[i - 1]) > max(inOpen[i - 2],inClose[i - 2])) ? 1 : 0)) || /* upside gap */ (((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == -1 && /* when 1st is black */ ((max(inOpen[i - 1],inClose[i - 1]) < min(inOpen[i - 2],inClose[i - 2])) ? 1 : 0))) ) /* downside gap */ { outInteger[outIdx++] = ((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) * 100; } else { outInteger[outIdx++] = 0; } /* add the current range and subtract the first range: this is done after the pattern recognition * when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) */ i += 1; } while( i <= endIdx ); /* All done. Indicate the output limits and return. */ *outNBElement= outIdx; *outBegIdx= startIdx; return TA_SUCCESS; } TA_RetCode TA_S_CDLXSIDEGAP3METHODS( int startIdx, int endIdx, const float inOpen[], const float inHigh[], const float inLow[], const float inClose[], int *outBegIdx, int *outNBElement, int outInteger[] ) { int i; int outIdx; int lookbackTotal; if( (startIdx < 0) || (startIdx > TA_INDEX_MAX) ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx > TA_INDEX_MAX) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( !inOpen ) return TA_BAD_PARAM; if( !inHigh ) return TA_BAD_PARAM; if( !inLow ) return TA_BAD_PARAM; if( !inClose ) return TA_BAD_PARAM; if( !outBegIdx || !outNBElement ) return TA_BAD_PARAM; if( !outInteger ) return TA_BAD_PARAM; lookbackTotal = TA_CDLXSIDEGAP3METHODS_Lookback(); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { *outBegIdx= 0; *outNBElement= 0; return TA_SUCCESS; } i = startIdx; outIdx = 0; do { if( (((double)inClose[i - 2] >= (double)inOpen[i - 2]) ? 1 : -1) == (((double)inClose[i - 1] >= (double)inOpen[i - 1]) ? 1 : -1) && (((double)inClose[i - 1] >= (double)inOpen[i - 1]) ? 1 : -1) == -(((double)inClose[i] >= (double)inOpen[i]) ? 1 : -1) && (double)inOpen[i] < max((double)inClose[i - 1],(double)inOpen[i - 1]) && (double)inOpen[i] > min((double)inClose[i - 1],(double)inOpen[i - 1]) && (double)inClose[i] < max((double)inClose[i - 2],(double)inOpen[i - 2]) && (double)inClose[i] > min((double)inClose[i - 2],(double)inOpen[i - 2]) && (((((double)inClose[i - 2] >= (double)inOpen[i - 2]) ? 1 : -1) == 1 && ((min((double)inOpen[i - 1],(double)inClose[i - 1]) > max((double)inOpen[i - 2],(double)inClose[i - 2])) ? 1 : 0)) || ((((double)inClose[i - 2] >= (double)inOpen[i - 2]) ? 1 : -1) == -1 && ((max((double)inOpen[i - 1],(double)inClose[i - 1]) < min((double)inOpen[i - 2],(double)inClose[i - 2])) ? 1 : 0))) ) { outInteger[outIdx++] = (((double)inClose[i - 2] >= (double)inOpen[i - 2]) ? 1 : -1) * 100; } else { outInteger[outIdx++] = 0; } i += 1; } while( i <= endIdx ); *outNBElement= outIdx; *outBegIdx= startIdx; return TA_SUCCESS; } /**** Streaming API *****/ struct TA_CDLXSIDEGAP3METHODS_Stream { /* The bars this handle has an output for (see TA_CDLXSIDEGAP3METHODS_OutRange). */ int outRangeBegIdx; int outRangeCount; /* The value(s) at the last bar the stream counted (see TA_CDLXSIDEGAP3METHODS_Value). */ int cur_outInteger; double lag1_inOpen; double lag2_inOpen; double lag1_inClose; double lag2_inClose; }; /* Private function, not in public API. */ static void TA_CDLXSIDEGAP3METHODS_StepImpl( struct TA_CDLXSIDEGAP3METHODS_Stream *sp, double inOpen, double inHigh, double inLow, double inClose, int *outInteger ) { if( ((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == ((sp->lag1_inClose >= sp->lag1_inOpen) ? 1 : -1) && /* 1st and 2nd of same color */ ((sp->lag1_inClose >= sp->lag1_inOpen) ? 1 : -1) == -((inClose >= inOpen) ? 1 : -1) && /* 3rd opposite color */ inOpen < max(sp->lag1_inClose,sp->lag1_inOpen) && /* 3rd opens within 2nd rb */ inOpen > min(sp->lag1_inClose,sp->lag1_inOpen) && inClose < max(sp->lag2_inClose,sp->lag2_inOpen) && /* 3rd closes within 1st rb */ inClose > min(sp->lag2_inClose,sp->lag2_inOpen) && ((((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == 1 && /* when 1st is white */ ((min(sp->lag1_inOpen,sp->lag1_inClose) > max(sp->lag2_inOpen,sp->lag2_inClose)) ? 1 : 0)) || /* upside gap */ (((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == -1 && /* when 1st is black */ ((max(sp->lag1_inOpen,sp->lag1_inClose) < min(sp->lag2_inOpen,sp->lag2_inClose)) ? 1 : 0))) ) /* downside gap */ { *outInteger= ((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) * 100; } else { *outInteger= 0; } /* add the current range and subtract the first range: this is done after the pattern recognition * when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) */ sp->cur_outInteger = *outInteger; sp->lag2_inOpen = sp->lag1_inOpen; sp->lag1_inOpen = inOpen; sp->lag2_inClose = sp->lag1_inClose; sp->lag1_inClose = inClose; } static TA_RetCode TA_CDLXSIDEGAP3METHODS_OpenImpl( struct TA_CDLXSIDEGAP3METHODS_Stream **stream, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int *outBegIdx, int *outNBElement, int outInteger[], int outStride ) { struct TA_CDLXSIDEGAP3METHODS_Stream *sp; int endIdx; if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_INDEX_MAX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inOpen || !inHigh || !inLow || !inClose || !outInteger ) return TA_BAD_PARAM; if( startIdx > historyLen - 1 ) { *outBegIdx = 0; *outNBElement = 0; return TA_INSUFFICIENT_HISTORY; } endIdx = historyLen - 1; { int i; int outIdx; int lookbackTotal; /* Identify the minimum number of price bar needed * to calculate at least one output. */ lookbackTotal = TA_CDLXSIDEGAP3METHODS_Lookback(); /* 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_INSUFFICIENT_HISTORY; } /* Do the calculation using tight loops. */ /* Add-up the initial period, except for the last value. */ i = startIdx; /* Proceed with the calculation for the requested range. * Must have: * - first candle: white (black) candle * - second candle: white (black) candle * - upside (downside) gap between the first and the second real bodies * - third candle: black (white) candle that opens within the second real body and closes within the first real body * outInteger is positive (1 to 100) when bullish or negative (-1 to -100) when bearish; * the user should consider that up/downside gap 3 methods is significant when it appears in a trend, while this * function does not consider it */ outIdx = 0; do { if( ((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == ((inClose[i - 1] >= inOpen[i - 1]) ? 1 : -1) && /* 1st and 2nd of same color */ ((inClose[i - 1] >= inOpen[i - 1]) ? 1 : -1) == -((inClose[i] >= inOpen[i]) ? 1 : -1) && /* 3rd opposite color */ inOpen[i] < max(inClose[i - 1],inOpen[i - 1]) && /* 3rd opens within 2nd rb */ inOpen[i] > min(inClose[i - 1],inOpen[i - 1]) && inClose[i] < max(inClose[i - 2],inOpen[i - 2]) && /* 3rd closes within 1st rb */ inClose[i] > min(inClose[i - 2],inOpen[i - 2]) && ((((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == 1 && /* when 1st is white */ ((min(inOpen[i - 1],inClose[i - 1]) > max(inOpen[i - 2],inClose[i - 2])) ? 1 : 0)) || /* upside gap */ (((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) == -1 && /* when 1st is black */ ((max(inOpen[i - 1],inClose[i - 1]) < min(inOpen[i - 2],inClose[i - 2])) ? 1 : 0))) ) /* downside gap */ { outInteger[outIdx++ * outStride] = ((inClose[i - 2] >= inOpen[i - 2]) ? 1 : -1) * 100; } else { outInteger[outIdx++ * outStride] = 0; } /* add the current range and subtract the first range: this is done after the pattern recognition * when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) */ i += 1; } while( i <= endIdx ); /* All done. Indicate the output limits and return. */ *outNBElement= outIdx; *outBegIdx= startIdx; /* Capture the live batch state into the handle. */ sp = (struct TA_CDLXSIDEGAP3METHODS_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->lag1_inOpen = inOpen[historyLen - 1]; sp->lag2_inOpen = inOpen[historyLen - 2]; sp->lag1_inClose = inClose[historyLen - 1]; sp->lag2_inClose = inClose[historyLen - 2]; sp->outRangeBegIdx = *outBegIdx; sp->outRangeCount = *outNBElement; sp->cur_outInteger = outInteger[(*outNBElement - 1) * outStride]; *stream = sp; return TA_SUCCESS; } } /* Private function, not in public API. */ TA_RetCode TA_CDLXSIDEGAP3METHODS_OpenInternal( struct TA_CDLXSIDEGAP3METHODS_Stream **stream, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int *outInteger ) { TA_RetCode retCode; int dummyBegIdx = 0; int dummyNBElement = 0; int sink_outInteger = 0; retCode = TA_CDLXSIDEGAP3METHODS_OpenImpl( stream, inOpen, inHigh, inLow, inClose, startIdx, historyLen, &dummyBegIdx, &dummyNBElement, &sink_outInteger, 0 ); if( retCode == TA_SUCCESS ) { *outInteger = sink_outInteger; } return retCode; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Open( TA_CDLXSIDEGAP3METHODS_Stream **stream, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int historyLen, int *outInteger ) { if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_INDEX_MAX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inOpen || !inHigh || !inLow || !inClose || !outInteger ) return TA_BAD_PARAM; return TA_CDLXSIDEGAP3METHODS_OpenInternal( stream, inOpen, inHigh, inLow, inClose, 0, historyLen, outInteger ); } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_OpenAndFill( TA_CDLXSIDEGAP3METHODS_Stream **stream, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int historyLen, int *outBegIdx, int *outNBElement, int outInteger[] ) { if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_INDEX_MAX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inOpen || !inHigh || !inLow || !inClose || !outBegIdx || !outNBElement || !outInteger ) return TA_BAD_PARAM; if( (const void *)outInteger == (const void *)inOpen || (const void *)outInteger == (const void *)inHigh || (const void *)outInteger == (const void *)inLow || (const void *)outInteger == (const void *)inClose ) return TA_BAD_PARAM; return TA_CDLXSIDEGAP3METHODS_OpenAndFillInternal( stream, inOpen, inHigh, inLow, inClose, 0, historyLen, outBegIdx, outNBElement, outInteger ); } /* Private function, not in public API. */ TA_RetCode TA_CDLXSIDEGAP3METHODS_OpenAndFillInternal( struct TA_CDLXSIDEGAP3METHODS_Stream **stream, const double inOpen[], const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int *outBegIdx, int *outNBElement, int outInteger[] ) { return TA_CDLXSIDEGAP3METHODS_OpenImpl( stream, inOpen, inHigh, inLow, inClose, startIdx, historyLen, outBegIdx, outNBElement, outInteger, 1 ); } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Update( TA_CDLXSIDEGAP3METHODS_Stream *stream, double inOpen, double inHigh, double inLow, double inClose, int *outInteger ) { if( !stream ) return TA_BAD_PARAM; if( stream->outRangeBegIdx + stream->outRangeCount > TA_INDEX_MAX ) return TA_OUT_OF_RANGE_END_INDEX; if( !outInteger ) return TA_BAD_PARAM; if( !TA_IS_FINITE( inOpen ) || !TA_IS_FINITE( inHigh ) || !TA_IS_FINITE( inLow ) || !TA_IS_FINITE( inClose ) ) return TA_BAD_PARAM; TA_CDLXSIDEGAP3METHODS_StepImpl( stream, inOpen, inHigh, inLow, inClose, outInteger ); stream->outRangeCount++; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Peek( const TA_CDLXSIDEGAP3METHODS_Stream *stream, double inOpen, double inHigh, double inLow, double inClose, int *outInteger ) { const struct TA_CDLXSIDEGAP3METHODS_Stream *sp = stream; if( !stream || !outInteger ) return TA_BAD_PARAM; if( !TA_IS_FINITE( inOpen ) || !TA_IS_FINITE( inHigh ) || !TA_IS_FINITE( inLow ) || !TA_IS_FINITE( inClose ) ) return TA_BAD_PARAM; if( ((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == ((sp->lag1_inClose >= sp->lag1_inOpen) ? 1 : -1) && /* 1st and 2nd of same color */ ((sp->lag1_inClose >= sp->lag1_inOpen) ? 1 : -1) == -((inClose >= inOpen) ? 1 : -1) && /* 3rd opposite color */ inOpen < max(sp->lag1_inClose,sp->lag1_inOpen) && /* 3rd opens within 2nd rb */ inOpen > min(sp->lag1_inClose,sp->lag1_inOpen) && inClose < max(sp->lag2_inClose,sp->lag2_inOpen) && /* 3rd closes within 1st rb */ inClose > min(sp->lag2_inClose,sp->lag2_inOpen) && ((((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == 1 && /* when 1st is white */ ((min(sp->lag1_inOpen,sp->lag1_inClose) > max(sp->lag2_inOpen,sp->lag2_inClose)) ? 1 : 0)) || /* upside gap */ (((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) == -1 && /* when 1st is black */ ((max(sp->lag1_inOpen,sp->lag1_inClose) < min(sp->lag2_inOpen,sp->lag2_inClose)) ? 1 : 0))) ) /* downside gap */ { *outInteger= ((sp->lag2_inClose >= sp->lag2_inOpen) ? 1 : -1) * 100; } else { *outInteger= 0; } return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Close( TA_CDLXSIDEGAP3METHODS_Stream *stream ) { if( stream ) TA_Free( stream ); return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Value( const TA_CDLXSIDEGAP3METHODS_Stream *stream, int *outInteger ) { if( !stream || !outInteger ) return TA_BAD_PARAM; *outInteger = stream->cur_outInteger; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_OutRange( const TA_CDLXSIDEGAP3METHODS_Stream *stream, int *outBegIdx, int *outNBElement ) { if( !stream || !outBegIdx || !outNBElement ) return TA_BAD_PARAM; *outBegIdx = stream->outRangeBegIdx; *outNBElement = stream->outRangeCount; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Advance( TA_CDLXSIDEGAP3METHODS_Stream *stream ) { if( !stream ) return TA_BAD_PARAM; if( stream->outRangeBegIdx + stream->outRangeCount > TA_INDEX_MAX ) return TA_OUT_OF_RANGE_END_INDEX; stream->outRangeCount++; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_CDLXSIDEGAP3METHODS_Clone( const TA_CDLXSIDEGAP3METHODS_Stream *stream, TA_CDLXSIDEGAP3METHODS_Stream **clone ) { struct TA_CDLXSIDEGAP3METHODS_Stream *sp; if( !clone ) return TA_BAD_PARAM; *clone = NULL; if( !stream ) return TA_BAD_PARAM; sp = (struct TA_CDLXSIDEGAP3METHODS_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) return TA_ALLOC_ERR; *sp = *stream; *clone = sp; return TA_SUCCESS; }