Files
AH-Oil-Trader/mql5/SR_Levels.mq5
T
Axel HocksandClaude Opus 4.8 03567adf6b MT5-Chart v1.18: Trade-Marker, Liquiditaetszonen, Kurs oben rechts + Pfeil-Bugfix
Pfeil-Bugfix (User: "liquiditaetspfeile werden immer noch nicht angezeigt"):
  (1) ANCHOR_LEFT ist fuer OBJ_ARROW UNGUELTIG (nur TOP/BOTTOM)
  (2) Pfeile sitzen rechts neben der letzten Kerze -> ohne CHART_SHIFT kein
      sichtbarer Bereich dort
Blink-Fix (User: "blinken nur manchmal auf"): hl_walls setzte den Cache bei jedem
Fehlschlag auf None -> LQ-Zeilen fehlten -> Indikator loeschte die Pfeile. Jetzt
letzter guter Stand 120s Grace.

Neu (alles reine Anzeige):
- TR;<O|C>;zeit  -> Kerze der Eroeffnung HELLGRUEN, des Close DUNKELGRUEN umrandet
- EQ;<H|L>;lo;hi;zeit -> Equal Highs/Lows aus M30-Pivots als goldenes Band +
  gestrichelte Kante (wie im User-Referenzbild). Als Signal gemessen verworfen.
- PX;bid -> aktueller Kurs fett oben rechts
- Beschriftung der Liquiditaets-Trendlinie per Default aus (v1.16)

Alles kompiliert und live in sr_levels.csv verifiziert.

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

579 lines
29 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.18"
// 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 InpWallBidColor = C'245,158,11'; // Liquidität Nachfrage (Bid) — Gold
input color InpWallAskColor = C'245,158,11'; // Liquidität Angebot (Ask) — Gold
input bool InpShowLiqTrend = true; // Liquiditäts-Trendlinie zeichnen
input color InpLiqTrendColor = clrMagenta; // Liquiditäts-Trend (pink)
input bool InpLiqTrendLabel = false; // Beschriftung der Trendlinie (aus per User-Wunsch)
input bool InpShowTrades = true; // Trade-Kerzen umranden (Eroeffnung/Close)
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 InpLiqZoneColor = C'146,94,10'; // Zonen-Band (gedaempftes Gold)
input bool InpShowPrice = true; // aktuellen Kurs oben rechts anzeigen
input int InpPriceSize = 20; // Schriftgroesse des Kurses
input color InpPriceColor = C'230,237,243'; // Kurs-Farbe
// ── 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
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. |
//+------------------------------------------------------------------+
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);
ChartSetInteger(0, CHART_COLOR_BID, InpThemeBull);
ChartSetInteger(0, CHART_COLOR_ASK, InpThemeBear);
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);
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);
}
//+------------------------------------------------------------------+
//| Hält die S/R-Beschriftungen beim Scrollen/Zoomen mittig |
//+------------------------------------------------------------------+
void RepositionLabels()
{
datetime ct = CenterTime();
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);
}
}
// 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 = iTime(_Symbol, PERIOD_CURRENT, 0) + (datetime)(PeriodSeconds() * 2);
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;
string lbl = (typ=="R" ? "Widerstand " : "Unterstützung ")
+ DoubleToString(price, (int)_Digits);
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);
ObjectSetString (0, nm, OBJPROP_TEXT, lbl); // Tooltip
}
// Beschriftung als eigenes Text-Objekt: horizontal ZENTRIERT im sicht-
// baren Chart, direkt über der Linie (bleibt via RepositionLabels()
// auch beim Scrollen/Zoomen zentriert)
string tn = PFX + "T" + typ + "_" + IntegerToString(idx);
if(ObjectCreate(0, tn, OBJ_TEXT, 0, CenterTime(), price))
{
ObjectSetString (0, tn, OBJPROP_TEXT, lbl);
ObjectSetInteger(0, tn, OBJPROP_COLOR, col);
ObjectSetInteger(0, tn, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(0, tn, OBJPROP_ANCHOR, ANCHOR_LOWER); // zentriert über dem Punkt
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_TEXT, "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 ? InpWallBidColor : InpWallAskColor;
// ⚠ 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 = iTime(_Symbol, PERIOD_CURRENT, 0)
+ (datetime)(PeriodSeconds() * 2);
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;
if(ObjectCreate(0, zn, OBJ_RECTANGLE, 0, zt, zlo, zend, zhi))
{
ObjectSetInteger(0, zn, OBJPROP_COLOR, InpLiqZoneColor);
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);
}
// 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, InpLiqZoneColor);
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;
}
// 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;
}
// 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, InpLiqTrendColor);
ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, nm, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, true);
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);
}
// 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, InpLiqTrendColor);
ObjectSetInteger(0, tl, OBJPROP_FONTSIZE, 9);
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();
}
//+------------------------------------------------------------------+