2026-01-18 19:02:03 -08:00
# EBSW: Ehlers Even Better Sinewave
2026-02-04 11:43:59 -08:00
> "When you combine a high-pass filter with a super-smoother, you get cleaner cycles with automatic gain control."
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
The Even Better Sinewave (EBSW) indicator is a refined cycle oscillator developed by John Ehlers. It combines a high-pass filter (trend removal) with a Super-Smoother filter (noise removal) and Automatic Gain Control to produce an oscillator normalized between -1 and +1 that synthesizes a clean sine wave from price action.
2026-01-18 19:02:03 -08:00
2026-02-04 11:43:59 -08:00
## Historical Context
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
Ehlers' original "Sinewave" indicator relied on the Hilbert Transform to extract phase. However, he found that direct Hilbert Transforms were often unstable on real market data. The "Even Better" Sinewave simplifies the approach: instead of complex phase math, it uses a tuned bandpass filter (High-Pass + Low-Pass) to isolate the wave, then normalizes it.
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
This resulted in a more robust tool for identifying turning points in both trending and ranging markets, first published in *Cycle Analytics for Traders* .
2026-01-18 19:02:03 -08:00
2026-02-04 11:43:59 -08:00
## Architecture & Physics
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
The transformation pipeline consists of four distinct stages.
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
### 1. High-Pass Filter (Trend Removal)
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
\alpha_1 = \frac{1 - \sin(2\pi/HP)}{\cos(2\pi/HP)}
2026-02-04 11:43:59 -08:00
$$
$$
2026-02-05 19:42:49 -08:00
HP_t = 0.5 (1 + \alpha_1)(P_t - P_{t-1}) + \alpha_1 \cdot HP_{t-1}
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
### 2. Super-Smoother Filter (Noise Removal)
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
\alpha_2 = e^{-\sqrt{2}\pi / SSF}
2026-02-04 11:43:59 -08:00
$$
$$
2026-02-05 19:42:49 -08:00
Filt_t = \frac{1 - 2\alpha_2\cos(\sqrt{2}\pi/SSF) - \alpha_2^2}{2}(HP_t + HP_{t-1}) + 2\alpha_2\cos(\sqrt{2}\pi/SSF) \cdot Filt_{t-1} - \alpha_2^2 \cdot Filt_{t-2}
$$
### 3. Wave & Power Calculation
$$
Wave = \frac{Filt_t + Filt_{t-1} + Filt_{t-2}}{3}
2026-02-04 11:43:59 -08:00
$$
$$
2026-02-05 19:42:49 -08:00
Power = \frac{Filt_t^2 + Filt_{t-1}^2 + Filt_{t-2}^2}{3}
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
### 4. Normalization (AGC)
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
EBSW = \frac{Wave}{\sqrt{Power}}
2026-02-04 11:43:59 -08:00
$$
2026-02-05 19:42:49 -08:00
Result is clamped to $\pm 1$.
2026-01-18 19:02:03 -08:00
## Performance Profile
2026-02-05 19:42:49 -08:00
### Operation Count (Streaming Mode, per Bar)
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
| Operation | Count | Cost (cycles) | Subtotal |
| :--- | :---: | :---: | :---: |
| FMA (filter updates) | 4 | 4 | 16 |
| MUL (power calc) | 3 | 3 | 9 |
| ADD/SUB | 6 | 1 | 6 |
| DIV | 1 | 15 | 15 |
| SQRT | 1 | 12 | 12 |
| **Total** | **15** | — | ** ~58 cycles** |
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
### Complexity Analysis
2026-01-18 19:02:03 -08:00
2026-02-05 19:42:49 -08:00
- **Streaming:** O(1) per bar—fixed cascaded IIR filters
- **Memory:** O(1)—only filter state variables
- **Warmup:** ~hpLength bars for HP filter convergence
2026-02-04 11:43:59 -08:00
## Validation
| Library | Status | Notes |
2026-02-05 19:42:49 -08:00
| :--- | :---: | :--- |
| TA-Lib | N/A | Not standard |
| Skender | N/A | Not standard |
| PineScript | ✅ | Matches `ebsw` script |
| Reference | ✅ | Matches *Cycle Analytics for Traders* logic |
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
## Usage & Pitfalls
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
- **Range is -1 to +1**—zero crossings signal cycle phase changes
- **HP Length is critical**—should match expected market cycle (e.g., 40 bars)
- **Too short HP Length** filters out everything as "trend"
- **AGC amplifies noise** in low volatility—verify with price action
- **Strong step moves** cause railing at ±1 for extended periods
- **Buy at valley** (EBSW turning up from -0.8), **sell at peak** (turning down from +0.8)
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
## API
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
```mermaid
classDiagram
class Ebsw {
+int HpLength
+int SsfLength
+double Value
+bool IsHot
+Ebsw(int hpLength, int ssfLength)
+Ebsw(ITValuePublisher source, int hpLength, int ssfLength)
+TValue Update(TValue input, bool isNew)
+void Reset()
}
```
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
### Class: `Ebsw`
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
| Parameter | Type | Default | Range | Description |
| :--- | :--- | :--- | :--- | :--- |
| `hpLength` | `int` | `40` | `≥1, ≠4` | High-pass filter period (detrending) |
| `ssfLength` | `int` | `10` | `≥1` | Super-smoother filter period |
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
### Properties
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
- `Value` (`double` ): The current EBSW value (bounded -1 to +1)
- `IsHot` (`bool` ): Returns `true` when warmup is complete
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
### Methods
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
- `Update(TValue input, bool isNew)` : Updates the indicator with a new data point
## C# Example
2026-02-04 11:43:59 -08:00
```csharp
using QuanTAlib ;
2026-02-05 19:42:49 -08:00
// Create EBSW for 40-bar cycle with 10-bar smoothing
2026-02-04 11:43:59 -08:00
var ebsw = new Ebsw ( hpLength : 40 , ssfLength : 10 );
2026-02-05 19:42:49 -08:00
// Update with streaming data
foreach ( var bar in quotes )
{
var result = ebsw . Update ( new TValue ( bar . Date , bar . Close ));
if ( ebsw . IsHot )
{
Console . WriteLine ( $"{bar.Date}: EBSW = {result.Value:F4}" );
// Cycle turning point detection
if ( result . Value < - 0.8 && result . Value > ebsw . Previous . Value )
Console . WriteLine ( " → Potential cycle bottom" );
else if ( result . Value > 0.8 && result . Value < ebsw . Previous . Value )
Console . WriteLine ( " → Potential cycle top" );
}
}
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
// Batch calculation
var output = Ebsw . Calculate ( sourceSeries , hpLength : 40 , ssfLength : 10 );
2026-02-04 11:43:59 -08:00
```