Metadata-Version: 2.4
Name: fin-eda
Version: 1.1.0
Summary: Comprehensive financial Exploratory Data Analysis for price series and tickers
License: MIT License
        
        Copyright (c) 2026 JR
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/yourname/fin-eda
Project-URL: Bug Tracker, https://github.com/yourname/fin-eda/issues
Keywords: finance,eda,stocks,risk,portfolio,yfinance
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas>=1.3.0
Requires-Dist: numpy>=1.21.0
Requires-Dist: scipy>=1.7.0
Requires-Dist: yfinance>=0.2.0
Requires-Dist: rich>=12.0.0
Provides-Extra: plot
Requires-Dist: matplotlib>=3.5.0; extra == "plot"
Dynamic: license-file

# fin-eda

Comprehensive financial Exploratory Data Analysis for any stock ticker or price series.
Produces a numerical tearsheet (`eda`) and a visual tearsheet (`eda_plot`) covering returns, risk, drawdowns, benchmark comparison, volatility, liquidity, and more — all in one call.

## Installation

```bash
# Numerical tearsheet only
pip install fin-eda

# Numerical + visual tearsheet
pip install fin-eda[plot]
```

## Quick Start — Numerical (`eda`)

```python
from fin_eda import eda

# Fetch data automatically via yfinance
eda("AAPL")

# Custom date range
eda("MSFT", start="2020-01-01", end="2024-01-01")

# Custom period
eda("TSLA", period="5y")

# Different benchmark
eda("QQQ", benchmark_ticker="SPY")

# Include a risk-free rate
eda("AAPL", risk_free_rate=0.05)

# Pass your own price series
import pandas as pd
prices = pd.Series(...)
eda(prices, benchmark_ticker="SPY")

# Return results as a dict (no print)
results = eda("AAPL", return_results=True, quiet=True)
```

## Quick Start — Visual (`eda_plot`)

Requires `pip install fin-eda[plot]`.

```python
from fin_eda import eda_plot

# Full 13-panel tearsheet
eda_plot("AAPL")

# Select specific panels
eda_plot("AAPL", panels=["price", "drawdown", "distribution", "heatmap"])

# Save to file (PNG, PDF, SVG — format inferred from extension)
eda_plot("MSFT", save_path="msft_tearsheet.png")

# Return the Figure for notebook embedding or further customisation
fig = eda_plot("TSLA", period="5y", return_fig=True)

# Custom benchmark and risk-free rate
eda_plot("QQQ", benchmark_ticker="^GSPC", risk_free_rate=0.05)
```

### Available panels

| Name | Description |
|---|---|
| `price` | Price history with 50D/200D moving averages and volume |
| `cumulative` | Cumulative return vs benchmark (log scale, shaded gap) |
| `drawdown` | Underwater drawdown chart with top-3 trough annotations |
| `heatmap` | Monthly returns heatmap (year × month grid) |
| `distribution` | Daily return histogram with normal overlay and VaR lines |
| `qq` | Q-Q plot vs normal distribution (tail points highlighted) |
| `beta_scatter` | Return scatter vs benchmark with OLS regression line |
| `rolling_sharpe` | Rolling 63D and 252D annualized Sharpe ratio |
| `rolling_vol` | Rolling 21D vs 252D volatility regime |
| `capture` | Up/down capture ratio bar chart by period |
| `autocorr` | Return autocorrelation at lags 1–21D with confidence bands |
| `parkinson` | Parkinson (H-L) vs close-to-close volatility comparison |
| `volume` | Daily volume (last 90 days) with 30D/90D averages and Amihud ratio |

Benchmark-dependent panels (`cumulative`, `beta_scatter`, `capture`) are automatically skipped
if no benchmark data is available. OHLCV-dependent panels (`parkinson`, `volume`) are
automatically skipped when a raw price Series is passed instead of a ticker.

## Output

