feat: TA-Lib candlestick patterns — crows & three-line (part 1 of 9) (#130)

* feat: add Two Crows candlestick pattern (CDL2CROWS)

* feat: add Upside Gap Two Crows candlestick pattern (CDLUPSIDEGAP2CROWS)

* feat: add Identical Three Crows candlestick pattern (CDLIDENTICAL3CROWS)

* feat: add Three Line Strike candlestick pattern (CDL3LINESTRIKE)

* feat: add Three Stars in the South candlestick pattern (CDL3STARSINSOUTH)
This commit is contained in:
kingchenc
2026-06-01 23:20:10 +02:00
committed by GitHub
parent 458ef2385e
commit f09057aaf1
18 changed files with 1302 additions and 22 deletions
+10
View File
@@ -240,6 +240,11 @@ from ._wickra import (
SpinningTop,
ThreeInside,
ThreeOutside,
TwoCrows,
UpsideGapTwoCrows,
IdenticalThreeCrows,
ThreeLineStrike,
ThreeStarsInSouth,
# Microstructure: order book
OrderBookImbalanceTop1,
OrderBookImbalanceTopN,
@@ -507,6 +512,11 @@ __all__ = [
"SpinningTop",
"ThreeInside",
"ThreeOutside",
"TwoCrows",
"UpsideGapTwoCrows",
"IdenticalThreeCrows",
"ThreeLineStrike",
"ThreeStarsInSouth",
# Microstructure: order book
"OrderBookImbalanceTop1",
"OrderBookImbalanceTopN",
+22
View File
@@ -11615,6 +11615,23 @@ candle_pattern_no_param!(PyTweezer, wc::Tweezer, "Tweezer");
candle_pattern_no_param!(PySpinningTop, wc::SpinningTop, "SpinningTop");
candle_pattern_no_param!(PyThreeInside, wc::ThreeInside, "ThreeInside");
candle_pattern_no_param!(PyThreeOutside, wc::ThreeOutside, "ThreeOutside");
candle_pattern_no_param!(PyTwoCrows, wc::TwoCrows, "TwoCrows");
candle_pattern_no_param!(
PyUpsideGapTwoCrows,
wc::UpsideGapTwoCrows,
"UpsideGapTwoCrows"
);
candle_pattern_no_param!(
PyIdenticalThreeCrows,
wc::IdenticalThreeCrows,
"IdenticalThreeCrows"
);
candle_pattern_no_param!(PyThreeLineStrike, wc::ThreeLineStrike, "ThreeLineStrike");
candle_pattern_no_param!(
PyThreeStarsInSouth,
wc::ThreeStarsInSouth,
"ThreeStarsInSouth"
);
// ============================== Microstructure: Order Book ==============================
//
@@ -14112,6 +14129,11 @@ fn _wickra(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PySpinningTop>()?;
m.add_class::<PyThreeInside>()?;
m.add_class::<PyThreeOutside>()?;
m.add_class::<PyTwoCrows>()?;
m.add_class::<PyUpsideGapTwoCrows>()?;
m.add_class::<PyIdenticalThreeCrows>()?;
m.add_class::<PyThreeLineStrike>()?;
m.add_class::<PyThreeStarsInSouth>()?;
// Microstructure: order book.
m.add_class::<PyOrderBookImbalanceTop1>()?;
m.add_class::<PyOrderBookImbalanceTopN>()?;
@@ -523,6 +523,26 @@ CANDLE_SCALAR = {
lambda: ta.ThreeOutside(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"TwoCrows": (
lambda: ta.TwoCrows(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"UpsideGapTwoCrows": (
lambda: ta.UpsideGapTwoCrows(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"IdenticalThreeCrows": (
lambda: ta.IdenticalThreeCrows(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"ThreeLineStrike": (
lambda: ta.ThreeLineStrike(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"ThreeStarsInSouth": (
lambda: ta.ThreeStarsInSouth(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
}
@@ -1851,6 +1871,42 @@ def test_three_outside_reference():
assert t.update((11.5, 13.0, 11.4, 12.5, 1.0, 2)) == pytest.approx(1.0)
def test_two_crows_reference():
t = ta.TwoCrows()
assert t.update((10.0, 12.2, 9.9, 12.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((14.0, 14.2, 12.9, 13.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((13.5, 13.6, 10.9, 11.0, 1.0, 2)) == pytest.approx(-1.0)
def test_upside_gap_two_crows_reference():
t = ta.UpsideGapTwoCrows()
assert t.update((10.0, 12.2, 9.9, 12.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((14.0, 14.2, 12.9, 13.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((15.0, 15.2, 12.4, 12.5, 1.0, 2)) == pytest.approx(-1.0)
def test_identical_three_crows_reference():
t = ta.IdenticalThreeCrows()
assert t.update((13.0, 13.1, 11.9, 12.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((12.0, 12.1, 10.9, 11.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((11.0, 11.1, 9.9, 10.0, 1.0, 2)) == pytest.approx(-1.0)
def test_three_line_strike_reference():
t = ta.ThreeLineStrike()
assert t.update((10.0, 11.1, 9.9, 11.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((10.5, 12.1, 10.4, 12.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((11.5, 13.1, 11.4, 13.0, 1.0, 2)) == pytest.approx(0.0)
assert t.update((13.5, 13.6, 9.4, 9.5, 1.0, 3)) == pytest.approx(1.0)
def test_three_stars_in_south_reference():
t = ta.ThreeStarsInSouth()
assert t.update((20.0, 20.1, 8.0, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((18.0, 18.1, 12.0, 16.0, 1.0, 1)) == pytest.approx(0.0)
assert t.update((15.0, 15.0, 14.0, 14.0, 1.0, 2)) == pytest.approx(1.0)
# --- Lifecycle ------------------------------------------------------------