summaryrefslogtreecommitdiff
path: root/services/backtester/tests/test_metrics.py
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 18:25:29 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 18:25:29 +0900
commit5cee0686e421b1f21484c23e413692616e9e2ffa (patch)
tree0a6343ebeca158d5881c57cb71e9f67800fda535 /services/backtester/tests/test_metrics.py
parent7bfdf07dccb09a613f66f63d1513b80f167a3881 (diff)
feat(backtester): Phase 1 complete — realistic backtesting engine
- Slippage modeling (configurable per-trade, buy higher/sell lower) - Trading fee deduction (maker/taker configurable) - Stop-loss and take-profit auto-execution per position - Short selling support (allow_short flag) - Walk-forward analysis engine (in-sample/out-of-sample, efficiency ratio) - Daily equity curve Sharpe/Sortino with risk-free rate adjustment - Recovery factor, consecutive win/loss streaks, fee-aware PnL - 312 tests passing
Diffstat (limited to 'services/backtester/tests/test_metrics.py')
-rw-r--r--services/backtester/tests/test_metrics.py68
1 files changed, 57 insertions, 11 deletions
diff --git a/services/backtester/tests/test_metrics.py b/services/backtester/tests/test_metrics.py
index 34314b3..582309a 100644
--- a/services/backtester/tests/test_metrics.py
+++ b/services/backtester/tests/test_metrics.py
@@ -111,11 +111,11 @@ def test_consecutive_losses():
"""Consecutive loss tracking should count streaks correctly."""
trades = [
_make_trade("BUY", "100", 0),
- _make_trade("SELL", "110", 10), # win
+ _make_trade("SELL", "110", 10), # win
_make_trade("BUY", "110", 20),
- _make_trade("SELL", "105", 30), # loss
+ _make_trade("SELL", "105", 30), # loss
_make_trade("BUY", "105", 40),
- _make_trade("SELL", "100", 50), # loss
+ _make_trade("SELL", "100", 50), # loss
]
metrics = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10005"))
assert metrics.max_consecutive_losses >= 1
@@ -126,12 +126,44 @@ def test_risk_free_rate_affects_sharpe():
"""Higher risk-free rate should lower Sharpe ratio."""
base = datetime(2025, 1, 1, tzinfo=timezone.utc)
trades = [
- TradeRecord(time=base, symbol="BTCUSDT", side="BUY", price=Decimal("100"), quantity=Decimal("1")),
- TradeRecord(time=base + timedelta(days=1), symbol="BTCUSDT", side="SELL", price=Decimal("110"), quantity=Decimal("1")),
- TradeRecord(time=base + timedelta(days=2), symbol="BTCUSDT", side="BUY", price=Decimal("105"), quantity=Decimal("1")),
- TradeRecord(time=base + timedelta(days=3), symbol="BTCUSDT", side="SELL", price=Decimal("115"), quantity=Decimal("1")),
- TradeRecord(time=base + timedelta(days=4), symbol="BTCUSDT", side="BUY", price=Decimal("110"), quantity=Decimal("1")),
- TradeRecord(time=base + timedelta(days=5), symbol="BTCUSDT", side="SELL", price=Decimal("108"), quantity=Decimal("1")),
+ TradeRecord(
+ time=base, symbol="BTCUSDT", side="BUY", price=Decimal("100"), quantity=Decimal("1")
+ ),
+ TradeRecord(
+ time=base + timedelta(days=1),
+ symbol="BTCUSDT",
+ side="SELL",
+ price=Decimal("110"),
+ quantity=Decimal("1"),
+ ),
+ TradeRecord(
+ time=base + timedelta(days=2),
+ symbol="BTCUSDT",
+ side="BUY",
+ price=Decimal("105"),
+ quantity=Decimal("1"),
+ ),
+ TradeRecord(
+ time=base + timedelta(days=3),
+ symbol="BTCUSDT",
+ side="SELL",
+ price=Decimal("115"),
+ quantity=Decimal("1"),
+ ),
+ TradeRecord(
+ time=base + timedelta(days=4),
+ symbol="BTCUSDT",
+ side="BUY",
+ price=Decimal("110"),
+ quantity=Decimal("1"),
+ ),
+ TradeRecord(
+ time=base + timedelta(days=5),
+ symbol="BTCUSDT",
+ side="SELL",
+ price=Decimal("108"),
+ quantity=Decimal("1"),
+ ),
]
m1 = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10018"), risk_free_rate=0.0)
m2 = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10018"), risk_free_rate=0.10)
@@ -154,8 +186,22 @@ def test_fee_subtracted_from_pnl():
"""Fees should be subtracted from trade PnL."""
base = datetime(2025, 1, 1, tzinfo=timezone.utc)
trades_with_fees = [
- TradeRecord(time=base, symbol="BTC", side="BUY", price=Decimal("100"), quantity=Decimal("1"), fee=Decimal("1")),
- TradeRecord(time=base + timedelta(minutes=10), symbol="BTC", side="SELL", price=Decimal("110"), quantity=Decimal("1"), fee=Decimal("1")),
+ TradeRecord(
+ time=base,
+ symbol="BTC",
+ side="BUY",
+ price=Decimal("100"),
+ quantity=Decimal("1"),
+ fee=Decimal("1"),
+ ),
+ TradeRecord(
+ time=base + timedelta(minutes=10),
+ symbol="BTC",
+ side="SELL",
+ price=Decimal("110"),
+ quantity=Decimal("1"),
+ fee=Decimal("1"),
+ ),
]
# PnL should be 10 - 1 - 1 = 8
metrics = compute_detailed_metrics(trades_with_fees, Decimal("10000"), Decimal("10008"))