User-Wunsch. Neue CSV-Zeile MS;<text>, im Indikator als gestapelte OBJ_LABEL an CORNER_LEFT_UPPER (oben rechts sind Kurs, G/V und HL belegt). Inhalt = dieselben Zeilen wie die Dashboard-Karte "Meldungen": Squeeze, Ueberdehnung, S/R-Ziel mit P(break), Stop-Seite, News-Blackout. NUR ZUSAMMENGESETZT, NICHT NEU GERECHNET -- alles aus bereits berechneten Snapshot-Teilen bzw. _last_sr_close_hint/_last_stop_approach; calendar.blackout() ist ein reiner Speicher-Zugriff. Der Konsens-Pfeil hat im 5-s-Export-Takt einmal ein komplettes zweites _verdict() gezogen. Zwei Felder vorher geprueft statt angenommen: _last_calendar und _export_meldungen gab es NICHT -- ohne die Pruefung haette das umgebende except Exception es still verschluckt und die Meldungen waeren dauerhaft leer geblieben (dieselbe Klasse wie der wave_snap-Fallstrick vom 04.08.). ASCII-SICHER, real noetig: der erste Lauf lieferte "MS; Kompression Ausbruch steht bevor" -- Emoji und Gedankenstrich waren zu Leerzeichen geworden. Der Indikator liest die CSV nicht als UTF-8 (deshalb steht dort auch "Unterstuetzung"). Jetzt Ersetzung + Filter auf 32-126. Verifiziert: MS;Squeeze-Ausbruch LONG @ 82.413, 0 Nicht-ASCII-Zeichen. Deckel 5 Zeilen a 70 Zeichen; eigener Praefix SRB_MSG_*, damit die Labels beim Redraw verschwinden. Abschaltbar per [trading] export_meldungen=false oder InpShowMeldungen. Kompiliert ins richtige Terminal (0 errors, 0 warnings), deployt und am laufenden Server verifiziert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1065 lines
58 KiB
Plaintext
1065 lines
58 KiB
Plaintext
//+------------------------------------------------------------------+
|
||
//| SR_Levels.mq5 |
|
||
//| Zeichnet Support-/Resistance-Linien + Zonen (Ranges), die der |
|
||
//| Python-Bot (Oil Trading Server) nach MQL5\Files\sr_levels.csv |
|
||
//| schreibt. Das Python-MetaTrader5-Paket kann selbst KEINE Chart- |
|
||
//| Objekte erzeugen — daher diese Datei-Bridge. |
|
||
//| |
|
||
//| Installation: |
|
||
//| 1) Diese Datei nach <Terminal>\MQL5\Indicators\ kopieren. |
|
||
//| 2) In MetaEditor öffnen und mit F7 kompilieren. |
|
||
//| 3) Im Navigator auf den WTI-Chart (SpotCrude) ziehen. |
|
||
//| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). |
|
||
//+------------------------------------------------------------------+
|
||
#property copyright "Oil Trading Bot"
|
||
#property version "1.36"
|
||
// v1.36 (2026-08-17): MELDUNGEN oben links (MS;<text>) — dieselben Zeilen wie
|
||
// die Dashboard-Karte "Meldungen" (Squeeze, Ueberdehnung, S/R-Ziel,
|
||
// Stop-Seite, News-Blackout). Der Bot setzt sie nur ZUSAMMEN aus bereits
|
||
// berechneten Snapshot-Teilen, er rechnet nichts neu -- die Lehre aus dem
|
||
// Konsens-Pfeil, der im 5-s-Takt ein zweites _verdict() zog.
|
||
// Abschaltbar per InpShowMeldungen oder [trading] export_meldungen=false.
|
||
// v1.35 (2026-08-13): S/R-LABEL WORTGLEICH ZUR M15-KARTE (User: „die Beschriftung
|
||
// fuer S/R im Chart stimmt nicht mit der Analyse in der M15-Karte ueberein").
|
||
// Das Label trug seit v1.27 die NACKTE Zahl = P(Durchbruch); die Karte klappt
|
||
// unter 45 % auf P(Abprall) um und nennt 45-55 % „unentschieden". Dasselbe
|
||
// Level stand damit im Chart als „33%" und in der Karte als „67 % Abprall" —
|
||
// beide Zahlen richtig, aber die Chart-Zahl sagte nicht, WAS sie ist.
|
||
// GEMESSEN in 88,1 % der Zeit verschieden (1.797 Vorhersagen/14 Tage).
|
||
// Jetzt: „69% Bruch" / „unentschieden" / „67% Abprall" — identisch zu app.js.
|
||
// v1.34 (2026-08-01): HYPERLIQUID-KURS (HL;...) unter Kurs und G/V oben rechts,
|
||
// bernstein. HL handelt 24/7, Pepperstone nicht - am Wochenende der einzige
|
||
// lebende Kurs; die Basis (~0,45 $ Kontrakt-Differenz) ist herausgerechnet,
|
||
// der Wert also direkt mit dem Broker-Kurs vergleichbar. InpShowHL/InpHLColor.
|
||
// v1.33 (2026-07-31): Konsens-Pfeil (K) per Default AUS + Pfeile kuerzer (8 statt
|
||
// 14 Bars). Grund: L und K starten am selben Punkt und zeigten oft in
|
||
// ENTGEGENGESETZTE Richtungen - zwei divergierende Linien aus einem Punkt
|
||
// sehen aus wie der Kegel, den sie ersetzen sollten. Jetzt normalerweise EIN
|
||
// Pfeil (L, der kalibrierte); S kommt nur beim Squeeze-Ausbruch dazu.
|
||
// InpShowConsensus=true holt den Konsens-Pfeil zurueck.
|
||
// v1.32 (2026-07-31): RICHTUNGS-PFEILE (AR;<art>;<von>;<nach>;<text>) statt des
|
||
// Kegels (User-Wunsch). DREI Arten mit UNTERSCHIEDLICHER Beleglage:
|
||
// L blau = am naechsten Level, aus dem kalibrierten P(break)
|
||
// (AUC 0,65 oos, live kalibriert) - BEDINGTE Aussage
|
||
// S neongruen = Squeeze-Ausbruch, das EINZIGE 2-Stichproben-validierte
|
||
// Richtungssignal - erscheint nur bei `active`
|
||
// K grau = Konsens der Verdict-Module - NICHT kalibriert, heisst
|
||
// deshalb "Konsens" und nicht "Prognose"
|
||
// ⚠ KEINER ist eine freie Kursprognose: die ist im Projekt gemessen ein
|
||
// Muenzwurf (analyze_reversal.py, AUC 0,499-0,509 oos, in-sample 0,52).
|
||
// Der Kegel bleibt im Code (InpShowCone), der Bot exportiert ihn aber per
|
||
// Default nicht mehr ([trading] export_cone).
|
||
// v1.31 (2026-07-31): WAHRSCHEINLICHKEITS-KEGEL (CN;<minuten>;<lo>;<hi>) — zwei sich
|
||
// oeffnende, gepunktete Pfade vom aktuellen Bar ueber 30/60/120 min.
|
||
// ⚠ KEINE Richtungsprognose, sondern STREUUNG: wie weit der Kurs plausibel
|
||
// gelaufen sein kann. Out-of-sample kalibriert (analyze_cone.py): das
|
||
// 80%-Band trifft real ~76%. Bewusst NEUTRAL grau (keine Richtungsfarbe).
|
||
// InpShowCone / InpConeColor.
|
||
// v1.30 (2026-07-30): Konsolidierungs-Box BESCHRIFTET (User-Frage „was bedeutet die
|
||
// graue Box") — sichtbares Label an der Oberkante, rechtsbuendig wie die
|
||
// uebrigen: „Konsolidierung (10-Bar-Spanne)" bzw. bei Kompression
|
||
// „Konsolidierung - komprimiert, Ausbruch steht bevor".
|
||
// v1.29 (2026-07-30): KONSOLIDIERUNGS-BOX (CO;lo;hi;tight) — die Spanne der letzten
|
||
// 10 M5-Bars, aus der der validierte Squeeze-Ausbruch kommt. Komprimiert
|
||
// (<=2,5xATR) wird sie deutlicher gezeichnet. ⚠ REINE ANZEIGE: alle
|
||
// Konsolidierungs-SETUPS sind gemessen verworfen (backtest_consolidation.py) —
|
||
// die Box zeigt WO gestaut wird, nicht WOHIN es geht.
|
||
// v1.28 (2026-07-30): G/V der offenen Position direkt UNTER dem Kurs oben rechts
|
||
// (User-Wunsch) — PL;wert;waehrung, NETTO wie im Dashboard (WHT-Quellensteuer
|
||
// bei Gewinn bereits abgezogen). Gruen im Plus, rot im Minus; ohne offene
|
||
// Position schickt der Bot keine PL-Zeile -> Label verschwindet.
|
||
// v1.27 (2026-07-30): S/R-Label zeigt nur noch die Prozentzahl statt
|
||
// „Durchbruch 34%" (User-Wunsch) — der ausgeschriebene Text bleibt im Tooltip.
|
||
// v1.26 (2026-07-30): Beschriftungen + Pfeile stehen jetzt GANZ rechts am
|
||
// Chartrand — auf Hoehe des Kurs-Labels (User: „genau so angeordnet wie der
|
||
// aktuelle Kurs"). RightTime() rechnet dafuer das Ende des Shift-Bereichs
|
||
// aus (CHART_WIDTH_IN_BARS x InpShiftPct) statt fix 2 Kerzen hinter die
|
||
// letzte Bar. Gilt beim Erzeugen UND beim Nachfuehren.
|
||
// v1.25 (2026-07-30): S/R-Labels zeigen die DURCHBRUCHWAHRSCHEINLICHKEIT
|
||
// (User-Wunsch) — der Bot haengt sie als drittes CSV-Feld an (R;preis;pct).
|
||
// Quelle = dasselbe kalibrierte P(break)-Modell wie der S/R-Auto-Close, auf
|
||
// die M30-Level nachtrainiert (AUC 0,72 out-of-sample). Niedrig = Level
|
||
// haelt eher. Abschaltbar via InpShowPBreak.
|
||
// v1.24 (2026-07-30): Farb-Inputs UMBENANNT — MT5 speichert Input-Werte je
|
||
// Chart-Instanz und ueberschreibt damit NEUE Defaults, auch nach Recompile
|
||
// (deshalb blieben die Pfeile gold). Durch die Umbenennung findet MT5 keinen
|
||
// gespeicherten Wert mehr und nimmt den Default:
|
||
// InpWallBidColor -> InpArrowUpColor (neongruen #00FF7F)
|
||
// InpWallAskColor -> InpArrowDownColor (rot #FF4500)
|
||
// InpLiqTrendColor -> InpTrendLineColor (neongruen)
|
||
// InpLiqZoneColor/Alpha -> InpZoneColor/InpZoneAlpha
|
||
// v1.23 (2026-07-30): (a) Pfeile wieder NEONGRUEN/ROT statt Gold (User-Wunsch).
|
||
// (b) Liquiditaets-Trendlinie neongruen wie der Up-Pfeil (statt pink).
|
||
// (c) FIX „Beschriftungen nicht komplett rechtsbuendig": auf den Linien war
|
||
// OBJPROP_TEXT gesetzt — den zeichnet MT5 LINKS am Chartrand. Jetzt
|
||
// OBJPROP_TOOLTIP + CHART_SHOW_OBJECT_DESCR=false.
|
||
// (e) ALLE Beschriftungen weiss (InpLabelColor) — die Linien behalten
|
||
// ihre Farbe, nur der Text ist einheitlich weiss.
|
||
// (d) MT5-Positions-Labels ("sell 0.36") stehen systembedingt LINKS und
|
||
// koennen nicht verschoben werden -> nur ab-/anschaltbar via
|
||
// InpShowTradeLevels.
|
||
// v1.22 (2026-07-30): Aufraeumen nach User-Feedback „das Bild sieht komisch aus":
|
||
// (a) Trade-Umrandungen ENTFERNT (InpShowTrades=false, Export im Bot aus).
|
||
// (b) Liquiditaets-Trendlinie nicht mehr RAY_RIGHT — eine 60-min-Regression
|
||
// 100 Bars in die Zukunft zu ziehen riss die Linie ins Bodenlose.
|
||
// (c) CHART_SHIFT_SIZE begrenzt (InpShiftPct=12 %) — ohne Begrenzung stand
|
||
// der Kursverlauf ganz links gequetscht.
|
||
// ⚠ MT5 uebernimmt beim Neukompilieren NICHT die neuen Default-Inputs, wenn
|
||
// der Indikator schon auf dem Chart liegt: einmal ENTFERNEN und neu aufziehen.
|
||
// v1.21 (2026-07-30): Beschriftungen aller Linien RECHTSBUENDIG am rechten
|
||
// Chart-Rand (vorher zentriert; ANCHOR_RIGHT_LOWER -> Text endet am Anker,
|
||
// laeuft nach links, ragt nicht raus) + Schriftgroesse 8 -> 12 (+4 px,
|
||
// User-Wunsch). Neu einstellbar via InpLabelSize.
|
||
// v1.20 (2026-07-30): aktuelle KURSLINIE weiss (User-Vorgabe) — CHART_COLOR_BID/
|
||
// ASK/LAST auf InpThemeBidLine, Bid-Linie explizit eingeschaltet.
|
||
// v1.19 (2026-07-30): Liquiditaetszone TRANSPARENT (User: „Transparenz der Zone
|
||
// auf 10 %"). MT5 kann bei OBJ_RECTANGLE kein echtes Alpha -> BlendBg()
|
||
// mischt die Fuellfarbe gegen den (bekannten, einfarbigen) Chart-Hintergrund;
|
||
// das Ergebnis sieht identisch aus. InpZoneAlpha = Deckkraft in %.
|
||
// Die gestrichelte Kante bleibt in voller Farbe (wie im Referenzbild).
|
||
// v1.18 (2026-07-30): NEU (User-Wuensche) — (a) LIQUIDITAETSZONEN: Equal Highs /
|
||
// Equal Lows aus den M30-Pivots als goldenes Band + gestrichelte Kante,
|
||
// nach rechts verlaengert (EQ;<H|L>;lo;hi;zeit). REINE ANZEIGE, als Signal
|
||
// gemessen verworfen. (b) AKTUELLER KURS oben rechts, fett (PX;bid).
|
||
// v1.17 (2026-07-30): FIX „Liquiditaets-Pfeile werden nicht angezeigt" — zwei
|
||
// Ursachen: (1) ANCHOR_LEFT ist fuer OBJ_ARROW UNGUELTIG (nur ANCHOR_TOP/
|
||
// ANCHOR_BOTTOM), (2) die Pfeile sitzen rechts NEBEN der letzten Kerze —
|
||
// ohne CHART_SHIFT gibt es dort keinen sichtbaren Bereich. Beides behoben.
|
||
// NEU: TRADE-MARKER (TR;<O|C>;zeit) — die Kerze der Eroeffnung wird HELLGRUEN,
|
||
// die des Close DUNKELGRUEN umrandet (InpShowTrades/InpTradeOpenColor/
|
||
// InpTradeCloseColor).
|
||
// v1.16 (2026-07-30): Beschriftung der Liquiditäts-Trendlinie per Default AUS
|
||
// (User: „die beschreibung der liquiditätslinie kann ausgeblendet werden") —
|
||
// Text steht jetzt im Tooltip der Linie; `InpLiqTrendLabel=true` holt sie zurück.
|
||
// v1.15 (2026-07-30): CHART-THEME (User: „Farben im MT5 wie im Bild") — setzt beim
|
||
// Start Hintergrund/Gitter/Kerzenfarben auf die Dashboard-Palette
|
||
// (Bull #3B82F6, Bear #EF4444, BG #0D1117, Gitter #10151C dezent).
|
||
// Liquiditäts-Pfeile jetzt GOLD #F59E0B (= „Liquiditätszone" der Legende).
|
||
// Abschaltbar via InpApplyTheme. ⚠ ändert das Chart dauerhaft.
|
||
// v1.14 (2026-07-30): Liquiditäts-LINIEN + Text-Labels ENTFERNT (User: „blende die
|
||
// liquiditätslinien aus, nur die Pfeile sollen rechtsbündig angezeigt werden").
|
||
// Es bleibt NUR der Pfeil auf dem Wand-Preis, RECHTSBÜNDIG am aktuellen Rand
|
||
// (wird in RepositionLabels() nachgeführt, bleibt beim Scrollen rechts).
|
||
// Details (Seite/Größe/Dominanz/Preis) jetzt im TOOLTIP statt im Chart.
|
||
// Die pinke Liquiditäts-Trendlinie bleibt unverändert.
|
||
// v1.13 (2026-07-30): Liquiditäts-Wände bekommen einen PFEIL in ihrer Wirkrichtung
|
||
// (Lesart „die Wand hält" — Nachfrage stützt hoch, Angebot deckelt runter;
|
||
// die GRÖSSERE Wand wird dicker gezeichnet + "<<"). NEU: pinke
|
||
// LIQUIDITÄTS-TRENDLINIE (LT;…) = Regression über den volumengewichteten
|
||
// Wand-Schwerpunkt der letzten ~60 min — zeigt, wohin das Gewicht der
|
||
// RUHENDEN Orders wandert (nicht der gehandelte Kurs).
|
||
// ⚠ Pfeilrichtung ist INTERPRETATION, nicht gemessen (s. analyze_bookflow.py).
|
||
// v1.12 (2026-07-30): Chartmuster-Linien (PT;…) ENTFERNT (User-Wunsch, Chart war zu
|
||
// voll — Kachel/PWA-Anzeige bleibt). NEU: ECHTE Liquiditäts-Wände (LQ;…) aus
|
||
// dem Hyperliquid-L2-Orderbuch, basis-korrigiert auf CFD-Niveau — die einzigen
|
||
// Linien im Chart, die nicht aus Pivots geschätzt sind, sondern tatsächlich
|
||
// ruhende Orders zeigen (dick gestrichelt + Größen-Label). Reine Anzeige.
|
||
// v1.11: Chartmuster-Linien (jetzt entfernt).
|
||
// ⚠ nach dem Update den Indikator NEU mit F7 kompilieren.
|
||
#property indicator_chart_window
|
||
#property indicator_plots 0
|
||
|
||
input string InpFile = "sr_levels.csv"; // Datei in MQL5\Files
|
||
input int InpRefreshS = 2; // Aktualisierung (Sekunden)
|
||
input color InpResColor = clrDodgerBlue; // Widerstand (blau kräftig)
|
||
input color InpSupColor = clrDeepSkyBlue; // Support (blau hell)
|
||
input bool InpShowRange = false; // dynamische Handels-Range zeichnen (aus per User-Wunsch)
|
||
input int InpRangeBars = 50; // Range = Hoch/Tief der letzten N Kerzen
|
||
input color InpRangeColor = clrGoldenrod; // Range-Farbe
|
||
input bool InpRangeFill = false; // Range füllen (aus = nur Umriss)
|
||
input bool InpShowChannel = true; // Regressionskanal (M30) zeichnen
|
||
input color InpChanColor = clrYellow; // Kanal-Farbe
|
||
input bool InpShowWalls = true; // echte Liquiditäts-Wände (Hyperliquid-Orderbuch)
|
||
input color InpArrowUpColor = C'0,255,127'; // Liquiditaet Nachfrage (Bid) — NEONGRUEN
|
||
input color InpArrowDownColor = C'255,69,0'; // Liquiditaet Angebot (Ask) — ROT
|
||
input bool InpShowLiqTrend = true; // Liquiditäts-Trendlinie zeichnen
|
||
input color InpTrendLineColor = C'0,255,127'; // Liquiditaets-Trend — NEONGRUEN (wie Up-Pfeil)
|
||
input bool InpLiqTrendLabel = false; // Beschriftung der Trendlinie (aus per User-Wunsch)
|
||
input bool InpShowTrades = false; // Trade-Kerzen umranden (AUS per User-Wunsch)
|
||
input color InpTradeOpenColor = C'134,239,172'; // Eroeffnung — hellgruen
|
||
input color InpTradeCloseColor = C'21,128,61'; // Close — dunkelgruen
|
||
input bool InpShowLiqZones = true; // Liquiditaetszonen (Equal Highs/Lows)
|
||
input color InpZoneColor = C'245,158,11'; // Zonen-Grundfarbe (Gold #F59E0B)
|
||
input int InpZoneAlpha = 10; // Deckkraft der Zonenfuellung in % (10 = sehr transparent)
|
||
input bool InpShowPrice = true; // aktuellen Kurs oben rechts anzeigen
|
||
input int InpPriceSize = 20; // Schriftgroesse des Kurses
|
||
input int InpLabelSize = 12; // Schriftgroesse der Linien-Beschriftungen (+4 per User-Wunsch)
|
||
input bool InpShowPBreak = true; // Durchbruchwahrscheinlichkeit am S/R-Label
|
||
input color InpLabelColor = clrWhite; // Farbe ALLER Linien-Beschriftungen (User-Wunsch: weiss)
|
||
input color InpPriceColor = clrWhite; // Kurs oben rechts (weiss)
|
||
input bool InpShowConsol = true; // Konsolidierungs-Box (10 M5-Bars) zeichnen
|
||
input color InpConsolColor = C'88,166,255'; // Box-Farbe (blau)
|
||
input int InpConsolAlpha = 8; // Deckkraft in % (komprimiert: x2)
|
||
input int InpConsolBars = 10; // Box-Laenge in Bars (= _SQ_N im Bot)
|
||
input bool InpShowCone = true; // Wahrscheinlichkeits-Kegel (Streuung, NICHT Richtung)
|
||
input bool InpShowArrows = true; // Richtungs-Pfeile (Level / Squeeze / Konsens)
|
||
input color InpArrLevel = C'88,166,255'; // Pfeil am naechsten Level (P(break)) - blau
|
||
input color InpArrSqueeze = C'0,255,127'; // Squeeze-Ausbruch (validiert) - neongruen
|
||
input color InpArrConsensus = C'139,148,158'; // Konsens der Module (NICHT kalibriert) - grau
|
||
// ⚠ Konsens-Pfeil per DEFAULT AUS (2026-07-31): er startet am selben Punkt wie der
|
||
// Level-Pfeil und lief oft in die GEGENrichtung - zwei divergierende Linien aus einem
|
||
// Punkt sehen aus wie der Kegel, den er ersetzen sollte (User: "trichter anstatt
|
||
// pfeil wird angezeigt"). Der Konsens steht ohnehin im Dashboard (Bias-Nadel).
|
||
input bool InpShowConsensus = false; // Konsens-Pfeil zusaetzlich zeichnen
|
||
input int InpArrBars = 8; // Pfeil-Laenge in Bars (kuerzer = Spitze sichtbar)
|
||
input color InpConeColor = C'139,148,158'; // Kegel-Farbe (neutral grau - bewusst KEINE Richtungsfarbe)
|
||
input bool InpShowHL = true; // Hyperliquid-Kurs unter dem Broker-Kurs
|
||
input color InpHLColor = C'232,160,0'; // HL-Kurs (bernstein, klar unterscheidbar)
|
||
input bool InpShowPnL = true; // G/V der offenen Position unter dem Kurs
|
||
input color InpPnLUpColor = C'0,255,127'; // G/V im Plus (neongruen)
|
||
input color InpPnLDownColor = C'255,69,0'; // G/V im Minus (rot)
|
||
// ── Chart-THEME (User-Vorgabe 2026-07-30 „Farben im MT5 wie im Bild") ────────
|
||
// Setzt beim Start die Chart-Eigenschaften auf die Dashboard-Palette, damit MT5
|
||
// und die PWA gleich aussehen. Farben in MQL5-Notation C'R,G,B'.
|
||
// Bullish #3B82F6 · Bearish #EF4444 · Liquidität #F59E0B · Entry/Target #22C55E
|
||
// Hintergrund #0D1117 · Gitter #10151C (sehr dezent) · Text #8B949E
|
||
// ⚠ Ändert das Chart dauerhaft (bleibt auch nach Entfernen des Indikators) —
|
||
// deshalb per Schalter abschaltbar.
|
||
input bool InpApplyTheme = true; // Chart-Farben setzen (Dashboard-Look)
|
||
input color InpThemeBull = C'59,130,246'; // Bullish Candle (blau)
|
||
input color InpThemeBear = C'239,68,68'; // Bearish Candle (rot)
|
||
input color InpThemeBg = C'13,17,23'; // Hintergrund
|
||
input color InpThemeGrid = C'16,21,28'; // Gitternetz (dezent)
|
||
input color InpThemeText = C'139,148,158'; // Achsen/Text
|
||
input color InpThemeBidLine = clrWhite; // aktuelle Kurslinie (Bid) — weiss
|
||
input double InpShiftPct = 12.0; // Platz rechts fuer Pfeile/Labels (% der Chartbreite)
|
||
input bool InpShowTradeLevels = true; // MT5-Positionslinien+Labels (stehen immer LINKS)
|
||
// Meldungen oben links (User-Wunsch 2026-08-17) — dieselben Zeilen wie die
|
||
// Dashboard-Karte „Meldungen". Der Bot deckelt auf 5; abschaltbar per ini
|
||
// (`[trading] export_meldungen=false`) ODER hier.
|
||
input bool InpShowMeldungen = true; // Meldungen oben links einblenden
|
||
input int InpMeldungSize = 10; // Schriftgroesse der Meldungen
|
||
input color InpMeldungColor = clrGainsboro; // Farbe der Meldungen
|
||
|
||
const string PFX = "SRB_"; // Präfix S/R-Linien (aus Datei)
|
||
const string RPFX = "SRR_"; // Präfix dynamische Range (aus Chart)
|
||
string g_last = "\x01"; // letzter Datei-Inhalt (gegen Flackern)
|
||
// Kegel: Verkettung der Horizonte (30->60->120). Die CSV liefert sie aufsteigend;
|
||
// jeder Abschnitt startet dort, wo der vorherige endete -> ein sich oeffnender
|
||
// Faecher statt drei unverbundener Geraden. Wird je Redraw zurueckgesetzt.
|
||
datetime g_coneT = 0;
|
||
double g_coneLo = 0.0, g_coneHi = 0.0;
|
||
double g_conePx = 0.0; // aktueller Kurs (aus der PX-Zeile)
|
||
bool g_range_drawn = false; // hat DIESE Instanz die Range gezeichnet?
|
||
|
||
//+------------------------------------------------------------------+
|
||
int OnInit()
|
||
{
|
||
if(InpApplyTheme) ApplyTheme();
|
||
EventSetTimer(MathMax(1, InpRefreshS));
|
||
Redraw();
|
||
DrawRange();
|
||
return(INIT_SUCCEEDED);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Chart-Farben auf die Dashboard-Palette setzen (User-Vorgabe). |
|
||
//| Kerzen werden GEFÜLLT gezeichnet (Body in Bull-/Bear-Farbe), damit|
|
||
//| es aussieht wie im Referenzbild. |
|
||
//+------------------------------------------------------------------+
|
||
//+------------------------------------------------------------------+
|
||
//| Farbe mit dem Chart-Hintergrund mischen — simuliert TRANSPARENZ. |
|
||
//| ⚠ MT5 kann bei OBJ_RECTANGLE KEIN echtes Alpha (nur Canvas- |
|
||
//| Objekte könnten das). Da der Hintergrund bekannt und einfarbig |
|
||
//| ist, sieht die Mischung exakt aus wie eine transparente Füllung. |
|
||
//| pct = Deckkraft in % (10 = sehr transparent, 100 = voll deckend). |
|
||
//+------------------------------------------------------------------+
|
||
color BlendBg(color c, int pct)
|
||
{
|
||
if(pct >= 100) return c;
|
||
if(pct < 0) pct = 0;
|
||
color bg = (color)ChartGetInteger(0, CHART_COLOR_BACKGROUND);
|
||
double a = pct / 100.0;
|
||
int r = (int)((c & 0xFF) * a + (bg & 0xFF) * (1 - a));
|
||
int g = (int)(((c >> 8) & 0xFF) * a + ((bg >> 8) & 0xFF) * (1 - a));
|
||
int b = (int)(((c >> 16)& 0xFF) * a + ((bg >> 16)& 0xFF) * (1 - a));
|
||
return (color)(r | (g << 8) | (b << 16));
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
void ApplyTheme()
|
||
{
|
||
ChartSetInteger(0, CHART_MODE, CHART_CANDLES);
|
||
ChartSetInteger(0, CHART_COLOR_BACKGROUND, InpThemeBg);
|
||
ChartSetInteger(0, CHART_COLOR_FOREGROUND, InpThemeText);
|
||
ChartSetInteger(0, CHART_SHOW_GRID, true);
|
||
ChartSetInteger(0, CHART_COLOR_GRID, InpThemeGrid);
|
||
// Body-Füllung
|
||
ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, InpThemeBull);
|
||
ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, InpThemeBear);
|
||
// Umriss + Docht in derselben Farbe → klare, flächige Kerzen wie im Bild
|
||
ChartSetInteger(0, CHART_COLOR_CHART_UP, InpThemeBull);
|
||
ChartSetInteger(0, CHART_COLOR_CHART_DOWN, InpThemeBear);
|
||
ChartSetInteger(0, CHART_COLOR_CHART_LINE, InpThemeText);
|
||
// Aktuelle Kurslinie WEISS (User-Vorgabe 2026-07-30) — sie soll sich klar von
|
||
// den blau/roten Kerzen und den farbigen Overlays abheben.
|
||
ChartSetInteger(0, CHART_COLOR_BID, InpThemeBidLine);
|
||
ChartSetInteger(0, CHART_COLOR_ASK, InpThemeBidLine);
|
||
ChartSetInteger(0, CHART_COLOR_LAST, InpThemeBidLine);
|
||
ChartSetInteger(0, CHART_SHOW_BID_LINE, true);
|
||
ChartSetInteger(0, CHART_COLOR_STOP_LEVEL, C'239,68,68');
|
||
ChartSetInteger(0, CHART_SHOW_PERIOD_SEP, false);
|
||
// ⚠ CHART_SHIFT MUSS an sein: die Liquiditäts-Pfeile sitzen rechts NEBEN der
|
||
// letzten Kerze. Ohne Shift gibt es dort keinen sichtbaren Bereich → die Pfeile
|
||
// wären unsichtbar (das war der zweite Grund für „Pfeile werden nicht angezeigt").
|
||
ChartSetInteger(0, CHART_SHIFT, true);
|
||
// Shift-Bereich klein halten: nur so viel Platz rechts, dass Pfeile und
|
||
// Beschriftungen hinpassen. Ohne Begrenzung stand der Kursverlauf ganz links
|
||
// gequetscht (User-Feedback „das Bild sieht komisch aus", 2026-07-30).
|
||
ChartSetDouble(0, CHART_SHIFT_SIZE, InpShiftPct);
|
||
// MT5 zeichnet Objekt-BESCHREIBUNGEN immer LINKS an den Chartrand — aus, damit
|
||
// nur die eigenen, rechtsbuendigen Labels sichtbar sind (User-Vorgabe).
|
||
ChartSetInteger(0, CHART_SHOW_OBJECT_DESCR, false);
|
||
// Positions-/Order-Beschriftungen ("sell 0.36 ...") stehen bei MT5 fest LINKS und
|
||
// lassen sich NICHT nach rechts holen — nur ganz aus- oder einschalten.
|
||
ChartSetInteger(0, CHART_SHOW_TRADE_LEVELS, InpShowTradeLevels);
|
||
ChartRedraw();
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
void OnDeinit(const int reason)
|
||
{
|
||
EventKillTimer();
|
||
ObjectsDeleteAll(0, PFX);
|
||
ObjectsDeleteAll(0, RPFX);
|
||
ChartRedraw();
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
void OnTimer() { Redraw(); DrawRange(); RepositionLabels(); }
|
||
//+------------------------------------------------------------------+
|
||
//| Zeitpunkt der horizontalen Chart-Mitte (sichtbarer Bereich) |
|
||
//+------------------------------------------------------------------+
|
||
datetime CenterTime()
|
||
{
|
||
long first = ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
|
||
long width = ChartGetInteger(0, CHART_WIDTH_IN_BARS);
|
||
int mid = (int)MathMax(0, first - width / 2);
|
||
return iTime(_Symbol, PERIOD_CURRENT, mid);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Zeitpunkt am RECHTEN Chart-Rand (im Shift-Bereich hinter der |
|
||
//| letzten Kerze) — dort sitzen ALLE Beschriftungen (User-Vorgabe |
|
||
//| 2026-07-30 „Beschriftung aller Linien bitte rechtsbündig"). |
|
||
//+------------------------------------------------------------------+
|
||
datetime RightTime()
|
||
{
|
||
// Ganz an den RECHTEN Chartrand — also ans Ende des Shift-Bereichs, nicht nur
|
||
// 2 Kerzen hinter die letzte (User 2026-07-30: „genau so angeordnet wie der
|
||
// aktuelle Kurs"). Der Shift-Bereich ist InpShiftPct % der sichtbaren Breite;
|
||
// ein Balken Reserve, damit der Text nicht am Rand abgeschnitten wird.
|
||
long width = ChartGetInteger(0, CHART_WIDTH_IN_BARS);
|
||
int bars = (int)MathMax(2, (double)width * InpShiftPct / 100.0 - 1.0);
|
||
return iTime(_Symbol, PERIOD_CURRENT, 0) + (datetime)(PeriodSeconds() * bars);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Hält die Beschriftungen beim Scrollen/Zoomen am rechten Rand |
|
||
//+------------------------------------------------------------------+
|
||
void RepositionLabels()
|
||
{
|
||
datetime ct = RightTime();
|
||
int total = ObjectsTotal(0, 0, OBJ_TEXT);
|
||
for(int i = 0; i < total; i++)
|
||
{
|
||
string nm = ObjectName(0, i, 0, OBJ_TEXT);
|
||
if(StringFind(nm, PFX + "T") == 0)
|
||
{
|
||
double pr = ObjectGetDouble(0, nm, OBJPROP_PRICE);
|
||
ObjectMove(0, nm, 0, ct, pr);
|
||
// rechtsbündig = Text endet am Anker und läuft nach LINKS
|
||
ObjectSetInteger(0, nm, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
|
||
}
|
||
}
|
||
// Liquiditäts-PFEILE rechtsbündig halten: die CSV ändert sich nicht bei jedem
|
||
// Tick, ohne Nachführung würden die Pfeile mit jeder neuen Kerze nach links
|
||
// wandern. Preis bleibt, nur die Zeit wird an den rechten Rand gezogen.
|
||
datetime rt = RightTime();
|
||
int na = ObjectsTotal(0, 0, OBJ_ARROW);
|
||
for(int i = 0; i < na; i++)
|
||
{
|
||
string nm = ObjectName(0, i, 0, OBJ_ARROW);
|
||
if(StringFind(nm, PFX + "ALQ_") == 0)
|
||
ObjectMove(0, nm, 0, rt, ObjectGetDouble(0, nm, OBJPROP_PRICE));
|
||
}
|
||
ChartRedraw();
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Dynamische Handels-Range = Hoch/Tief der letzten N Kerzen des |
|
||
//| AKTUELLEN Charts (TF-genau). In-place via ObjectMove → kein |
|
||
//| Flackern, passt sich an M1/M5/…/H1 automatisch an. |
|
||
//+------------------------------------------------------------------+
|
||
void DrawRange()
|
||
{
|
||
string nm = RPFX + "BOX";
|
||
if(!InpShowRange)
|
||
{
|
||
// Nur löschen, was DIESE Instanz gezeichnet hat — sonst kämpfen zwei
|
||
// Instanzen (eine an/eine aus) um die Box → Blinken im 2-s-Takt.
|
||
if(g_range_drawn) { ObjectDelete(0, nm); g_range_drawn = false; ChartRedraw(); }
|
||
return;
|
||
}
|
||
int total = Bars(_Symbol, PERIOD_CURRENT);
|
||
if(total < 5) return;
|
||
int n = InpRangeBars;
|
||
if(n > total - 1) n = total - 1;
|
||
int hi_i = iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, n, 0);
|
||
int lo_i = iLowest (_Symbol, PERIOD_CURRENT, MODE_LOW, n, 0);
|
||
if(hi_i < 0 || lo_i < 0) return;
|
||
double hi = iHigh(_Symbol, PERIOD_CURRENT, hi_i);
|
||
double lo = iLow (_Symbol, PERIOD_CURRENT, lo_i);
|
||
datetime t0 = iTime(_Symbol, PERIOD_CURRENT, n - 1);
|
||
datetime t1 = iTime(_Symbol, PERIOD_CURRENT, 0) + PeriodSeconds();
|
||
if(ObjectFind(0, nm) < 0)
|
||
{
|
||
ObjectCreate(0, nm, OBJ_RECTANGLE, 0, t0, lo, t1, hi);
|
||
ObjectSetInteger(0, nm, OBJPROP_COLOR, InpRangeColor);
|
||
ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, nm, OBJPROP_FILL, InpRangeFill);
|
||
ObjectSetInteger(0, nm, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
||
ObjectSetString (0, nm, OBJPROP_TEXT, "Range " + IntegerToString(n));
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, nm, 0, t0, lo); // linke untere Ecke
|
||
ObjectMove(0, nm, 1, t1, hi); // rechte obere Ecke
|
||
}
|
||
g_range_drawn = true;
|
||
ChartRedraw();
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Pflicht-Funktion jedes Indikators — hier No-op (wir zeichnen |
|
||
//| über OnTimer aus der Datei, nicht aus den Kursreihen). |
|
||
//+------------------------------------------------------------------+
|
||
int OnCalculate(const int rates_total,
|
||
const int prev_calculated,
|
||
const datetime &time[],
|
||
const double &open[],
|
||
const double &high[],
|
||
const double &low[],
|
||
const double &close[],
|
||
const long &tick_volume[],
|
||
const long &volume[],
|
||
const int &spread[])
|
||
{
|
||
return(rates_total);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
void Redraw()
|
||
{
|
||
int h = FileOpen(InpFile, FILE_READ|FILE_TXT|FILE_ANSI|FILE_SHARE_READ|FILE_SHARE_WRITE);
|
||
if(h == INVALID_HANDLE)
|
||
return; // Datei (noch) nicht da → nächster Tick
|
||
|
||
// Ganze Datei in einen String lesen und mit dem letzten Stand vergleichen —
|
||
// nur bei ÄNDERUNG neu zeichnen (sonst flackert der delete/recreate alle 2 s).
|
||
string content = "";
|
||
while(!FileIsEnding(h))
|
||
content += FileReadString(h) + "\n";
|
||
FileClose(h);
|
||
if(content == g_last)
|
||
return; // nichts geändert → nicht anfassen
|
||
g_last = content;
|
||
|
||
ObjectsDeleteAll(0, PFX);
|
||
string rows[];
|
||
int nr = StringSplit(content, '\n', rows);
|
||
int idx = 0;
|
||
int msg_idx = 0; // Meldungs-Stapel oben links
|
||
// Kegel-Verkettung je Redraw zuruecksetzen (sonst haengt der Faecher am Stand
|
||
// des vorherigen Durchlaufs)
|
||
g_coneT = 0; g_coneLo = 0.0; g_coneHi = 0.0; g_conePx = 0.0;
|
||
|
||
for(int r = 0; r < nr; r++)
|
||
{
|
||
string line = rows[r];
|
||
if(StringLen(line) < 2) continue;
|
||
string p[];
|
||
int k = StringSplit(line, ';', p);
|
||
if(k < 2) continue;
|
||
string typ = p[0];
|
||
|
||
// 1. Zeile: SYM;<symbol> — nur auf dem passenden Chart zeichnen
|
||
if(typ == "SYM")
|
||
{
|
||
if(p[1] != _Symbol)
|
||
{
|
||
ObjectsDeleteAll(0, PFX);
|
||
ChartRedraw();
|
||
return;
|
||
}
|
||
continue;
|
||
}
|
||
// Horizontale S/R-Linien + sichtbares Text-Label an der Linie
|
||
if(typ == "R" || typ == "S")
|
||
{
|
||
double price = StringToDouble(p[1]);
|
||
if(price <= 0) continue;
|
||
// Feld 3 (optional) = P(Durchbruch) in % aus dem kalibrierten Modell des
|
||
// Bots. Niedrig = Level haelt eher, hoch = bricht eher.
|
||
// ⚠⚠ WORTGLEICH ZUR M15-KARTE (Fix 2026-08-13, v1.35, User: „die
|
||
// Beschriftung fuer S/R im Chart stimmt nicht mit der Analyse in der
|
||
// M15-Karte ueberein"). Hier stand bis dahin die NACKTE Zahl = P(Bruch).
|
||
// Die Karte (`app.js` lesart()/pTxt()) klappt unter 45 % aber auf den
|
||
// GEGENWERT P(Abprall) um und nennt 45–55 % „unentschieden" — dasselbe
|
||
// Level trug damit im Chart „33%" und in der Karte „67 % Abprall".
|
||
// Beide Zahlen waren richtig, aber die Chart-Zahl sagte nicht, WAS sie
|
||
// ist. GEMESSEN betraf das 88,1 % der Zeit (1.797 Vorhersagen/14 Tage:
|
||
// 66,3 % lagen unter 45 %, 21,9 % im unentschiedenen Band).
|
||
// ➜ Wer die Formulierung hier aendert, muss `lesart()` in app.js
|
||
// mitaendern — sonst laufen sie wieder auseinander.
|
||
string lbl = (typ=="R" ? "Widerstand " : "Unterstuetzung ")
|
||
+ DoubleToString(price, (int)_Digits);
|
||
if(InpShowPBreak && k > 2 && StringLen(p[2]) > 0)
|
||
{
|
||
int pb = (int)StringToInteger(p[2]);
|
||
if(pb >= 45 && pb <= 55) lbl += " · unentschieden";
|
||
else if(pb > 55) lbl += " · " + IntegerToString(pb) + "% Bruch";
|
||
else lbl += " · " + IntegerToString(100-pb) + "% Abprall";
|
||
}
|
||
color col = (typ=="R" ? InpResColor : InpSupColor);
|
||
string nm = PFX + typ + "_" + IntegerToString(idx);
|
||
if(ObjectCreate(0, nm, OBJ_HLINE, 0, 0, price))
|
||
{
|
||
ObjectSetInteger(0, nm, OBJPROP_COLOR, col);
|
||
ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_DASH);
|
||
ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, nm, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
||
// ⚠ TOOLTIP, NICHT OBJPROP_TEXT: den TEXT zeichnet MT5 LINKS am
|
||
// Chartrand (Option „Objektbeschreibungen") — das war die
|
||
// linksbuendige Beschriftung. Als Tooltip stoert er nicht.
|
||
ObjectSetString (0, nm, OBJPROP_TOOLTIP, lbl);
|
||
}
|
||
// Beschriftung als eigenes Text-Objekt — RECHTSBÜNDIG am rechten Chart-
|
||
// Rand (User-Vorgabe 2026-07-30; vorher horizontal zentriert). Bleibt via
|
||
// RepositionLabels() beim Scrollen/Zoomen dort. ANCHOR_RIGHT_LOWER: der
|
||
// Text ENDET am Anker und läuft nach links → ragt nicht aus dem Chart.
|
||
string tn = PFX + "T" + typ + "_" + IntegerToString(idx);
|
||
if(ObjectCreate(0, tn, OBJ_TEXT, 0, RightTime(), price))
|
||
{
|
||
ObjectSetString (0, tn, OBJPROP_TEXT, lbl);
|
||
ObjectSetInteger(0, tn, OBJPROP_COLOR, InpLabelColor);
|
||
ObjectSetInteger(0, tn, OBJPROP_FONTSIZE, InpLabelSize);
|
||
ObjectSetInteger(0, tn, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
|
||
ObjectSetInteger(0, tn, OBJPROP_BACK, false);
|
||
ObjectSetInteger(0, tn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
idx++;
|
||
}
|
||
// Regressionskanal: CH;<U|M|L>;t1;p1;t2;p2 → diagonale Trendlinie (OBJ_TREND),
|
||
// nach rechts verlängert. Anker in Broker-Zeit (= Server-Zeit im Terminal).
|
||
if(typ == "CH")
|
||
{
|
||
if(!InpShowChannel) continue;
|
||
if(k < 6) continue;
|
||
string kind = p[1];
|
||
datetime t1 = (datetime)StringToInteger(p[2]);
|
||
double pr1 = StringToDouble(p[3]);
|
||
datetime t2 = (datetime)StringToInteger(p[4]);
|
||
double pr2 = StringToDouble(p[5]);
|
||
if(pr1 <= 0 || pr2 <= 0 || t1 <= 0 || t2 <= 0) continue;
|
||
string nm = PFX + "CH_" + kind;
|
||
if(ObjectCreate(0, nm, OBJ_TREND, 0, t1, pr1, t2, pr2))
|
||
{
|
||
ObjectSetInteger(0, nm, OBJPROP_COLOR, InpChanColor);
|
||
ObjectSetInteger(0, nm, OBJPROP_STYLE, (kind == "M" ? STYLE_DOT : STYLE_DASH));
|
||
ObjectSetInteger(0, nm, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, true); // nach rechts verlängern
|
||
ObjectSetInteger(0, nm, OBJPROP_RAY_LEFT, false);
|
||
ObjectSetInteger(0, nm, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
||
ObjectSetString (0, nm, OBJPROP_TOOLTIP, "Kanal " + kind);
|
||
}
|
||
continue;
|
||
}
|
||
// ECHTE Liquiditäts-Wände: LQ;<B|A>;preis;size (B = Nachfrage/Bid-Wand,
|
||
// A = Angebot/Ask-Wand). Quelle = Hyperliquid-L2-Orderbuch, größtes Level je
|
||
// Seite, im Bot BASIS-KORRIGIERT auf CFD-Niveau (HL notiert ~0,45 $ tiefer).
|
||
// ⚠ Das ist die EINZIGE Linie im Chart, die nicht aus Pivots geschätzt ist,
|
||
// sondern tatsächlich ruhende Orders zeigt. Dick + gestrichelt, damit sie sich
|
||
// klar von den dünnen S/R-Linien abhebt. REINE ANZEIGE (kein Signal).
|
||
// (Chartmuster-Linien „PT;…" wurden 2026-07-30 auf User-Wunsch entfernt.)
|
||
if(typ == "LQ")
|
||
{
|
||
if(k < 3) continue;
|
||
if(!InpShowWalls) continue;
|
||
string side = p[1];
|
||
double lpx = StringToDouble(p[2]);
|
||
double lsz = (k > 3) ? StringToDouble(p[3]) : 0.0;
|
||
if(lpx <= 0) continue;
|
||
bool isBid = (side == "B");
|
||
color lcol = isBid ? InpArrowUpColor : InpArrowDownColor;
|
||
// ⚠ 2026-07-30 (User): KEINE waagerechte Linie und KEIN Text-Label mehr —
|
||
// der Chart war zu voll. Es bleibt NUR der Pfeil, RECHTSBÜNDIG am aktuellen
|
||
// Rand, auf dem Preisniveau der Wand. Die Details (Seite/Größe/Dominanz)
|
||
// stehen im TOOLTIP (Maus drüber) statt fest im Chart.
|
||
string dirc = (k > 4) ? p[4] : (isBid ? "U" : "D");
|
||
bool isDom = (k > 5 && p[5] == "1");
|
||
string an = PFX + "ALQ_" + side;
|
||
// Rechter Rand = aktuelle (rechteste) Kerze + kleiner Versatz, damit der
|
||
// Pfeil frei neben dem Kursverlauf steht und beim Scrollen rechts bleibt.
|
||
datetime atime = RightTime();
|
||
if(ObjectCreate(0, an, OBJ_ARROW, 0, atime, lpx))
|
||
{
|
||
ObjectSetInteger(0, an, OBJPROP_ARROWCODE, (dirc == "U" ? 233 : 234));
|
||
ObjectSetInteger(0, an, OBJPROP_COLOR, lcol);
|
||
ObjectSetInteger(0, an, OBJPROP_WIDTH, (isDom ? 4 : 2));
|
||
// ⚠ KEIN ANCHOR_LEFT: OBJ_ARROW unterstützt NUR ANCHOR_TOP/ANCHOR_BOTTOM
|
||
// — ein ungültiger Anker war (neben dem fehlenden Chart-Shift) der Grund,
|
||
// warum die Pfeile nicht erschienen (Fix 2026-07-30).
|
||
ObjectSetInteger(0, an, OBJPROP_ANCHOR, ANCHOR_TOP);
|
||
ObjectSetInteger(0, an, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, an, 0, atime, lpx);
|
||
ObjectSetInteger(0, an, OBJPROP_WIDTH, (isDom ? 4 : 2));
|
||
ObjectSetInteger(0, an, OBJPROP_COLOR, lcol);
|
||
ObjectSetInteger(0, an, OBJPROP_ARROWCODE, (dirc == "U" ? 233 : 234));
|
||
}
|
||
ObjectSetString(0, an, OBJPROP_TOOLTIP,
|
||
(isBid ? "Liquiditaet NACHFRAGE " : "Liquiditaet ANGEBOT ")
|
||
+ DoubleToString(lsz, 0) + (isDom ? " (dominant)" : "")
|
||
+ " @ " + DoubleToString(lpx, (int)_Digits));
|
||
// evtl. noch vorhandene Alt-Objekte (Linie/Label aus v1.13) entfernen
|
||
ObjectDelete(0, PFX + "LQ_" + side);
|
||
ObjectDelete(0, PFX + "TLQ_" + side);
|
||
continue;
|
||
}
|
||
// LIQUIDITÄTSZONE: EQ;<H|L>;lo;hi;<broker_time> → goldenes Band über die
|
||
// Equal Highs / Equal Lows (M30), ab dem ersten Pivot nach rechts verlängert,
|
||
// plus gestrichelte Kante — Darstellung wie im Referenzbild des Users.
|
||
// ⚠ REINE ANZEIGE: als Signal gemessen und verworfen (backtest_liquidity_sweep.py).
|
||
if(typ == "EQ")
|
||
{
|
||
if(k < 5) continue;
|
||
if(!InpShowLiqZones) continue;
|
||
string zs = p[1];
|
||
double zlo = StringToDouble(p[2]), zhi = StringToDouble(p[3]);
|
||
datetime zt = (datetime)StringToInteger(p[4]);
|
||
if(zlo <= 0 || zhi <= 0 || zt <= 0) continue;
|
||
datetime zend = iTime(_Symbol, PERIOD_CURRENT, 0) + (datetime)(PeriodSeconds() * 3);
|
||
string zn = PFX + "EQZ_" + zs;
|
||
color zfill = BlendBg(InpZoneColor, InpZoneAlpha);
|
||
if(ObjectCreate(0, zn, OBJ_RECTANGLE, 0, zt, zlo, zend, zhi))
|
||
{
|
||
ObjectSetInteger(0, zn, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, zn, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, zn, OBJPROP_FILL, true);
|
||
ObjectSetInteger(0, zn, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, zn, OBJPROP_SELECTABLE, false);
|
||
ObjectSetString (0, zn, OBJPROP_TOOLTIP,
|
||
(zs == "H" ? "Equal Highs - Sell-Side Liquidity"
|
||
: "Equal Lows - Buy-Side Liquidity"));
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, zn, 0, zt, zlo);
|
||
ObjectMove(0, zn, 1, zend, zhi);
|
||
}
|
||
// Farbe IMMER setzen (auch beim Bewegen) — sonst bliebe nach einer
|
||
// Alpha-Änderung die alte Füllung stehen, bis das Objekt neu entsteht.
|
||
ObjectSetInteger(0, zn, OBJPROP_COLOR, zfill);
|
||
// gestrichelte Kante auf Höhe des Levels (wie im Bild)
|
||
string zl = PFX + "EQL_" + zs;
|
||
double edge = (zs == "H" ? zhi : zlo);
|
||
if(ObjectCreate(0, zl, OBJ_TREND, 0, zt, edge, zend, edge))
|
||
{
|
||
ObjectSetInteger(0, zl, OBJPROP_COLOR, InpZoneColor);
|
||
ObjectSetInteger(0, zl, OBJPROP_STYLE, STYLE_DASH);
|
||
ObjectSetInteger(0, zl, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, zl, OBJPROP_RAY_RIGHT, true);
|
||
ObjectSetInteger(0, zl, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, zl, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, zl, 0, zt, edge);
|
||
ObjectMove(0, zl, 1, zend, edge);
|
||
}
|
||
continue;
|
||
}
|
||
// KONSOLIDIERUNGS-BOX: CO;lo;hi;<0|1> — die Spanne der letzten 10 M5-Bars
|
||
// (dieselbe Box, aus der der validierte Squeeze-Ausbruch kommt). Feld 3 = 1
|
||
// bedeutet KOMPRIMIERT (≤2,5×ATR) → Ausbruch steht bevor, dann kräftiger.
|
||
// ⚠ REINE ANZEIGE: alle Konsolidierungs-SETUPS (False Breakout, Distribution,
|
||
// Accumulation, Retest) sind gemessen verworfen — die Box sagt WO gestaut
|
||
// wird, nicht WOHIN es geht.
|
||
if(typ == "CO")
|
||
{
|
||
if(k < 3) continue;
|
||
if(!InpShowConsol) continue;
|
||
double clo = StringToDouble(p[1]), chi = StringToDouble(p[2]);
|
||
bool tight = (k > 3 && p[3] == "1");
|
||
if(clo <= 0 || chi <= clo) continue;
|
||
datetime ct0 = iTime(_Symbol, PERIOD_CURRENT, 0)
|
||
- (datetime)(PeriodSeconds() * InpConsolBars);
|
||
datetime ct1 = RightTime();
|
||
string cn = PFX + "CONSOL";
|
||
if(ObjectCreate(0, cn, OBJ_RECTANGLE, 0, ct0, clo, ct1, chi))
|
||
{
|
||
ObjectSetInteger(0, cn, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, cn, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, cn, OBJPROP_FILL, true);
|
||
ObjectSetInteger(0, cn, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, cn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, cn, 0, ct0, clo);
|
||
ObjectMove(0, cn, 1, ct1, chi);
|
||
}
|
||
// komprimiert = deutlicher sichtbar (Ausbruch steht bevor)
|
||
ObjectSetInteger(0, cn, OBJPROP_COLOR,
|
||
BlendBg(InpConsolColor, tight ? InpConsolAlpha * 2
|
||
: InpConsolAlpha));
|
||
string ctip = (tight ? "Konsolidierung (komprimiert - Ausbruch steht bevor)"
|
||
: "aktuelle 10-Bar-Spanne")
|
||
+ " " + DoubleToString(clo, (int)_Digits) + " - "
|
||
+ DoubleToString(chi, (int)_Digits);
|
||
ObjectSetString (0, cn, OBJPROP_TOOLTIP, ctip);
|
||
// SICHTBARE BESCHRIFTUNG (User-Frage 2026-07-30 „was bedeutet die graue Box"):
|
||
// eigenes OBJ_TEXT an der OBERKANTE, rechtsbündig wie alle anderen Labels
|
||
// (Name mit PFX+"T" → RepositionLabels() führt es beim Scrollen nach).
|
||
string ctn = PFX + "TCONSOL";
|
||
if(ObjectCreate(0, ctn, OBJ_TEXT, 0, RightTime(), chi))
|
||
{
|
||
ObjectSetInteger(0, ctn, OBJPROP_COLOR, InpLabelColor);
|
||
ObjectSetInteger(0, ctn, OBJPROP_FONTSIZE, InpLabelSize);
|
||
ObjectSetInteger(0, ctn, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
|
||
ObjectSetInteger(0, ctn, OBJPROP_BACK, false);
|
||
ObjectSetInteger(0, ctn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
ObjectMove(0, ctn, 0, RightTime(), chi);
|
||
ObjectSetString(0, ctn, OBJPROP_TEXT,
|
||
tight ? "Konsolidierung - komprimiert, Ausbruch steht bevor"
|
||
: "Konsolidierung (10-Bar-Spanne)");
|
||
ObjectSetString(0, ctn, OBJPROP_TOOLTIP, ctip);
|
||
continue;
|
||
}
|
||
// WAHRSCHEINLICHKEITS-KEGEL: CN;<minuten>;<lo>;<hi>
|
||
// Zwei sich oeffnende Pfade vom aktuellen Bar aus. ⚠ Das ist KEINE Prognose
|
||
// der Richtung, sondern der STREUUNG: wie weit der Kurs in 30/60/120 min
|
||
// plausibel gelaufen sein kann. Out-of-sample kalibriert (analyze_cone.py):
|
||
// das 80%-Band trifft real ~76%. Bewusst NEUTRAL grau, kein gruen/rot.
|
||
if(typ == "CN")
|
||
{
|
||
if(k < 4) continue;
|
||
if(!InpShowCone) continue;
|
||
int mins = (int)StringToInteger(p[1]);
|
||
double clo = StringToDouble(p[2]);
|
||
double chi = StringToDouble(p[3]);
|
||
if(clo <= 0 || chi <= 0 || mins <= 0) continue;
|
||
// Anker: vom aktuellen Bar bis +mins Minuten (in Broker-Zeit)
|
||
datetime t0 = iTime(_Symbol, PERIOD_CURRENT, 0);
|
||
datetime t1 = t0 + (datetime)(mins * 60);
|
||
// Vorgaenger-Punkt: der naechstkleinere Horizont, sonst der aktuelle Kurs.
|
||
// g_coneT/g_coneLo/g_coneHi halten ihn zwischen den CSV-Zeilen fest; die
|
||
// Zeilen kommen aufsteigend sortiert vom Bot.
|
||
datetime pt = (g_coneT > 0 ? g_coneT : t0);
|
||
double plo = (g_coneT > 0 ? g_coneLo : g_conePx);
|
||
double phi = (g_coneT > 0 ? g_coneHi : g_conePx);
|
||
if(plo <= 0 || phi <= 0) { plo = clo; phi = chi; pt = t0; }
|
||
string ln = PFX + "CONE_L" + IntegerToString(mins);
|
||
string un = PFX + "CONE_U" + IntegerToString(mins);
|
||
string tip = "Streuung (keine Richtung): in " + IntegerToString(mins)
|
||
+ " min liegt der Kurs mit ~76% zwischen "
|
||
+ DoubleToString(clo, (int)_Digits) + " und "
|
||
+ DoubleToString(chi, (int)_Digits);
|
||
for(int s = 0; s < 2; s++)
|
||
{
|
||
string nm2 = (s == 0 ? ln : un);
|
||
double a2 = (s == 0 ? plo : phi);
|
||
double b2 = (s == 0 ? clo : chi);
|
||
if(ObjectCreate(0, nm2, OBJ_TREND, 0, pt, a2, t1, b2))
|
||
{
|
||
ObjectSetInteger(0, nm2, OBJPROP_COLOR, InpConeColor);
|
||
ObjectSetInteger(0, nm2, OBJPROP_STYLE, STYLE_DOT);
|
||
ObjectSetInteger(0, nm2, OBJPROP_WIDTH, 1);
|
||
ObjectSetInteger(0, nm2, OBJPROP_RAY_RIGHT, false);
|
||
ObjectSetInteger(0, nm2, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, nm2, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, nm2, 0, pt, a2);
|
||
ObjectMove(0, nm2, 1, t1, b2);
|
||
}
|
||
ObjectSetString(0, nm2, OBJPROP_TOOLTIP, tip);
|
||
}
|
||
g_coneT = t1; g_coneLo = clo; g_coneHi = chi;
|
||
continue;
|
||
}
|
||
// RICHTUNGS-PFEILE: AR;<art>;<von>;<nach>;<text> art = L | S | K
|
||
// ⚠ KEINE freie Kursprognose (die ist gemessen ein Muenzwurf) - jede Art hat
|
||
// ihre eigene Beleglage, s. Versionshinweis oben.
|
||
if(typ == "AR")
|
||
{
|
||
if(k < 5) continue;
|
||
if(!InpShowArrows) continue;
|
||
string art = p[1];
|
||
if(art == "K" && !InpShowConsensus) continue; // Konsens-Pfeil optional
|
||
double a_from = StringToDouble(p[2]);
|
||
double a_to = StringToDouble(p[3]);
|
||
string a_txt = p[4];
|
||
if(a_from <= 0 || a_to <= 0) continue;
|
||
color ac = (art == "S") ? InpArrSqueeze
|
||
: (art == "K") ? InpArrConsensus : InpArrLevel;
|
||
int aw = (art == "S") ? 3 : 2; // der validierte Pfeil dicker
|
||
datetime at0 = iTime(_Symbol, PERIOD_CURRENT, 0);
|
||
datetime at1 = at0 + (datetime)(PeriodSeconds() * InpArrBars);
|
||
string an = PFX + "ARR_" + art;
|
||
if(ObjectCreate(0, an, OBJ_ARROWED_LINE, 0, at0, a_from, at1, a_to))
|
||
{
|
||
ObjectSetInteger(0, an, OBJPROP_COLOR, ac);
|
||
ObjectSetInteger(0, an, OBJPROP_WIDTH, aw);
|
||
ObjectSetInteger(0, an, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, an, OBJPROP_RAY_RIGHT, false);
|
||
ObjectSetInteger(0, an, OBJPROP_BACK, false);
|
||
ObjectSetInteger(0, an, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, an, 0, at0, a_from);
|
||
ObjectMove(0, an, 1, at1, a_to);
|
||
ObjectSetInteger(0, an, OBJPROP_COLOR, ac);
|
||
}
|
||
ObjectSetString(0, an, OBJPROP_TOOLTIP, a_txt);
|
||
// Beschriftung an der Pfeilspitze (rechtsbuendig wie alle anderen Labels)
|
||
string atn = PFX + "ALBL_" + art; // NICHT "T..." (s. RepositionLabels)
|
||
if(ObjectCreate(0, atn, OBJ_TEXT, 0, at1, a_to))
|
||
{
|
||
ObjectSetInteger(0, atn, OBJPROP_COLOR, ac);
|
||
ObjectSetInteger(0, atn, OBJPROP_FONTSIZE, InpLabelSize);
|
||
ObjectSetInteger(0, atn, OBJPROP_ANCHOR, ANCHOR_LEFT);
|
||
ObjectSetInteger(0, atn, OBJPROP_BACK, false);
|
||
ObjectSetInteger(0, atn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
ObjectMove(0, atn, 0, at1, a_to);
|
||
ObjectSetString(0, atn, OBJPROP_TEXT, " " + a_txt);
|
||
continue;
|
||
}
|
||
// HYPERLIQUID-KURS unter dem Broker-Kurs: HL;<mt5_aequiv>;<alter_s>;<bid>;<ask>;<U|D|->
|
||
// HL (`xyz:CL`) handelt 24/7, Pepperstone nicht - am Wochenende der einzige
|
||
// lebende Kurs. Bereits basis-korrigiert, also direkt vergleichbar.
|
||
if(typ == "HL")
|
||
{
|
||
if(k < 6) continue;
|
||
if(!InpShowHL) continue;
|
||
double hlp = StringToDouble(p[1]);
|
||
if(hlp <= 0) continue;
|
||
int hage = (int)StringToInteger(p[2]);
|
||
string htr = p[5];
|
||
string hn = PFX + "HLPX";
|
||
if(ObjectFind(0, hn) < 0)
|
||
{
|
||
ObjectCreate(0, hn, OBJ_LABEL, 0, 0, 0);
|
||
ObjectSetInteger(0, hn, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
|
||
ObjectSetInteger(0, hn, OBJPROP_XDISTANCE, 12);
|
||
// unter Kurs (14) und G/V (14+PriceSize+6) einreihen
|
||
ObjectSetInteger(0, hn, OBJPROP_YDISTANCE, 14 + InpPriceSize + 6 + InpPriceSize - 4);
|
||
ObjectSetInteger(0, hn, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
|
||
ObjectSetInteger(0, hn, OBJPROP_SELECTABLE, false);
|
||
ObjectSetString (0, hn, OBJPROP_FONT, "Arial");
|
||
}
|
||
ObjectSetInteger(0, hn, OBJPROP_FONTSIZE, (int)MathMax(10, InpPriceSize - 7));
|
||
ObjectSetInteger(0, hn, OBJPROP_COLOR, InpHLColor);
|
||
ObjectSetString (0, hn, OBJPROP_TEXT,
|
||
"HL " + DoubleToString(hlp, (int)_Digits)
|
||
+ (htr == "U" ? " ^" : htr == "D" ? " v" : ""));
|
||
ObjectSetString (0, hn, OBJPROP_TOOLTIP,
|
||
"Hyperliquid xyz:CL, basis-korrigiert auf MT5-Niveau - "
|
||
+ IntegerToString(hage) + " s alt. Waende "
|
||
+ p[3] + " / " + p[4]);
|
||
continue;
|
||
}
|
||
// AKTUELLER KURS oben rechts, fett (User-Wunsch): PX;bid
|
||
if(typ == "PX")
|
||
{
|
||
if(k < 2) continue;
|
||
double pxv = StringToDouble(p[1]);
|
||
if(pxv <= 0) continue;
|
||
// Kegel-Startpunkt IMMER merken - auch wenn das Kurs-Label aus ist
|
||
// (sonst verliert der Faecher seinen Anker).
|
||
g_conePx = pxv;
|
||
if(!InpShowPrice) continue;
|
||
string pn = PFX + "PRICE";
|
||
if(ObjectFind(0, pn) < 0)
|
||
{
|
||
ObjectCreate(0, pn, OBJ_LABEL, 0, 0, 0);
|
||
ObjectSetInteger(0, pn, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
|
||
ObjectSetInteger(0, pn, OBJPROP_XDISTANCE, 12);
|
||
ObjectSetInteger(0, pn, OBJPROP_YDISTANCE, 14);
|
||
ObjectSetInteger(0, pn, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
|
||
ObjectSetString (0, pn, OBJPROP_FONT, "Arial Black");
|
||
ObjectSetInteger(0, pn, OBJPROP_FONTSIZE, InpPriceSize);
|
||
ObjectSetInteger(0, pn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
ObjectSetString (0, pn, OBJPROP_TEXT, DoubleToString(pxv, (int)_Digits));
|
||
ObjectSetInteger(0, pn, OBJPROP_COLOR, InpPriceColor);
|
||
continue;
|
||
}
|
||
// MELDUNGEN oben LINKS (MS;<text>) — User-Wunsch 2026-08-17.
|
||
// Dieselben Zeilen wie die Dashboard-Karte „Meldungen"; der Bot setzt sie
|
||
// zusammen und deckelt auf 5. Hier nur gestapelt darstellen.
|
||
// ⚠ Eigener Praefix MSPFX, damit sie beim Redraw sauber verschwinden, wenn
|
||
// der Bot keine MS-Zeile mehr schickt (sonst blieben Alt-Meldungen
|
||
// stehen — genau der Fehler, den die HL-Pfeile schon einmal hatten).
|
||
if(typ == "MS")
|
||
{
|
||
if(!InpShowMeldungen || k < 2) continue;
|
||
string mn = PFX + "MSG_" + IntegerToString(msg_idx);
|
||
if(ObjectFind(0, mn) < 0)
|
||
{
|
||
ObjectCreate(0, mn, OBJ_LABEL, 0, 0, 0);
|
||
ObjectSetInteger(0, mn, OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
||
ObjectSetInteger(0, mn, OBJPROP_XDISTANCE, 12);
|
||
ObjectSetInteger(0, mn, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
|
||
ObjectSetString (0, mn, OBJPROP_FONT, "Arial");
|
||
ObjectSetInteger(0, mn, OBJPROP_FONTSIZE, InpMeldungSize);
|
||
ObjectSetInteger(0, mn, OBJPROP_SELECTABLE, false);
|
||
ObjectSetInteger(0, mn, OBJPROP_BACK, false);
|
||
}
|
||
ObjectSetInteger(0, mn, OBJPROP_YDISTANCE,
|
||
16 + msg_idx * (InpMeldungSize + 6));
|
||
ObjectSetString (0, mn, OBJPROP_TEXT, p[1]);
|
||
ObjectSetInteger(0, mn, OBJPROP_COLOR, InpMeldungColor);
|
||
msg_idx++;
|
||
continue;
|
||
}
|
||
// G/V der offenen Position — direkt UNTER dem Kurs (User-Wunsch 2026-07-30):
|
||
// PL;wert;waehrung. Wert ist NETTO (Bot rechnet die WHT-Quellensteuer schon
|
||
// raus, wie im Dashboard). Gruen im Plus, rot im Minus. Ohne offene Position
|
||
// schickt der Bot keine PL-Zeile -> das Label wird unten geloescht.
|
||
if(typ == "PL")
|
||
{
|
||
if(k < 2) continue;
|
||
if(!InpShowPnL) continue;
|
||
double plv = StringToDouble(p[1]);
|
||
string cur = (k > 2) ? p[2] : "";
|
||
string qn = PFX + "PNL";
|
||
if(ObjectFind(0, qn) < 0)
|
||
{
|
||
ObjectCreate(0, qn, OBJ_LABEL, 0, 0, 0);
|
||
ObjectSetInteger(0, qn, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
|
||
ObjectSetInteger(0, qn, OBJPROP_XDISTANCE, 12);
|
||
// direkt unter dem Kurs: dessen Y (14) + Schrifthoehe + kleiner Abstand
|
||
ObjectSetInteger(0, qn, OBJPROP_YDISTANCE, 14 + InpPriceSize + 10);
|
||
ObjectSetInteger(0, qn, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
|
||
ObjectSetString (0, qn, OBJPROP_FONT, "Arial Black");
|
||
ObjectSetInteger(0, qn, OBJPROP_SELECTABLE, false);
|
||
}
|
||
ObjectSetInteger(0, qn, OBJPROP_FONTSIZE, (int)MathMax(8, InpPriceSize - 4));
|
||
ObjectSetString (0, qn, OBJPROP_TEXT,
|
||
(plv >= 0 ? "+" : "") + DoubleToString(plv, 2)
|
||
+ (StringLen(cur) > 0 ? " " + cur : ""));
|
||
ObjectSetInteger(0, qn, OBJPROP_COLOR,
|
||
(plv >= 0 ? InpPnLUpColor : InpPnLDownColor));
|
||
continue;
|
||
}
|
||
// TRADE-MARKER: TR;<O|C>;<broker_time> → die Kerze, in der eröffnet bzw.
|
||
// geschlossen wurde, wird umrandet (User-Vorgabe 2026-07-30):
|
||
// O = Eröffnung → HELLGRÜN · C = Close → DUNKELGRÜN
|
||
// Umrandung = OBJ_RECTANGLE über die Bar-Spanne (Zeit) und High/Low (Preis),
|
||
// ungefüllt. Die Zeit wird auf den Bar-Beginn der aktuellen Chart-TF gerundet,
|
||
// damit die Box exakt auf einer Kerze sitzt — egal auf welcher TF man schaut.
|
||
if(typ == "TR")
|
||
{
|
||
if(k < 3) continue;
|
||
if(!InpShowTrades) continue;
|
||
string tkind = p[1];
|
||
datetime tts = (datetime)StringToInteger(p[2]);
|
||
if(tts <= 0) continue;
|
||
int bi = iBarShift(_Symbol, PERIOD_CURRENT, tts, false);
|
||
if(bi < 0) continue; // Zeit liegt außerhalb der History
|
||
datetime bt = iTime(_Symbol, PERIOD_CURRENT, bi);
|
||
double bh = iHigh(_Symbol, PERIOD_CURRENT, bi);
|
||
double bl = iLow (_Symbol, PERIOD_CURRENT, bi);
|
||
if(bh <= 0 || bl <= 0) continue;
|
||
double pad = (bh - bl) * 0.12; // etwas Luft um die Kerze
|
||
if(pad <= 0) pad = _Point * 10;
|
||
string tn2 = PFX + "TRD_" + tkind + "_" + IntegerToString((int)tts);
|
||
if(ObjectCreate(0, tn2, OBJ_RECTANGLE, 0, bt, bl - pad,
|
||
bt + PeriodSeconds(), bh + pad))
|
||
{
|
||
ObjectSetInteger(0, tn2, OBJPROP_COLOR,
|
||
(tkind == "O" ? InpTradeOpenColor : InpTradeCloseColor));
|
||
ObjectSetInteger(0, tn2, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, tn2, OBJPROP_WIDTH, 2);
|
||
ObjectSetInteger(0, tn2, OBJPROP_FILL, false);
|
||
ObjectSetInteger(0, tn2, OBJPROP_BACK, false);
|
||
ObjectSetInteger(0, tn2, OBJPROP_SELECTABLE, false);
|
||
ObjectSetString (0, tn2, OBJPROP_TOOLTIP,
|
||
(tkind == "O" ? "Trade EROEFFNET" : "Trade GESCHLOSSEN"));
|
||
}
|
||
continue;
|
||
}
|
||
// Liquiditäts-TRENDLINIE: LT;t1;p1;t2;p2;<U|D> (pink, nach rechts verlängert).
|
||
// Regression über den VOLUMENGEWICHTETEN Schwerpunkt der beiden Wände über die
|
||
// letzten ~60 min: zeigt, wohin das Gewicht der RUHENDEN Orders wandert —
|
||
// NICHT wohin der gehandelte Kurs läuft. Steigt sie, ziehen die Käufer ihre
|
||
// großen Gebote hoch. Zeiten kommen bereits in Broker-Zeit aus dem Bot.
|
||
if(typ == "LT")
|
||
{
|
||
if(k < 5) continue;
|
||
if(!InpShowLiqTrend) continue;
|
||
datetime t1 = (datetime)StringToInteger(p[1]);
|
||
double q1 = StringToDouble(p[2]);
|
||
datetime t2 = (datetime)StringToInteger(p[3]);
|
||
double q2 = StringToDouble(p[4]);
|
||
string td = (k > 5) ? p[5] : "";
|
||
if(t1 <= 0 || t2 <= 0 || q1 <= 0 || q2 <= 0) continue;
|
||
string nm = PFX + "LIQTREND";
|
||
if(ObjectCreate(0, nm, OBJ_TREND, 0, t1, q1, t2, q2))
|
||
{
|
||
ObjectSetInteger(0, nm, OBJPROP_COLOR, InpTrendLineColor);
|
||
ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_SOLID);
|
||
ObjectSetInteger(0, nm, OBJPROP_WIDTH, 2);
|
||
// ⚠ KEIN RAY_RIGHT: eine 60-min-Regression 100 Bars in die Zukunft zu
|
||
// verlängern ergibt keinen Sinn und riss die Linie optisch ins
|
||
// Bodenlose (User-Feedback „das Bild sieht komisch aus", 2026-07-30).
|
||
// Die Linie endet jetzt am aktuellen Rand.
|
||
ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, false);
|
||
ObjectSetInteger(0, nm, OBJPROP_RAY_LEFT, false);
|
||
ObjectSetInteger(0, nm, OBJPROP_BACK, true);
|
||
ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, nm, 0, t1, q1);
|
||
ObjectMove(0, nm, 1, t2, q2);
|
||
ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, false);
|
||
}
|
||
// Beschriftung der Liquiditäts-Trendlinie: auf User-Wunsch (2026-07-30)
|
||
// per Default AUS — der Chart soll sauber bleiben. Die Richtung liest man
|
||
// an der Linie selbst ab; Details stehen im Tooltip der Linie.
|
||
string tl = PFX + "TLIQTREND";
|
||
string tt = "Liquiditaets-Trend " + (td == "U" ? CharToString(94) : CharToString(118));
|
||
ObjectSetString(0, nm, OBJPROP_TOOLTIP, tt);
|
||
if(InpLiqTrendLabel)
|
||
{
|
||
if(ObjectCreate(0, tl, OBJ_TEXT, 0, t2, q2))
|
||
{
|
||
ObjectSetString (0, tl, OBJPROP_TEXT, tt);
|
||
ObjectSetInteger(0, tl, OBJPROP_COLOR, InpLabelColor);
|
||
ObjectSetInteger(0, tl, OBJPROP_FONTSIZE, InpLabelSize);
|
||
ObjectSetInteger(0, tl, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
||
ObjectSetInteger(0, tl, OBJPROP_SELECTABLE, false);
|
||
}
|
||
else
|
||
{
|
||
ObjectMove(0, tl, 0, t2, q2);
|
||
ObjectSetString(0, tl, OBJPROP_TEXT, tt);
|
||
}
|
||
}
|
||
else
|
||
ObjectDelete(0, tl); // evtl. Alt-Label aus v1.13–1.15 entfernen
|
||
continue;
|
||
}
|
||
// ("Z;"-Zonen-Zeilen schreibt der Bot nicht mehr — die dynamische Handels-
|
||
// Range zeichnet DrawRange() selbst aus den Chart-Kerzen.)
|
||
}
|
||
ChartRedraw();
|
||
}
|
||
//+------------------------------------------------------------------+
|