feat(indicators): A5b Fibonacci tools (geometric) (#172)
Completes the **Fibonacci** family with the four geometric/time tools (catalogue 373 -> 377). All extend the internal `pattern_swing` ZigZag tracker with a per-pivot bar index and a current-bar counter (additive — the chart/harmonic detectors are unaffected), and emit `Candle -> struct` outputs via custom Python/Node/WASM bindings. | Tool | Output | |------|--------| | `FibFan` | three trendlines fanning from a swing start through its 38.2/50/61.8% retracement levels, extended to the current bar | | `FibArcs` | semicircular retracement levels centred on the swing end, normalised by the leg's bar-width (chart-scale-free) | | `FibChannel` | a sloped base trendline plus parallel lines at Fibonacci multiples of the channel width | | `FibTimeZones` | markers at Fibonacci bar-distances (1/2/3/5/8/...) from the latest swing pivot | The geometric tools are novel as streaming indicators; each normalises its geometry to the swing leg's bar-width so the output is chart-scale-free. Formulas are documented in each module and deep-dive. Fully wired: core (100% unit-tested branches incl. the new `pattern_swing` bar tracking), Python/Node/WASM struct bindings, fuzz, reference + streaming-vs-batch tests. Verification: `cargo test --workspace` green, clippy `-D warnings` clean, node 454 tests, python 768 tests.
This commit is contained in:
@@ -860,6 +860,26 @@ def test_candle_scalar_streaming_matches_batch(name, ohlcv):
|
||||
# --- Candle-input, multi-output indicators --------------------------------
|
||||
|
||||
MULTI = {
|
||||
"FibFan": (
|
||||
lambda: ta.FibFan(),
|
||||
lambda ind, h, l, c, v: ind.batch(h, l),
|
||||
3,
|
||||
),
|
||||
"FibArcs": (
|
||||
lambda: ta.FibArcs(),
|
||||
lambda ind, h, l, c, v: ind.batch(h, l),
|
||||
3,
|
||||
),
|
||||
"FibChannel": (
|
||||
lambda: ta.FibChannel(),
|
||||
lambda ind, h, l, c, v: ind.batch(h, l),
|
||||
4,
|
||||
),
|
||||
"FibTimeZones": (
|
||||
lambda: ta.FibTimeZones(),
|
||||
lambda ind, h, l, c, v: ind.batch(h, l),
|
||||
2,
|
||||
),
|
||||
"FibRetracement": (
|
||||
lambda: ta.FibRetracement(),
|
||||
lambda ind, h, l, c, v: ind.batch(h, l),
|
||||
@@ -2652,6 +2672,41 @@ def test_fib_confluence_reference():
|
||||
assert t.update((101.0, 160.0, 101.0, 101.0, 1.0, 2)) is None
|
||||
assert t.update((144.0, 158.4, 144.0, 144.0, 1.0, 3)) == pytest.approx((137.64, 2.0))
|
||||
|
||||
|
||||
def test_fib_fan_reference():
|
||||
t = ta.FibFan()
|
||||
assert t.update((199.0, 200.0, 199.0, 199.0, 1.0, 0)) is None
|
||||
assert t.update((160.0, 190.0, 160.0, 160.0, 1.0, 1)) is None
|
||||
assert t.update((100.0, 150.0, 100.0, 100.0, 1.0, 2)) is None
|
||||
assert t.update((105.0, 110.0, 105.0, 105.0, 1.0, 3)) == pytest.approx((142.7, 125.0, 107.3))
|
||||
|
||||
|
||||
def test_fib_arcs_reference():
|
||||
t = ta.FibArcs()
|
||||
assert t.update((199.0, 200.0, 199.0, 199.0, 1.0, 0)) is None
|
||||
assert t.update((160.0, 190.0, 160.0, 160.0, 1.0, 1)) is None
|
||||
assert t.update((100.0, 150.0, 100.0, 100.0, 1.0, 2)) is None
|
||||
assert t.update((105.0, 110.0, 105.0, 105.0, 1.0, 3)) == pytest.approx((133.082181, 143.30127, 153.52037))
|
||||
|
||||
|
||||
def test_fib_channel_reference():
|
||||
t = ta.FibChannel()
|
||||
assert t.update((199.0, 200.0, 199.0, 199.0, 1.0, 0)) is None
|
||||
assert t.update((100.0, 190.0, 100.0, 100.0, 1.0, 1)) is None
|
||||
assert t.update((108.0, 110.0, 108.0, 108.0, 1.0, 2)) is None
|
||||
assert t.update((210.0, 220.0, 210.0, 210.0, 1.0, 3)) is None
|
||||
assert t.update((150.0, 200.0, 150.0, 150.0, 1.0, 4)) == pytest.approx((226.666667, 160.746667, 120.0, 54.08))
|
||||
|
||||
|
||||
def test_fib_time_zones_reference():
|
||||
t = ta.FibTimeZones()
|
||||
assert t.update((199.0, 200.0, 199.0, 199.0, 1.0, 0)) is None
|
||||
assert t.update((150.0, 190.0, 150.0, 150.0, 1.0, 1)) == pytest.approx((1.0, 1.0))
|
||||
assert t.update((151.0, 155.0, 151.0, 151.0, 1.0, 2)) == pytest.approx((1.0, 1.0))
|
||||
assert t.update((151.0, 155.0, 151.0, 151.0, 1.0, 3)) == pytest.approx((1.0, 2.0))
|
||||
assert t.update((151.0, 155.0, 151.0, 151.0, 1.0, 4)) == pytest.approx((0.0, 1.0))
|
||||
assert t.update((151.0, 155.0, 151.0, 151.0, 1.0, 5)) == pytest.approx((1.0, 3.0))
|
||||
|
||||
# --- Lifecycle ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user