feat: TA-Lib candlestick patterns — abandoned/advance/belt/break/counter (part 2 of 9) (#132)

* feat: add Abandoned Baby candlestick pattern (CDLABANDONEDBABY)

* feat: add Advance Block candlestick pattern (CDLADVANCEBLOCK)

* feat: add Belt Hold candlestick pattern (CDLBELTHOLD)

* feat: add Breakaway and Counterattack candlestick patterns (CDLBREAKAWAY, CDLCOUNTERATTACK)

Breakaway is a 5-bar reversal: a trend gaps away on the second bar, drifts
two more bars, then the fifth bar snaps back and closes inside the bar1/bar2
body gap (bullish +1, bearish -1). Counterattack is a 2-bar reversal where an
opposite-coloured long second bar closes level with the first (the counterattack
line; bullish +1, bearish -1).

Also suppress libtest's spanless `large_stack_arrays` false positive in
wickra-core test builds: the `#[test]` harness collects every test into a
compiler-generated array of references that crosses clippy's 16 KB threshold
once the suite passes ~2048 unit tests. The allow is scoped to `cfg(test)`, so
library code is still linted for genuinely large stack arrays.

* chore: sync indicator count to 254

---------

Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com>
This commit is contained in:
kingchenc
2026-06-02 16:34:15 +02:00
committed by GitHub
parent 73415cd2dc
commit 03ceac1f3b
19 changed files with 1343 additions and 41 deletions
@@ -543,6 +543,26 @@ CANDLE_SCALAR = {
lambda: ta.ThreeStarsInSouth(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"AbandonedBaby": (
lambda: ta.AbandonedBaby(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"AdvanceBlock": (
lambda: ta.AdvanceBlock(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"BeltHold": (
lambda: ta.BeltHold(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"Breakaway": (
lambda: ta.Breakaway(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"Counterattack": (
lambda: ta.Counterattack(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
}
@@ -1644,6 +1664,27 @@ def test_fractal_chaos_bands_detects_peak_and_trough():
assert out[5, 1] == pytest.approx(0.5)
def test_belt_hold_reference():
t = ta.BeltHold()
assert t.update((10.0, 12.0, 10.0, 11.5, 1.0, 0)) == pytest.approx(1.0)
assert t.update((12.0, 12.0, 10.0, 10.5, 1.0, 1)) == pytest.approx(-1.0)
def test_breakaway_reference():
t = ta.Breakaway()
assert t.update((20.0, 20.2, 14.8, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((14.0, 14.1, 11.9, 12.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((12.5, 13.0, 10.5, 11.0, 1.0, 2)) == pytest.approx(0.0)
assert t.update((11.0, 11.5, 9.0, 9.5, 1.0, 3)) == pytest.approx(0.0)
assert t.update((9.5, 14.7, 9.4, 14.5, 1.0, 4)) == pytest.approx(1.0)
def test_counterattack_reference():
t = ta.Counterattack()
assert t.update((20.0, 20.1, 14.9, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((10.0, 15.1, 9.9, 15.0, 1.0, 1)) == pytest.approx(1.0)
# --- Lifecycle ------------------------------------------------------------
@@ -1907,6 +1948,20 @@ def test_three_stars_in_south_reference():
assert t.update((15.0, 15.0, 14.0, 14.0, 1.0, 2)) == pytest.approx(1.0)
def test_abandoned_baby_reference():
t = ta.AbandonedBaby()
assert t.update((20.0, 20.1, 14.9, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((13.0, 13.1, 12.9, 13.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((16.0, 18.1, 15.9, 18.0, 1.0, 2)) == pytest.approx(1.0)
def test_advance_block_reference():
t = ta.AdvanceBlock()
assert t.update((10.0, 13.1, 9.9, 13.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((12.0, 14.3, 11.9, 14.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((13.5, 15.0, 13.4, 14.5, 1.0, 2)) == pytest.approx(-1.0)
# --- Lifecycle ------------------------------------------------------------