File size: 3,126 Bytes
d53dc44 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | """
tests/test_order_manager.py — Order routing and management tests.
Covers:
- Fractional → 3-step flow
- Whole → bracket order routing
- DRY_RUN simulation
- Spread check threshold
- Limit price computation
"""
from __future__ import annotations
import datetime
from unittest.mock import patch, MagicMock
import pytest
from contracts import OrderRequest
from execution.order_manager import (
submit_order,
check_spread,
compute_limit_price,
)
@pytest.fixture
def buy_order():
return OrderRequest(
symbol="AAPL",
side="buy",
qty=10.0,
limit_price=150.50,
stop_price=148.00,
tp_price=155.00,
is_fractional=False,
dry_run=True,
)
@pytest.fixture
def fractional_order():
return OrderRequest(
symbol="AAPL",
side="buy",
qty=0.5,
limit_price=150.50,
stop_price=148.00,
tp_price=155.00,
is_fractional=True,
dry_run=True,
)
class TestOrderRouting:
def test_dry_run_whole_order(self, buy_order):
"""DRY_RUN whole-share order should return a simulated fill."""
result = submit_order(buy_order, alert_callback=lambda *a, **kw: None)
assert result is not None
def test_dry_run_fractional_order(self, fractional_order):
"""DRY_RUN fractional order should return a simulated fill."""
result = submit_order(fractional_order, alert_callback=lambda *a, **kw: None)
assert result is not None
class TestSpreadCheck:
def test_dry_run_spread_always_passes(self):
"""In DRY_RUN, spread check always passes."""
ok, bid, ask, spread_pct = check_spread("AAPL")
assert ok
@patch("execution.order_manager.config.DRY_RUN", False)
@patch("execution.order_manager.broker.get_latest_quote")
def test_acceptable_spread(self, mock_quote):
mock_quote.return_value = {"bp": 150.00, "ap": 150.10}
ok, bid, ask, spread_pct = check_spread("AAPL")
assert ok
assert spread_pct < 0.5 # 0.067% spread
@patch("execution.order_manager.config.DRY_RUN", False)
@patch("execution.order_manager.broker.get_latest_quote")
def test_wide_spread_rejected(self, mock_quote):
mock_quote.return_value = {"bp": 150.00, "ap": 155.00}
ok, bid, ask, spread_pct = check_spread("AAPL")
assert not ok
assert spread_pct > 0.5
class TestLimitPrice:
def test_buy_limit_within_spread(self):
price = compute_limit_price("buy", bid=150.00, ask=150.10)
assert price >= 150.00
assert price <= 150.10
def test_sell_limit_within_spread(self):
price = compute_limit_price("sell", bid=150.00, ask=150.10)
assert price >= 150.00
assert price <= 150.10
class TestDryRunSimulation:
def test_dry_run_returns_fill(self, buy_order):
buy_order.dry_run = True
result = submit_order(buy_order, alert_callback=lambda *a, **kw: None)
assert result is not None
|