Metadata-Version: 2.4
Name: quant-pulse
Version: 0.2.9
Summary: Quant Pulse — reusable Python library for on-demand financial market signals
Author: koder0x
License: MIT
Project-URL: Homepage, https://github.com/gsscoder/quant-pulse
Project-URL: Repository, https://github.com/gsscoder/quant-pulse
Project-URL: Issues, https://github.com/gsscoder/quant-pulse/issues
Keywords: quant-pulse,trading,signals,market-data
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy==2.3.4
Requires-Dist: TA-Lib==0.6.8
Requires-Dist: requests==2.32.5
Requires-Dist: hyperliquid-python-sdk==0.20.1
Provides-Extra: dev
Requires-Dist: pytest==9.0.1; extra == "dev"
Requires-Dist: PyYAML==6.0.3; extra == "dev"
Dynamic: license-file

# Quant Pulse

Quant Pulse is a lightweight Python library for generating market signals on demand. It supports various targets (asset classes, markets, etc.) and signal operations through a modular architecture that allows for easy extension and customization.

Current Version: **0.2.9 (alpha)**

## Core Principles

- Scoped to financial domain, whether decentralized or centralized.

- Remain fully open source to promote transparency and wider adoption.

## Design Goals

- Offer automatic **trading systems** raw or processed data to support **decisions-making**, embedded directly in-process.

- **Prototype** composite signals from raw ones using **Jupyter Notebook** or similar environments.

## Non-Goals

- Not designed for high‑frequency trading (HFT) or other fast trading systems.

- Direct interaction with markets is explicitly out of scope.

- Not a server or service — no network interface is provided; embed it in your own process.

## Further Notes

- The codebase is still stabilizing, and contributions via **pull request** are not open yet. Key interfaces are subject to refinement; feel free to experiment with modules, but keep in mind that **breaking changes** may occur.

- **Note:** custom signal handlers and services (extending the internal `SignalHandler`/`Service` base types) cannot yet be plugged in from an external project — the config-driven loader only resolves modules inside this package's own namespace. External extensibility (e.g. entry-point/plugin registration) is a coming-soon update.

## Installation

```sh
pip install quant-pulse
```

Requires Python 3.10+. [TA-Lib](https://ta-lib.org/install/) must be installed on the system before `pip install` (the Python package wraps the native library).

## Modules

**Path:**

```sh
src/quant_pulse
├── handlers   # signal handlers
├── services   # core services
└── _core      # framework internals (abstractions, registries, config)
```

**Handlers:**

- `RSISignal`: RSI indicator signal handler
- `MASignal`: MA indicator signal handler (supports `sma`, `ema`, `wma`)
- `ATRSignal`: ATR indicator signal handler
- `DMISignal`: DMI indicator signal handler (combines ADX, DI+, DI-)
- `PriceStructSignal`: Price structure signal handler
- `TrendDirectSignal`: Trend direction signal handler
- `MntmQualitySignal`: Momentum Quality signal handler
- `MACDSignal`: MACD indicator signal handler
- `SupertrendSignal`: Supertrend signal handler (composes `ATRSignal`)
- `MarketVolumeSignal`: tradeable markets on a venue, ranked by 24h quote volume

**Services:**

- `CacheManager`: factory-pattern based caching to create scoped caches
- `ExchangeClient`: abstract base type for exchange implementations
- `BinanceClient`: provides access to OHLCV data from Binance CEX
- `HyperliquidClient`: provides access to OHLCV data from Hyperliquid DEX
- `OHLCVFetcher`: abstracts OHLCV data fetching and provides caching

## Usage

```python
from quant_pulse import Context, ConfigBuilder

cfg = (
    ConfigBuilder()
    .hyperliquid_client('hl_client')
    .cache_manager()
    .ohlcv('hl_ohlcv', using=['hl_client', 'cache_manager'])
    .signal('rsi_hyperliquid', 'rsi_signal', ohlcv_service='hl_ohlcv')
    .build()
)

with Context.from_dict(cfg) as ctx:
    sig = ctx.get_signal_handler('rsi_hyperliquid')
    out = sig.compute_signal(
        target='BTC',
        signal_op='compute_rsi',
        request={'period': 14, 'timeframe': '1h'}
    )

    if out.errors:
        print('errors:', out.errors)
    else:
        print(f"latest_rsi: {out.result['latest_rsi']}")
        print(f"regime: {out.result['regime']}")
```

`out.result` is a plain Python object (`dict`/`list`/etc.) — no serialization step, nothing to decode.

`ConfigBuilder` also has typed shortcuts for other bundled exchange clients (`binance_spot_client`, `binance_mf_client`) and a raw `.service()` escape hatch for anything custom — see [`builder.py`](src/quant_pulse/builder.py).

A runnable version of the first example is at [`samples/rsi_sample.py`](samples/rsi_sample.py). For the simplest possible no-network usage, see [`samples/hello_world.py`](samples/hello_world.py).

## Signal Sample

```python
def _compute_signal_impl(self, target: str, signal_op: str, request: Optional[dict]) -> Outcome:
    """
    Compute RSI signal
    """
    try:
        period = int(request['period'])
        timeframe = request['timeframe']

        ohlcv_fetcher = self._ctx.get_service(self._ohlcv_service_name)
        if not ohlcv_fetcher or not hasattr(ohlcv_fetcher, 'retrieve_ohlcv'):
            return self._error(f"OHLCV service '{self._ohlcv_service_name}' not found or invalid")

        limit = period + 100
        candles = ohlcv_fetcher.retrieve_ohlcv(symbol=self._symbol, timeframe=timeframe, limit=limit)
        if not candles or len(candles) < period:
            return self._error(f"Insufficient candle data: need {period}, got {len(candles) if candles else 0}")

        close_prices = np.array([candle.close for candle in candles])
        rsi_values = talib.RSI(close_prices, timeperiod=period)
        rsi_list = rsi_values[~np.isnan(rsi_values)].round(2).tolist()

        latest_rsi = next((float(v) for v in reversed(rsi_values) if not np.isnan(v)), None)
        if latest_rsi is None:
            return self._error('Failed to compute RSI: all values are NaN')

        regime = 'overbought' if latest_rsi >= 70 else 'oversold' if latest_rsi <= 30 else 'neutral'

        return Outcome(
            result={'symbol': self._symbol, 'rsi': rsi_list, 'latest_rsi': round(latest_rsi, 2), 'regime': regime},
            computation=self.get_metadata()['name']
        )
    except Exception as e:
        self.logger.error(f"Error computing RSI: {e}", exc_info=True)
        return self._error(str(e))
```

## License

MIT — see [LICENSE](LICENSE).
