# Coinrule X Indicators

Standard library of trading indicators for the Coinrule X execution platform.

## Installation

```bash
pip install crx-indicators
```

## Usage Patterns

Coinrule X Indicators supports two main calculation patterns depending on your environment:

### 1. Stateless (Batch) Calculation

Ideal for backtesting or one-off analysis where you have a full history of candles.

```python
indicator = RSI(period=14)
result = indicator.calculate(candles) # Processes entire history
```

### 2. Stateful (Incremental) Calculation

Optimized for **live trading** and minimized latency. Instead of recalculating the entire history on every tick, the indicator maintains internal state and updates in $O(1)$ time.

```python
# Initialization (typically on startup)
indicator = RSI(period=14)
indicator.seed(historical_candles)

# Live update (on every new closed candle)
latest_value = indicator.update(new_candle)
```

## Structure

Indicators are located in the `coinrule_x_indicators/indicators` directory.
Each indicator implements the standard interface `CandleIndicator` defined in `coinrule_x_indicators.core`.

## Contributing

We welcome contributions of new indicators! Please follow these guidelines to ensure consistency and quality.

### Adding a New Indicator

1.  **Create the Indicator File**:
    Create a new file in `coinrule_x_indicators/indicators/` (e.g., `ema.py`).

2.  **Implement the Class**:
    Inherit from the `CandleIndicator` base class and implement both the `calculate` (stateless) and `update` (stateful) methods.

    ```python
    from coinrule_x_indicators.core import CandleIndicator, Candle
    from typing import List, Union

    class EMA(CandleIndicator):
        def __init__(self, period: int = 8):
            self.period = period
            self.alpha = 2.0 / (period + 1.0)
            super().__init__(period=period)

        def calculate(self, candles: List[Candle]) -> float:
            # Batch implementation (e.g., using pandas)
            pass

        def update(self, candle: Candle) -> float:
            # Incremental implementation (O(1) update)
            # Update self._value and return it
            pass
    ```

3.  **Register the Indicator**:
    Add your new class to `coinrule_x_indicators/indicators/__init__.py` to export it.

4.  **Update Registry**:
    Add your indicator to `coinrule_x_indicators/registry.yaml`. This is used by the Coinrule X platform to discover available indicators.
    ```yaml
    ema:
      latest: "1.0.0"
      versions:
        "1.0.0":
          class: "coinrule_x_indicators.indicators.ema.EMA"
          label: "EMA"
          description: "Exponential Moving Average"
          arguments:
            period:
              type: int
              default: 8
              label: "Period"
              description: "Number of periods for EMA calculation"
    ```
5.  **Validate Registry**:
    Ensure your registry entry is valid before submitting:
    ```bash
    # Run validation script
    poetry run python coinrule_x_indicators/validation.py coinrule_x_indicators/registry.yaml
    ```

### Versioning & Immutability Policy

To guarantee **strategy reproducibility**, Coinrule X Indicators follows a strict **Add-Only** policy for breaking changes. Strategies written today must produce the exact same signals 5 years from now.

#### 1. Immutable Logic

Once an indicator version (e.g., `ema` v1.0.0) is published and used, its calculation logic **MUST NOT** change.

- **Bug Fixes**: Critical bugs in logic require a **Patch** version (e.g., v1.0.1).
- **New Features**: New arguments or logic require a **New Version** (e.g., v1.1.0 or v2.0.0).

#### 2. Creating New Versions

If you need to change the behavior of an indicator:

1.  **Do NOT edit definitions** of existing released classes.
2.  **Create a New Class**: e.g., `class EMAv2(Indicator)`.
3.  **Register New Version**: Add the new version to `registry.yaml` alongside the old one.

**Example `registry.yaml` structure for multi-version support:**

```yaml
ema:
  latest: "2.0.0"
  label: "EMA"
  versions:
    "1.0.0":
      class: "coinrule_x_indicators.indicators.ema.EMA"
      description: "Standard Exponential Moving Average"
    "2.0.0":
      class: "coinrule_x_indicators.indicators.ema_v2.EMAv2"
      description: "EMA with adjustable smoothing factor"
      arguments:
        period: { label: "Period", type: int, default: 14 }
        smoothing: { label: "Smoothing", type: float, default: 2.0 }
```

#### 3. Deprecation

Old versions remain in the codebase indefinitely unless they pose a security risk. They can be marked as `deprecated: true` in the registry to warn developers against using them for new strategies, but existing strategies will continue to function.

### Testing Guidelines

Every indicator **must** have a corresponding test file in the `tests/` directory.

1.  **Create Test File**:
    Create `tests/test_<indicator_name>.py` (e.g., `tests/test_ema.py`).

2.  **Use Standard Data**:
    Use the provided `load_candles` utility to load the standardized test dataset (`tests/data/candles.json`). This dataset contains HYPE 1h candles, with the latest candle starting at 24 Dec 2025 15:00 UTC. This ensures all indicators are tested against the same market conditions.

    ```python
    from tests.utils import load_candles
    from coinrule_x_indicators.indicators.ema import EMA

    def test_ema_calculation():
        candles = load_candles("candles.json")
        ema = EMA(period=8)
        result = ema.calculate(candles)

        # Verify result against known valid value (e.g. from TradingView or known lib)
        assert round(result, 2) == <EXPECTED_VALUE>
    ```

3.  **Required Test Cases**:
    - **Initialization**: Verify arguments are stored correctly.
    - **Batch Calculation**: Verify that `calculate()` correctly processes a list of candles.
    - **Precise Value**: A test asserting the exact value (to 2 decimal places) against the provided dataset.
    - **Incremental Consistency**: Verify that `update()` produces the same result as `calculate()` when processing the same sequence of candles.

### Running Tests

Run the test suite using `pytest`:

```bash
poetry run pytest
```

### Submission Process

1.  **Fork the Repository**: Create a fork of the repository to your own GitHub account.
2.  **Create a Feature Branch**: Create a new branch for your changes (e.g., `feat/add-rsi-indicator`).
3.  **Implement & Test**: Apply your changes and ensure all tests pass.
4.  **Create Pull Request**: Submit a pull request to the main repository.

_Note: Version numbers and the official CHANGELOG will be updated by maintainers upon release._

### Development Guidelines

- **Type Hinting**: All methods must be fully type-hinted.
- **Pandas/Numpy**: Use vectorized operations where possible for performance.
- **Zero Dependencies**: Do not add new external dependencies without prior discussion.
