feat: add CMOU and candlestick pattern wrappers

- add CMOU momentum wrapper in `momentum_indicators.go`
- add `Cdl*` pattern-recognition wrappers in `pattern_recognitions.go`
- register `TA_CMOU` and `TA_CDL*` symbols in `loader.go`
- add corresponding function pointer signatures in `functions.go`
- sync `README.md` with CMOU and pattern-recognition API docs
This commit is contained in:
2026-07-28 16:23:50 +09:00
parent 88997a62ef
commit c7f21b073e
5 changed files with 1608 additions and 1 deletions
+9 -1
View File
@@ -25,7 +25,7 @@ This project currently exposes a focused subset of TA-Lib functions:
**Momentum Indicators**
- Directional Movement: `ADX`, `ADXR`, `DX`, `MinusDI`, `MinusDM`, `PlusDI`, `PlusDM`
- Oscillators: `APO`, `Aroon`, `AroonOsc`, `BOP`, `CCI`, `CMO`, `IMI`, `MFI`, `MOM`, `PPO`, `RSI`, `Trix`, `WillR`, `UltOsc`
- 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`
@@ -45,6 +45,13 @@ This project currently exposes a focused subset of TA-Lib functions:
**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`
## Requirements
- Go `1.26`
@@ -134,6 +141,7 @@ func main() {
- Native TA-Lib functions are exposed with Go-style exported names such as `Add`, `Div`, `Max`, and `Sum`.
- Functions accepting a moving-average type use the `MAType` constant (`MA_SMA`, `MA_EMA`, `MA_WMA`, `MA_DEMA`, `MA_TEMA`, `MA_TRIMA`, `MA_KAMA`, `MA_MAMA`, `MA_T3`).
- Functions returning multiple outputs (e.g. `Aroon`, `MACD`, `Stoch`) return multiple slices; all are `nil` on failure.
- Pattern-recognition functions (`Cdl*`) return `[]int32` signals; typical values are `-100` (bearish), `0` (no pattern), and `100` (bullish).
## Project status
+446
View File
@@ -392,6 +392,16 @@ var (
outReal []float64,
) int32
cmou func(
startIdx int32,
endIdx int32,
inReal []float64,
optInTimePeriod int32,
outBegIdx *int32,
outNBElement *int32,
outReal []float64,
) int32
dx func(
startIdx int32,
endIdx int32,
@@ -1140,4 +1150,440 @@ var (
outNBElement *int32,
outReal []float64,
) int32
cdl2crows func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3blackcrows func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3inside func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3linestrike func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3outside func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3starsinsouth func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdl3whitesoldiers func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlabandonedbaby func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
inPenetration float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdladvanceblock func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlbelthold func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlbreakaway func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlclosingmarubozu func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlconcealbabyswall func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlcounterattack func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdldarkcloudcover func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
inPenetration float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdldoji func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdldojistar func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdldragonflydoji func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlengulfing func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdleveningdojistar func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
inPenetration float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdleveningstar func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
inPenetration float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlgapsidesidewhite func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlgravestonedoji func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhammer func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhangingman func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlharami func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlharamicross func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhighwave func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhikkake func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhikkakemod func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlhomingpigeon func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlidentical3crows func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlinneck func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlinvertedhammer func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlkicking func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
cdlkickingbylength func(
startIdx int32,
endIdx int32,
inOpen []float64,
inHigh []float64,
inLow []float64,
inClose []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []int32,
) int32
)
+38
View File
@@ -97,6 +97,7 @@ func internalLoad() (uintptr, error) {
purego.RegisterLibFunc(&bop, ptr, "TA_BOP")
purego.RegisterLibFunc(&cci, ptr, "TA_CCI")
purego.RegisterLibFunc(&cmo, ptr, "TA_CMO")
purego.RegisterLibFunc(&cmou, ptr, "TA_CMOU")
purego.RegisterLibFunc(&dx, ptr, "TA_DX")
purego.RegisterLibFunc(&imi, ptr, "TA_IMI")
purego.RegisterLibFunc(&macd, ptr, "TA_MACD")
@@ -168,6 +169,43 @@ func internalLoad() (uintptr, error) {
purego.RegisterLibFunc(&pvi, ptr, "TA_PVI")
purego.RegisterLibFunc(&pvo, ptr, "TA_PVO")
purego.RegisterLibFunc(&cdl2crows, ptr, "TA_CDL2CROWS")
purego.RegisterLibFunc(&cdl3blackcrows, ptr, "TA_CDL3BLACKCROWS")
purego.RegisterLibFunc(&cdl3inside, ptr, "TA_CDL3INSIDE")
purego.RegisterLibFunc(&cdl3linestrike, ptr, "TA_CDL3LINESTRIKE")
purego.RegisterLibFunc(&cdl3outside, ptr, "TA_CDL3OUTSIDE")
purego.RegisterLibFunc(&cdl3starsinsouth, ptr, "TA_CDL3STARSINSOUTH")
purego.RegisterLibFunc(&cdl3whitesoldiers, ptr, "TA_CDL3WHITESOLDIERS")
purego.RegisterLibFunc(&cdlabandonedbaby, ptr, "TA_CDLABANDONEDBABY")
purego.RegisterLibFunc(&cdladvanceblock, ptr, "TA_CDLADVANCEBLOCK")
purego.RegisterLibFunc(&cdlbelthold, ptr, "TA_CDLBELTHOLD")
purego.RegisterLibFunc(&cdlbreakaway, ptr, "TA_CDLBREAKAWAY")
purego.RegisterLibFunc(&cdlclosingmarubozu, ptr, "TA_CDLCLOSINGMARUBOZU")
purego.RegisterLibFunc(&cdlconcealbabyswall, ptr, "TA_CDLCONCEALBABYSWALL")
purego.RegisterLibFunc(&cdlcounterattack, ptr, "TA_CDLCOUNTERATTACK")
purego.RegisterLibFunc(&cdldarkcloudcover, ptr, "TA_CDLDARKCLOUDCOVER")
purego.RegisterLibFunc(&cdldoji, ptr, "TA_CDLDOJI")
purego.RegisterLibFunc(&cdldojistar, ptr, "TA_CDLDOJISTAR")
purego.RegisterLibFunc(&cdldragonflydoji, ptr, "TA_CDLDRAGONFLYDOJI")
purego.RegisterLibFunc(&cdlengulfing, ptr, "TA_CDLENGULFING")
purego.RegisterLibFunc(&cdleveningdojistar, ptr, "TA_CDLEVENINGDOJISTAR")
purego.RegisterLibFunc(&cdleveningstar, ptr, "TA_CDLEVENINGSTAR")
purego.RegisterLibFunc(&cdlgapsidesidewhite, ptr, "TA_CDLGAPSIDESIDEWHITE")
purego.RegisterLibFunc(&cdlgravestonedoji, ptr, "TA_CDLGRAVESTONEDOJI")
purego.RegisterLibFunc(&cdlhammer, ptr, "TA_CDLHAMMER")
purego.RegisterLibFunc(&cdlhangingman, ptr, "TA_CDLHANGINGMAN")
purego.RegisterLibFunc(&cdlharami, ptr, "TA_CDLHARAMI")
purego.RegisterLibFunc(&cdlharamicross, ptr, "TA_CDLHARAMICROSS")
purego.RegisterLibFunc(&cdlhighwave, ptr, "TA_CDLHIGHWAVE")
purego.RegisterLibFunc(&cdlhikkake, ptr, "TA_CDLHIKKAKE")
purego.RegisterLibFunc(&cdlhikkakemod, ptr, "TA_CDLHIKKAKEMOD")
purego.RegisterLibFunc(&cdlhomingpigeon, ptr, "TA_CDLHOMINGPIGEON")
purego.RegisterLibFunc(&cdlidentical3crows, ptr, "TA_CDLIDENTICAL3CROWS")
purego.RegisterLibFunc(&cdlinneck, ptr, "TA_CDLINNECK")
purego.RegisterLibFunc(&cdlinvertedhammer, ptr, "TA_CDLINVERTEDHAMMER")
purego.RegisterLibFunc(&cdlkicking, ptr, "TA_CDLKICKING")
purego.RegisterLibFunc(&cdlkickingbylength, ptr, "TA_CDLKICKINGBYLENGTH")
return ptr, nil
}
+42
View File
@@ -276,6 +276,48 @@ func CMO(inReal []float64, optInTimePeriod int) []float64 {
return outReal
}
// CMOU - Chande Momentum Oscillator: Tushar Chande's original momentum oscillator,
// computed from plain moving-window sums of the up-moves and down-moves over the period.
// Bounded in [-100,+100]; positive = net upward momentum, negative = net downward.
//
// CMOU is the version as defined by Chande in his book The New Technical Trader (1994),
// and is the more common implementation used by TradingView (ta.cmo), QuantConnect and pandas-ta's default.
// See talib.CMO for a smoothed variant of talib.CMOU.
//
// d = P[t]-P[t-1];
// over the trailing optInTimePeriod changes accumulate Su = sum of the positive d,
// Sd = sum of -d for negative d.
//
// CMOU = 100 * (Su-Sd)/(Su+Sd); 0 when Su+Sd == 0 (an exactly flat window).
// Unlike talib.CMO, the sums are the plain period totals (a moving-window sum), not Wilder-smoothed averages,
// so there is no unstable period.
//
// since TA-Lib 0.8.1
func CMOU(inReal []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outReal = make([]float64, len(inReal))
)
if retCode := cmou(
startIdx,
endIdx,
inReal,
int32(optInTimePeriod),
&outBegIdx,
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("CMOU", "result", retCode)
return nil
}
return outReal
}
// DX - Wilder's Directional Movement Index: the normalized spread between +DI and -DI.
// Measures the strength of directional (trending) movement, irrespective of direction.
// Higher DX = stronger trend (either direction); low DX = ranging market.
File diff suppressed because it is too large Load Diff