You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.7 KiB
Python

from __future__ import annotations
import datetime as dt
from types import SimpleNamespace
import pytest
from apps.web.routers import orb_trading
from libs.oracle_client.alpaca import AlpacaSnapshot
class _FakeORBState:
def __init__(self, positions: list[SimpleNamespace]) -> None:
self._positions = positions
def get_session(self, session_id: str) -> SimpleNamespace | None:
return SimpleNamespace(session_id=session_id, session_name="test")
def get_open_positions(self, session_id: str, date: str) -> list[SimpleNamespace]:
assert date == dt.date.today().isoformat()
return self._positions
def _position(
ticker: str,
*,
direction: str,
entry_price: float,
shares: int = 2,
) -> SimpleNamespace:
return SimpleNamespace(
ticker=ticker,
direction=direction,
entry_price=entry_price,
entry_time="2026-05-04T09:59:00-04:00",
shares=shares,
current_stop=entry_price * 0.95,
peak_price=entry_price,
trailing_active=False,
atr_at_entry=1.0,
stop_distance=5.0,
rvol=1.0,
composite_score=0.5,
)
def test_orb_positions_change_pct_is_position_return_not_day_change(monkeypatch: pytest.MonkeyPatch) -> None:
positions = [
_position("LONG", direction="long", entry_price=100.0),
_position("SHORT", direction="short", entry_price=100.0),
]
monkeypatch.setattr(orb_trading, "_state", lambda: _FakeORBState(positions))
def fake_snapshots(tickers: list[str]) -> dict[str, AlpacaSnapshot]:
assert tickers == ["LONG", "SHORT"]
return {
# Positive day change must not make a losing long look profitable.
"LONG": AlpacaSnapshot(ticker="LONG", price=95.0, change_pct=12.34),
# Negative day change must not make a winning short look losing.
"SHORT": AlpacaSnapshot(ticker="SHORT", price=95.0, change_pct=-7.89),
}
monkeypatch.setattr("libs.oracle_client.alpaca.get_snapshots", fake_snapshots)
result = orb_trading.get_positions("session-1")
by_ticker = {p["ticker"]: p for p in result["positions"]}
assert by_ticker["LONG"]["current_price"] == pytest.approx(95.0)
assert by_ticker["LONG"]["change_pct"] == pytest.approx(-5.0)
assert by_ticker["LONG"]["unrealized_pnl"] == pytest.approx(-10.0)
assert by_ticker["LONG"]["day_change_pct"] == pytest.approx(12.34)
assert by_ticker["SHORT"]["current_price"] == pytest.approx(95.0)
assert by_ticker["SHORT"]["change_pct"] == pytest.approx(5.0)
assert by_ticker["SHORT"]["unrealized_pnl"] == pytest.approx(10.0)
assert by_ticker["SHORT"]["day_change_pct"] == pytest.approx(-7.89)