Files
AH-Oil-Trader/mql5/SR_Levels.mq5
T
Axel HocksandClaude Opus 5 a6f370ac02 Wirtschaftskalender-Blackout + Konsolidierungs-Box beschriftet
core/econ_calendar.py (NEU): High-Impact-News-Fenster als Handels-Sperre.
Quelle Forex Factory JSON (kostenlos, kein Key, mit impact-Feld), beide
Wochen (thisweek endet Sa, Markt oeffnet So 23:00 -> sonst blinder Fleck),
1x/h im Daemon-Thread, dedupliziert. Filter: High+USD ODER Oil/OPEC-Titel.

WICHTIG - nicht gemessen: Events sind zu selten fuer eine 2-Stichproben-
Aussage. Das ist die Handbuch-Regel, kein belegter Edge. Deshalb bewusst
asymmetrisch: sperrt NUR die autonomen Entries (Auto-Squeeze + Auto-Signal,
ohne Dedup-Marker -> feuert nach dem Fenster nach), in der Entry-Checkliste
nur "warn" statt "fail". Manuelle Orders bleiben frei. Der gemessene
EIA-Blackout (Mi 15:30-16:30) bleibt unabhaengig aktiv und greift auch
ohne Netz.

Verifiziert: Live-Fetch (EIA korrekt Mi 16:30 Berlin, FOMC/GDP/PCE erkannt)
+ 4 synthetische Szenarien (5 min vor/nach Event, 50 min davor, disabled).

MQL5 v1.30: graue 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". 0 Fehler kompiliert.

Frontend v=122: #cal-note in der Meldungen-Karte (laufendes Fenster bzw.
Vorwarnung <=60 min).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 22:58:58 +02:00

811 lines
44 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//+------------------------------------------------------------------+
//| 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.30"
// 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 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)
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)
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;
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. Im LABEL steht nur
// die nackte Zahl („Widerstand 84.536 · 34%", User-Wunsch 2026-07-30);
// der ausgeschriebene Hinweis bleibt im Tooltip der Linie.
string lbl = (typ=="R" ? "Widerstand " : "Unterstuetzung ")
+ DoubleToString(price, (int)_Digits);
if(InpShowPBreak && k > 2 && StringLen(p[2]) > 0)
lbl += " · " + p[2] + "%"; // nur die Zahl (User-Wunsch 2026-07-30)
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;
}
// AKTUELLER KURS oben rechts, fett (User-Wunsch): PX;bid
if(typ == "PX")
{
if(k < 2) continue;
if(!InpShowPrice) continue;
double pxv = StringToDouble(p[1]);
if(pxv <= 0) 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;
}
// 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.131.15 entfernen
continue;
}
// ("Z;"-Zonen-Zeilen schreibt der Bot nicht mehr — die dynamische Handels-
// Range zeichnet DrawRange() selbst aus den Chart-Kerzen.)
}
ChartRedraw();
}
//+------------------------------------------------------------------+