2026-02-18 19:08:15 -08:00
# CG: Ehlers Center of Gravity
2026-01-18 19:02:03 -08:00
2026-02-27 07:48:12 -08:00
| Property | Value |
| ---------------- | -------------------------------- |
| **Category** | Cycle |
| **Inputs** | Source (close) |
| **Parameters** | `period` (default 10) |
| **Outputs** | Single series (Cg) |
| **Output range** | Varies (see docs) |
| **Warmup** | `period` bars |
### TL;DR
- CG identifies potential turning points using the physics concept of weighted center of mass applied to a price window.
- Parameterized by `period` (default 10).
- Output range: Varies (see docs).
- Requires `period` bars of warmup before first valid output (IsHot = true).
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
2026-02-20 21:40:32 -08:00
CG identifies potential turning points using the physics concept of weighted center of mass applied to a price window. Developed by John Ehlers, the oscillator measures where the "weight" of prices is concentrated within a lookback period, producing a leading indicator that oscillates around zero with minimal lag compared to traditional moving average crossover systems.
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-20 21:40:32 -08:00
John Ehlers introduced the Center of Gravity oscillator in *Cybernetic Analysis for Stocks and Futures* (2002). Drawing from classical mechanics, the indicator applies the concept that the center of mass of a distribution reveals its balance point. In the price context, the CG identifies where momentum is concentrated within a sliding window. Unlike momentum oscillators that differentiate price (and amplify noise), CG integrates position-weighted price, providing smoother turning point detection. The indicator's leading characteristic arises from the weighting scheme: as new prices shift the balance point, the CG responds before the window's simple average would.
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
### 1. Weighted Sum (Numerator)
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
Position-weighted accumulation over the lookback window:
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
$$Num = \sum_{i=1}^{n} i \cdot P_{t-n+i}$$
where $i$ ranges from 1 (oldest) to $n$ (newest), giving linearly increasing weight to more recent data.
2026-02-05 19:42:49 -08:00
### 2. Simple Sum (Denominator)
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
$$Den = \sum_{i=1}^{n} P_{t-n+i}$$
2026-02-04 11:43:59 -08:00
2026-02-05 19:42:49 -08:00
### 3. Center of Gravity
2026-02-20 21:40:32 -08:00
$$CG_t = \frac{Num}{Den} - \frac{n + 1}{2}$$
2026-02-05 19:42:49 -08:00
2026-02-20 21:40:32 -08:00
The term $\frac{n + 1}{2}$ is the geometric center of the window, centering the output around zero. When recent prices dominate, $CG > 0$ (bullish); when older prices dominate, $CG < 0$ (bearish).
2026-01-18 19:02:03 -08:00
2026-02-20 21:40:32 -08:00
### 4. Complexity
2026-01-18 19:02:03 -08:00
2026-02-20 21:40:32 -08:00
Streaming uses running sums for both numerator and denominator: $O(1)$ per bar with $O(n)$ memory for the ring buffer.
2026-01-18 19:02:03 -08:00
2026-02-20 21:40:32 -08:00
## Mathematical Foundation
2026-01-18 19:02:03 -08:00
2026-02-20 21:40:32 -08:00
### Parameters
2026-01-18 19:02:03 -08:00
2026-02-20 21:40:32 -08:00
| Parameter | Description | Default | Constraint |
|-----------|-------------|---------|------------|
| `period` | Lookback window length | 10 | $> 0$ |
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
### Pseudo-code
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
```
function CG(source, period):
buffer ← RingBuffer(period)
runNum ← 0 // weighted sum
runDen ← 0 // simple sum
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
for each price in source:
buffer.Add(price)
if buffer.Count < period: continue
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
// Compute from buffer (or maintain running sums)
num = 0
den = 0
for i = 0 to period-1:
w = i + 1
num += w * buffer[i]
den += buffer[i]
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
cg = (den ≠ 0) ? (num / den) - (period + 1) / 2.0 : 0
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
emit cg
2026-02-05 19:42:49 -08:00
```
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
### Output Interpretation
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
| Condition | Meaning |
|-----------|---------|
| $CG > 0$ | Weight concentrated in recent prices (bullish momentum) |
| $CG < 0$ | Weight concentrated in older prices (bearish momentum) |
| Zero crossing up | Momentum shifting bullish |
| Zero crossing down | Momentum shifting bearish |
| Hanging at extremes | Strong trend in progress |
2026-02-04 11:43:59 -08:00
2026-02-21 20:45:38 -08:00
## Performance Profile
### Operation Count (Streaming Mode)
| Operation | Count | Cost (cycles) | Subtotal |
| :--- | :---: | :---: | :---: |
| ADD/SUB | 2× N | 1 | 2N |
| MUL | N | 3 | 3N |
| DIV | 1 | 15 | 15 |
| **Total** | ** ~3N+1** | — | ** ~5N+15** |
The `RecalculateSums()` loop iterates over the full buffer each bar, making this O(N) per bar. For default $N = 10$: ~65 cycles. A periodic resync every 1000 bars maintains numerical stability.
### Quality Metrics
| Metric | Score | Notes |
| :--- | :---: | :--- |
| **Accuracy** | 10/10 | Exact weighted center-of-mass calculation |
| **Timeliness** | 9/10 | Leads price movement by construction |
| **Smoothness** | 7/10 | Raw oscillator; no internal smoothing |
| **Memory** | 9/10 | O(N) ring buffer + 2 running sums |
2026-02-20 21:40:32 -08:00
## Resources
2026-02-04 11:43:59 -08:00
2026-02-20 21:40:32 -08:00
- **Ehlers, J.F.** *Cybernetic Analysis for Stocks and Futures* . Wiley, 2002.
- **Ehlers, J.F.** *Rocket Science for Traders* . Wiley, 2001.