42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from arbitrade.risk.trade_limits import TradeLimitsGuard
|
|
|
|
|
|
def test_trade_limits_guard_blocks_when_max_concurrent_reached() -> None:
|
|
guard = TradeLimitsGuard(max_concurrent_trades=1)
|
|
|
|
guard.open_trade({"BTC": 10.0})
|
|
|
|
assert not guard.is_trade_allowed({"BTC": 1.0})
|
|
|
|
|
|
def test_trade_limits_guard_blocks_when_asset_exposure_would_breach_cap() -> None:
|
|
guard = TradeLimitsGuard(max_exposure_per_asset=100.0)
|
|
|
|
guard.open_trade({"BTC": 80.0})
|
|
|
|
assert not guard.is_trade_allowed({"BTC": 25.0})
|
|
assert guard.is_trade_allowed({"ETH": 25.0})
|
|
|
|
|
|
def test_trade_limits_guard_releases_exposure_on_close() -> None:
|
|
guard = TradeLimitsGuard(max_concurrent_trades=2, max_exposure_per_asset=100.0)
|
|
|
|
guard.open_trade({"BTC": 80.0})
|
|
guard.close_trade({"BTC": 80.0})
|
|
|
|
assert guard.active_trades == 0
|
|
assert guard.exposure_for_asset("BTC") == 0.0
|
|
assert guard.is_trade_allowed({"BTC": 100.0})
|
|
|
|
|
|
def test_trade_limits_guard_rejects_invalid_configuration() -> None:
|
|
with pytest.raises(ValueError, match="max_concurrent_trades"):
|
|
TradeLimitsGuard(max_concurrent_trades=0)
|
|
|
|
with pytest.raises(ValueError, match="max_exposure_per_asset"):
|
|
TradeLimitsGuard(max_exposure_per_asset=0.0)
|