# NORMALIZE: Min-Max Normalization

> "Normalization is the art of making apples and oranges comparable—by insisting that everything lives on the same scale from 0 to 1."

The Normalize transformer applies min-max scaling to map any value series into the bounded range [0, 1] based on the observed minimum and maximum within a rolling lookback window. This technique is fundamental for feature scaling, creating bounded oscillators, and comparing series with different magnitudes.

## Mathematical Foundation

### Core Formula

$$
\text{Norm}_t = \frac{x_t - \min_{[t-n+1, t]}}{\max_{[t-n+1, t]} - \min_{[t-n+1, t]}}
$$

where:
- $x_t$ is the input value at time $t$
- $n$ is the lookback period
- $\min_{[t-n+1, t]}$ is the minimum value in the window
- $\max_{[t-n+1, t]}$ is the maximum value in the window

### Edge Case: Flat Range

When $\max = \min$ (all values identical):

$$
\text{Norm}_t = 0.5
$$

This neutral value is returned since the "position" within a zero-width range is undefined.

### Key Properties

| Property | Value | Description |
|:---------|:------|:------------|
| **Range** | $[0, 1]$ | Guaranteed bounded output |
| **Min maps to** | 0 | Lowest value in window → 0 |
| **Max maps to** | 1 | Highest value in window → 1 |
| **Linear** | Yes | Preserves relative distances within window |
| **Invertible** | Yes* | If you know min/max |

*Given the min and max used, original value = Norm × (max - min) + min

## Financial Applications

### Oscillator Construction

Convert any price-based measure to oscillator form:

$$
\text{NormalizedRSI} = \text{Normalize}(\text{RSI}, 100)
$$

### Cross-Asset Comparison

Compare instruments with different price scales:

$$
\text{RelativeStrength} = \text{Normalize}(\text{Price}_A, n) - \text{Normalize}(\text{Price}_B, n)
$$

### Machine Learning Features

Prepare inputs for models requiring bounded features:

$$
\text{Feature}_i = \text{Normalize}(x_i, \text{lookback})
$$

### Dynamic Range Detection

Identify where price sits within recent range:

$$
\text{Position} = \text{Normalize}(\text{Close}, 20)
$$

Values near 1.0 indicate price at recent highs; near 0.0 at recent lows.

## Parameter Guide

### Period Selection

| Period | Behavior | Use Case |
|:-------|:---------|:---------|
| 5-10 | Highly responsive | Short-term oscillators |
| 14-20 | Standard | General normalization |
| 50-100 | Smooth | Position within broader context |
| 200+ | Very stable | Long-term percentile-like behavior |

### Period Effects

- **Shorter periods**: More volatile output, quicker adaptation to new ranges
- **Longer periods**: Smoother output, but slower to adapt; may stay near extremes longer

## Implementation Details

### Rolling Window Approach

The implementation maintains a ring buffer of size $n$ and recalculates min/max on each update. This provides O(n) complexity per update but ensures correctness with the rolling window semantics.

### Streaming Characteristics

| Metric | Value |
|:-------|:------|
| **Warmup Period** | $n$ (period) |
| **Memory** | O(n) for ring buffer |
| **Complexity** | O(n) per update |

### Precision Considerations

| Scenario | Handling |
|:---------|:---------|
| **Zero range** | Returns 0.5 |
| **Very small range** | Full precision maintained |
| **NaN/Infinity input** | Last valid value substituted |

## Performance Profile

### Operation Count (Streaming Mode)

| Operation | Count | Notes |
|:----------|:-----:|:------|
| Buffer add | 1 | O(1) ring buffer |
| Min scan | n | Linear scan of window |
| Max scan | n | Combined with min scan |
| SUB | 2 | value - min, max - min |
| DIV | 1 | Final division |
| **Total** | O(n) | Dominated by min/max scan |

### Quality Metrics

| Metric | Score | Notes |
|:-------|:-----:|:------|
| **Accuracy** | 10/10 | Exact min-max scaling |
| **Boundedness** | 10/10 | Guaranteed [0, 1] output |
| **Adaptability** | 8/10 | Adapts to rolling window |
| **Timeliness** | 7/10 | Requires warmup period |

## Usage Examples

### Basic Usage

```csharp
// Create Normalize with 14-period lookback
var norm = new Normalize(14);

// Feed price data
var price = new TValue(DateTime.UtcNow, 105.0);
var normalized = norm.Update(price);  // Value in [0, 1]
```

### Creating Oscillator from Any Series

```csharp
var rsi = new Rsi(14);
var normRsi = new Normalize(rsi, 100);  // Chain: RSI → Normalize

// RSI output (0-100) gets normalized to [0, 1] over 100 periods
foreach (var bar in data)
{
    rsi.Update(new TValue(bar.Time, bar.Close));
    // normRsi automatically updates via event
}
```

### Comparing Multiple Assets

```csharp
var normA = new Normalize(50);
var normB = new Normalize(50);

// Compare where each asset sits in its own range
var posA = normA.Update(new TValue(now, priceA));
var posB = normB.Update(new TValue(now, priceB));

var relativeStrength = posA.Value - posB.Value;  // [-1, 1]
```

### Span API for Batch Processing

```csharp
double[] prices = GetHistoricalPrices();
double[] normalized = new double[prices.Length];

Normalize.Calculate(prices, normalized, period: 20);
```

## Common Pitfalls

1. **Lookback Dependency**: Output depends heavily on what's in the lookback window. Unusual spikes or crashes in the window can distort normalization for the entire period duration.

2. **Not Truly Bounded During Warmup**: Before the warmup period completes, the window is partial, which may produce less meaningful normalization.

3. **Flat Market Handling**: When a series has no variation over the period, output becomes 0.5. This may need special handling if your strategy interprets 0.5 differently.

4. **Window Lag**: When price breaks out of a long-established range, the old min/max remains in the window until it ages out, causing the normalized value to stay pinned at 0 or 1.

5. **Memory Requirements**: Each instance requires O(period) memory for the ring buffer. For many indicators with long periods, this can add up.

6. **Non-Stationarity**: Min-max normalization assumes the range is representative. In trending markets, the normalization may consistently return values near 0 or 1.

## Validation

| Test | Status |
|:-----|:------:|
| **Output in [0, 1]** | ✅ |
| **Max value → 1** | ✅ |
| **Min value → 0** | ✅ |
| **Flat range → 0.5** | ✅ |
| **Linear mapping** | ✅ |
| **Rolling window correctness** | ✅ |
| **Streaming = Batch** | ✅ |

## References

- Aksoy, S., & Haralick, R. M. (2001). "Feature normalization and likelihood-based similarity measures for image retrieval." *Pattern Recognition Letters*.
- Patro, S., & Sahu, K. K. (2015). "Normalization: A preprocessing stage." *IARJSET*.
- Géron, A. (2019). *Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow*. O'Reilly Media.
