Files
arbitrade/tests/unit/test_stat_arb_experiment.py
T
zwitschi 38e1d64437
CI / lint-test-build (push) Successful in 2m31s
feat: add backtesting functionality with UI and API endpoints
- Introduced backtesting page and fragment in the dashboard for running backtests and viewing recent reports.
- Implemented backtest run logic with configuration options including event path, starting balances, trade capital, and fee profiles.
- Added recent backtest reports storage and retrieval.
- Created a new strategy module for statistical arbitrage experiments with validation on configuration parameters.
- Updated settings to include parameters for the statistical arbitrage strategy.
- Enhanced dashboard controls to support the new strategy mode.
- Added unit tests for backtesting functionality and strategy validation.
- Updated templates for backtesting UI integration.
2026-06-02 09:28:22 +02:00

67 lines
2.0 KiB
Python

from __future__ import annotations
from datetime import UTC, datetime, timedelta
from arbitrade.strategy.stat_arb import StatArbExperiment, StatArbExperimentConfig
def test_stat_arb_experiment_warmup_then_entry_and_exit() -> None:
started_at = datetime(2026, 6, 2, 12, 0, tzinfo=UTC)
experiment = StatArbExperiment(
StatArbExperimentConfig(
pair_a="BTC/USD",
pair_b="ETH/USD",
lookback_window=5,
entry_zscore=1.5,
exit_zscore=0.2,
max_holding_seconds=0.5,
)
)
# Warmup with nearly stationary spread around 0.
for idx in range(5):
signal = experiment.observe(
price_a=100.0 + (0.02 * idx),
price_b=100.0,
observed_at=started_at + timedelta(seconds=idx),
)
assert signal.action in {"warmup", "hold"}
# Large positive spread should trigger short-spread entry.
entry = experiment.observe(
price_a=104.0,
price_b=100.0,
observed_at=started_at + timedelta(seconds=10),
)
assert entry.action == "enter_short_spread"
assert entry.position == "short"
assert entry.zscore is not None
# Mean reversion toward center should trigger exit.
exit_signal = experiment.observe(
price_a=100.05,
price_b=100.0,
observed_at=started_at + timedelta(seconds=11),
)
assert exit_signal.action == "exit_position"
assert exit_signal.position == "flat"
def test_stat_arb_experiment_rejects_invalid_prices() -> None:
experiment = StatArbExperiment(
StatArbExperimentConfig(
pair_a="BTC/USD",
pair_b="ETH/USD",
lookback_window=5,
)
)
at = datetime(2026, 6, 2, 12, 0, tzinfo=UTC)
try:
experiment.observe(price_a=0.0, price_b=100.0, observed_at=at)
except ValueError as exc:
assert "prices must be > 0" in str(exc)
else:
raise AssertionError("Expected ValueError for non-positive price")