VWAP-Baender auf M15 gemessen = verworfen (24. Signal-Eingriff)
User-Wunsch nach einem M15-Daytrading-Modul auf Profi-Methodik. Abgleich: fast
alles aus dem Werkzeugkasten ist hier schon durchgefallen (Volume Profile,
Liquidity Sweeps, Market Structure, ORB, RSI/MACD, Inter-Market);
Footprint/CVD/DOM existieren nicht (Market-Maker-Broker). VWAP war die EINZIGE
nie gemessene Zutat.
Gemessen: 26.000 M15-Bars, session-verankert auf den Berliner Kalendertag,
2 Haelften, kanonischer Exit, Echtkosten, Fill bei Beruehrung.
ZUERST DER EIGENE FEHLER: der erste Lauf zeigte Reversion mit OeR +0,13 bis
+0,27 und PF bis 1,71 in beiden Haelften - verdaechtig sauber. Das Band an Bar i
wird MIT Bar i berechnet, und getestet wurde, ob genau diese Bar es beruehrt.
Ein Ausschlag zieht das Band zu sich hin und erzeugt seine eigene Beruehrung.
Mit Band aus i-1 bleibt:
k=2,0 +0,130/+0,130 -> +0,041/-0,009
k=2,5 +0,189/+0,235 -> +0,046/+0,087
k=3,0 +0,162/+0,272 -> +0,024/+0,010
Der Look-ahead war 0,10-0,25 R wert.
Alle drei vorab fixierten Kriterien verfehlt:
(b) Eine WILLKUERLICHE Linie gleicher Distanz haelt in 9 von 10 Zellen
genauso gut oder besser (VWAP 70,3-75,1 %, Zufall 73,9-76,6 %) - der
Fibonacci-Befund reproduziert.
(c) k=2,0 kippt in H2, also der Nachbar der besten Zelle. Und alle sechs
95-%-Bootstrap-Intervalle enthalten die Null (beste Zelle k=2,5 H2:
+0,087 [-0,012 ... +0,185]).
(a) Die Regel war von mir unterspezifiziert ("<= Squeeze-Box-Niveau" = 0 ist
fuer ein gleitendes Band unerfuellbar). Gemessen: Median 0,03-0,05xATR je
Bar, 90-Perzentil aber bis 0,34xATR - mehr als die Einstiegstoleranz.
Kohaerenz-Kontrolle: der Ausbruch an den Baendern ist spiegelbildlich negativ.
Reversion leicht positiv, Ausbruch klar negativ - ein stimmiges Bild.
Nichts gebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
30c8616280
commit
56a3fe31d8
@@ -4942,6 +4942,58 @@ Modell schliesst keine Trades.
|
|||||||
„die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die
|
„die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die
|
||||||
Basisraten-/Kalibrierungslücke.
|
Basisraten-/Kalibrierungslücke.
|
||||||
|
|
||||||
|
## ⚠⚠ VWAP-BÄNDER AUF M15 = VERWORFEN (2026-08-08) — die letzte ungetestete Zutat
|
||||||
|
|
||||||
|
Anlass: User-Wunsch nach einem **M15-Daytrading-Modul** auf Profi-Methodik
|
||||||
|
(Order-Flow, Volume Profile, VWAP, Session-Struktur, Liquidity Sweeps, MSS,
|
||||||
|
Mean-Reversion). Abgleich mit dem Gemessenen ergab: **fast alles davon ist in
|
||||||
|
diesem Projekt bereits durchgefallen** — Volume Profile (POC-Reversion
|
||||||
|
beidhälftig negativ), Liquidity Sweeps (alle 9 Kombis), Market Structure (24/24
|
||||||
|
Zellen), ORB (mit realer Fill-Annahme alle 4), RSI/MACD, Inter-Market.
|
||||||
|
Footprint/CVD/DOM existieren hier nicht (Market-Maker-Broker ohne Orderbuch; das
|
||||||
|
HL-Orderbuch ist gemessen 0,2–1,0 bp gegen ~3 bp Kostenhürde und läuft dem CFD
|
||||||
|
**hinterher**). Kpler/Bloomberg scheitern am Preis, CoT und Cushing an der
|
||||||
|
wöchentlichen Frequenz.
|
||||||
|
**VWAP war die EINZIGE nie gemessene Zutat** (`calc_vwap` existiert in
|
||||||
|
`core/analysis/indicators.py`, taucht in CLAUDE.md nirgends als Signal auf).
|
||||||
|
Jetzt gemessen: `backtest_vwap_m15.py`, 26.000 M15-Bars (02.07.25–07.08.26),
|
||||||
|
session-verankert auf den Berliner Kalendertag, 2 Hälften, kanonischer Exit,
|
||||||
|
Echtkosten, **Fill bei Berührung**.
|
||||||
|
|
||||||
|
⚠⚠ **ZUERST DER EIGENE FEHLER — er ist die halbe Lehre.** Der erste Lauf zeigte
|
||||||
|
Reversion bei k=2,0–3,0 mit **ØR +0,13 bis +0,27 und PF bis 1,71 in BEIDEN
|
||||||
|
Hälften** — verdächtig sauber. Ursache: das Band an Bar `i` wird **mit** Bar `i`
|
||||||
|
berechnet (der VWAP kumuliert sie), und getestet wurde, ob genau diese Bar es
|
||||||
|
berührt. **Ein Ausschlag zieht das Band zu sich hin und erzeugt seine eigene
|
||||||
|
Berührung.** Mit Band aus `i−1` (live zwangsläufig der Fall) bleibt:
|
||||||
|
| k | vorher H1/H2 | **nach dem Fix** |
|
||||||
|
|---|---|---|
|
||||||
|
| 2,0 | +0,130 / +0,130 | **+0,041 / −0,009** |
|
||||||
|
| 2,5 | +0,189 / +0,235 | **+0,046 / +0,087** |
|
||||||
|
| 3,0 | +0,162 / +0,272 | **+0,024 / +0,010** |
|
||||||
|
**Der Look-ahead war 0,10–0,25 R wert** — dieselbe Größenordnung wie beim
|
||||||
|
Squeeze (0,32), Momentum (0,45) und SIG (0,77–0,85).
|
||||||
|
|
||||||
|
**ALLE DREI vorab fixierten Kriterien verfehlt:**
|
||||||
|
· **(b) Haltequote gegen Zufallskontrolle** — eine **willkürliche Linie gleicher
|
||||||
|
Distanz** hält in **9 von 10 Zellen genauso gut oder besser** (VWAP 70,3–75,1 %,
|
||||||
|
Zufall 73,9–76,6 %). Exakt der Fibonacci-Befund reproduziert: die Frage ist nie
|
||||||
|
„hält das Level?", sondern „hält es BESSER als eine beliebige Linie?".
|
||||||
|
· **(c) Ertrag** — k=2,0 kippt in H2 (−0,009), also kippt der **Nachbar** der
|
||||||
|
besten Zelle. Und **alle sechs 95-%-Bootstrap-Intervalle enthalten die Null**
|
||||||
|
(k=2,5 H2, die beste Zelle: +0,087 [−0,012 … +0,185]).
|
||||||
|
· **(a) Beweglichkeit** — ⚠ **die Regel war von mir unterspezifiziert**
|
||||||
|
(„≤ Squeeze-Box-Niveau" = 0 ist für ein gleitendes Band unerfüllbar). Gemessen
|
||||||
|
rückt das Band im Median nur 0,03–0,05×ATR je Bar, im **90-Perzentil aber bis
|
||||||
|
0,34×ATR** — mehr als die Einstiegstoleranz von 0,15. Eine ruhende Order müsste
|
||||||
|
also laufend nachgezogen werden: dasselbe operative Problem wie bei `_pend`.
|
||||||
|
|
||||||
|
✅ **Kohärenz-Kontrolle:** der **Ausbruch** an den Bändern ist spiegelbildlich
|
||||||
|
negativ (H1 −0,107…−0,230 über alle k). Reversion leicht positiv, Ausbruch klar
|
||||||
|
negativ — ein stimmiges Bild, kein Zufallsrauschen.
|
||||||
|
**24. verworfener Signal-Eingriff.** Damit ist aus dem eingereichten
|
||||||
|
Profi-Werkzeugkasten **keine ungetestete Zutat mehr offen.**
|
||||||
|
|
||||||
## ⚠⚠ VERLUSTBEGRENZUNG BEI „FALSCHEN" EINSTIEGEN — BEIDE IDEEN GEMESSEN, BEIDE DURCHGEFALLEN (2026-08-07)
|
## ⚠⚠ VERLUSTBEGRENZUNG BEI „FALSCHEN" EINSTIEGEN — BEIDE IDEEN GEMESSEN, BEIDE DURCHGEFALLEN (2026-08-07)
|
||||||
|
|
||||||
User: „um meine Verluste bei falschen Einstiegen zu begrenzen würde ich gerne den
|
User: „um meine Verluste bei falschen Einstiegen zu begrenzen würde ich gerne den
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""VWAP-Bänder auf M15 — taugen sie als LEVEL für ein Daytrading-Modul?
|
||||||
|
|
||||||
|
ANLASS (2026-08-08, User-Wunsch nach einem M15-Modul auf Profi-Methodik). Vom
|
||||||
|
eingereichten Werkzeugkasten ist fast alles in diesem Projekt schon gemessen und
|
||||||
|
durchgefallen — Volume Profile (POC-Reversion beidhälftig negativ), Liquidity
|
||||||
|
Sweeps (alle 9 Kombis), Market Structure (24/24 Zellen), ORB (alle 4 Varianten
|
||||||
|
mit realer Fill-Annahme), RSI/MACD, Inter-Market. Footprint/CVD/DOM gibt es hier
|
||||||
|
gar nicht (Market-Maker-Broker ohne Orderbuch).
|
||||||
|
**VWAP ist die einzige Zutat aus der Liste, die nie gemessen wurde** —
|
||||||
|
`core/analysis/indicators.calc_vwap` existiert, taucht in CLAUDE.md aber nirgends
|
||||||
|
als Signal auf.
|
||||||
|
|
||||||
|
⚠⚠ DIE VORFRAGE ENTSCHEIDET ALLES — und sie steht deshalb ganz vorne:
|
||||||
|
**STEHT das Band still?** Der einzige im Projekt belegte Hebel ist die
|
||||||
|
Ausführung: eine ruhende Order an einem STEHENDEN Level (Squeeze +0,32 R
|
||||||
|
gegenüber Market; SIG +0,35/+0,32 am Level gegen −0,09/−0,11 am Markt). Und der
|
||||||
|
Gegenbeleg ist genauso klar: das Momentum-Level WANDERT jede Bar, deshalb fällt
|
||||||
|
es durch (+0,45 R Aufschlag war reines Look-ahead). Ein VWAP-Band bewegt sich
|
||||||
|
per Konstruktion mit jedem Tick. Wandert es so stark wie das Momentum-Level, ist
|
||||||
|
das Modul erledigt, bevor irgendein Ertrag gerechnet wird.
|
||||||
|
|
||||||
|
GEMESSEN WIRD, in dieser Reihenfolge:
|
||||||
|
0) BEWEGLICHKEIT — wie weit rückt das Band je Bar (in ×ATR)? Gegen zwei
|
||||||
|
Referenzen: die Squeeze-Box (steht, trägt) und `C[i−N]` (wandert, trägt nicht).
|
||||||
|
1) HALTEQUOTE — prallt der Kurs am Band ab? ⚠ MIT KONTROLLGRUPPE: eine
|
||||||
|
Zufallslinie gleicher Distanz. Die Fibonacci-Messung hat gezeigt, dass ein
|
||||||
|
BELIEBIGES Level hier zu ~55 % hält — ohne Kontrolle misst man die Basisrate.
|
||||||
|
2) ERTRAG — Reversion (Limit am Band) und Ausbruch (Stop hinter dem
|
||||||
|
Band), beide mit FILL BEI BERÜHRUNG (die ehrliche Annahme, s. 06.08.),
|
||||||
|
kanonischer Exit, Echtkosten, 2 Halbjahre.
|
||||||
|
|
||||||
|
⚠⚠ ENTSCHEIDUNGSREGEL, VORAB FESTGELEGT:
|
||||||
|
(a) Beweglichkeit ≤ Squeeze-Box-Niveau, sonst Abbruch — ein wanderndes Level
|
||||||
|
ist als ruhende Order nicht handelbar.
|
||||||
|
(b) Haltequote muss die Zufallskontrolle in BEIDEN Hälften schlagen.
|
||||||
|
(c) ØR > 0 und PF > 1 in BEIDEN Hälften, und die Nachbar-k dürfen nicht kippen.
|
||||||
|
Sonst: kein Einbau. Bei 23 gescheiterten Signal-Eingriffen gilt hohe Beweislast.
|
||||||
|
|
||||||
|
Aufruf: python backtest_vwap_m15.py [n_M15_bars] (Default 26000 ≈ 9 Monate)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
import MetaTrader5 as mt5
|
||||||
|
|
||||||
|
from core.exit_model import LIVE, simulate
|
||||||
|
|
||||||
|
_BERLIN = ZoneInfo("Europe/Berlin")
|
||||||
|
_BROKER = timezone(timedelta(hours=3)) # Brokerzeit = UTC+3
|
||||||
|
_ATRMIN = 0.12
|
||||||
|
_BAENDER = (1.0, 1.5, 2.0, 2.5, 3.0)
|
||||||
|
_ZONE = 0.15 # „am Band" in ×ATR (wie `at_level` live)
|
||||||
|
|
||||||
|
|
||||||
|
def _berlin(ts: int) -> datetime:
|
||||||
|
"""⚠ MT5 liefert die BROKER-Wallclock, keinen echten UTC-Epoch. Genau hier
|
||||||
|
ist `analyze_tageszeit.py` am 05.08. um drei Stunden verrutscht."""
|
||||||
|
return datetime.fromtimestamp(ts, timezone.utc).replace(
|
||||||
|
tzinfo=_BROKER).astimezone(_BERLIN)
|
||||||
|
|
||||||
|
|
||||||
|
def atr_series(H, L, C, p=14):
|
||||||
|
tr = [0.0]
|
||||||
|
for i in range(1, len(C)):
|
||||||
|
tr.append(max(H[i] - L[i], abs(H[i] - C[i - 1]), abs(L[i] - C[i - 1])))
|
||||||
|
out = [None]
|
||||||
|
for i in range(1, len(C)):
|
||||||
|
seg = tr[max(1, i - p + 1):i + 1]
|
||||||
|
out.append(sum(seg) / len(seg))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def vwap_baender(T, H, L, C, V):
|
||||||
|
"""Session-verankerter VWAP + kumulierte Standardabweichung je M15-Bar.
|
||||||
|
|
||||||
|
Anker = Berliner Kalendertag (Reset 00:00). ⚠ KAUSAL: an Bar i fliessen nur
|
||||||
|
Bars bis EINSCHLIESSLICH i ein — das Band an i ist also aus i bekannt, und
|
||||||
|
eine Order kann fruehestens ab i+1 liegen (so wird unten auch gehandelt).
|
||||||
|
"""
|
||||||
|
vw = [None] * len(C)
|
||||||
|
sd = [None] * len(C)
|
||||||
|
cum_pv = cum_v = cum_p2v = 0.0
|
||||||
|
tag = None
|
||||||
|
for i in range(len(C)):
|
||||||
|
d = _berlin(T[i]).date()
|
||||||
|
if d != tag:
|
||||||
|
tag = d
|
||||||
|
cum_pv = cum_v = cum_p2v = 0.0
|
||||||
|
tp = (H[i] + L[i] + C[i]) / 3.0
|
||||||
|
v = float(V[i] or 1)
|
||||||
|
cum_pv += tp * v
|
||||||
|
cum_v += v
|
||||||
|
cum_p2v += tp * tp * v
|
||||||
|
if cum_v <= 0:
|
||||||
|
continue
|
||||||
|
m = cum_pv / cum_v
|
||||||
|
var = max(0.0, cum_p2v / cum_v - m * m)
|
||||||
|
vw[i] = m
|
||||||
|
sd[i] = var ** 0.5
|
||||||
|
return vw, sd
|
||||||
|
|
||||||
|
|
||||||
|
def beweglichkeit(vw, sd, AT, k):
|
||||||
|
"""Wie weit rueckt das obere Band je Bar, in ×ATR? Median + 90-Perzentil."""
|
||||||
|
d = []
|
||||||
|
for i in range(1, len(vw)):
|
||||||
|
if not (vw[i] and vw[i - 1] and sd[i] is not None and sd[i - 1] is not None):
|
||||||
|
continue
|
||||||
|
a = AT[i]
|
||||||
|
if not a or a <= 0:
|
||||||
|
continue
|
||||||
|
o1 = vw[i - 1] + k * sd[i - 1]
|
||||||
|
o2 = vw[i] + k * sd[i]
|
||||||
|
d.append(abs(o2 - o1) / max(a, _ATRMIN))
|
||||||
|
if not d:
|
||||||
|
return None
|
||||||
|
d.sort()
|
||||||
|
return d[len(d) // 2], d[int(0.9 * len(d))]
|
||||||
|
|
||||||
|
|
||||||
|
def halte_quote(H, L, C, AT, vw, sd, k, lo, hi, fenster=8, zufall=False):
|
||||||
|
"""Prallt der Kurs am Band ab? Beruehrung = Bar-Spanne trifft die Zone.
|
||||||
|
Ausgang: erreicht er zuerst Band∓0,5×ATR (haelt) oder Band±0,5×ATR (bricht)?
|
||||||
|
`zufall=True` = Kontrolllinie in derselben Distanz, aber ohne VWAP-Bezug."""
|
||||||
|
import random
|
||||||
|
rnd = random.Random(7)
|
||||||
|
haelt = bricht = 0
|
||||||
|
war = False
|
||||||
|
for i in range(max(lo, 1), min(hi, len(C) - fenster - 1)):
|
||||||
|
# ⚠⚠ BAND AUS i-1, NICHT AUS i. Der VWAP an i enthaelt Bar i selbst —
|
||||||
|
# gegen die Spanne DERSELBEN Bar zu testen ist Look-ahead: ein Ausschlag
|
||||||
|
# zieht das Band zu sich hin und erzeugt so seine eigene „Beruehrung".
|
||||||
|
# Live liegt die Order zwangslaeufig auf dem Stand des VORBARS.
|
||||||
|
if not vw[i - 1] or sd[i - 1] is None:
|
||||||
|
war = False
|
||||||
|
continue
|
||||||
|
a = AT[i]
|
||||||
|
if not a or a <= 0:
|
||||||
|
war = False
|
||||||
|
continue
|
||||||
|
a = max(a, _ATRMIN)
|
||||||
|
lvl = vw[i - 1] + k * sd[i - 1]
|
||||||
|
if zufall:
|
||||||
|
# gleiche Distanz zum Kurs, aber willkuerliche Lage
|
||||||
|
dist = abs(lvl - C[i])
|
||||||
|
lvl = C[i] + dist * rnd.choice((1, -1))
|
||||||
|
oben = lvl > C[i]
|
||||||
|
beruehrt = (L[i] <= lvl + _ZONE * a) and (H[i] >= lvl - _ZONE * a)
|
||||||
|
if beruehrt and not war:
|
||||||
|
durch = lvl + (0.5 * a if oben else -0.5 * a)
|
||||||
|
zurueck = lvl - (0.5 * a if oben else -0.5 * a)
|
||||||
|
aus = None
|
||||||
|
for j in range(i + 1, i + 1 + fenster):
|
||||||
|
if (H[j] >= durch) if oben else (L[j] <= durch):
|
||||||
|
aus = "break"; break
|
||||||
|
if (L[j] <= zurueck) if oben else (H[j] >= zurueck):
|
||||||
|
aus = "halt"; break
|
||||||
|
if aus == "break":
|
||||||
|
bricht += 1
|
||||||
|
else:
|
||||||
|
haelt += 1 # Timeout zaehlt als Halt (wie im P(break)-Training)
|
||||||
|
war = beruehrt
|
||||||
|
n = haelt + bricht
|
||||||
|
return (n, haelt / n if n else None)
|
||||||
|
|
||||||
|
|
||||||
|
def ertrag(H, L, C, AT, SP, vw, sd, k, lo, hi, art):
|
||||||
|
"""`art`: 'reversion' = Limit AM Band, Richtung zurueck zum VWAP ·
|
||||||
|
'ausbruch' = Stop HINTER dem Band, Richtung weiter.
|
||||||
|
⚠ FILL BEI BERUEHRUNG — die einzige live erreichbare Annahme (s. 06.08.:
|
||||||
|
der Close-Bruch-Fill ist Look-ahead und schenkt 0,3–0,85 R)."""
|
||||||
|
Rs = []
|
||||||
|
i = max(lo, 1)
|
||||||
|
war = False
|
||||||
|
while i < min(hi, len(C) - LIVE.max_hold - 2):
|
||||||
|
# ⚠⚠ Band aus i-1 (s. `halte_quote`): das an i berechnete Band enthaelt
|
||||||
|
# Bar i selbst und waere Look-ahead.
|
||||||
|
if not vw[i - 1] or sd[i - 1] is None:
|
||||||
|
war = False; i += 1; continue
|
||||||
|
a = AT[i]
|
||||||
|
if not a or a <= 0:
|
||||||
|
war = False; i += 1; continue
|
||||||
|
a = max(a, _ATRMIN)
|
||||||
|
for seite in (1, -1): # oberes und unteres Band
|
||||||
|
lvl = vw[i - 1] + seite * k * sd[i - 1]
|
||||||
|
beruehrt = (L[i] <= lvl + _ZONE * a) and (H[i] >= lvl - _ZONE * a)
|
||||||
|
if not beruehrt or war:
|
||||||
|
continue
|
||||||
|
d = -seite if art == "reversion" else seite
|
||||||
|
kosten = (SP[i] if SP[i] > 0 else 0.0225) / a
|
||||||
|
R, xb = simulate(lvl, d, a, H, L, C, i + 1, LIVE, ret_bar=True)
|
||||||
|
Rs.append(R - kosten)
|
||||||
|
i = xb
|
||||||
|
break
|
||||||
|
if vw[i - 1] and sd[i - 1] is not None:
|
||||||
|
_o = vw[i - 1] + k * sd[i - 1]
|
||||||
|
war = (L[i] <= _o + _ZONE * a) and (H[i] >= _o - _ZONE * a)
|
||||||
|
else:
|
||||||
|
war = False
|
||||||
|
i += 1
|
||||||
|
return Rs
|
||||||
|
|
||||||
|
|
||||||
|
def kz(Rs):
|
||||||
|
if not Rs:
|
||||||
|
return "n=0"
|
||||||
|
n = len(Rs); w = sum(1 for x in Rs if x > 0); s = sum(Rs)
|
||||||
|
g = sum(x for x in Rs if x > 0); v = -sum(x for x in Rs if x < 0)
|
||||||
|
return (f"n={n:>4} WR={100*w/n:>3.0f}% ØR={s/n:+.3f} "
|
||||||
|
f"PF={(g/v if v > 0 else 9.99):>4.2f} ΣR={s:>+6.0f}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
n = int(sys.argv[1]) if len(sys.argv) > 1 else 26000
|
||||||
|
mt5.initialize()
|
||||||
|
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD")
|
||||||
|
if mt5.symbol_info(c)), None)
|
||||||
|
bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M15, 0, n)
|
||||||
|
point = mt5.symbol_info(sym).point
|
||||||
|
mt5.shutdown()
|
||||||
|
if bars is None or len(bars) < 5000:
|
||||||
|
print(f"zu wenige M15-Bars ({0 if bars is None else len(bars)})"); return
|
||||||
|
T = [int(b["time"]) for b in bars]
|
||||||
|
H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars]
|
||||||
|
C = [float(b["close"]) for b in bars]
|
||||||
|
V = [float(b["tick_volume"]) for b in bars]
|
||||||
|
SP = [float(b["spread"]) * point for b in bars]
|
||||||
|
AT = atr_series(H, L, C)
|
||||||
|
vw, sd = vwap_baender(T, H, L, C, V)
|
||||||
|
mid = len(C) // 2
|
||||||
|
|
||||||
|
print("=" * 92)
|
||||||
|
print(f" VWAP-BÄNDER auf M15 — {sym}, {len(C)} Bars "
|
||||||
|
f"({_berlin(T[0]):%d.%m.%Y} bis {_berlin(T[-1]):%d.%m.%Y})")
|
||||||
|
print("=" * 92)
|
||||||
|
|
||||||
|
# ── 0) DIE VORFRAGE ───────────────────────────────────────────────────
|
||||||
|
print("\n 0) BEWEGLICHKEIT — steht das Band still? (Verschiebung je Bar in ×ATR)")
|
||||||
|
print(f" {'k':>5}{'Median':>10}{'90-Perzentil':>15}")
|
||||||
|
for k in _BAENDER:
|
||||||
|
b = beweglichkeit(vw, sd, AT, k)
|
||||||
|
if b:
|
||||||
|
print(f" {k:>5.1f}{b[0]:>10.3f}{b[1]:>15.3f}")
|
||||||
|
print(" Referenz: Squeeze-Box steht (0,000 zwischen den Ausbrüchen) und TRÄGT;")
|
||||||
|
print(" das Momentum-Level `C[i−N]` wandert und TRÄGT NICHT.")
|
||||||
|
|
||||||
|
# ── 1) HALTEQUOTE mit Kontrolle ───────────────────────────────────────
|
||||||
|
print("\n 1) HALTEQUOTE am oberen Band — gegen eine Zufallslinie gleicher Distanz")
|
||||||
|
print(f" {'k':>5}{'H1 VWAP':>12}{'H1 Zufall':>12}{'H2 VWAP':>12}{'H2 Zufall':>12}")
|
||||||
|
for k in _BAENDER:
|
||||||
|
z = []
|
||||||
|
for lo, hi in ((0, mid), (mid, len(C))):
|
||||||
|
for zuf in (False, True):
|
||||||
|
nn, q = halte_quote(H, L, C, AT, vw, sd, k, lo, hi, zufall=zuf)
|
||||||
|
z.append(f"{100*q:.1f}% ({nn})" if q is not None else "—")
|
||||||
|
print(f" {k:>5.1f}" + "".join(f"{x:>12}" for x in z))
|
||||||
|
|
||||||
|
# ── 2) ERTRAG ─────────────────────────────────────────────────────────
|
||||||
|
for art in ("reversion", "ausbruch"):
|
||||||
|
print(f"\n 2) ERTRAG — {art.upper()} (Fill bei Berührung, kanonischer Exit, Echtkosten)")
|
||||||
|
for k in _BAENDER:
|
||||||
|
r1 = ertrag(H, L, C, AT, SP, vw, sd, k, 0, mid, art)
|
||||||
|
r2 = ertrag(H, L, C, AT, SP, vw, sd, k, mid, len(C), art)
|
||||||
|
print(f" k={k:<4} H1 {kz(r1)}")
|
||||||
|
print(f" {'':<7}H2 {kz(r2)}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user