# T3: Tillson T3 Moving Average ## What It Does The T3 Moving Average is a hyper-smooth, low-lag indicator developed by Tim Tillson. It uses a unique "volume factor" to control how aggressively the moving average tracks the price. Unlike standard moving averages that simply smooth data, T3 applies multiple layers of smoothing (specifically, a generalized DEMA) to create a curve that is exceptionally smooth yet responsive to significant price moves. ## Historical Context Tim Tillson introduced the T3 in his article "Smoothing Techniques for More Accurate Signals" in *Technical Analysis of Stocks & Commodities* (January 1998). His goal was to improve upon the lag characteristics of traditional moving averages and the overshoot problems of DEMA (Double Exponential Moving Average). ## How It Works ### The Core Idea T3 is essentially a "moving average of a moving average of a moving average..." but using a generalized DEMA (GD) instead of a simple EMA. - **GD (Generalized DEMA):** A mix of EMA and DEMA controlled by a volume factor $v$. - **T3:** Applying the GD filter six times in sequence ($GD(GD(GD(GD(GD(GD(Price))))))$). The "Volume Factor" ($v$) determines how much "DEMA" (fast, overshooting) vs "EMA" (slow, lagging) is mixed in. - $v=0$: T3 behaves like a triple EMA (very smooth, some lag). - $v=1$: T3 behaves like a DEMA (very fast, prone to overshoot). - $v=0.7$: The standard default, offering a balance. ### Mathematical Foundation 1. **Generalized DEMA (GD):** $$ GD(x, v) = EMA(x) \times (1 + v) - EMA(EMA(x)) \times v $$ 2. **T3 Sequence:** $$ e1 = GD(Price) $$ $$ e2 = GD(e1) $$ $$ e3 = GD(e2) $$ $$ ... $$ $$ T3 = e6 $$ ### Implementation Details Our implementation uses the recursive GD formula for O(1) updates. - **Complexity:** O(1) per update (6 GD calculations). - **Stability:** Requires a warmup period to stabilize all 6 internal layers. ## Configuration | Parameter | Default | Purpose | Adjustment Guidelines | |-----------|---------|---------|----------------------| | Period | 14 | Smoothing period | Standard lookback. | | Volume Factor (v) | 0.7 | Responsiveness | 0.7 is standard. Lower (0.1-0.5) = smoother/slower. Higher (0.8-1.0) = faster/responsive. | ## Performance Profile | Operation | Complexity | Description | |-----------|------------|-------------------| | Streaming update | O(1) | 6 layers of GD calculation | | Bar correction | O(1) | Efficient state rollback | | Batch processing | O(N) | Single pass through data | | Memory footprint | O(1) | Stores state for 6 internal layers | ## Interpretation ### Trading Signals #### Trend Identification - **Smoothness:** T3 is famous for filtering out "noise" better than almost any other MA. If T3 is rising, the trend is likely real, not just a blip. - **Crossovers:** Price crossing T3 is a significant event due to the indicator's smoothness. ### When It Works Best - **Noisy Markets:** T3 shines in markets with lots of wicks and erratic movement, where standard EMAs would get chopped up. ### When It Struggles - **Lag:** Despite its clever math, applying a filter 6 times introduces lag. It will turn after the market turns, not with it. ## Architecture Notes This implementation makes specific trade-offs: ### Choice: 6 Layers - **Implementation:** We implement the standard "T3" which implies 6 layers of smoothing. - **Rationale:** While "T2" or "T4" are possible, "T3" (6 layers) is the industry standard definition. ## References - Tillson, Tim. "Smoothing Techniques for More Accurate Signals." *Technical Analysis of Stocks & Commodities*, V. 16:1 (33-37), 1998. ## C# Usage ### Streaming Updates (Single Instance) ```csharp using QuanTAlib; var t3 = new T3(period: 14, vFactor: 0.7); // Process each new bar TValue result = t3.Update(new TValue(timestamp, closePrice)); Console.WriteLine($"T3: {result.Value:F2}"); // Check if buffer is full if (t3.IsHot) { // Indicator is fully initialized } ``` ### Batch Processing (Historical Data) ```csharp // TSeries API TSeries prices = ...; TSeries t3Values = T3.Batch(prices, period: 14, vFactor: 0.7); // Span API (High Performance) double[] prices = new double[1000]; double[] output = new double[1000]; T3.Calculate(prices.AsSpan(), output.AsSpan(), period: 14, vFactor: 0.7); ``` ### Bar Correction (isNew Parameter) ```csharp var t3 = new T3(14); // New bar t3.Update(new TValue(time, 100), isNew: true); // Intra-bar update t3.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101