Files
AH-Oil-Trader/tests/test_pending_fill.py
T
Axel HocksandClaude Opus 5 bf7e382818 Auto-Signal-Entry (SIG) komplett entfernt inkl. Button (v=166)
User-Entscheidung. Der Pfad war seit 01.08. aus und auf BEIDEN
Ausfuehrungs-Achsen gemessen negativ: Markt-Einstieg in allen 8
Feldern, ruhende Order mit Touch-Fill -0,392/-0,338 in allen 6 und
damit sogar schlechter als Markt. Die +0,35/+0,32 aus
backtest_auto_signal_v3.py galten in Variante B (Fill beim
Close-Bruch) und waren Look-ahead - Aufschlag 0,77-0,85 R. Ursache
strukturell: das Bestaetigungs-Level _pend WANDERT.

Nebenbei entfaellt der offene Churn-Defekt (4x setzen/stornieren in
76 s bei identischem Level, gefunden 06.08., nie behoben).

Entfernt: _check_auto_signal, set_auto_signal, der Signal-Zweig in
_pending_ziel, /api/autosignal, Button + Handler, vier Snapshot-Felder,
die auto_signal*/signal_pending_entry-Leser.
Geblieben: AUTOSIG_*-Trades in der DB, die Backtests, wave_rec.breakout
(speist block_reason) und _confirm_breakout selbst.
Sicherung: .removed_backup/auto_signal_2026-08-12.py + Git.

Das Risiko war nicht SIG, sondern der GETEILTE Pending-Manager (zwei
getrennte Manager wuerden sich gegenseitig stornieren). Deshalb wurde
das Squeeze-Verhalten VOR dem Eingriff in tests/test_pending_ziel.py
festgenagelt - 7 Tests, vorher gruen, laufen unveraendert weiter.

Zwei Folgefehler fing die Pruefkette sofort: ruff F821 ein verwaistes
_t, py_compile ein dangling if. Zwei Tests wurden mitgezogen statt
geloescht - test_signal_fill_long ist jetzt umgedreht (unbekannte
Quelle darf NICHT als Squeeze durchgehen).

Live verifiziert: alle vier Snapshot-Felder weg, Endpunkt tot,
auto_squeeze/squeeze_pending unveraendert, 67 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 18:47:28 +02:00

85 lines
3.6 KiB
Python

"""`engine._check_pending_fill` — ordnet eine gefüllte Stop-Order dem Bot zu.
HINTERGRUND (2026-08-06): eine ruhende Stop-Order füllt IM BROKER, nicht über
`engine._open`. `trader._refresh_locked` adoptiert die Position dann per
magic-match und loggt sie OHNE `setup` — vier reale Squeeze-Trades waren dadurch
von manuellen nicht unterscheidbar, und B4-Monitor, `squeeze_b5` sowie
`squeeze_entry_gap` zählten **null**. Deployment-Drift Fall 8: nicht die Strategie
driftete, sondern ihre Beobachtbarkeit.
Die Zuordnung ist eindeutig, weil bei einem Pending-Fill die POSITIONS-Nummer
identisch mit der ORDER-Nummer ist (an allen vier Broker-Datensätzen verifiziert).
"""
def test_squeeze_fill_wird_getaggt(engine):
engine._pending_tickets = {49483981: "squeeze"}
engine.trader.snap = {"ticket": 49483981, "order_type": 1,
"entry_price": 75.127}
engine._check_pending_fill()
assert engine._squeeze_entry_count == 1
assert engine._bot_open_ticket == 49483981
assert engine._bot_open_source == "auto_squeeze"
assert 49483981 not in engine._pending_tickets # Merker verbraucht
def test_unbekannte_quelle_wird_NICHT_getaggt(engine):
"""⚠ Ersetzt `test_signal_fill_long` (der Auto-Signal-Pfad ist am
2026-08-12 entfernt). Der Test wurde NICHT geloescht, sondern umgedreht:
seit es nur noch den Squeeze gibt, darf ein Fill mit einer FREMDEN Quelle
nicht stillschweigend als Squeeze durchgehen — das waere genau
Deployment-Drift Fall 8 (vier reale Trades landeten als `setup=NULL` und
waren von manuellen nicht unterscheidbar), nur mit umgekehrtem Vorzeichen:
ein Fremd-Trade wuerde die B4-/B5-Monitore verfaelschen."""
engine._pending_tickets = {777: "signal"} # Altbestand / unbekannt
engine.trader.snap = {"ticket": 777, "order_type": 0, "entry_price": 75.2}
engine._check_pending_fill()
assert engine._squeeze_entry_count == 0
assert engine._bot_open_source is None
# ⚠ Der Merker bleibt STEHEN — nur ein sauber zugeordneter Fill verbraucht
# ihn. So wird derselbe Fall beim naechsten Tick erneut gemeldet, statt
# still zu verschwinden.
assert 777 in engine._pending_tickets
def test_fremde_position_wird_nicht_getaggt(engine):
"""Der gefährliche Fall: ein manueller Trade darf NICHT als Bot-Trade gelten —
sonst verfälscht er genau die Monitore, die der Fix reparieren soll."""
engine._pending_tickets = {111: "squeeze"}
engine.trader.snap = {"ticket": 999, "order_type": 0, "entry_price": 75.0}
engine._check_pending_fill()
assert engine._squeeze_entry_count == 0
assert engine._bot_open_ticket is None
assert engine._pending_tickets == {111: "squeeze"} # bleibt liegen
def test_derselbe_fill_zaehlt_nur_einmal(engine):
"""Der `_pos_loop` läuft im Sekundentakt — ohne Dedup zählte ein Trade
hundertfach und der B4-Monitor wäre wertlos."""
engine._pending_tickets = {222: "squeeze"}
engine.trader.snap = {"ticket": 222, "order_type": 1, "entry_price": 74.9}
for _ in range(5):
engine._check_pending_fill()
assert engine._squeeze_entry_count == 1
def test_flat_ist_ein_no_op(engine):
engine._pending_tickets = {333: "squeeze"}
engine.trader.snap = {"ticket": None}
engine._check_pending_fill()
assert engine._squeeze_entry_count == 0
assert engine._pending_tickets == {333: "squeeze"}
def test_ohne_pending_merker_sofort_raus(engine):
"""Der häufigste Fall — es darf keine DB-Arbeit anfallen."""
engine.trader.snap = {"ticket": 444, "order_type": 0}
engine._check_pending_fill()
assert engine._bot_open_ticket is None