Skip to content

Commit 89617c3

Browse files
committed
feat: add TBN chart script, docs integration, and white theme
- Create scripts/charts/indicators/trendline_breakout_navigator.py using the shared white theme (generate_all compatible) - Add TBN to scripts/generate_docs.py INDICATOR_MAP - Add TBN to docs support-resistance overview grid and tables - Update notebook from dark (#131722) to white theme matching the project standard (bg=white, bull=#26a69a, bear=#ef5350) - Regenerate chart PNGs with the new theme
1 parent b394e26 commit 89617c3

6 files changed

Lines changed: 17918 additions & 35 deletions

File tree

analysis/indicators/trendline_breakout_navigator.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

analysis/indicators/trendline_breakout_navigator.ipynb

Lines changed: 17731 additions & 34 deletions
Large diffs are not rendered by default.

docs/content/indicators/support-resistance/overview.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ Premium / Discount Zones
154154

155155
</a>
156156

157+
<a href="trendline-breakout-navigator" className="indicator-card">
158+
159+
![Trendline Breakout Navigator](/img/indicators/trendline_breakout_navigator.png)
160+
161+
Trendline Breakout Navigator
162+
163+
</a>
164+
157165
</div>
158166

159167
## Indicators at a glance
@@ -178,6 +186,7 @@ Premium / Discount Zones
178186
| [Liquidity Levels / Voids (VP)](liquidity-levels-voids) | 🟢 Real-time | `detection_length` bars |`detection_length` bars | Highlights volume-profile voids — price areas with little trading activity. Price tends to move quickly through voids. Use them to spot potential fast-move zones. |
179187
| [Internal & External Liquidity Zones](internal-external-liquidity-zones) | 🟢 Real-time | `2 × external_pivot_length + 1` bars |`external_pivot_length` bars | Distinguishes between internal (range-bound) and external (breakout) liquidity. Use it to understand whether price is targeting internal or external levels. |
180188
| [Premium / Discount Zones](premium-discount-zones) | 🟢 Real-time | `2 × swing_length + 1` bars |`swing_length` bars after the swing | Divides the current range into premium (upper) and discount (lower) zones. Buy in discount, sell in premium — the core SMC/ICT framework for directional bias. |
189+
| [Trendline Breakout Navigator](trendline-breakout-navigator) | 🔴 Lagging | `2 × swing_long + 1` bars |`swing_long` bars after the pivot | Multi-timeframe trendline detection. Constructs trendlines on HH/LL reversals at long, medium, and short swing lengths with a composite trend score (−3 to +3). |
181190

182191
## Detailed descriptions
183192

@@ -325,3 +334,10 @@ Distinguishes between internal (range-bound) and external (breakout) liquidity.
325334
326335
Divides the current range into premium (upper) and discount (lower) zones. Buy in discount, sell in premium — the core SMC/ICT framework for directional bias.
327336

337+
### [Trendline Breakout Navigator](trendline-breakout-navigator)
338+
339+
> 🔴 **Lagging** — ≈ `swing_long` bars after the pivot
340+
>
341+
> **Warmup:** `2 × swing_long + 1` bars (default: 121 bars (swing_long=60))
342+
343+
Multi-timeframe trendline detection ported from LuxAlgo PineScript. Constructs trendlines on HH/LL reversals at three swing lengths with a composite trend score (−3 to +3). Detects wick breaks and trend changes.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
"""Trendline Breakout Navigator chart."""
2+
import numpy as np
3+
from pathlib import Path
4+
from scripts.charts.theme import (
5+
load_data, subplot_figure, apply_layout, save, COLORS,
6+
)
7+
import pyindicators as pi
8+
9+
10+
OUTPUT_IMAGE = "trendline_breakout_navigator.png"
11+
12+
# Trendline colours
13+
TL_BULL = COLORS["bull"]
14+
TL_BEAR = COLORS["bear"]
15+
TL_BULL_MED = "rgba(8,153,129,0.60)"
16+
TL_BEAR_MED = "rgba(239,54,69,0.60)"
17+
TL_BULL_SHORT = "rgba(8,153,129,0.35)"
18+
TL_BEAR_SHORT = "rgba(239,54,69,0.35)"
19+
20+
21+
def generate(output_dir: Path | None = None,
22+
data_dir: Path | None = None) -> bool:
23+
df = load_data(dataset="btc_1d", data_dir=data_dir)
24+
df = pi.trendline_breakout_navigator(
25+
df, swing_long=60, swing_medium=30, swing_short=10,
26+
)
27+
df = pi.trendline_breakout_navigator_signal(df)
28+
29+
fig = subplot_figure(df, row_heights=[0.70, 0.30])
30+
31+
trend_long = df["tbn_trend_long"].values
32+
trend_med = df["tbn_trend_medium"].values
33+
trend_short = df["tbn_trend_short"].values
34+
val_long = df["tbn_value_long"].values
35+
val_med = df["tbn_value_medium"].values
36+
val_short = df["tbn_value_short"].values
37+
composite = (
38+
df["tbn_composite_trend"].fillna(0).astype(int).values
39+
)
40+
41+
# ── Long trendlines (solid, thick) ──────────────────────────
42+
fig.add_scatter(
43+
x=df["Datetime"],
44+
y=np.where(trend_long == 1, val_long, np.nan),
45+
mode="lines",
46+
line=dict(color=TL_BULL, width=2.5),
47+
name="Long TL ↑",
48+
connectgaps=False,
49+
row=1, col=1,
50+
)
51+
fig.add_scatter(
52+
x=df["Datetime"],
53+
y=np.where(trend_long == -1, val_long, np.nan),
54+
mode="lines",
55+
line=dict(color=TL_BEAR, width=2.5),
56+
name="Long TL ↓",
57+
connectgaps=False,
58+
row=1, col=1,
59+
)
60+
61+
# ── Medium trendlines (dashed) ──────────────────────────────
62+
fig.add_scatter(
63+
x=df["Datetime"],
64+
y=np.where(trend_med == 1, val_med, np.nan),
65+
mode="lines",
66+
line=dict(color=TL_BULL_MED, width=1.8, dash="dash"),
67+
name="Med TL ↑",
68+
connectgaps=False,
69+
row=1, col=1,
70+
)
71+
fig.add_scatter(
72+
x=df["Datetime"],
73+
y=np.where(trend_med == -1, val_med, np.nan),
74+
mode="lines",
75+
line=dict(color=TL_BEAR_MED, width=1.8, dash="dash"),
76+
name="Med TL ↓",
77+
connectgaps=False,
78+
row=1, col=1,
79+
)
80+
81+
# ── Short trendlines (dotted, thin) ─────────────────────────
82+
fig.add_scatter(
83+
x=df["Datetime"],
84+
y=np.where(trend_short == 1, val_short, np.nan),
85+
mode="lines",
86+
line=dict(
87+
color=TL_BULL_SHORT, width=1.2, dash="dot",
88+
),
89+
name="Short TL ↑",
90+
connectgaps=False,
91+
row=1, col=1,
92+
)
93+
fig.add_scatter(
94+
x=df["Datetime"],
95+
y=np.where(trend_short == -1, val_short, np.nan),
96+
mode="lines",
97+
line=dict(
98+
color=TL_BEAR_SHORT, width=1.2, dash="dot",
99+
),
100+
name="Short TL ↓",
101+
connectgaps=False,
102+
row=1, col=1,
103+
)
104+
105+
# ── HH / LL markers ────────────────────────────────────────
106+
hh = df["tbn_hh"] == 1
107+
ll = df["tbn_ll"] == 1
108+
109+
if hh.any():
110+
fig.add_scatter(
111+
x=df.loc[hh, "Datetime"],
112+
y=df.loc[hh, "Low"] * 0.993,
113+
mode="markers", name="HH",
114+
marker=dict(
115+
symbol="triangle-up", size=10,
116+
color=COLORS["bull"],
117+
),
118+
row=1, col=1,
119+
)
120+
121+
if ll.any():
122+
fig.add_scatter(
123+
x=df.loc[ll, "Datetime"],
124+
y=df.loc[ll, "High"] * 1.007,
125+
mode="markers", name="LL",
126+
marker=dict(
127+
symbol="triangle-down", size=10,
128+
color=COLORS["bear"],
129+
),
130+
row=1, col=1,
131+
)
132+
133+
# ── Row 2: composite trend bar chart ────────────────────────
134+
comp_colors = [
135+
COLORS["bull"] if c > 0
136+
else COLORS["bear"] if c < 0
137+
else COLORS["grid"]
138+
for c in composite
139+
]
140+
141+
fig.add_bar(
142+
x=df["Datetime"], y=composite,
143+
marker_color=comp_colors,
144+
showlegend=False, name="Composite",
145+
opacity=0.85,
146+
row=2, col=1,
147+
)
148+
fig.add_hline(
149+
y=0, line_dash="solid",
150+
line_color=COLORS["grid"], line_width=0.8,
151+
row=2, col=1,
152+
)
153+
154+
apply_layout(
155+
fig,
156+
"Trendline Breakout Navigator",
157+
height=800,
158+
)
159+
fig.update_layout(showlegend=False)
160+
fig.update_yaxes(
161+
title_text="Composite",
162+
range=[-3.5, 3.5], dtick=1,
163+
row=2, col=1,
164+
)
165+
save(fig, OUTPUT_IMAGE, output_dir)
166+
return True

scripts/generate_docs.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@
123123
"Premium / Discount Zones": (
124124
"indicators/support-resistance", "premium-discount-zones", 18
125125
),
126+
"Trendline Breakout Navigator": (
127+
"indicators/support-resistance",
128+
"trendline-breakout-navigator", 19
129+
),
126130
# ── Pattern Recognition ──
127131
"Detect Peaks": (
128132
"indicators/pattern-recognition", "detect-peaks", 1
-76.3 KB
Loading

0 commit comments

Comments
 (0)