diff --git a/README.md b/README.md index 7a6f1fd..be04ba3 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,21 @@ # talib -Go wrapper for selected [TA-Lib](https://ta-lib.org/) functions using [`purego`](https://github.com/ebitengine/purego) to dynamically load the native TA-Lib shared library at runtime. +Go wrapper for all [TA-Lib](https://ta-lib.org/) functions using [`purego`](https://github.com/ebitengine/purego) to dynamically load the native TA-Lib shared library at runtime. -This project currently exposes a focused subset of TA-Lib functions: +This package exposes the complete TA-Lib function set across these categories: -**Cycle Indicators (Hilbert Transform)** -- `HT_DCPERIOD` -- `HT_DCPHASE` -- `HT_PHASOR` -- `HT_SINE` -- `HT_TRENDMODE` +- **Cycle Indicators**: Hilbert Transform (`HT_*`) +- **Math Operators**: Vector operations (Add, Sub, Mult, Div, Max, Min, Sum, etc.) +- **Math Transforms**: Trigonometric, hyperbolic, exponential, and rounding functions +- **Momentum Indicators**: ADX, MACD, RSI, Stoch, Aroon, oscillators, ROC, directional movement +- **Overlap Studies**: Moving averages and bands (EMA, SMA, BBands, KAMA, MAMA, SAR, etc.) +- **Price Transforms**: Per-bar price composites (AvgPrice, TypPrice, WCLPrice, etc.) +- **Statistic Functions**: Regression, correlation, and dispersion (Beta, Correl, LinearReg*, StdDev, Var) +- **Volatility Indicators**: ATR, NATR, TRANGE +- **Volume Indicators**: AD, ADOsc, CMF, OBV, PVI, PVO +- **Pattern Recognition**: 61 candlestick patterns (`Cdl*`) -**Math Operators** -- `Add`, `Sub`, `Mult`, `Div` -- `Max`, `MaxIndex`, `Min`, `MinIndex` -- `MinMax`, `MinMaxIndex` -- `Sum` - -**Math Transforms** -- Trigonometric: `Cos`, `Sin`, `Tan`, `ACos`, `ASin`, `ATan` -- Hyperbolic: `CosH`, `SinH`, `TanH` -- Exponential/Logarithmic: `Exp`, `Ln`, `Log10` -- Rounding: `Ceil`, `Floor`, `Sqrt` - -**Momentum Indicators** -- Directional Movement: `ADX`, `ADXR`, `DX`, `MinusDI`, `MinusDM`, `PlusDI`, `PlusDM` -- Oscillators: `APO`, `Aroon`, `AroonOsc`, `BOP`, `CCI`, `CMO`, `CMOU`, `IMI`, `MFI`, `MOM`, `PPO`, `RSI`, `Trix`, `WillR`, `UltOsc` -- Rate of Change: `ROC`, `ROCP`, `ROCR`, `ROCR100` -- MACD family: `MACD`, `MACDExt`, `MACDFix` -- Stochastic family: `Stoch`, `StochF`, `StochRSI` - -**Overlap Studies** -- `AccBands`, `BBands`, `DEMA`, `EMA`, `HT_TRENDLINE`, `KAMA`, `MA`, `MAMA`, `MAVP`, `MidPoint`, `MidPrice`, `SAR`, `SARExt`, `SMA`, `T3`, `TEMA`, `TRIMA`, `WMA` - -**Price Transforms** -- `AvgPrice`, `MedPrice`, `TypPrice`, `WCLPrice` - -**Statistic Functions** -- `AvgDev`, `Beta`, `Correl`, `LinearReg`, `LinearRegAngle`, `LinearRegIntercept`, `LinearRegSlope`, `StdDev`, `TSF`, `Var` - -**Volatility Indicators** -- `ATR`, `NATR`, `TRANGE` - -**Volume Indicators** -- `AD`, `ADOsc`, `CMF`, `NVI`, `OBV`, `PVI`, `PVO` - -**Pattern Recognition** -- `Cdl2Crows`, `Cdl3BlackCrows`, `Cdl3Inside`, `Cdl3LineStrike`, `Cdl3Outside`, `Cdl3StarsInSouth`, `Cdl3WhiteSoldiers` -- `CdlAbandonedBaby`, `CdlAdvanceBlock`, `CdlBeltHold`, `CdlBreakaway`, `CdlClosingMarubozu`, `CdlConcealBabysWall`, `CdlCounterAttack` -- `CdlDarkCloudCover`, `CdlDoji`, `CdlDojiStar`, `CdlDragonflyDoji`, `CdlEngulfing`, `CdlEveningDojiStar`, `CdlEveningStar` -- `CdlGapSideBySideWhite`, `CdlGravestoneDoji`, `CdlHammer`, `CdlHangingMan`, `CdlHarami`, `CdlHaramiCross`, `CdlHighWave` -- `CdlHikkake`, `CdlHikkakeMod`, `CdlHomingPigeon`, `CdlIdentical3Crows`, `CdlInNeck`, `CdlInvertedHammer`, `CdlKicking`, `CdlKickingByLength` +For a complete function reference with descriptions, see [TA-Lib's official function list](https://ta-lib.org/functions/). ## Requirements @@ -145,4 +110,4 @@ func main() { ## Project status -This is currently a focused wrapper around a limited subset of TA-Lib. Additional indicators can be added by registering more native functions in `Load()` and exposing Go wrappers for them. +This wrapper provides **complete coverage** of the TA-Lib function library. All ~100 indicators across 10 function categories are exposed with Go-idiomatic APIs. New versions of TA-Lib may introduce additional functions; updating this wrapper requires adding function pointer declarations in `functions.go`, registering them in `loader.go`, and exposing Go wrappers in the appropriate `*_indicators.go` file. diff --git a/functions.go b/functions.go index 2075f69..ce723d3 100644 --- a/functions.go +++ b/functions.go @@ -1586,4 +1586,307 @@ var ( outNBElement *int32, outReal []int32, ) int32 + + cdlladderbottom func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdllongleggeddoji func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdllongline func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlmarubozu func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlmatchinglow func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlmathold func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + inPenetration float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlmorningdojistar func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + inPenetration float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlmorningstar func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + inPenetration float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlonneck func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlpiercing func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlrickshawman func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlrisefall3methods func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlseparatinglines func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlshootingstar func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlshortline func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlspinningtop func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlstalledpattern func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlsticksandwich func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdltakuri func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdltasukigap func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlthrusting func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdltristar func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlunique3river func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlupsidegap2crows func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 + + cdlxsidegap3methods func( + startIdx int32, + endIdx int32, + inOpen []float64, + inHigh []float64, + inLow []float64, + inClose []float64, + outBegIdx *int32, + outNBElement *int32, + outReal []int32, + ) int32 ) diff --git a/loader.go b/loader.go index eba210f..e27a22a 100644 --- a/loader.go +++ b/loader.go @@ -205,6 +205,31 @@ func internalLoad() (uintptr, error) { purego.RegisterLibFunc(&cdlinvertedhammer, ptr, "TA_CDLINVERTEDHAMMER") purego.RegisterLibFunc(&cdlkicking, ptr, "TA_CDLKICKING") purego.RegisterLibFunc(&cdlkickingbylength, ptr, "TA_CDLKICKINGBYLENGTH") + purego.RegisterLibFunc(&cdlladderbottom, ptr, "TA_CDLLADDERBOTTOM") + purego.RegisterLibFunc(&cdllongleggeddoji, ptr, "TA_CDLLONGLEGGEDDOJI") + purego.RegisterLibFunc(&cdllongline, ptr, "TA_CDLLONGLINE") + purego.RegisterLibFunc(&cdlmarubozu, ptr, "TA_CDLMARUBOZU") + purego.RegisterLibFunc(&cdlmatchinglow, ptr, "TA_CDLMATCHINGLOW") + purego.RegisterLibFunc(&cdlmathold, ptr, "TA_CDLMATHOLD") + purego.RegisterLibFunc(&cdlmorningdojistar, ptr, "TA_CDLMORNINGDOJISTAR") + purego.RegisterLibFunc(&cdlmorningstar, ptr, "TA_CDLMORNINGSTAR") + purego.RegisterLibFunc(&cdlonneck, ptr, "TA_CDLONNECK") + purego.RegisterLibFunc(&cdlpiercing, ptr, "TA_CDLPIERCING") + purego.RegisterLibFunc(&cdlrickshawman, ptr, "TA_CDLRICKSHAWMAN") + purego.RegisterLibFunc(&cdlrisefall3methods, ptr, "TA_CDLRISEFALL3METHODS") + purego.RegisterLibFunc(&cdlseparatinglines, ptr, "TA_CDLSEPARATINGLINES") + purego.RegisterLibFunc(&cdlshootingstar, ptr, "TA_CDLSHOOTINGSTAR") + purego.RegisterLibFunc(&cdlshortline, ptr, "TA_CDLSHORTLINE") + purego.RegisterLibFunc(&cdlspinningtop, ptr, "TA_CDLSPINNINGTOP") + purego.RegisterLibFunc(&cdlstalledpattern, ptr, "TA_CDLSTALLEDPATTERN") + purego.RegisterLibFunc(&cdlsticksandwich, ptr, "TA_CDLSTICKSANDWICH") + purego.RegisterLibFunc(&cdltakuri, ptr, "TA_CDLTAKURI") + purego.RegisterLibFunc(&cdltasukigap, ptr, "TA_CDLTASUKIGAP") + purego.RegisterLibFunc(&cdlthrusting, ptr, "TA_CDLTHRUSTING") + purego.RegisterLibFunc(&cdltristar, ptr, "TA_CDLTRISTAR") + purego.RegisterLibFunc(&cdlunique3river, ptr, "TA_CDLUNIQUE3RIVER") + purego.RegisterLibFunc(&cdlupsidegap2crows, ptr, "TA_CDLUPSIDEGAP2CROWS") + purego.RegisterLibFunc(&cdlxsidegap3methods, ptr, "TA_CDLXSIDEGAP3METHODS") return ptr, nil } diff --git a/pattern_recognitions.go b/pattern_recognitions.go index 463c836..639209a 100644 --- a/pattern_recognitions.go +++ b/pattern_recognitions.go @@ -1071,3 +1071,826 @@ func CdlKickingByLength(inOpen, inHigh, inLow, inClose []float64) []int32 { return outReal } + +// CdlLadderBottom - Five-candle bullish reversal pattern: three consecutively lower black candles, +// a fourth black candle with a non-very-short upper shadow, +// then a white candle that opens above the prior open and closes above the prior high. +// Signals a potential bottom reversal. A hit (+100) is a bullish reversal signal, most meaningful after a downtrend. +// +// Note: Does not verify the preceding downtrend that this bullish reversal classically assumes. +// +// @returns +// +// +100 on a detected ladder bottom, 0 otherwise. +// Only ever emits +100 (never -100); inherently bullish +func CdlLadderBottom(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlladderbottom( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlLadderBottom", "result", retCode) + return nil + } + + return outReal +} + +// CdlLongLeggedDoji - Single-candle doji (open ~ close) with at least one long shadow. +// Signals market indecision, not a directional bias. Marks indecision/uncertainty; +// not inherently bullish or bearish despite the positive sign. +// +// One candle. +// Hit when: real body <= BodyDoji average (doji body) AND (lower shadow > ShadowLong average OR upper shadow > ShadowLong average), +// i.e. at least one long shadow. +// +// Note: Only one long shadow (upper or lower) is required, whereas the classic pattern shows both long upper and lower shadows. +// +// @returns +// +// +100 when the pattern is present, 0 otherwise. +// Only +100 is emitted; the code never emits -100, and the positive sign does NOT mean bullish +func CdlLongLeggedDoji(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdllongleggeddoji( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlLongLeggedDoji", "result", retCode) + return nil + } + + return outReal +} + +// CdlLongLine - A single-candle pattern: a long real body with short upper and short lower shadow. +// The signal direction follows the candle color (bullish if white, bearish if black). +// Signals strong directional conviction on the bar: +100 white/bullish, -100 black/bearish. +// Not intrinsically a reversal or continuation signal. +// +// @returns +// +// +100 on a white (close>=open) long line, -100 on a black long line, 0 when no pattern +func CdlLongLine(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdllongline( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlLongLine", "result", retCode) + return nil + } + + return outReal +} + +// CdlMarubozu - Single candle with a long real body and no/very-short upper and lower shadows, so open and close sit at the range extremes. +// Bullish (white) or bearish (black) reversal/strength signal per the body color. +// +100 = white marubozu (strong buying pressure); -100 = black marubozu (strong selling pressure). +// +// One candle at i. +// Match when: realbody(i) > BodyLong average AND upperShadow(i) < ShadowVeryShort average AND lowerShadow(i) < ShadowVeryShort average. +// If matched emit candlecolor(i)*100 (+100 white when close>=open, -100 black when close=0). +// @returns +// +// +100 when the bullish Mat Hold is detected, 0 otherwise. +// Never emits -100 +func CdlMatHold(inOpen, inHigh, inLow, inClose []float64, penetration float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlmathold( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + penetration, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlMatHold", "result", retCode) + return nil + } + + return outReal +} + +// CdlMorningDojiStar - A three-candle bullish reversal pattern: +// a long black candle, then a doji that gaps down, then a white candle closing well up into the first candle's body. +// It is the doji-star variant of the morning star. +// A hit (+100) signals a bullish reversal; most meaningful after a downtrend, which this function does not verify. +// +// Note: The gap-down is measured between the candles' real bodies, not between their high/low ranges. +// A prior downtrend is not verified. +// +// @param penetration - Fraction of the 1st candle's real body the 3rd close must exceed above close[i-2]; +// larger values demand deeper penetration into the black body; default is 0.3 (>=0). +// +// @returns +// +// +100 when the pattern is detected, 0 otherwise. +// Always bullish; never emits -100 +func CdlMorningDojiStar(inOpen, inHigh, inLow, inClose []float64, penetration float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlmorningdojistar( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, penetration, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlMorningDojiStar", "result", retCode) + return nil + } + + return outReal +} + +// CdlMorningStar - A three-candle bottom-reversal pattern: +// a long black candle, a small-bodied star gapping down, then a white candle closing well up into the first candle's body. +// Bullish reversal signal. +// A hit signals a bullish reversal (most meaningful after a downtrend, which the code does not check). +// +// Note: The gap-down is measured between the candles' real bodies, not between their high/low ranges. +// A prior downtrend is not verified. +// +// @param penetration - Fraction of the 1st candle's body the 3rd close must exceed above the 1st close; larger = deeper penetration required; default is 0.3 (>=0). +// +// @returns +// +// +100 when the morning star is detected, 0 otherwise. Never negative (pattern is exclusively bullish) +func CdlMorningStar(inOpen, inHigh, inLow, inClose []float64, penetration float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlmorningstar( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, penetration, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlMorningStar", "result", retCode) + return nil + } + + return outReal +} + +// CdlOnNeck - A two-candle on-neck pattern: +// a long black candle followed by a white candle that opens below the prior candle's low and closes right at that low. +// Bearish continuation signal. +// A hit is bearish (bearish continuation); the code does not verify the assumed prior downtrend. +// +// Two candles. +// 1st: black (close BodyLong average). +// 2nd: white (close>=open); open < prior low; close within the Equal band of the prior low, +// i.e. (prior_low - EqualAvg) <= close2 <= (prior_low + EqualAvg). +// +// Note: The bearish-continuation reading assumes a prior downtrend, which is not verified. +// +// @returns +// +// -100 on a match, 0 otherwise. +// Only -100 is ever emitted (never +100); on-neck is always bearish +func CdlOnNeck(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlonneck( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlOnNeck", "result", retCode) + return nil + } + + return outReal +} + +// CdlPiercing - Two-candle pattern: +// a long black candle followed by a long white candle that opens below the prior low and closes back above the midpoint of the prior black body. +// Bullish reversal signal. +// A hit (+100) is a bullish reversal signal. +// +// Note: A prior downtrend is not verified. +// +// @returns +// +// +100 when the piercing pattern is detected; 0 otherwise. +// Always bullish, never emits -100 +func CdlPiercing(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlpiercing( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlPiercing", "result", retCode) + return nil + } + + return outReal +} + +// CdlRickshawMan - Single-candle doji with two long shadows whose body sits near the midpoint of the high-low range. +// It is a neutral indecision signal, not a directional (bullish/bearish) reversal. +// A hit marks market indecision/uncertainty; neutral, neither bullish nor bearish. +// +// @returns +// +// +100 when the pattern is present, 0 otherwise. +// Never -100; the code notes the positive value does NOT imply bullish, it signals uncertainty +func CdlRickshawMan(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlrickshawman( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlRickshawMan", "result", retCode) + return nil + } + + return outReal +} + +// CdlRiseFall3Methods - A five-candle continuation pattern: +// a long candle, three small counter-color candles that stay partly within the first candle's high-low range, then a long same-color candle that resumes the trend. +// Bullish (rising) or bearish (falling) continuation signal. +// A hit signals trend continuation: +100 = bullish (rising three methods), -100 = bearish (falling three methods). +// +// Note: Only the three-small-candle variant is detected; the classic pattern allowing two or more small candles is not supported. +// The middle candles need only partially overlap the first candle's range, not be fully contained within it. +// The prior trend the continuation reading assumes is not verified. +// +// @returns +// +// +100 when candle 1 is white (rising/bullish continuation), -100 when candle 1 is black (falling/bearish continuation), 0 otherwise. +// Sign = 100 * color of candle 1 +func CdlRiseFall3Methods(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlrisefall3methods( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlRiseFall3Methods", "result", retCode) + return nil + } + + return outReal +} + +// CdlSeparatingLines - A two-candle continuation pattern: +// the second candle opposes the first in color, opens at the same price as the first, and is a long-bodied belt hold. +// Bullish (white second candle) or bearish (black second candle) continuation signal. +// Trend continuation: +100 = bullish (white belt hold), -100 = bearish (black belt hold). +// +// Two consecutive candles i-1, i: +// (1) opposite colors: color(i-1) == -color(i); +// (2) same open: open[i-1]-Equal_avg <= open[i] <= open[i-1]+Equal_avg; +// (3) long body: realbody(i) > BodyLong_avg; +// (4) belt hold: if i is white, lowershadow(i) < ShadowVeryShort_avg; if i is black, uppershadow(i) < ShadowVeryShort_avg. +// +// Note: A prior trend is not verified, nor that the pattern aligns with it. +// +// @returns +// +// +100 for a bullish (white second candle) hit, -100 for a bearish (black second candle) hit, 0 otherwise +func CdlSeparatingLines(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlseparatinglines( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlSeparatingLines", "result", retCode) + return nil + } + + return outReal +} + +// CdlShootingStar - Single-candle pattern: +// a small real body with a long upper shadow and little-to-no lower shadow that gaps up from the prior candle's real body. +// Bearish reversal signal. A hit (-100) flags a bearish reversal at the top of an uptrend. +// +// Note: A preceding uptrend is not verified. +// +// @returns +// +// -100 when the shooting star is detected, 0 otherwise. +// Only ever emits negative (bearish); never +100 +func CdlShootingStar(inOpen, inHigh, inLow, inClose []float64) []int32 { + var ( + startIdx int32 + endIdx = int32(len(inClose) - 1) + outBegIdx int32 + outNBElement int32 + outReal = make([]int32, len(inClose)) + ) + + if retCode := cdlshootingstar( + startIdx, endIdx, + inOpen, inHigh, inLow, inClose, + &outBegIdx, &outNBElement, outReal, + ); SUCCESS != taResult(retCode) { + slog.Debug("CdlShootingStar", "result", retCode) + return nil + } + + return outReal +} + +// CdlShortLine - Single-candle pattern: a short real body with short upper and lower shadows (a small-range candle). +// Not a directional signal — the output sign encodes candle color, not bullish/bearish sentiment. +// A hit only flags a small-range candle; the +/- sign is the candle's color (white/black), not a reversal or continuation call. +// +// One candle at i, all three: +// +// short real body: real body < the BodyShort average +// short upper shadow: upper shadow < the ShadowShort average +// short lower shadow: lower shadow < the ShadowShort average +// If matched: output = candle color * 100 (+100 white, -100 black); else 0. +// +// @returns +// +// +100 for a matching white candle (close>=open), -100 for a matching black candle (close real body AND lower shadow > real body AND real body < the BodyShort average. +// The BodyShort average is the factor-scaled mean body over the prior avgPeriod candles. +// +// @returns +// +// +100 when the candle is white (close>=open), -100 when black (close