PriceChannelWidth — Price Channel Width
תוכן זה אינו זמין עדיין בשפה שלך.
The width of the close-based Donchian channel: highest close minus lowest close over the last N bars. A volatility measure with no smoothing in it at all.
PriceChannelWidth is the identifier a strategy writes; Price Channel Width is the label the chart’s indicator picker shows. Single value — .value is the only accessor.
Signature
PriceChannelWidth(period, on=<source>)| Argument | Type | Required | Notes |
|---|---|---|---|
period |
int Param or literal | Yes | Lookback window. Default 20, bounds 2–200. |
on= |
symbol, OHLCV field, or indicator | No | Source. Defaults to the trade symbol’s close. |
Formula
$$ \text{Width}t = \max(\text{close}{t-N+1..t}) - \min(\text{close}_{t-N+1..t}) $$
Always ≥ 0, in the source’s units (normally price). It is the distance between DonchianHigh and DonchianLow over the same window.
Warmup
period bars — that is when the buffer is full and execute() starts.
The value has no dead zone: both branches of the seeded source return max(buffer) − min(buffer), so the leading bars plot the width of a partial window. That width starts near zero and can only grow as the window fills, which makes the left edge of the plot slope upward for reasons that have nothing to do with the market.
Reading the value
width.value # price unitswidth.value / self.trade.close # fraction of price — portable across instrumentswidth.value_at(1)width > width.value_at(10) # is the range expanding?Example
class WidthFilteredBreakout(Strategy): """Take breakouts only out of a channel that has gone quiet.""" period = Param(20, min=2, max=200) max_width = Param(5, min=1, max=50) trade = Symbol() sizing = FixedCapital()
def execute(self): width = PriceChannelWidth(self.period, on=self.trade) upper = DonchianHigh(self.period, on=self.trade) self.stop_loss(2.0)
width_pct = width.value / self.trade.close * 100 breakout_level = upper.value_at(1)
if width_pct < self.max_width and self.trade.close > breakout_level and self.trade.is_flat: self.buy(self.trade, reason=f"Breakout from a {width_pct:.1f}% channel")
if self.trade.close < breakout_level and self.trade.is_long: self.sell(self.trade, self.trade.position, reason="Lost the channel high")Notes
- Unbounded and price-scaled. A width of
4.0is a wide channel on a $20 stock and a rounding error on a $4,000 index. Divide by price before comparing instruments — or useNormalizedRange, which is exactly this measure divided by the channel midpoint. - Two closes decide the entire value; the rest of the window is ignored. That makes it jump when an extreme leaves the window, in a way
ATRandStdDevnever do. - Close-based, so it measures the range of settled prices. It will read narrower than the true high-low range whenever wicks are doing the work.
- A contracting width is the classic “squeeze” setup: quiet range, then a breakout. That is the shape the example above trades.