diff --git a/src/multi_swarm/agents/market_summary.py b/src/multi_swarm/agents/market_summary.py new file mode 100644 index 0000000..4c42117 --- /dev/null +++ b/src/multi_swarm/agents/market_summary.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import pandas as pd # type: ignore[import-untyped] +from scipy import stats # type: ignore[import-untyped] + +from .hypothesis import MarketSummary + + +def build_market_summary( + ohlcv: pd.DataFrame, + symbol: str, + timeframe: str, +) -> MarketSummary: + returns = ohlcv["close"].pct_change().dropna() + return_mean = float(returns.mean()) + return_std = float(returns.std(ddof=1)) + skew = float(stats.skew(returns, bias=False)) + kurt = float(stats.kurtosis(returns, fisher=True, bias=False)) + + if return_std < 0.005: + regime = "low" + elif return_std < 0.02: + regime = "medium" + else: + regime = "high" + + return MarketSummary( + symbol=symbol, + timeframe=timeframe, + n_bars=len(ohlcv), + return_mean=return_mean, + return_std=return_std, + skew=skew, + kurtosis=kurt, + volatility_regime=regime, + ) diff --git a/tests/unit/test_market_summary.py b/tests/unit/test_market_summary.py new file mode 100644 index 0000000..a89d640 --- /dev/null +++ b/tests/unit/test_market_summary.py @@ -0,0 +1,33 @@ +import numpy as np +import pandas as pd + +from multi_swarm.agents.market_summary import build_market_summary + + +def test_build_summary_basic() -> None: + idx = pd.date_range("2024-01-01", periods=200, freq="1h", tz="UTC") + np.random.seed(0) + close = 100 + np.cumsum(np.random.normal(0, 1, 200)) + df = pd.DataFrame( + {"open": close, "high": close + 0.5, "low": close - 0.5, "close": close, "volume": 1.0}, + index=idx, + ) + s = build_market_summary(df, symbol="BTC/USDT", timeframe="1h") + assert s.symbol == "BTC/USDT" + assert s.timeframe == "1h" + assert s.n_bars == 200 + assert isinstance(s.return_mean, float) + assert isinstance(s.return_std, float) + assert s.volatility_regime in {"low", "medium", "high"} + + +def test_volatility_regime_high_for_volatile() -> None: + idx = pd.date_range("2024-01-01", periods=200, freq="1h", tz="UTC") + np.random.seed(0) + close = 100 + np.cumsum(np.random.normal(0, 5.0, 200)) # alta vol + df = pd.DataFrame( + {"open": close, "high": close + 0.5, "low": close - 0.5, "close": close, "volume": 1.0}, + index=idx, + ) + s = build_market_summary(df, symbol="BTC/USDT", timeframe="1h") + assert s.volatility_regime in {"medium", "high"}