Metadata-Version: 2.4
Name: arro
Version: 0.1.5
Summary: A quantitative finance library for portfolio analytics
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pandas>=2.0
Requires-Dist: numpy>=1.25
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"

# arro

`arro` is a small quantitative-finance library for calculating return and
risk metrics from periodic return series.

## Input contract

Metric functions currently accept a `pandas.Series` whose:

- values are finite decimal returns, such as `0.01` for 1%;
- index is a unique, ascending `pandas.DatetimeIndex`;
- values contain no missing data; and
- returns are never below `-1.0`, because an unlevered investment cannot lose
  more than 100% of its value.

The metric layer is intentionally strict. Data-provider integrations should
normalize prices and timestamps before calling these functions rather than
silently repairing malformed data during a calculation.

```python
import pandas as pd

import arro

returns = pd.Series(
    [0.01, -0.02, 0.015, 0.003, -0.005],
    index=pd.date_range("2024-01-01", periods=5, freq="B"),
)

print(arro.cumulative_return(returns))
print(arro.annualized_return(returns))
print(arro.volatility(returns))
print(arro.sharpe_ratio(returns, rf=0.04))
print(arro.sortino_ratio(returns, rf=0.04))
print(arro.max_drawdown(returns))
print(arro.calmar_ratio(returns))
```

## Prices versus returns

`arro` metrics operate on returns, not prices. Convert a price series with
Pandas before calculating metrics:

```python
returns = prices.pct_change().dropna()
```

For adjusted equity data, use an adjusted price field so stock splits and
distributions do not appear as investment losses. The correct field depends on
the provider and its adjustment settings.

## Annualization

When `periods_per_year` is omitted, `arro` infers these regular frequencies:

| Frequency           | Periods per year |
| ------------------- | ---------------: |
| Business day or day |              252 |
| Week                |               52 |
| Month               |               12 |
| Quarter             |                4 |
| Year                |                1 |

Pass `periods_per_year` explicitly for irregular or intraday data:

```python
arro.volatility(minute_returns, periods_per_year=252 * 390)
```

Daily timestamps are ambiguous: US equity analytics normally use 252, while
continuously traded assets may use 365. Use
`periods_per_year=365` for daily crypto data when that matches the intended
methodology.

## Metric conventions

- Annualized return uses geometric compounding.
- Volatility and Sharpe use sample standard deviation (`ddof=1`).
- `rf` is an effective annual rate and is compounded into a periodic rate.
- Sortino uses all observations when calculating target downside deviation.
- Maximum drawdown is returned as a negative decimal.
- Calmar divides annualized return by the absolute maximum drawdown.

## Development

Install development dependencies and run:

```bash
python3 -m pytest
```

Pytest is configured to import code from `src`, avoiding accidental use of a
globally installed `arro` package.
