11"""
22Liquidity Pools Indicator
33
4- Faithful Python translation of the **Liquidity Pools [LuxAlgo]**
5- indicator from TradingView (Pine Script v5, Oct 16 2024, 332 lines).
6-
74Identifies liquidity pool zones by analysing high and low wicked
85price areas, the number of contacts, and the frequency of visits.
96
10- Algorithm overview (matching Pine Script exactly)
7+ Algorithm overview
118-------------------------------------------------
1291. Track a *highest* (``hst``) and *lowest* (``lst``) reference
1310 candle. On each bar, adjust these references when price makes
1916 body level must be stable (unchanged for 2 bars).
2017
21183. When enough contacts accumulate (``contact_count``) and the
22- bars-since-last-wick counter crosses above ``confirmation_bars``
23- (``ta.crossover(bs_hw, wait)`` in Pine), AND the close is on
19+ bars-since-last-wick counter crosses above ``confirmation_bars``,
20+ AND the close is on
2421 the correct side of the reference body level, a zone is created.
2522
26234. Zone creation uses a *running zone* pattern (``h_zn`` / ``l_zn``)
3128 - No overlap -> create a fresh running zone and push to array.
3229
33305. Zone extension: the most recent zone accumulates fractional volume
34- from every overlapping candle (``get_civ`` in Pine) .
31+ from every overlapping candle.
3532
36336. Zone mitigation: when price closes beyond the zone boundary for
3734 two consecutive bars, the zone is removed.
5552def _get_civ (h : float , lo : float , v : float ,
5653 zone_top : float , zone_bot : float ) -> float :
5754 """Return the fraction of candle volume that lies inside *zone*.
58-
59- Mirrors Pine Script's ``get_civ`` helper:
60- ``nz((_h - _l) / _r, 1) * volume`` where _h/_l are clamped to
61- the zone boundaries.
6255 """
6356 r = h - lo
6457 if r <= 0 :
@@ -94,17 +87,11 @@ def liquidity_pools(
9487) -> Union [PdDataFrame , PlDataFrame ]:
9588 """Detect Liquidity Pool zones on OHLC(V) data.
9689
97- Faithful translation of:
98- *Liquidity Pools [LuxAlgo]* -- Pine Script v5, Oct 16 2024.
99-
10090 Args:
10191 data: pandas or polars DataFrame with OHLC(V) data.
10292 contact_count: Minimum wick contacts required to form a zone
103- (Pine: ``cNum``, default 2).
10493 gap_bars: Minimum bars between successive contacts
105- (Pine: ``gapCount``, default 5).
10694 confirmation_bars: Bars to wait before confirming a zone
107- (Pine: ``wait``, default 10).
10895 high_column: Column name for highs.
10996 low_column: Column name for lows.
11097 open_column: Column name for opens.
@@ -188,7 +175,6 @@ def liquidity_pools(
188175 return pl .from_pandas (df )
189176 return df
190177
191- # -- Pine: var declarations (persistent across bars) --------------
192178 c_top_0 = max (opens [0 ], closes [0 ])
193179 c_bot_0 = min (opens [0 ], closes [0 ])
194180
@@ -210,7 +196,6 @@ def liquidity_pools(
210196 hi_vol = 0.0 # var float hi_vol = 0
211197 lo_vol = 0.0 # var float lo_vol = 0
212198
213- # Running zones (Pine: var zn h_zn, l_zn -- initially na)
214199 # Each: {top, bottom, state, vol, start_bar, right_bar} or None
215200 h_zn = None
216201 l_zn = None
@@ -219,11 +204,10 @@ def liquidity_pools(
219204 bull_zones : list [dict ] = []
220205 bear_zones : list [dict ] = []
221206
222- # Pine: var int bs_hw = 0, bs_lw = 0
207+ # var int bs_hw = 0, bs_lw = 0
223208 bs_hw = 0
224209 bs_lw = 0
225210
226- # Previous-bar references for Pine [1] / [2] lookbacks
227211 prev_h_wick = False
228212 prev_l_wick = False
229213 hst_t_1ago = hst ["t" ]
@@ -244,8 +228,6 @@ def liquidity_pools(
244228 c_bot = min (o , c )
245229
246230 # -- 1. Adjusting High and Low Check Boundaries ---------------
247- # Pine: if (high > hst.h) and ((c_top > hst.h) or
248- # (c_top < hst.t))
249231 if h > hst ["h" ] and (c_top > hst ["h" ] or c_top < hst ["t" ]):
250232 if h_count > 1 :
251233 # Reset low reference to current candle
@@ -264,8 +246,6 @@ def liquidity_pools(
264246 h_count = 1
265247 last_h_wick = bar
266248
267- # Pine: if (low < lst.l) and ((c_bot < lst.l) or
268- # (c_bot > lst.b))
269249 if lo < lst ["l" ] and (c_bot < lst ["l" ] or c_bot > lst ["b" ]):
270250 if l_count > 1 :
271251 # Reset high reference to current candle
@@ -285,43 +265,34 @@ def liquidity_pools(
285265 last_l_wick = bar
286266
287267 # -- 2. Compute wicks for current bar -------------------------
288- # Pine: h_wick = high > hst.t and c_top <= hst.t
289268 h_wick = (h > hst ["t" ]) and (c_top <= hst ["t" ])
290- # Pine: l_wick = low < lst.b and c_bot >= lst.b
291269 l_wick = (lo < lst ["b" ]) and (c_bot >= lst ["b" ])
292270
293- # -- 3. Counting contacts (Pine uses [1] / [2] refs) ---------
294- # Pine: if (h_wick[1] and (hst.t[1] == hst.t[2])
295- # and (bs_hw > gapCount))
271+ # -- 3. Counting contacts ---------
296272 if (prev_h_wick
297273 and hst_t_1ago == hst_t_2ago
298274 and prev_bs_hw > gap_bars ):
299275 h_count += 1
300276 last_h_wick = bar - 1
301277
302- # Pine: if (l_wick[1] and (lst.b[1] == lst.b[2])
303- # and (bs_lw > gapCount))
304278 if (prev_l_wick
305279 and lst_b_1ago == lst_b_2ago
306280 and prev_bs_lw > gap_bars ):
307281 l_count += 1
308282 last_l_wick = bar - 1
309283
310284 # -- 4. Bars since last wick ----------------------------------
311- # Pine: bs_hw := math.abs(last_h_wick - bar_index)
312285 bs_hw = abs (last_h_wick - bar )
313286 bs_lw = abs (last_l_wick - bar )
314287
315288 # -- 5. Track outer extremes ----------------------------------
316- # Pine: if (high > hst.h) hst.h := high
317289 if h > hst ["h" ]:
318290 hst ["h" ] = h
319- # Pine: if (low < lst.l) lst.l := low
291+
320292 if lo < lst ["l" ]:
321293 lst ["l" ] = lo
322294
323295 # -- 6. Volume tracking (reference-level volume) --------------
324- # Pine: hst_vol = max((high - hst.t), 0) / (high-low) * vol
325296 h_range = h - lo
326297 if h_range > 0 :
327298 hi_vol += max (h - hst ["t" ], 0 ) / h_range * v
@@ -338,8 +309,6 @@ def liquidity_pools(
338309 )
339310
340311 # -- 7a. Bearish pool (resistance) from high contacts ---------
341- # Pine: if (h_count >= cNum) and ta.crossover(bs_hw, wait)
342- # and (close < hst.t)
343312 if (h_count >= contact_count
344313 and hw_cross
345314 and c < hst ["t" ]):
@@ -394,8 +363,6 @@ def liquidity_pools(
394363 bear_zones .append (h_zn )
395364
396365 # -- 7b. Bullish pool (support) from low contacts -------------
397- # Pine: if (l_count >= cNum) and ta.crossover(bs_lw, wait)
398- # and (close > lst.b)
399366 if (l_count >= contact_count
400367 and lw_cross
401368 and c > lst ["b" ]):
@@ -460,7 +427,7 @@ def liquidity_pools(
460427 zb = z ["bottom" ]
461428
462429 # Most recent zone: accumulate candle volume if
463- # overlapping (Pine get_civ) and extend line
430+ # overlapping and extend line
464431 if i == len (bull_zones ) - 1 :
465432 if c > zt :
466433 z ["right_bar" ] = bar
@@ -488,7 +455,7 @@ def liquidity_pools(
488455 zb = z ["bottom" ]
489456
490457 # Most recent zone: accumulate candle volume if
491- # overlapping (Pine get_civ) and extend line
458+ # overlapping and extend line
492459 if i == len (bear_zones ) - 1 :
493460 if c < zb :
494461 z ["right_bar" ] = bar
0 commit comments