Tagestrend: vier Varianten gemessen, keine besteht - nichts gebaut

User: "hast du Optimierungsvorschlaege um den Tagestrend mehr Gewicht zu
verleihen?" Vier konkrete Vorschlaege, alle VORHER gemessen statt gebaut.
backtest_tagestrend.py (neu): 60k M5 = 244 Handelstage, voller Live-Gate-Stack
(echtes `_build` + Breakout k=0,3 + `_room_gate`), kanonischer Exit,
Echtkosten, 2 Halbjahre, 95-%-Bootstrap, Schwellen 0,15 / 0,30 / 0,60 %.
Tagestrend = Kurs gegen die TAGESEROEFFNUNG (Berlin, DST-korrekt) - das, was
ein Mensch sieht, und es braucht keinen 16.000-Bar-Vorlauf.

                        H1 OeR/SR        H2 OeR/SR       n
  BASIS               -0,062 / -34,9   -0,107 / -88,9   563/831
  A VETO              -0,058 / -31,5   -0,114 / -89,5   543/785
  B NUR-MIT           -0,010 /  -4,8   -0,126 / -86,1   483/683
  C SPAET (3,5->5,0)  -0,031 / -20,3   -0,089 / -84,8   656/953
  D PULLBACK          -0,008 /  -1,6   -0,012 /  -3,5   196/291

A und B: in H2 an ALLEN DREI Schwellen schlechter als BASIS; die von ihnen
entfernte Gruppe kippt zwischen den Haelften (+0,032 bzw. +0,208 in H2) - sie
werfen also teils die BESSEREN Trades weg. Vierte Messung dieser Klasse nach
Hoeher-TF-Winkel, H1-Staerke und Konfluenz-Strafe.

C sieht beidhaelftig besser aus und ist trotzdem kein Beleg: die zusaetzlich
genommenen Trades sind H1 -0,134 / H2 +0,060, also gegenlaeufig. Aufloesung in
der Mechanik: die Sim hat EINEN Slot, ein Extra-Trade verschiebt die GANZE
Folge. C ist keine Obermenge von BASIS, sondern eine andere Trade-Folge - der
scheinbare Gewinn ist ein Selektionseffekt (die Falle vom 14.08.).

D hat als EINZIGE die richtige Signatur: beidhaelftig besser an allen drei
Schwellen, und die ENTFERNTE Gruppe ist an allen SECHS Stellen negativ
(-0,068/-0,060/-0,063 und -0,072/-0,080/-0,053). Trotzdem kein Bau: jedes
Intervall enthaelt die Null, und der SR-Sprung kommt fast vollstaendig daher,
dass D nur noch 35 % der Trades nimmt - Handelsvermeidung, nicht Edge (Muster
aus backtest_metalabel.py).

INHALTLICHE ANTWORT im Vergleich C gegen D: wenn der Tagestrend etwas
beitraegt, dann NICHT als Erlaubnis fuer den spaeten Einstieg, sondern als
Kontext fuer den RUECKSETZER. Deckt sich mit dem einzigen belegten
Einstiegs-Effekt (Pullback-Bonus +15) und mit dem invertierten Winkel-Befund
vom 04.08.
Ehrlichster Satz zum Lauf: die BASIS-Population ist mit -0,062/-0,107 selbst
negativ. Kein Umgang mit dem Tagestrend macht daraus einen Edge.
29. verworfener Signal-Eingriff.

METHODEN-BEFUND ueber den Lauf hinaus: das Werkzeug fuer den gepaarten
Vergleich war hier das FALSCHE - und es hat es selbst gezeigt (Delta +0,000,
KI von exakt 0,000 bis 0,000 in ALLEN acht Zellen). Diese Varianten aendern
nicht den EXIT, sondern WELCHE Einstiege genommen werden; auf gemeinsamen
Faellen sind die R-Werte per Konstruktion identisch.
Regel: gepaart fuer EXIT-Varianten, Auswertung der entfernten bzw.
hinzugefuegten Gruppe fuer AUSWAHL-Varianten. Ein Intervall von exakt
[0,000 .. 0,000] ist kein Ergebnis, sondern die Fehlermeldung eines falsch
gewaehlten Tests.

