86 lines
2.7 KiB
Python
86 lines
2.7 KiB
Python
|
|
"""Tests for slippage model."""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from decimal import Decimal
|
||
|
|
from src.backtesting.slippage import SlippageModel, FeeModel
|
||
|
|
|
||
|
|
|
||
|
|
class TestSlippageModel:
|
||
|
|
"""Tests for SlippageModel."""
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def slippage_model(self):
|
||
|
|
"""Create slippage model."""
|
||
|
|
return SlippageModel(slippage_rate=0.001)
|
||
|
|
|
||
|
|
def test_calculate_fill_price_market_buy(self, slippage_model):
|
||
|
|
"""Test fill price calculation for market buy."""
|
||
|
|
order_price = Decimal('50000.0')
|
||
|
|
market_price = Decimal('50000.0')
|
||
|
|
|
||
|
|
fill_price = slippage_model.calculate_fill_price(
|
||
|
|
order_price, "buy", "market", market_price
|
||
|
|
)
|
||
|
|
|
||
|
|
assert fill_price > market_price # Buy orders pay more
|
||
|
|
|
||
|
|
def test_calculate_fill_price_market_sell(self, slippage_model):
|
||
|
|
"""Test fill price calculation for market sell."""
|
||
|
|
order_price = Decimal('50000.0')
|
||
|
|
market_price = Decimal('50000.0')
|
||
|
|
|
||
|
|
fill_price = slippage_model.calculate_fill_price(
|
||
|
|
order_price, "sell", "market", market_price
|
||
|
|
)
|
||
|
|
|
||
|
|
assert fill_price < market_price # Sell orders receive less
|
||
|
|
|
||
|
|
def test_calculate_fill_price_limit(self, slippage_model):
|
||
|
|
"""Test fill price for limit orders."""
|
||
|
|
order_price = Decimal('49000.0')
|
||
|
|
market_price = Decimal('50000.0')
|
||
|
|
|
||
|
|
fill_price = slippage_model.calculate_fill_price(
|
||
|
|
order_price, "buy", "limit", market_price
|
||
|
|
)
|
||
|
|
|
||
|
|
assert fill_price == order_price # Limit orders fill at order price
|
||
|
|
|
||
|
|
|
||
|
|
class TestFeeModel:
|
||
|
|
"""Tests for FeeModel."""
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def fee_model(self):
|
||
|
|
"""Create fee model."""
|
||
|
|
return FeeModel(maker_fee=0.001, taker_fee=0.002)
|
||
|
|
|
||
|
|
def test_calculate_fee_maker(self, fee_model):
|
||
|
|
"""Test maker fee calculation."""
|
||
|
|
fee = fee_model.calculate_fee(
|
||
|
|
quantity=Decimal('0.01'),
|
||
|
|
price=Decimal('50000.0'),
|
||
|
|
is_maker=True
|
||
|
|
)
|
||
|
|
|
||
|
|
assert fee > 0
|
||
|
|
# Fee should be 0.1% of trade value
|
||
|
|
expected = Decimal('0.01') * Decimal('50000.0') * Decimal('0.001')
|
||
|
|
assert abs(float(fee - expected)) < 0.01
|
||
|
|
|
||
|
|
def test_calculate_fee_taker(self, fee_model):
|
||
|
|
"""Test taker fee calculation."""
|
||
|
|
fee = fee_model.calculate_fee(
|
||
|
|
quantity=Decimal('0.01'),
|
||
|
|
price=Decimal('50000.0'),
|
||
|
|
is_maker=False
|
||
|
|
)
|
||
|
|
|
||
|
|
assert fee > 0
|
||
|
|
# Taker fee should be higher than maker
|
||
|
|
maker_fee = fee_model.calculate_fee(
|
||
|
|
Decimal('0.01'), Decimal('50000.0'), is_maker=True
|
||
|
|
)
|
||
|
|
assert fee > maker_fee
|
||
|
|
|