pyreto 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyreto/__init__.py +6 -0
- pyreto/distributions/__init__.py +8 -0
- pyreto/distributions/alpha_stable.py +103 -0
- pyreto/distributions/base.py +48 -0
- pyreto/distributions/fit.py +86 -0
- pyreto/distributions/normal_inverse_gaussian.py +83 -0
- pyreto/distributions/student_t.py +44 -0
- pyreto-0.2.0.dist-info/METADATA +82 -0
- pyreto-0.2.0.dist-info/RECORD +11 -0
- pyreto-0.2.0.dist-info/WHEEL +5 -0
- pyreto-0.2.0.dist-info/top_level.txt +1 -0
pyreto/__init__.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Alpha-Stable distribution."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.optimize import minimize
|
|
5
|
+
from scipy.integrate import quad
|
|
6
|
+
from scipy.optimize import brentq
|
|
7
|
+
from scipy.stats import norm
|
|
8
|
+
from .base import DistributionFitter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AlphaStable(DistributionFitter):
|
|
12
|
+
"""Alpha-Stable distribution."""
|
|
13
|
+
|
|
14
|
+
def _char_func(self, t, alpha, beta, c, mu):
|
|
15
|
+
if alpha == 1:
|
|
16
|
+
return np.exp(1j * mu * t - c * np.abs(t) * (1 + 1j * beta * np.sign(t) * np.log(np.abs(t))))
|
|
17
|
+
else:
|
|
18
|
+
return np.exp(1j * mu * t - c**alpha * np.abs(t)**alpha *
|
|
19
|
+
(1 - 1j * beta * np.sign(t) * np.tan(np.pi * alpha / 2)))
|
|
20
|
+
|
|
21
|
+
def _pdf(self, x, alpha, beta, c, mu):
|
|
22
|
+
if alpha == 2.0:
|
|
23
|
+
return norm.pdf(x, loc=mu, scale=c)
|
|
24
|
+
|
|
25
|
+
t = np.linspace(-50, 50, 1024)
|
|
26
|
+
x = np.atleast_1d(x)
|
|
27
|
+
results = np.zeros_like(x)
|
|
28
|
+
|
|
29
|
+
for i, xi in enumerate(x):
|
|
30
|
+
cf = self._char_func(t, alpha, beta, c, mu - xi)
|
|
31
|
+
dt = t[1] - t[0]
|
|
32
|
+
cf_sym = np.concatenate([cf, np.conj(cf[-1:0:-1])])
|
|
33
|
+
pdf_component = np.fft.ifft(cf_sym).real[:len(t)] * len(t) / (2 * np.pi)
|
|
34
|
+
results[i] = np.abs(pdf_component[0])
|
|
35
|
+
|
|
36
|
+
return np.maximum(results, 1e-10)
|
|
37
|
+
|
|
38
|
+
def fit(self) -> dict:
|
|
39
|
+
"""Fit using MLE. Returns dict with alpha, beta, c, mu."""
|
|
40
|
+
def neg_loglik(params):
|
|
41
|
+
alpha, beta, c, mu = params
|
|
42
|
+
if not (0.1 < alpha <= 2.0) or not (-1 <= beta <= 1) or c <= 0:
|
|
43
|
+
return 1e10
|
|
44
|
+
try:
|
|
45
|
+
pdf_vals = self._pdf(self.returns, alpha, beta, c, mu)
|
|
46
|
+
if np.any(pdf_vals <= 0):
|
|
47
|
+
return 1e10
|
|
48
|
+
return -np.sum(np.log(pdf_vals))
|
|
49
|
+
except:
|
|
50
|
+
return 1e10
|
|
51
|
+
|
|
52
|
+
mu0 = np.mean(self.returns)
|
|
53
|
+
c0 = np.std(self.returns) / np.sqrt(2)
|
|
54
|
+
alpha0 = 1.8
|
|
55
|
+
beta0 = 0.0
|
|
56
|
+
x0 = np.array([alpha0, beta0, c0, mu0])
|
|
57
|
+
bounds = [(0.1, 2.0), (-0.999, 0.999), (1e-6, 10.0), (None, None)]
|
|
58
|
+
|
|
59
|
+
res = minimize(neg_loglik, x0, method='Nelder-Mead',
|
|
60
|
+
options={'maxiter': 500, 'xatol': 1e-6, 'fatol': 1e-6})
|
|
61
|
+
|
|
62
|
+
alpha, beta, c, mu = res.x
|
|
63
|
+
self.params = {'alpha': alpha, 'beta': beta, 'c': c, 'mu': mu}
|
|
64
|
+
return self.params
|
|
65
|
+
|
|
66
|
+
def pdf(self, x: np.ndarray) -> np.ndarray:
|
|
67
|
+
if not self.params:
|
|
68
|
+
self.fit()
|
|
69
|
+
params = self.params
|
|
70
|
+
return self._pdf(x, params['alpha'], params['beta'], params['c'], params['mu'])
|
|
71
|
+
|
|
72
|
+
def cdf(self, x: np.ndarray) -> np.ndarray:
|
|
73
|
+
if not self.params:
|
|
74
|
+
self.fit()
|
|
75
|
+
x = np.atleast_1d(x)
|
|
76
|
+
results = np.zeros_like(x)
|
|
77
|
+
for i, xi in enumerate(x):
|
|
78
|
+
results[i], _ = quad(lambda xx: self.pdf(np.array([xx]))[0], -np.inf, xi)
|
|
79
|
+
return results
|
|
80
|
+
|
|
81
|
+
def ppf(self, q: np.ndarray) -> np.ndarray:
|
|
82
|
+
if not self.params:
|
|
83
|
+
self.fit()
|
|
84
|
+
q = np.atleast_1d(q)
|
|
85
|
+
results = np.zeros_like(q)
|
|
86
|
+
for i, qi in enumerate(q):
|
|
87
|
+
def f(x):
|
|
88
|
+
return self.cdf(np.array([x]))[0] - qi
|
|
89
|
+
results[i] = brentq(f, -10, 10)
|
|
90
|
+
return results
|
|
91
|
+
|
|
92
|
+
def es(self, alpha: float) -> float:
|
|
93
|
+
if not (0 < alpha < 1):
|
|
94
|
+
raise ValueError("Alpha must be between 0 and 1")
|
|
95
|
+
if not self.params:
|
|
96
|
+
self.fit()
|
|
97
|
+
var = self.var(alpha)
|
|
98
|
+
|
|
99
|
+
def integrand(x):
|
|
100
|
+
return x * self.pdf(np.array([x]))[0]
|
|
101
|
+
|
|
102
|
+
es_val, _ = quad(integrand, -np.inf, var)
|
|
103
|
+
return es_val / alpha
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Base class for distribution fitters."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DistributionFitter(ABC):
|
|
8
|
+
"""Abstract base class for distribution fitting."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, returns: np.ndarray):
|
|
11
|
+
returns = np.array(returns, dtype=np.float64).flatten()
|
|
12
|
+
if not np.isfinite(returns).all():
|
|
13
|
+
raise ValueError("Returns must be finite (no NaN or Inf)")
|
|
14
|
+
if len(returns) == 0:
|
|
15
|
+
raise ValueError("Returns cannot be empty")
|
|
16
|
+
self.returns = returns
|
|
17
|
+
self.params = {}
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def fit(self) -> dict:
|
|
21
|
+
"""Fit distribution and return parameters."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def pdf(self, x: np.ndarray) -> np.ndarray:
|
|
26
|
+
"""Probability density function."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def cdf(self, x: np.ndarray) -> np.ndarray:
|
|
31
|
+
"""Cumulative distribution function."""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def ppf(self, q: np.ndarray) -> np.ndarray:
|
|
36
|
+
"""Percent point function (inverse CDF)."""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def es(self, alpha: float) -> float:
|
|
41
|
+
"""Expected Shortfall at significance level alpha."""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def var(self, alpha: float) -> float:
|
|
45
|
+
"""Value at Risk (quantile) at significance level alpha."""
|
|
46
|
+
if not (0 < alpha < 1):
|
|
47
|
+
raise ValueError("Alpha must be between 0 and 1")
|
|
48
|
+
return self.ppf(np.array([alpha]))[0]
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Main fit function."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from .student_t import StudentT
|
|
5
|
+
from .alpha_stable import AlphaStable
|
|
6
|
+
from .normal_inverse_gaussian import NormalInverseGaussian
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
MODEL_MAP = {
|
|
10
|
+
'student_t': StudentT,
|
|
11
|
+
'alpha_stable': AlphaStable,
|
|
12
|
+
'nig': NormalInverseGaussian,
|
|
13
|
+
'normal_inverse_gaussian': NormalInverseGaussian
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def load_returns(data, column=None):
|
|
18
|
+
"""Load and validate returns from various input types."""
|
|
19
|
+
try:
|
|
20
|
+
import polars as pl
|
|
21
|
+
except ImportError:
|
|
22
|
+
raise ImportError("Polars is required for DataFrame/CSV support. Install with: pip install polars")
|
|
23
|
+
|
|
24
|
+
if isinstance(data, str):
|
|
25
|
+
df = pl.read_csv(data)
|
|
26
|
+
if column is None:
|
|
27
|
+
numeric_cols = [col for col, dtype in df.schema.items()
|
|
28
|
+
if dtype in [pl.Float64, pl.Float32, pl.Int64, pl.Int32]]
|
|
29
|
+
if len(numeric_cols) == 1:
|
|
30
|
+
column = numeric_cols[0]
|
|
31
|
+
else:
|
|
32
|
+
raise ValueError("Multiple numeric columns found. Specify column parameter.")
|
|
33
|
+
returns = df[column].to_numpy()
|
|
34
|
+
elif hasattr(data, 'to_numpy'):
|
|
35
|
+
if column is None:
|
|
36
|
+
numeric_cols = [col for col, dtype in data.schema.items()
|
|
37
|
+
if dtype in [pl.Float64, pl.Float32, pl.Int64, pl.Int32]]
|
|
38
|
+
if len(numeric_cols) == 1:
|
|
39
|
+
column = numeric_cols[0]
|
|
40
|
+
else:
|
|
41
|
+
raise ValueError("Multiple numeric columns found. Specify column parameter.")
|
|
42
|
+
returns = data[column].to_numpy()
|
|
43
|
+
elif isinstance(data, np.ndarray):
|
|
44
|
+
returns = data.flatten()
|
|
45
|
+
elif isinstance(data, list):
|
|
46
|
+
returns = np.array(data)
|
|
47
|
+
else:
|
|
48
|
+
raise TypeError(f"Unsupported data type: {type(data)}")
|
|
49
|
+
|
|
50
|
+
returns = returns.astype(np.float64)
|
|
51
|
+
if not np.isfinite(returns).all():
|
|
52
|
+
raise ValueError("Returns contain non-finite values (NaN or Inf)")
|
|
53
|
+
if len(returns) == 0:
|
|
54
|
+
raise ValueError("Returns cannot be empty")
|
|
55
|
+
|
|
56
|
+
return returns
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def fit(data, column=None, model='student_t'):
|
|
60
|
+
"""Fit a single distribution model to returns data.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
data : str, DataFrame, np.ndarray, or list
|
|
65
|
+
Returns data
|
|
66
|
+
column : str, optional
|
|
67
|
+
Column name if data is DataFrame or CSV
|
|
68
|
+
model : str
|
|
69
|
+
Model to fit: 'student_t', 'alpha_stable', 'nig'
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
DistributionFitter
|
|
74
|
+
Fitted distribution object
|
|
75
|
+
"""
|
|
76
|
+
returns = load_returns(data, column)
|
|
77
|
+
model_name = model.lower()
|
|
78
|
+
|
|
79
|
+
if model_name not in MODEL_MAP:
|
|
80
|
+
raise ValueError(f"Unknown model: {model}. Available: {list(MODEL_MAP.keys())}")
|
|
81
|
+
|
|
82
|
+
ModelClass = MODEL_MAP[model_name]
|
|
83
|
+
instance = ModelClass(returns)
|
|
84
|
+
instance.fit()
|
|
85
|
+
|
|
86
|
+
return instance
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Normal-Inverse Gaussian distribution."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.optimize import minimize
|
|
5
|
+
from scipy.special import kv as bessel_k
|
|
6
|
+
from scipy.integrate import quad
|
|
7
|
+
from scipy.optimize import brentq
|
|
8
|
+
from .base import DistributionFitter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class NormalInverseGaussian(DistributionFitter):
|
|
12
|
+
"""Normal-Inverse Gaussian distribution."""
|
|
13
|
+
|
|
14
|
+
def _pdf(self, x, alpha, beta, delta, mu):
|
|
15
|
+
gamma = np.sqrt(alpha**2 - beta**2)
|
|
16
|
+
z = (x - mu) / delta
|
|
17
|
+
factor = alpha * delta * np.sqrt(1 + z**2)
|
|
18
|
+
numerator = alpha * delta * bessel_k(1, factor)
|
|
19
|
+
denominator = np.pi * np.sqrt(1 + z**2)
|
|
20
|
+
return (numerator / denominator) * np.exp(delta * gamma + beta * (x - mu))
|
|
21
|
+
|
|
22
|
+
def fit(self) -> dict:
|
|
23
|
+
"""Fit using MLE. Returns dict with alpha, beta, delta, mu."""
|
|
24
|
+
def neg_loglik(params):
|
|
25
|
+
alpha, beta, delta, mu = params
|
|
26
|
+
if alpha <= 0 or delta <= 0 or abs(beta) >= alpha:
|
|
27
|
+
return 1e10
|
|
28
|
+
try:
|
|
29
|
+
pdf_vals = self._pdf(self.returns, alpha, beta, delta, mu)
|
|
30
|
+
return -np.sum(np.log(pdf_vals))
|
|
31
|
+
except:
|
|
32
|
+
return 1e10
|
|
33
|
+
|
|
34
|
+
mu0 = np.mean(self.returns)
|
|
35
|
+
delta0 = np.std(self.returns) * 0.8
|
|
36
|
+
alpha0 = 2.0
|
|
37
|
+
beta0 = 0.0
|
|
38
|
+
x0 = np.array([alpha0, beta0, delta0, mu0])
|
|
39
|
+
bounds = [(1e-4, 50), (-49, 49), (1e-4, 50), (None, None)]
|
|
40
|
+
|
|
41
|
+
res = minimize(neg_loglik, x0, method='SLSQP', bounds=bounds,
|
|
42
|
+
options={'ftol': 1e-8, 'maxiter': 1000})
|
|
43
|
+
|
|
44
|
+
alpha, beta, delta, mu = res.x
|
|
45
|
+
self.params = {'alpha': alpha, 'beta': beta, 'delta': delta, 'mu': mu,
|
|
46
|
+
'gamma': np.sqrt(alpha**2 - beta**2)}
|
|
47
|
+
return self.params
|
|
48
|
+
|
|
49
|
+
def pdf(self, x: np.ndarray) -> np.ndarray:
|
|
50
|
+
if not self.params:
|
|
51
|
+
self.fit()
|
|
52
|
+
return self._pdf(x, **{k: self.params[k] for k in ['alpha', 'beta', 'delta', 'mu']})
|
|
53
|
+
|
|
54
|
+
def cdf(self, x: np.ndarray) -> np.ndarray:
|
|
55
|
+
if not self.params:
|
|
56
|
+
self.fit()
|
|
57
|
+
results = np.zeros_like(x)
|
|
58
|
+
for i, xi in enumerate(x):
|
|
59
|
+
results[i], _ = quad(lambda xx: self.pdf(np.array([xx]))[0], -np.inf, xi)
|
|
60
|
+
return results
|
|
61
|
+
|
|
62
|
+
def ppf(self, q: np.ndarray) -> np.ndarray:
|
|
63
|
+
if not self.params:
|
|
64
|
+
self.fit()
|
|
65
|
+
results = np.zeros_like(q)
|
|
66
|
+
for i, qi in enumerate(q):
|
|
67
|
+
def f(x):
|
|
68
|
+
return self.cdf(np.array([x]))[0] - qi
|
|
69
|
+
results[i] = brentq(f, -10, 10)
|
|
70
|
+
return results
|
|
71
|
+
|
|
72
|
+
def es(self, alpha: float) -> float:
|
|
73
|
+
if not (0 < alpha < 1):
|
|
74
|
+
raise ValueError("Alpha must be between 0 and 1")
|
|
75
|
+
if not self.params:
|
|
76
|
+
self.fit()
|
|
77
|
+
var = self.var(alpha)
|
|
78
|
+
|
|
79
|
+
def integrand(x):
|
|
80
|
+
return x * self.pdf(np.array([x]))[0]
|
|
81
|
+
|
|
82
|
+
es_val, _ = quad(integrand, -np.inf, var)
|
|
83
|
+
return es_val / alpha
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Student's T distribution."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.stats import t as student_t
|
|
5
|
+
from scipy.integrate import quad
|
|
6
|
+
from .base import DistributionFitter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StudentT(DistributionFitter):
|
|
10
|
+
"""Student's T distribution."""
|
|
11
|
+
|
|
12
|
+
def fit(self) -> dict:
|
|
13
|
+
"""Fit using MLE. Returns dict with df, loc, scale."""
|
|
14
|
+
df, loc, scale = student_t.fit(self.returns)
|
|
15
|
+
self.params = {'df': df, 'loc': loc, 'scale': scale}
|
|
16
|
+
return self.params
|
|
17
|
+
|
|
18
|
+
def pdf(self, x: np.ndarray) -> np.ndarray:
|
|
19
|
+
if not self.params:
|
|
20
|
+
self.fit()
|
|
21
|
+
return student_t.pdf(x, **self.params)
|
|
22
|
+
|
|
23
|
+
def cdf(self, x: np.ndarray) -> np.ndarray:
|
|
24
|
+
if not self.params:
|
|
25
|
+
self.fit()
|
|
26
|
+
return student_t.cdf(x, **self.params)
|
|
27
|
+
|
|
28
|
+
def ppf(self, q: np.ndarray) -> np.ndarray:
|
|
29
|
+
if not self.params:
|
|
30
|
+
self.fit()
|
|
31
|
+
return student_t.ppf(q, **self.params)
|
|
32
|
+
|
|
33
|
+
def es(self, alpha: float) -> float:
|
|
34
|
+
if not (0 < alpha < 1):
|
|
35
|
+
raise ValueError("Alpha must be between 0 and 1")
|
|
36
|
+
if not self.params:
|
|
37
|
+
self.fit()
|
|
38
|
+
var = self.var(alpha)
|
|
39
|
+
|
|
40
|
+
def integrand(x):
|
|
41
|
+
return x * self.pdf(np.array([x]))[0]
|
|
42
|
+
|
|
43
|
+
es_val, _ = quad(integrand, -np.inf, var)
|
|
44
|
+
return es_val / alpha
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyreto
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Tail risk management library
|
|
5
|
+
Author-email: Developer <dev@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: numpy>=1.20.0
|
|
10
|
+
Requires-Dist: scipy>=1.7.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
13
|
+
|
|
14
|
+
# pyreto
|
|
15
|
+
|
|
16
|
+
Tail risk management library.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install pyreto
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires: numpy, scipy
|
|
25
|
+
Optional: polars (for CSV/DataFrame support)
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import pyreto
|
|
31
|
+
|
|
32
|
+
# Fit Student's T distribution
|
|
33
|
+
model = pyreto.dist.fit('returns.csv', column='daily_return', model='student_t')
|
|
34
|
+
|
|
35
|
+
# Calculate 1% Expected Shortfall
|
|
36
|
+
es_1 = model.es(0.01)
|
|
37
|
+
|
|
38
|
+
# Calculate 5% Value at Risk
|
|
39
|
+
var_5 = model.var(0.05)
|
|
40
|
+
|
|
41
|
+
# Get fitted parameters
|
|
42
|
+
params = model.params
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Models
|
|
46
|
+
|
|
47
|
+
- `student_t`: Student's T distribution (recommended)
|
|
48
|
+
- `alpha_stable`: Alpha stable distribution (flexible, slower)
|
|
49
|
+
- `nig`: Normal-inverse Gaussian (good middle ground)
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
All models support:
|
|
54
|
+
- `fit()` - Fit parameters
|
|
55
|
+
- `pdf(x)` - Density function
|
|
56
|
+
- `cdf(x)` - Distribution function
|
|
57
|
+
- `ppf(q)` - Quantile function
|
|
58
|
+
- `var(alpha)` - Value at Risk
|
|
59
|
+
- `es(alpha)` - Expected Shortfall
|
|
60
|
+
- `params` - Fitted parameters dict
|
|
61
|
+
|
|
62
|
+
## Example
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import numpy as np
|
|
66
|
+
import pyreto
|
|
67
|
+
|
|
68
|
+
# Generate heavy-tailed returns
|
|
69
|
+
returns = np.random.standard_t(3, 1000) * 0.01
|
|
70
|
+
|
|
71
|
+
# Fit and calculate tail risk
|
|
72
|
+
model = pyreto.dist.fit(returns, model='student_t')
|
|
73
|
+
print(f"5% VaR: {model.var(0.05):.4f}")
|
|
74
|
+
print(f"5% ES: {model.es(0.05):.4f}")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Error Handling
|
|
78
|
+
|
|
79
|
+
The library fails loudly on invalid inputs:
|
|
80
|
+
- Non-finite values (NaN, Inf) throw `ValueError`
|
|
81
|
+
- Invalid alpha values throw `ValueError`
|
|
82
|
+
- Missing parameters throw `ValueError`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
pyreto/__init__.py,sha256=yfQfScj6LZ9z_4kj9FUhYz5m5msxEcg3KW7ZQN0z44U,117
|
|
2
|
+
pyreto/distributions/__init__.py,sha256=11IhaYFDoth3-b_HbMHT1nG4ZUmMpE6wgz8yLUE3eZI,250
|
|
3
|
+
pyreto/distributions/alpha_stable.py,sha256=f5yktEuCPdHosY7FwaNvbrINec5JK6PQ_EPiwFBt9p8,3622
|
|
4
|
+
pyreto/distributions/base.py,sha256=uBG6ksORlwBs1Tx3aJpDS0qlUp-GP7jhQRMzSLoW-WU,1474
|
|
5
|
+
pyreto/distributions/fit.py,sha256=QAXixS7dAHmR1IMLtRQ_eX7ZkSDGcLyNZi6I6myjzFQ,2795
|
|
6
|
+
pyreto/distributions/normal_inverse_gaussian.py,sha256=0phdT1BFucX58Ps34JfeyWL18m3OuW_dosYjMwmLAog,2964
|
|
7
|
+
pyreto/distributions/student_t.py,sha256=WQdHxVHBn6AJKE3RkwfbaEU_cQug6Neoqg2TdicHIII,1318
|
|
8
|
+
pyreto-0.2.0.dist-info/METADATA,sha256=ujtd_zw9UyLRql6x3caPjgvNVReNduIXztl1JZJbLBw,1732
|
|
9
|
+
pyreto-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
+
pyreto-0.2.0.dist-info/top_level.txt,sha256=W3ftAjmrhZHXGDjIYS5P1eimmjeytWJ2FsSnViAyAGs,7
|
|
11
|
+
pyreto-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyreto
|