דלגו לתוכן
פתיחת RaamTrade

UltimateOscillator — Ultimate Oscillator

תוכן זה אינו זמין עדיין בשפה שלך.

Buying pressure measured against true range, blended across three horizons (7/14/28, weighted 4/2/1) so a single lookback cannot dominate. Reads 0–100; divergences at extremes are the classic signal.

Signature

UltimateOscillator(fast, mid, slow, on=<source>)
Argument Type Required Notes
fast int Param or literal Yes Short horizon. Convention 7. Bounds 1–100.
mid int Param or literal Yes Middle horizon. Convention 14. Bounds 1–200.
slow int Param or literal Yes Long horizon; also the buffer size. Convention 28. Bounds 1–400.
on= symbol No Source symbol. Defaults to the trade symbol. Reads high, low, close.

Formula

$$ BP = C - \min(L, C_{prev}), \quad TR = \max(H, C_{prev}) - \min(L, C_{prev}) $$ $$ \text{UO} = 100 \cdot \frac{4,\frac{\sum BP_7}{\sum TR_7} + 2,\frac{\sum BP_{14}}{\sum TR_{14}} + \frac{\sum BP_{28}}{\sum TR_{28}}}{7} $$

Warmup

slow + 1 bars; 50 (neutral) until then, and 50 on a fully flat stretch where a true-range sum is zero.

Reading the value

uo.value
uo < 30
uo.crossed_above(50)

Example

class UoOversold(Strategy):
"""Buy an Ultimate Oscillator dip under 30, exit above 50."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
uo = UltimateOscillator(7, 14, 28, on=self.trade)
if uo.value < 30 and self.trade.is_flat:
self.buy(self.trade, reason=f"UO {uo.value:.0f}")
if uo.value > 50 and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="UO recovered")

Notes

  • Larry Williams (1976). The weights 4/2/1 and horizons n, 2n, 4n are his.
  • Proven by an assert-via-trade run on SPY daily (matched a strategy-side BP/TR reference to 0.01 on every bar, including the sub-window sums; zero alarm trades; canary fired on this assertion).
  • The three horizons scale from slow; keep fast < mid < slow — the code does not reorder them for you.