ZenQuant.Trend (zen_quant v0.7.0)

Copy Markdown View Source

Range geometry and momentum mechanics over chronologically ordered candles.

Every lookback, smoothing length, and pivot-selection rule is supplied by the caller. Range boundaries are envelopes over the selected pivots (not mid-lines through them), and distances to those boundaries are signed. The functions report quantities only: they do not name chart patterns, apply thresholds, or emit trading signals.

Pivot prominence is measured within each requested range window. A side with no more-extreme pivot uses the window border as its search limit. If a pivot lies on a window border, its own value is that side's base, so its prominence is zero. range_geometry/5 itself detects pivots only where the requested lookback exists on both sides, so it does not return border extrema.

dss_bressert/3 follows the published ProRealTime construction: stochastic close position, EMA, normalization of that smoothed series against its own rolling bounds, then a second EMA. This differs from prose descriptions that instead smooth separate stochastic numerators and denominators.

Positional OHLCV rows can be converted to the shared candle-map shape with ZenQuant.Volatility.normalize_candles/1 before calling this module.

API Functions

FunctionArityDescriptionParam Kinds
dss_bressert3Calculate DSS Bressert using the published double-smoothed construction.candles: exchange_data, period: value, ema_length: value
stoch_rsi3Normalize Wilder RSI within a caller-selected rolling RSI range.candles: exchange_data, rsi_period: value, stochastic_period: value
rsi2Calculate Wilder's Relative Strength Index from candle closes.candles: exchange_data, period: value
rate_of_change2Calculate close-to-close percentage rate of change.candles: exchange_data, period: value
range_geometry5Measure pivot-envelope range boundaries for every requested window.candles: exchange_data, windows: value, pivot_lookback: value, price: value, select_pivots: value
prominence_selector1Build a pivot selector using a caller-supplied minimum prominence.minimum_prominence: value

Summary

Types

An envelope boundary evaluated at both ends of its range window

Measured range geometry for one requested window

A local high or low with topographic prominence in price units

Caller-supplied rule that chooses which detected pivots enter the envelope fit

Functions

Calculate DSS Bressert using the published double-smoothed construction.

Build a pivot selector using a caller-supplied minimum prominence.

Measure pivot-envelope range boundaries for every requested window.

Calculate close-to-close percentage rate of change.

Calculate Wilder's Relative Strength Index from candle closes.

Normalize Wilder RSI within a caller-selected rolling RSI range.

Types

boundary()

@type boundary() :: %{
  slope: float(),
  intercept: float(),
  start_value: float(),
  end_value: float()
}

An envelope boundary evaluated at both ends of its range window

geometry()

@type geometry() :: %{
  upper_pivots: [pivot()],
  lower_pivots: [pivot()],
  upper_boundary: boundary() | nil,
  lower_boundary: boundary() | nil,
  upper_slope: float() | nil,
  lower_slope: float() | nil,
  converging?: boolean() | nil,
  width_start: float() | nil,
  width_end: float() | nil,
  distance_to_upper: float() | nil,
  distance_to_lower: float() | nil
}

Measured range geometry for one requested window

pivot()

@type pivot() :: %{index: non_neg_integer(), price: float(), prominence: float()}

A local high or low with topographic prominence in price units

pivot_selector()

@type pivot_selector() :: ([pivot()] -> [pivot()])

Caller-supplied rule that chooses which detected pivots enter the envelope fit

Functions

dss_bressert(candles, period, ema_length)

@spec dss_bressert([ZenQuant.Volatility.candle()], pos_integer(), pos_integer()) :: [
  float()
]

Calculate DSS Bressert using the published double-smoothed construction.

Parameters

  • candles - Chronological candle maps with a :close field (exchange_data)
  • period - Caller-selected stochastic and normalization period (value)
  • ema_length - Caller-selected length for both EMA smoothing passes (value)

Returns

Chronological DSS values on a 0-100 scale (list)

Example

[36.2, 48.9, 67.4]
# descripex:contract
%{
  params: %{
    period: %{
      description: "Caller-selected stochastic and normalization period",
      kind: :value
    },
    candles: %{
      description: "Chronological candle maps with a :close field",
      source: "fetch_ohlcv(symbol) |> ZenQuant.Volatility.normalize_candles()",
      kind: :exchange_data
    },
    ema_length: %{
      description: "Caller-selected length for both EMA smoothing passes",
      kind: :value
    }
  },
  returns: %{
    type: :list,
    description: "Chronological DSS values on a 0-100 scale"
  },
  returns_example: [36.2, 48.9, 67.4]
}

prominence_selector(minimum_prominence)

@spec prominence_selector(number()) :: pivot_selector()

Build a pivot selector using a caller-supplied minimum prominence.

Parameters

  • minimum_prominence - Minimum pivot prominence in the same units as candle prices (value)

Returns

Function ([pivot] -> [pivot]) retaining pivots at or above the supplied threshold (function)

Example

"fn pivots -> Enum.filter(pivots, &(&1.prominence >= minimum_prominence)) end"
# descripex:contract
%{
  params: %{
    minimum_prominence: %{
      description: "Minimum pivot prominence in the same units as candle prices",
      kind: :value
    }
  },
  returns: %{
    type: :function,
    description: "Function ([pivot] -> [pivot]) retaining pivots at or above the supplied threshold"
  },
  returns_example: "fn pivots -> Enum.filter(pivots, &(&1.prominence >= minimum_prominence)) end"
}

range_geometry(candles, windows, pivot_lookback, price, select_pivots)