Nachtrag: die Nachricht des ersten Commit-Versuchs wurde von der
dokumentierten Backtick-Falle beschaedigt (Kommando-Substitution in der
Bash-Zeile). Diese Fassung kommt ueber eine Datei.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-20 13:26:37 +02:00
co-authored by Claude Opus 5
parent 6ed8980eab
commit a35ea38d31
2 changed files with 361 additions and 0 deletions
+78
View File
@@ -8960,6 +8960,84 @@ negativ (0,003 / 0,023), der bärische **kippt das Vorzeichen**. Ein Kanal
nichts vorhersagt, bekommt keine Stimme — dieselbe Begründung wie bei TU (2026-07-06)
und beim Orderbuch (06.08.).
## ⚠⚠ „TAGESTREND MEHR GEWICHT?" — VIER VARIANTEN GEMESSEN, KEINE BESTEHT (2026-08-20)
User-Frage nach dem Stretch-Befund. Vier konkrete Vorschläge, **alle vorher
gemessen statt gebaut** (`backtest_tagestrend.py`, 60k M5 = 244 Handelstage,
voller Live-Gate-Stack — echtes `_build` + Breakout k=0,3 + `_room_gate`,
Reversal aus —, kanonischer Exit, Echtkosten, 2 Halbjahre, 95-%-Bootstrap,
Schwellen 0,15 / **0,30** / 0,60 % als Nachbar-Probe).
**Tagestrend = Kurs gegen die TAGESERÖFFNUNG** (Berlin-Tag, DST-korrekt) —
bewusst so und nicht als D1-EMA: das ist, was ein Mensch sieht, wenn er sagt
„der Tagestrend ist aufwärts", und es braucht keinen 16.000-Bar-Vorlauf.
| Variante | H1 ØR / ΣR | H2 ØR / ΣR | n (H1/H2) |
|---|---|---|---|
| **BASIS (wie live)** | 0,062 / 34,9 | 0,107 / 88,9 | 563 / 831 |
| A) VETO gegen den Tagestrend | 0,058 / 31,5 | **0,114** / 89,5 | 543 / 785 |
| B) NUR MIT dem Tagestrend | 0,010 / 4,8 | **0,126** / 86,1 | 483 / 683 |
| C) Spät-Einstieg erlaubt (stretch → 5,0) | 0,031 / 20,3 | 0,089 / 84,8 | 656 / 953 |
| **D) Pullback im Tagestrend** | **0,008 / 1,6** | **0,012 / 3,5** | **196 / 291** |
**A und B fallen sofort:** beide sind in H2 an **allen drei** Schwellen
schlechter als BASIS. Die von ihnen entfernte Gruppe kippt zwischen den Hälften
(A: 0,105 / **+0,032**; bei 0,15 % sogar **+0,208** in H2) — sie werfen also
teils die *besseren* Trades weg. Damit ist die Klasse zum **vierten Mal**
gemessen (Höher-TF-Winkel · H1-Stärke · Konfluenz-Strafe · jetzt Tagestrend).
⚠⚠ **C sieht in der Tabelle gut aus und ist trotzdem kein Beleg.** Es ist in
**beiden** Hälften und an **allen drei** Schwellen besser als BASIS — aber die
Trades, die es zusätzlich nimmt, sind **H1 0,134 / H2 +0,060**, also
gegenläufig. Der Widerspruch löst sich in der Mechanik auf: die Sim hat EINEN
Slot (`i = xj + _COOL`), ein zusätzlicher Trade **verschiebt die gesamte
Folge**. C ist damit keine Obermenge von BASIS, sondern eine andere
Trade-Folge — der scheinbare Gewinn ist ein **Selektionseffekt**, exakt die
Falle vom 14.08.
✅ Nebenbefund, der zum Stretch-Lauf desselben Tages passt: der Spät-Einstieg
zahlt auch dann nicht, wenn der Tagestrend ihn stützt.
⚠⚠ **D ist die einzige Variante mit der RICHTIGEN Signatur — und trotzdem kein
Bau.** Sie ist beidhälftig besser als BASIS, an allen drei Schwellen, und die
Gruppe, die sie **entfernt**, ist an **allen sechs** Stellen negativ
(H1 0,068/0,060/0,063 · H2 0,072/0,080/0,053) — sie wirft also
konsistent Schlechtes weg, nicht Gutes. Das ist die Form, die A, B und C fehlt.
❌ **Aber Bedingung (2) ist verfehlt: JEDES Intervall enthält die Null**
(D selbst: [0,266 … +0,257]).
❌ Und der ΣR-Sprung (34,9 → **1,6**) kommt fast vollständig daher, dass D nur
noch **35 %** der Trades nimmt. Das ist **Handelsvermeidung**, kein Edge —
dasselbe Muster, an dem `backtest_metalabel.py` gescheitert ist („ΣR steigt nur,
weil n fällt; ØR bleibt negativ"). D verwandelt eine verlierende Population in
eine **breakeven** Population, indem sie zwei Drittel davon nicht handelt.
✅✅ **DIE INHALTLICHE ANTWORT AUF DIE FRAGE steckt im Vergleich C gegen D:** wenn
der Tagestrend etwas beiträgt, dann **nicht als Erlaubnis, spät einzusteigen**
(C: die Zusatz-Trades kippen), sondern als **Kontext für den Rücksetzer**
(D: die entfernte Gruppe ist an allen sechs Stellen negativ). Das deckt sich mit
dem einzigen im Projekt belegten Einstiegs-Effekt — dem **Pullback-Bonus**
(„⭐ tiefer Pullback" +15, `backtest_pullback.py`) — und mit dem invertierten
Winkel-Befund vom 04.08. („LONG bei fallendem Kurzfrist-Winkel trägt doppelt
so gut").
⚠ Es heißt **nicht**, dass D gebaut werden sollte. Es heißt: **die Richtung, in
der man suchen müsste, ist der Pullback, nicht der späte Einstieg.**
**Der ehrlichste Satz zum ganzen Lauf:** die BASIS-Population ist mit
0,062/0,107 selbst negativ. Kein Umgang mit dem Tagestrend macht daraus einen
Edge — das deckt sich mit dem Ausrichtungs-Split (MIT Signal 56,5 % gegen OHNE
Signal 56,6 % = identisch) und mit `analyze_signal_live.py` (Richtung 4851 %).
**29. verworfener Signal-Eingriff** (A, B, C zusammen als eine Klasse gezählt).
⚠⚠ **METHODEN-BEFUND, der über diesen Lauf hinausgeht: `paarweise` war hier das
FALSCHE Werkzeug — und es hat es selbst gezeigt.** Der erste Entwurf verglich
gepaart auf gemeinsamen Einstiegen und lieferte in **allen acht** Zellen
`Delta = +0,000, KI [0,000 … 0,000]`. Der Grund ist offensichtlich, sobald man
ihn sieht: diese Varianten ändern nicht den **Exit**, sondern **welche Einstiege
genommen werden** — auf gemeinsamen Fällen sind die R-Werte per Konstruktion
identisch.
➜ **Regel: `paarweise` für EXIT-Varianten (gleiche Einstiege, anderes Ergebnis),
die Auswertung der ENTFERNTEN bzw. HINZUGEFÜGTEN Gruppe für AUSWAHL-Varianten**
(Muster `backtest_htf_vola.py`). Ein Intervall von exakt [0,000 … 0,000] ist
kein Ergebnis, sondern die Fehlermeldung eines falsch gewählten Tests.
## ⚠⚠⚠ P(break) IST LIVE **INVERTIERT** — und es steuert echtes Geld (2026-08-19)
Die fällige Messung ist entscheidbar geworden: **n=530 entkoppelt** gegen die
+283
View File
@@ -0,0 +1,283 @@
"""Bringt es etwas, dem TAGESTREND mehr Gewicht zu geben? (2026-08-20)
ANLASS (User): "hast du Optimierungsvorschlaege, um den Tagestrend mehr Gewicht
zu verleihen?" - nach dem Befund, dass die Empfehlung heute um 09:13 LONG sagte
und seit 12:58 wegen Ueberdehnung schweigt, waehrend der Tag +2,89 % lief.
⚠ HOHE BEWEISLAST. Signal-Eingriffe sind in diesem Projekt 28-mal gescheitert,
darunter dreimal genau diese Klasse (Hoeher-TF-Winkel-Filter, H1-Staerke-Filter,
Konfluenz-Strafe - alle gemessen SCHLECHTER). Deshalb wird hier NICHTS gebaut,
sondern zuerst gemessen.
VIER VARIANTEN, alle auf DERSELBEN Population (voller Live-Gate-Stack: echtes
`_build` + Breakout-Bestaetigung k=0,3 + `_room_gate`, Reversal aus):
BASIS wie live
A VETO Signal GEGEN den Tagestrend verwerfen - die einzige Form, die
im Projekt je robust war (Ausrichtungs-Split: gegen das Signal
-6,60 EUR/Lot, beidhaelftig)
B NUR-MIT nur Signale MIT dem Tagestrend (strenger als A: auch neutrale
Tage fallen weg)
C SPAET `_STRETCH_MAX` 3,5 -> 5,0, solange der Tagestrend in
Signalrichtung zeigt. Das ist EXAKT die heutige Lage.
D PULLBACK nur MIT dem Tagestrend UND nur bei kleiner Ueberdehnung
(|stretch| <= 1,5) - nicht spaet kaufen, sondern den
Ruecksetzer nehmen. Nutzt den im Projekt BELEGTEN
Pullback-Effekt ("tiefer Pullback" +15).
TAGESTREND = Kurs gegen die TAGESEROEFFNUNG (Berlin-Kalendertag, DST-korrekt).
Bewusst so und nicht als D1-EMA: das ist, was ein Mensch sieht, wenn er sagt
"der Tagestrend ist aufwaerts" - und es braucht keinen 16.000-Bar-Vorlauf.
Schwelle 0,30 % vom Kurs; 0,15 / 0,60 % werden als Nachbarn mitgeprueft.
⚠ KAUSAL: die Eroeffnung des LAUFENDEN Tages ist jederzeit bekannt, es fliesst
nichts aus der Zukunft ein.
REGEL VORAB FIXIERT: eine Variante wird nur dann zum Bauen empfohlen, wenn sie
(1) in BEIDEN Halbjahren einen hoeheren OeR liefert als BASIS,
(2) ihr GEPAARTES 95-%-Intervall (gemeinsame Einstiege - die Falle vom 14.08.)
die Null ausschliesst, und
(3) die Nachbar-Schwellen nicht kippen.
Aufruf: python backtest_tagestrend.py [bars]
"""
import datetime as dt
import sys
from bisect import bisect_left, bisect_right
from zoneinfo import ZoneInfo
import MetaTrader5 as mt5
import core.wave_rec as WR
from backtest_breakout_gated import (_ATRMIN, _ATR_FLOOR_PB, _COOL, _PIV_K,
_PIV_LOOK, _TIMEOUT_BARS, _TU,
_atr_series, _htf_sign)
from backtest_cost_gate import kennzahlen
from core.analysis import calc_trend_angle
from core.exit_model import LIVE, simulate
from core.wave_rec import (WaveRecommender, _ANGLE_LR, _EMA_FAST, _EMA_SLOW,
_ema_series)
BERLIN = ZoneInfo("Europe/Berlin")
BROKER = dt.timezone(dt.timedelta(hours=3))
K_BREAKOUT = 0.3
PULLBACK_MAX = 1.5
STRETCH_LOCKER = 5.0
MODI = (("basis", "BASIS (wie live)"),
("veto", "A) VETO gegen Tagestrend"),
("nurmit", "B) NUR MIT Tagestrend"),
("spaet", "C) Spaet-Einstieg bis 5,0"),
("pullback", "D) Pullback im Tagestrend"))
def _tagesoeffnung(T, C):
"""Index -> Eroeffnungskurs SEINES Berliner Kalendertags (kausal).
⚠ MT5 liefert in `time` die Broker-WALLCLOCK, keinen echten UTC-Epoch -
genau der Fehler, der `analyze_tageszeit.py` am 05.08. um 3 h verschoben hat.
"""
out = [None] * len(C)
tag = op = None
for i, ts in enumerate(T):
d = dt.datetime.fromtimestamp(ts, dt.timezone.utc) \
.replace(tzinfo=BROKER).astimezone(BERLIN).date()
if d != tag:
tag, op = d, C[i]
out[i] = op
return out
def _tagestrend(C, OP, i, schwelle):
if not OP[i]:
return 0
rel = (C[i] - OP[i]) / OP[i]
return 0 if abs(rel) < schwelle else (1 if rel > 0 else -1)
def run(w, H, L, C, A, SP, EF, ES, AD, HTF, H1, PH, PL, OP,
lo, hi, modus, schwelle):
Rs, keys = [], []
pend = None
i = max(lo, _PIV_LOOK + _EMA_SLOW + 5)
while i < hi:
atr = A[i]
if not atr or atr < _ATRMIN:
i += 1
continue
w._pb_feats = {"atr": max(atr, _ATR_FLOOR_PB)}
a1 = bisect_left(PH, i - _PIV_LOOK)
b1 = bisect_right(PH, i - _PIV_K)
a2 = bisect_left(PL, i - _PIV_LOOK)
b2 = bisect_right(PL, i - _PIV_K)
w._pb_levels = {"ph": [C[j] for j in PH[a1:b1]],
"pl": [C[j] for j in PL[a2:b2]]}
td = _tagestrend(C, OP, i, schwelle)
WR._STRETCH_MAX = 3.5
if modus == "spaet" and td:
stretch = (C[i] - ES[i]) / atr
if (td > 0 and stretch > 0) or (td < 0 and stretch < 0):
WR._STRETCH_MAX = STRETCH_LOCKER
rec, _ = w._build(EF[i], ES[i], C[i], atr, "M5", 5,
htf_trend=HTF[i], h1_trend=H1[i], angle=AD[i])
WR._STRETCH_MAX = 3.5
sig = rec.get("signal")
if K_BREAKOUT > 0 and sig in ("LONG", "SHORT"):
d = 1 if sig == "LONG" else -1
if pend is None or pend["dir"] != d:
pend = {"dir": d, "level": C[i] + d * K_BREAKOUT * atr,
"invalid": C[i] - d * K_BREAKOUT * atr,
"confirmed": False, "bar": i}
if not pend["confirmed"]:
broke = (C[i] >= pend["level"]) if d > 0 else (C[i] <= pend["level"])
gegen = (C[i] <= pend["invalid"]) if d > 0 else (C[i] >= pend["invalid"])
if broke:
pend["confirmed"] = True
else:
if gegen or (i - pend["bar"]) > _TIMEOUT_BARS:
pend = {"dir": d, "level": C[i] + d * K_BREAKOUT * atr,
"invalid": C[i] - d * K_BREAKOUT * atr,
"confirmed": False, "bar": i}
i += 1
continue
elif sig == "WARTEN":
pend = None
if sig not in ("LONG", "SHORT"):
i += 1
continue
rec = w._room_gate(rec, C[i])
if rec.get("signal") not in ("LONG", "SHORT"):
i += 1
continue
d = 1 if rec["signal"] == "LONG" else -1
if modus == "veto" and td and td != d:
i += 1
pend = None
continue
if modus in ("nurmit", "pullback") and td != d:
i += 1
pend = None
continue
if modus == "pullback" and abs((C[i] - ES[i]) / atr) > PULLBACK_MAX:
i += 1
pend = None
continue
a = max(atr, _ATRMIN)
r, xj = simulate(C[i], d, a, H, L, C, i + 1, LIVE,
timestop=True, use_tp=True, ret_bar=True)
Rs.append(r - ((SP[i] if SP[i] > 0 else 0.0225) / a))
keys.append(i)
pend = None
i = xj + _COOL
return Rs, keys
def zeig(lbl, k):
if not k:
print(" {:<28} --".format(lbl))
return
ci = k.get("ci")
m = ""
if ci:
m = (" [{:+.3f} .. {:+.3f}]".format(ci[0], ci[1])
+ ("" if ci[0] * ci[1] > 0 else " ~0"))
print(" {:<28} n={:>4} WR={:>3.0f}% OeR={:+.3f} PF={:.2f}{}"
.format(lbl, k["n"], k["wr"], k["oer"], k["pf"], m))
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 60000
schwellen = [0.0030, 0.0015, 0.0060]
mt5.initialize()
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD")
if mt5.symbol_info(c)), None)
b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, n)
point = mt5.symbol_info(sym).point
mt5.shutdown()
T = [int(x["time"]) for x in b]
H = [float(x["high"]) for x in b]
L = [float(x["low"]) for x in b]
C = [float(x["close"]) for x in b]
SP = [float(x["spread"]) * point for x in b]
A = _atr_series(H, L, C)
EF = _ema_series(C, _EMA_FAST)
ES = _ema_series(C, _EMA_SLOW)
OP = _tagesoeffnung(T, C)
AD = [calc_trend_angle(C[max(0, i - _ANGLE_LR):i + 1]) if i >= _ANGLE_LR else 90.0
for i in range(len(C))]
HTF = [_htf_sign(C, i, 6, A[i]) for i in range(len(C))]
H1 = [_htf_sign(C, i, 12, A[i]) for i in range(len(C))]
PH = [j for j in range(_PIV_K, len(C) - _PIV_K)
if C[j] == max(C[j - _PIV_K:j + _PIV_K + 1])]
PL = [j for j in range(_PIV_K, len(C) - _PIV_K)
if C[j] == min(C[j - _PIV_K:j + _PIV_K + 1])]
w = WaveRecommender(_TU(), mt5.TIMEFRAME_M5)
w.set_reversal_enabled(False)
w.set_entry_room(0.6)
w.set_breakout_k(0.0)
N = len(C)
mid = N // 2
ende = N - LIVE.max_hold - 1
tage = len({dt.datetime.fromtimestamp(t, dt.timezone.utc)
.replace(tzinfo=BROKER).astimezone(BERLIN).date() for t in T})
print("=" * 104)
print(" TAGESTREND MEHR GEWICHT? - {} · {} M5-Bars · {} Handelstage"
.format(sym, N, tage))
print(" voller Live-Gate-Stack (echtes _build · Breakout k=0,3 · _room_gate)"
" · kanonischer Exit · Echtkosten")
print("=" * 104)
for schwelle in schwellen:
titel = "Tagestrend-Schwelle {:.2f} %".format(schwelle * 100)
if schwelle != schwellen[0]:
titel += " (Nachbar-Probe)"
print("\n " + titel)
print(" " + "-" * 100)
erg = {}
for modus, lbl in MODI:
r1, k1 = run(w, H, L, C, A, SP, EF, ES, AD, HTF, H1, PH, PL, OP,
0, mid, modus, schwelle)
r2, k2 = run(w, H, L, C, A, SP, EF, ES, AD, HTF, H1, PH, PL, OP,
mid, ende, modus, schwelle)
erg[modus] = (dict(zip(k1, r1)), dict(zip(k2, r2)))
zeig("H1 " + lbl, kennzahlen(r1))
zeig("H2 " + lbl, kennzahlen(r2))
print()
# ⚠⚠ KEIN gepaarter Test hier - er waere DEGENERIERT. Die Varianten
# aendern nicht den EXIT, sondern WELCHE Einstiege genommen werden;
# auf den gemeinsamen Faellen sind die R-Werte per Konstruktion
# IDENTISCH (erster Lauf: Delta +0,000, KI [0,000 .. 0,000] in allen
# acht Zellen). `paarweise` ist das Werkzeug fuer Exit-Varianten
# (Falle vom 14.08.), nicht fuer Auswahl-Varianten.
# Entscheidend ist stattdessen, WAS der Eingriff wegnimmt bzw.
# hinzufuegt - Muster wie in `backtest_htf_vola.py`.
print(" WAS DER EINGRIFF WEGNIMMT / HINZUFUEGT (die eigentliche Frage):")
b1, b2 = erg["basis"]
for modus, lbl in MODI[1:]:
v1, v2 = erg[modus]
for hl, bb, vv in (("H1", b1, v1), ("H2", b2, v2)):
weg = [bb[k] for k in bb if k not in vv]
neu_ = [vv[k] for k in vv if k not in bb]
gruppe, txt = (neu_, "hinzugefuegt") if len(neu_) > len(weg) else (weg, "entfernt")
kk = kennzahlen(gruppe)
if not kk:
print(" {:<28} {} {} n={} - zu wenig"
.format(lbl, hl, txt, len(gruppe)))
continue
ci = kk.get("ci"); m = ""
if ci:
m = (" [{:+.3f} .. {:+.3f}]".format(ci[0], ci[1])
+ ("" if ci[0] * ci[1] > 0 else " ~0"))
print(" {:<28} {} {:<12} n={:>4} WR={:>3.0f}% OeR={:+.3f}{}"
.format(lbl, hl, txt, kk["n"], kk["wr"], kk["oer"], m))
print("\n " + "=" * 100)
print(" REGEL: bauen nur, wenn beidhaelftig besser UND das gepaarte")
print(" Intervall die Null ausschliesst UND die Nachbarn nicht kippen.")
if __name__ == "__main__":
main()