summaryrefslogtreecommitdiff
path: root/services/backtester/tests/test_simulator.py
diff options
context:
space:
mode:
Diffstat (limited to 'services/backtester/tests/test_simulator.py')
-rw-r--r--services/backtester/tests/test_simulator.py53
1 files changed, 27 insertions, 26 deletions
diff --git a/services/backtester/tests/test_simulator.py b/services/backtester/tests/test_simulator.py
index a407c21..f85594f 100644
--- a/services/backtester/tests/test_simulator.py
+++ b/services/backtester/tests/test_simulator.py
@@ -1,11 +1,12 @@
"""Tests for the OrderSimulator."""
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from decimal import Decimal
-from shared.models import OrderSide, Signal
from backtester.simulator import OrderSimulator
+from shared.models import OrderSide, Signal
+
def make_signal(
symbol: str,
@@ -36,20 +37,20 @@ def test_simulator_initial_balance():
def test_simulator_buy_reduces_balance():
sim = OrderSimulator(Decimal("10000"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
result = sim.execute(signal)
assert result is True
assert sim.balance == Decimal("5000")
- assert sim.positions["BTCUSDT"] == Decimal("0.1")
+ assert sim.positions["AAPL"] == Decimal("0.1")
def test_simulator_sell_increases_balance():
sim = OrderSimulator(Decimal("10000"))
- buy_signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ buy_signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(buy_signal)
balance_after_buy = sim.balance
- sell_signal = make_signal("BTCUSDT", OrderSide.SELL, "55000", "0.1")
+ sell_signal = make_signal("AAPL", OrderSide.SELL, "55000", "0.1")
result = sim.execute(sell_signal)
assert result is True
assert sim.balance > balance_after_buy
@@ -59,20 +60,20 @@ def test_simulator_sell_increases_balance():
def test_simulator_reject_buy_insufficient_balance():
sim = OrderSimulator(Decimal("100"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
result = sim.execute(signal)
assert result is False
assert sim.balance == Decimal("100")
- assert sim.positions.get("BTCUSDT", Decimal("0")) == Decimal("0")
+ assert sim.positions.get("AAPL", Decimal("0")) == Decimal("0")
def test_simulator_trade_history():
sim = OrderSimulator(Decimal("10000"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal)
assert len(sim.trades) == 1
trade = sim.trades[0]
- assert trade.symbol == "BTCUSDT"
+ assert trade.symbol == "AAPL"
assert trade.side == OrderSide.BUY
assert trade.price == Decimal("50000")
assert trade.quantity == Decimal("0.1")
@@ -86,7 +87,7 @@ def test_simulator_trade_history():
def test_slippage_on_buy():
"""Buy price should increase by slippage_pct."""
sim = OrderSimulator(Decimal("100000"), slippage_pct=0.01) # 1%
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal)
trade = sim.trades[0]
expected_price = Decimal("50000") * Decimal("1.01") # 50500
@@ -97,10 +98,10 @@ def test_slippage_on_sell():
"""Sell price should decrease by slippage_pct."""
sim = OrderSimulator(Decimal("100000"), slippage_pct=0.01)
# Buy first (no slippage check here, just need a position)
- buy = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ buy = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(buy)
# Sell
- sell = make_signal("BTCUSDT", OrderSide.SELL, "50000", "0.1")
+ sell = make_signal("AAPL", OrderSide.SELL, "50000", "0.1")
sim.execute(sell)
trade = sim.trades[1]
expected_price = Decimal("50000") * Decimal("0.99") # 49500
@@ -116,7 +117,7 @@ def test_fee_deducted_from_balance():
"""Fees should reduce balance beyond the raw cost."""
fee_pct = 0.001 # 0.1%
sim = OrderSimulator(Decimal("100000"), taker_fee_pct=fee_pct)
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal)
# cost = 50000 * 0.1 = 5000, fee = 5000 * 0.001 = 5
expected_balance = Decimal("100000") - Decimal("5000") - Decimal("5")
@@ -132,10 +133,10 @@ def test_fee_deducted_from_balance():
def test_stop_loss_triggers():
"""Long position auto-closed when candle_low <= stop_loss."""
sim = OrderSimulator(Decimal("100000"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal, stop_loss=Decimal("48000"))
- ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
+ ts = datetime(2025, 1, 1, tzinfo=UTC)
closed = sim.check_stops(
candle_high=Decimal("50500"),
candle_low=Decimal("47500"), # below stop_loss
@@ -150,10 +151,10 @@ def test_stop_loss_triggers():
def test_take_profit_triggers():
"""Long position auto-closed when candle_high >= take_profit."""
sim = OrderSimulator(Decimal("100000"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal, take_profit=Decimal("55000"))
- ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
+ ts = datetime(2025, 1, 1, tzinfo=UTC)
closed = sim.check_stops(
candle_high=Decimal("56000"), # above take_profit
candle_low=Decimal("50000"),
@@ -168,10 +169,10 @@ def test_take_profit_triggers():
def test_stop_not_triggered_within_range():
"""No auto-close when price stays within stop/tp range."""
sim = OrderSimulator(Decimal("100000"))
- signal = make_signal("BTCUSDT", OrderSide.BUY, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.BUY, "50000", "0.1")
sim.execute(signal, stop_loss=Decimal("48000"), take_profit=Decimal("55000"))
- ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
+ ts = datetime(2025, 1, 1, tzinfo=UTC)
closed = sim.check_stops(
candle_high=Decimal("52000"),
candle_low=Decimal("49000"),
@@ -189,10 +190,10 @@ def test_stop_not_triggered_within_range():
def test_short_sell_allowed():
"""Can open short position with allow_short=True."""
sim = OrderSimulator(Decimal("100000"), allow_short=True)
- signal = make_signal("BTCUSDT", OrderSide.SELL, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.SELL, "50000", "0.1")
result = sim.execute(signal)
assert result is True
- assert sim.positions["BTCUSDT"] == Decimal("-0.1")
+ assert sim.positions["AAPL"] == Decimal("-0.1")
assert len(sim.open_positions) == 1
assert sim.open_positions[0].side == OrderSide.SELL
@@ -200,19 +201,19 @@ def test_short_sell_allowed():
def test_short_sell_rejected():
"""Short rejected when allow_short=False (default)."""
sim = OrderSimulator(Decimal("100000"), allow_short=False)
- signal = make_signal("BTCUSDT", OrderSide.SELL, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.SELL, "50000", "0.1")
result = sim.execute(signal)
assert result is False
- assert sim.positions.get("BTCUSDT", Decimal("0")) == Decimal("0")
+ assert sim.positions.get("AAPL", Decimal("0")) == Decimal("0")
def test_short_stop_loss():
"""Short position stop-loss triggers on candle high >= stop_loss."""
sim = OrderSimulator(Decimal("100000"), allow_short=True)
- signal = make_signal("BTCUSDT", OrderSide.SELL, "50000", "0.1")
+ signal = make_signal("AAPL", OrderSide.SELL, "50000", "0.1")
sim.execute(signal, stop_loss=Decimal("52000"))
- ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
+ ts = datetime(2025, 1, 1, tzinfo=UTC)
closed = sim.check_stops(
candle_high=Decimal("53000"), # above stop_loss
candle_low=Decimal("49000"),