Metadata-Version: 2.5
Name: norn-mimird
Version: 0.3.0
Summary: A small, contribution-friendly framework for market-data strategies and signal interpreters.
Requires-Python: >=3.11
Requires-Dist: polars>=1.44.1
Requires-Dist: pydantic>=2.7
Requires-Dist: ramonavocado-logger>=0.1.3
Description-Content-Type: text/markdown

# norn

A small framework for market-data **strategies** (OHLCV → signal) and
**interpreters** (signal → position changes). norn owns the contracts, a name
registry, a typed error hierarchy and structured logging. It has no data-provider
dependency — market data is the caller's to supply.

```python
from norn.strategies import SMACrossoverStrategy
from norn.interpreter import BuyAndHoldInterpreter

# `ohlcv` is a Polars DataFrame with the norn.schema.OHLCV column names.
signals = SMACrossoverStrategy({"fast": 10, "slow": 30}).run(ohlcv)
operations = BuyAndHoldInterpreter().run(ohlcv, signals)
```

`run()` is **symmetric by input type**: pass Polars frames to get a frame back,
or pass sequences of the `norn.contracts` dataclasses to get a list back.

```python
from norn.contracts import bars_from_frame

bars = bars_from_frame(ohlcv)  # list[OHLCVBar]
points = SMACrossoverStrategy({"fast": 10}).run(bars)  # list[SignalPoint]
operations = BuyAndHoldInterpreter().run(bars, points)  # list[Operation]
```

Don't know the class ahead of time? Look it up by name in the registry:

```python
from norn.strategies import STRATEGY_REGISTRY

signals = STRATEGY_REGISTRY.get("sma_crossover")({"fast": 10, "slow": 30}).run(ohlcv)
```

## Concepts

| | contract | input → output |
|---|---|---|
| **Strategy** | `norn.strategies.BaseStrategy` | OHLCV → `date, ticker, signal` (`signal` ∈ [-1, 1]) |
| **Interpreter** | `norn.interpreter.BaseInterpreter` | OHLCV + signals → `target_position` (∈ [-1, 1]) and the position changes as `operation_side` / `operation_pct` |

Frame form uses the canonical column names in `norn.schema` (`OHLCV`, `SIGNAL`);
object form uses the dataclasses in `norn.contracts` (`OHLCVBar`, `SignalPoint`,
`Operation`). An interpreter always needs the OHLCV data alongside the signals.
The `Operation` list holds only the bars where the position actually moves.

Built-ins: strategies `sma_crossover`, `rsi_mean_reversion`; interpreters
`signal_following`, `buy_and_hold`.

## sandbox/

A dev playground — not part of the package. `sandbox/run_sma.py` is a worked
example of the OHLCV → signals → operations path. It fetches live data with
[`heimdall-mimird`](https://pypi.org/project/heimdall-mimird/) (a **dev-only**
dependency), so it needs network access:

```bash
uv run python sandbox/run_sma.py
```

## Extending

Add a strategy or interpreter in your own package and expose it through an entry
point so `pip install` is all a user needs. See [CONTRIBUTING.md](CONTRIBUTING.md).

## Development

```bash
uv sync
uv run pytest
uv run ruff check . && uv run ruff format --check .
uv run mypy
```