@spec range_geometry(
  [ZenQuant.Volatility.candle()],
  [pos_integer()],
  pos_integer(),
  number(),
  pivot_selector()
) ::
  %{required(pos_integer()) => geometry()}
  | {:error, {:insufficient_candles, pos_integer()}}

Measure pivot-envelope range boundaries for every requested window.

Parameters

  • candles - Chronological candle maps with :high and :low fields (exchange_data)
  • windows - Set of trailing window lengths to measure (value)
  • pivot_lookback - Bars required on each side of a strict local high or low (value)
  • price - Price whose signed distance to each ending boundary is measured (price - end_value; positive means above the boundary) (value)
  • select_pivots - Function ([pivot] -> [pivot]) choosing which detected pivots enter each envelope fit; applied independently to upper and lower pivots (value)

Returns

Map of window to prominent pivots, envelope boundaries, slopes, convergence, widths, and signed price distances; error if a window exceeds the series (map)

Example

%{
  60 => %{
    upper_slope: -0.08,
    lower_slope: 0.03,
    converging?: true,
    width_start: 12.4,
    width_end: 5.91,
    distance_to_upper: -1.2,
    distance_to_lower: 2.4
  }
}

Errors

  • :insufficient_candles
# descripex:contract
%{
  params: %{
    windows: %{
      description: "Set of trailing window lengths to measure",
      kind: :value
    },
    price: %{
      description: "Price whose signed distance to each ending boundary is measured (price - end_value; positive means above the boundary)",
      kind: :value
    },
    candles: %{
      description: "Chronological candle maps with :high and :low fields",
      source: "fetch_ohlcv(symbol) |> ZenQuant.Volatility.normalize_candles()",
      kind: :exchange_data
    },
    pivot_lookback: %{
      description: "Bars required on each side of a strict local high or low",
      kind: :value
    },
    select_pivots: %{
      description: "Function ([pivot] -> [pivot]) choosing which detected pivots enter each envelope fit; applied independently to upper and lower pivots",
      kind: :value
    }
  },
  errors: [:insufficient_candles],
  returns: %{
    type: :map,
    description: "Map of window to prominent pivots, envelope boundaries, slopes, convergence, widths, and signed price distances; error if a window exceeds the series"
  },
  returns_example: %{
    60 => %{
      upper_slope: -0.08,
      lower_slope: 0.03,
      converging?: true,
      width_start: 12.4,
      width_end: 5.91,
      distance_to_upper: -1.2,
      distance_to_lower: 2.4
    }
  }
}

rate_of_change(candles, period)

@spec rate_of_change([ZenQuant.Volatility.candle()], pos_integer()) :: [float()]

Calculate close-to-close percentage rate of change.

Parameters

  • candles - Chronological candle maps with a :close field (exchange_data)
  • period - Caller-selected comparison period (value)

Returns

Chronological percentage rate-of-change values (list)

Example

[2.5, -1.2, 0.8]
# descripex:contract
%{
  params: %{
    period: %{description: "Caller-selected comparison period", kind: :value},
    candles: %{
      description: "Chronological candle maps with a :close field",
      source: "fetch_ohlcv(symbol) |> ZenQuant.Volatility.normalize_candles()",
      kind: :exchange_data
    }
  },
  returns: %{
    type: :list,
    description: "Chronological percentage rate-of-change values"
  },
  returns_example: [2.5, -1.2, 0.8]
}

rsi(candles, period)

@spec rsi([ZenQuant.Volatility.candle()], pos_integer()) :: [float()]

Calculate Wilder's Relative Strength Index from candle closes.

Parameters

  • candles - Chronological candle maps with a :close field (exchange_data)
  • period - Caller-selected Wilder smoothing period (value)

Returns

Chronological RSI values on a 0-100 scale (list)

Example

[48.3, 51.7, 55.1]
# descripex:contract
%{
  params: %{
    period: %{
      description: "Caller-selected Wilder smoothing period",
      kind: :value
    },
    candles: %{
      description: "Chronological candle maps with a :close field",
      source: "fetch_ohlcv(symbol) |> ZenQuant.Volatility.normalize_candles()",
      kind: :exchange_data
    }
  },
  returns: %{
    type: :list,
    description: "Chronological RSI values on a 0-100 scale"
  },
  returns_example: [48.3, 51.7, 55.1]
}

stoch_rsi(candles, rsi_period, stochastic_period)

@spec stoch_rsi([ZenQuant.Volatility.candle()], pos_integer(), pos_integer()) :: [
  float()
]

Normalize Wilder RSI within a caller-selected rolling RSI range.

Parameters

  • candles - Chronological candle maps with a :close field (exchange_data)
  • rsi_period - Caller-selected Wilder RSI period (value)
  • stochastic_period - Caller-selected RSI normalization period (value)

Returns

Chronological StochRSI values on a 0-100 scale (list)

Example

[18.4, 42.7, 100.0]
# descripex:contract
%{
  params: %{
    candles: %{
      description: "Chronological candle maps with a :close field",
      source: "fetch_ohlcv(symbol) |> ZenQuant.Volatility.normalize_candles()",
      kind: :exchange_data
    },
    rsi_period: %{
      description: "Caller-selected Wilder RSI period",
      kind: :value
    },
    stochastic_period: %{
      description: "Caller-selected RSI normalization period",
      kind: :value
    }
  },
  returns: %{
    type: :list,
    description: "Chronological StochRSI values on a 0-100 scale"
  },
  returns_example: [18.4, 42.7, 100.0]
}