`eda()` renders in the terminal using [Rich](https://github.com/Textualize/rich) with
colour-coded values (green = positive/good, yellow = neutral, red = negative/risk).
A header panel shows the current trend snapshot, followed by one table per section.

`eda_plot()` produces a single dark-themed `matplotlib` figure with up to 13 panels.
Use `save_path` to export, or `return_fig=True` to get the `Figure` object.

## Metrics Covered

| Section | Key Metrics |
|---|---|
| **Core Return & Risk** | Cumulative return, arithmetic & geometric mean, median, std dev, annualized volatility & variance — across 1M, 3M, 6M, 1Y, 3Y, 5Y, 10Y, YTD |
| **Risk-Adjusted Performance** | Sharpe ratio, Sortino ratio, downside deviation, semi-variance, profit factor — from 6M+ |
| **Drawdown & Capital Destruction** | Max drawdown, average drawdown, time to recovery, max consecutive loss days — from 3M+ |
| **Trend Structure & Price Health** | 50/100/200D moving averages, price vs 200D MA, golden/death cross spread, trend persistence, 52W high distance |
| **Relative Performance vs Benchmark** | Excess return, information ratio — from 6M+ |
| **Beta, Correlation & Market Dependence** | Beta, correlation vs benchmark — from 3M+ |
| **Capture Ratios** | Up-market and down-market capture (annualized) — from 6M+ |
| **Return Distribution & Non-Normality** | Skewness, kurtosis, Jarque-Bera statistic — from 3M+ |
| **Tail Risk & Stress** | Historical VaR (95% & 99%), Expected Shortfall/CVaR, worst daily/weekly/monthly return, extreme loss frequency |
| **Regime & Time-Series Behavior** | Return autocorrelation at 1D, 5D, 21D lags |
| **Volatility Metrics** | Parkinson volatility (21D/63D/126D), rolling vol percentile, volatility of volatility, current vs 1Y vol ratio |
| **Liquidity Metrics** | Average daily volume (30D/90D), volume trend, Amihud illiquidity ratio (30D/90D/full) |

## Parameters

### `eda()` — shared with `eda_plot()`

| Parameter | Type | Default | Description |
|---|---|---|---|
| `ticker_or_prices` | `str` or `pd.Series` | — | Yahoo Finance ticker or a Series of close prices |
| `benchmark_ticker` | `str` or `None` | `'SPY'` | Benchmark symbol. Pass `None` to skip |
| `risk_free_rate` | `float` | `0.0` | Annual risk-free rate (e.g. `0.05` for 5%) |
| `period` | `str` or `None` | `'10y'` | yfinance history period (ignored if `start`/`end` provided) |
| `start` | `str` or `None` | `None` | Start date `YYYY-MM-DD` |
| `end` | `str` or `None` | `None` | End date `YYYY-MM-DD` |
| `quiet` | `bool` | `False` | Suppress benchmark fetch status messages |

### `eda()` only

| Parameter | Type | Default | Description |
|---|---|---|---|
| `return_results` | `bool` | `False` | Return the metrics dict instead of (or in addition to) printing |

### `eda_plot()` only

| Parameter | Type | Default | Description |
|---|---|---|---|
| `panels` | `list[str]` or `None` | `None` | Panels to render. `None` = all 13. See panel name table above |
| `save_path` | `str` or `None` | `None` | Save figure to this path before showing (e.g. `'out.png'`, `'report.pdf'`) |
| `return_fig` | `bool` | `False` | Return the `matplotlib.Figure` instead of calling `plt.show()` |

## Dependencies

**Core** (installed automatically):

- [pandas](https://pandas.pydata.org/)
- [numpy](https://numpy.org/)
- [scipy](https://scipy.org/)
- [yfinance](https://github.com/ranaroussi/yfinance)
- [rich](https://github.com/Textualize/rich)

**Optional** (for `eda_plot`, installed via `pip install fin-eda[plot]`):

- [matplotlib](https://matplotlib.org/) ≥ 3.5

## License

MIT

---

## Changelog

### 1.1.0

**New: `eda_plot()` — visual tearsheet**

- 13-panel dark-themed matplotlib tearsheet mirroring all `eda()` inputs.
- Panels: price history, cumulative return vs benchmark, underwater drawdown, monthly returns
  heatmap, return distribution, Q-Q plot, beta scatter, rolling Sharpe, rolling volatility
  regime, up/down capture ratios, autocorrelation, Parkinson volatility, and volume/liquidity.
- `panels=[...]` parameter for rendering any subset of panels in one call.
- `save_path` parameter to export to PNG, PDF, SVG, or any matplotlib-supported format.
- `return_fig=True` for notebook embedding or programmatic figure composition.
- Benchmark-dependent and OHLCV-dependent panels degrade gracefully when data is unavailable.
- Style applied via `mpl.rc_context` — does not pollute the caller's global matplotlib state.
- Added as an optional dependency: `pip install fin-eda[plot]`.

### 1.0.1

**Bug fixes**

- **YTD period** — corrected to use the current calendar year at runtime rather than the last year present in the data, which produced wrong results when analyzing historical series ending before the current year.
- **Average drawdown** — now returns `—` (no data) when a period has no negative drawdown observations, instead of incorrectly showing `0.0`.
- **Time to recovery** — now returns `—` when a period has no drawdown to recover from, instead of showing `0` (which implied an instantaneous recovery had occurred).
- **Volatility of volatility key name** — internal key mismatch between the success and failure paths caused the metric to appear twice in the output under different names. Now consistently labeled `Volatility of volatility (21D rolling, annualized)`.
- **`quiet=True` not fully respected** — benchmark data-fetch status messages were always printed to stdout regardless of the `quiet` flag. They now correctly respect `quiet=True` and route through the Rich console for consistent formatting.
- **Monthly return resampling** — added compatibility fallback for pandas < 2.2, where the `'ME'` month-end alias was not yet available.

**Numerical improvements**

- **Cumulative and geometric mean returns** — switched from chained `.prod()` to log-sum form (`np.expm1(np.log1p(r).sum())`). Mathematically equivalent, but avoids floating-point overflow on very long return histories (20Y+) and resolves a pandas type-stub incompatibility with newer versions.
- **Capture ratios** — same log-sum refactor applied to up- and down-market annualization, eliminating potential overflow for assets with extreme up-market streaks.

**Code quality**

- `period`, `start`, `end`, and `benchmark_ticker` parameters now carry correct `Optional[str]` type annotations (previously typed as `str` despite accepting `None`).
- Period-pattern regex precompiled at module load time instead of on every report render.
- Removed stale internal comment referencing previously deleted metrics.
- Docstrings added to all internal helper functions.
