(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{"/jgc":function(e,t,n){"use strict";n.r(t),n.d(t,"_frontmatter",(function(){return c})),n.d(t,"default",(function(){return p}));var a=n("Fcif"),r=n("dV/x"),l=(n("mXGw"),n("/FXl")),i=n("TjRS"),b=n("wCAC");n("l1C2");const d=["components"],c={};void 0!==c&&c&&c===Object(c)&&Object.isExtensible(c)&&!Object.prototype.hasOwnProperty.call(c,"__filemeta")&&Object.defineProperty(c,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/components/de/Scripting.mdx"}});const o={_frontmatter:c},s=i.a;function p(e){let{components:t}=e,n=Object(r.a)(e,d);return Object(l.b)(s,Object(a.a)({},o,n,{components:t,mdxType:"MDXLayout"}),Object(l.b)("h1",{id:"api-für-benutzerdefinierte-indikatoren"},"API für benutzerdefinierte Indikatoren"),Object(l.b)(b.e,{mdxType:"Lead"},"Schreiben Sie Ihre eigenen Indikatoren in JavaScript, führen Sie sie in einer sicheren Sandbox neben dem Chart aus und teilen Sie sie mit anderen Nutzern. Die API liefert Ihnen Marktdaten (Kerzen, Orderbücher, Cluster, Liquidationen, Derivatedaten), Zeichenprimitive, Hilfsfunktionen für die technische Analyse und Alarme."),Object(l.b)("h2",{id:"indikatoren-mit-ki-generieren"},"Indikatoren mit KI generieren"),Object(l.b)("p",null,"Die gesamte API ist auch als einzelne Textdatei für Sprachmodelle verfügbar: ",Object(l.b)("a",{parentName:"p",href:"../../public/AI-scripting.txt"},"AI-scripting.txt"),". Hängen Sie sie an ChatGPT, Claude, Gemini oder ein anderes LLM an und beschreiben Sie den gewünschten Indikator."),Object(l.b)("p",null,"Beispielanfrage:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-text"},"Read the attached [AI-scripting.txt] https://mobchart.com/docs/public/AI-scripting.txt file and use it as the only reference for the MobChart scripting API.\n\nCreate a custom indicator that plots a 20-period EMA and a 50-period EMA on the chart. Color the candles green when EMA20 is above EMA50 and red otherwise.\n\nUse only the documented API. Do not invent functions. Return the complete indicator code.\n")),Object(l.b)("h2",{id:"sandbox-und-limits"},"Sandbox und Limits"),Object(l.b)(b.b,{type:"warning",title:"Aktuelle Limits",mdxType:"Callout"},Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Skripte laufen in einer sicheren JavaScript-Sandbox."),Object(l.b)("li",{parentName:"ul"},"Ein Skript hat ein Ausführungszeitlimit von ",Object(l.b)("inlineCode",{parentName:"li"},"1500ms"),"."),Object(l.b)("li",{parentName:"ul"},"Die zurückgegebenen Datenarrays sind auf ",Object(l.b)("strong",{parentName:"li"},"5000")," Elemente begrenzt, ein Indikator kann also nicht tiefer als ",Object(l.b)("strong",{parentName:"li"},"5000 Kerzen")," zurückblicken."),Object(l.b)("li",{parentName:"ul"},"Innerhalb eines einzelnen Indikators sind bis zu ",Object(l.b)("strong",{parentName:"li"},"8 Datenquellen-Anfragen"),' erlaubt. Eine Anfrage über dem Limit wirft einen Fehler, und der Lauf endet mit dem Hinweis "too much sources".'),Object(l.b)("li",{parentName:"ul"},"Innerhalb eines einzelnen Laufs sind bis zu ",Object(l.b)("strong",{parentName:"li"},"3 HTTP-Anfragen")," (",Object(l.b)("inlineCode",{parentName:"li"},"http.get")," / ",Object(l.b)("inlineCode",{parentName:"li"},"http.post"),") erlaubt, siehe ",Object(l.b)("strong",{parentName:"li"},"HTTP-Anfragen"),"."))),Object(l.b)("h2",{id:"indikator-entwicklung"},"Indikator-Entwicklung"),Object(l.b)("p",null,"Die Entwicklung von Indikatoren erfolgt in einem eigenen Widget, das neben dem Chart platziert werden kann, in dem der Indikator aktiviert wird."),Object(l.b)(b.f,{src:"../../public/chart_code.png",mdxType:"Screenshot"}),Object(l.b)("h2",{id:"einen-indikator-erstellen"},"Einen Indikator erstellen"),Object(l.b)("h3",{id:"definetitle-description-type-ispublic-ispubliccode-options"},Object(l.b)("inlineCode",{parentName:"h3"},"define(title, description, type, isPublic, isPublicCode, options)")),Object(l.b)("p",null,"Registriert den Indikator im System."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Parameter"),Object(l.b)("th",{parentName:"tr",align:null},"Typ"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"title")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")),Object(l.b)("td",{parentName:"tr",align:null},"Name des Indikators")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"description")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")),Object(l.b)("td",{parentName:"tr",align:null},"Kurze Beschreibung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"type")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"'onchart'")," ","|"," ",Object(l.b)("inlineCode",{parentName:"td"},"'offchart'")),Object(l.b)("td",{parentName:"tr",align:null},"Platzierung des Indikators (im Chart oder in einem eigenen Panel)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"isPublic")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},"Ob der Indikator öffentlich ist")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"isPublicCode")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},"Ob der Quellcode öffentlich ist")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"options")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"object")," (optional)"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"{ fullRange, warmup }"),", siehe unten")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'define("My Indicator", "Shows EMA line", "onchart", true, false);\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Berechnungsbereich.")," Standardmäßig berechnet ein Skript nur den Teil des Charts, der es braucht: die beim Zurückscrollen geladenen Kerzen oder die neuesten Kerzen bei einer Aktualisierung, plus ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"warmup"))," Kerzen Historie davor (Standard 500), die für die Berechnung nötig sind, aber nicht zurückgegeben werden. Deklarieren Sie ",Object(l.b)("inlineCode",{parentName:"p"},"warmup"),", wenn Ihr Indikator mehr oder weniger Historie braucht, z. B. ",Object(l.b)("inlineCode",{parentName:"p"},"{ warmup: 200 }")," für einen EMA(200). Ein Skript, dessen Werte oder Formen vom ",Object(l.b)("strong",{parentName:"p"},"gesamten sichtbaren Bereich")," abhängen (VWAP ab der ersten sichtbaren Kerze, kumuliertes Delta, ein Label am Maximum des Fensters, Levels über den ganzen Chart), muss ",Object(l.b)("inlineCode",{parentName:"p"},"{ fullRange: true }")," deklarieren, sonst sind seine Ergebnisse nach dem Nachladen von Historie falsch. Der Modus wird bei jedem Speichern aus ",Object(l.b)("inlineCode",{parentName:"p"},"define()")," gelesen: ein ohne ",Object(l.b)("inlineCode",{parentName:"p"},"fullRange")," gespeichertes Skript wird teilweise berechnet. Ergänzen Sie das Flag daher bei bestehenden kumulativen Skripten, wenn Sie sie bearbeiten. Teilweise berechnete Skripte werden auch stückweise geladen: Wird eines über eine lange Historie eingeschaltet, fordert der Chart zuerst die neuesten 500 Kerzen an (oder ",Object(l.b)("inlineCode",{parentName:"p"},"warmup")," Kerzen, wenn das mehr ist), die älteren Teile folgen mit je einer Anfrage, sodass der sichtbare Teil sofort erscheint. Skripte mit ",Object(l.b)("inlineCode",{parentName:"p"},"fullRange")," werden immer in einer einzigen Anfrage über den gesamten Bereich berechnet."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'define("Window max", "Label at the highest visible high", "onchart", true, true, { fullRange: true });\n')),Object(l.b)("p",null,"Platzierung des Indikators für ",Object(l.b)("strong",{parentName:"p"},"onchart")," und ",Object(l.b)("strong",{parentName:"p"},"offchart"),":"),Object(l.b)(b.f,{src:"../../public/onchart_offchart.png",mdxType:"Screenshot"}),Object(l.b)("h2",{id:"eingabeparameter"},"Eingabeparameter"),Object(l.b)("p",null,"Die Klassen ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"input"))," und ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"style"))," ermöglichen es Ihnen, vom Nutzer konfigurierbare Einstellungen zu erstellen (ähnlich wie ",Object(l.b)("inlineCode",{parentName:"p"},"input()")," in PineScript)."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(l.b)("td",{parentName:"tr",align:null},"Numerische Eingabe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(l.b)("td",{parentName:"tr",align:null},"Bereichseingabe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(l.b)("td",{parentName:"tr",align:null},"Dropdown-Auswahl")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(l.b)("td",{parentName:"tr",align:null},"Farbauswahl")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(l.b)("td",{parentName:"tr",align:null},"Boolesche Eingabe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers(title, defaultValue, exchange)")),Object(l.b)("td",{parentName:"tr",align:null},"Mehrfachauswahl der Ticker einer Börse (Standard: die Börse des Charts); liefert die gewählten Ticker als Array")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel (input) für Hauptparameter:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const length = input.number("Period", 14, 1, 100, 1);\nconst type = input.select("Type", \'sma\', [\'sma\', \'ema\']);\nconst color = input.color("Line Color", "#FF0000");\n// Paare zum Ein- / Ausschließen, aus den Tickern der Chart-Börse gewählt\nconst include = input.tickers("Include pairs", []);\nconst exclude = input.tickers("Exclude pairs", []);\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Oder (style) für visuelle Parameter:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const length = style.number("Size", 14, 1, 100, 1);\nconst color = style.select("Background Color", \'#FF0000\', ["#FF0000", "#AA0000", "#BB0000"]);\nconst color = style.color("Background Color", "#FF0000");\n')),Object(l.b)(b.f,{src:"../../public/input_style.png",mdxType:"Screenshot"}),Object(l.b)("h2",{id:"datenquellen"},"Datenquellen"),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"source"))," ruft Marktdaten vom Server ab. Die kerzenbasierten Methoden nehmen dieselben Parameter entgegen; die beiden Live-Schnappschüsse weichen ab: ",Object(l.b)("inlineCode",{parentName:"p"},"orderbook()")," nimmt Börse und Ticker, ",Object(l.b)("inlineCode",{parentName:"p"},"levels()")," eine Börse und ein Einstellungsobjekt."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Parameter"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"exchange"),", ",Object(l.b)("inlineCode",{parentName:"td"},"ticker"),", ",Object(l.b)("inlineCode",{parentName:"td"},"timeframe")),Object(l.b)("td",{parentName:"tr",align:null},"Standardmäßig das Chart, in dem der Indikator geöffnet ist. Übergeben Sie andere Werte, um Daten eines anderen Marktes abzurufen.")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"lookback")),Object(l.b)("td",{parentName:"tr",align:null},"Anzahl der Bars an Historie ab dem aktuellen Datum, ",Object(l.b)("strong",{parentName:"td"},"nicht mehr als 5000"),".")))),Object(l.b)(b.b,{type:"note",title:"Daten sind an den Chart-Kerzen ausgerichtet",mdxType:"Callout"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"ohlcv()"),", ",Object(l.b)("inlineCode",{parentName:"p"},"depths()"),", ",Object(l.b)("inlineCode",{parentName:"p"},"clusters()"),", ",Object(l.b)("inlineCode",{parentName:"p"},"liquidations()")," und ",Object(l.b)("inlineCode",{parentName:"p"},"moreData()")," des Chart-Zeitrahmens liefern ",Object(l.b)("strong",{parentName:"p"},"einen Eintrag pro Chart-Kerze"),": ",Object(l.b)("inlineCode",{parentName:"p"},"depths()[i]")," ist das Orderbuch von ",Object(l.b)("inlineCode",{parentName:"p"},"ohlcv()[i]"),", ",Object(l.b)("inlineCode",{parentName:"p"},"moreData()[i]")," enthält dessen Derivate-Daten und so weiter. Hat eine Quelle keinen Datensatz für eine Kerze (zum Beispiel weil die Orderbuch-Historie kürzer ist als die Kerzen-Historie), ist der Eintrag ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"null"))," – prüfen Sie das immer. Daten, die mit ",Object(l.b)("inlineCode",{parentName:"p"},"lookback")," oder für einen anderen Zeitrahmen angefordert werden, kommen unverändert zurück und müssen anhand der ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"startTime"))," zugeordnet werden. ",Object(l.b)("inlineCode",{parentName:"p"},"ohlcv()")," des Chart-Markts enthält nur die Kerzen, die der Server bereits geladen hat, niemals ",Object(l.b)("inlineCode",{parentName:"p"},"null"),"; solange ältere Historie noch geladen wird, wird der Indikator automatisch neu berechnet.")),Object(l.b)("h3",{id:"ohlcvexchange-ticker-timeframe-lookback"},Object(l.b)("inlineCode",{parentName:"h3"},"ohlcv(exchange, ticker, timeframe, lookback?)")),Object(l.b)("p",null,"Kerzendaten."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "open": 115886.17,\n "high": 115911.96,\n "low": 115764.27,\n "close": 115815.16,\n "volume": 228.41528,\n "startTime": 1757699100000\n },\n {...},\n ...\n] \n')),Object(l.b)("h3",{id:"depthsexchange-ticker-timeframe-lookback"},Object(l.b)("inlineCode",{parentName:"h3"},"depths(exchange, ticker, timeframe, lookback?)")),Object(l.b)("p",null,"Historische Orderbuch-Snapshots, einer pro Kerze. Nur die größten Limit-Orders werden gespeichert (die Daten hinter der Heatmap)."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "33000": 3.746,\n "35000": 16.49,\n ...\n }\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(l.b)("h3",{id:"clustersexchange-ticker-timeframe-lookback"},Object(l.b)("inlineCode",{parentName:"h3"},"clusters(exchange, ticker, timeframe, lookback?)")),Object(l.b)("p",null,"Cluster-Daten (Footprints): Kauf- und Verkaufsvolumen auf jedem Preisniveau der Kerze."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(l.b)("h3",{id:"liquidationsexchange-ticker-timeframe-lookback"},Object(l.b)("inlineCode",{parentName:"h3"},"liquidations(exchange, ticker, timeframe, lookback?)")),Object(l.b)("p",null,"Liquidiertes Volumen auf jedem Preisniveau der Kerze (nur Futures-Märkte). Dasselbe Format wie ",Object(l.b)("inlineCode",{parentName:"p"},"clusters()"),"."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(l.b)("h3",{id:"moredataexchange-ticker-timeframe-lookback"},Object(l.b)("inlineCode",{parentName:"h3"},"moreData(exchange, ticker, timeframe, lookback?)")),Object(l.b)("p",null,"Derivatedaten pro Kerze: Funding Rate, Open-Interest-Kerze, Long/Short-Verhältnisse (nur Futures-Märkte)."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'[\n { \n "data": {\n "FR": 0.00003777, // Funding Rate\n "OI": { // Open Interest Candle\n "open": 85645.708,\n "close": 83496.225,\n "high": 85801.04,\n "low": 83397.918\n },\n "LS": { "l": 0.5426, "s": 0.4574 }, // Long/Short Ratio\n "taLS": { "l": 0.552, "s": 0.448 }, // Top Traders Account Ratio\n "tpLS": { "l": 0.5996, "s": 0.4004 } // Top Traders Position Ratio\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(l.b)("h3",{id:"orderbookexchange-ticker"},Object(l.b)("inlineCode",{parentName:"h3"},"orderbook(exchange, ticker)")),Object(l.b)("p",null,"Live-Snapshot des Orderbuchs: das aktuelle vollständige Buch, nicht an Kerzen gebunden."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'{\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "109400": 1.2,\n "109390": 0.8,\n ...\n }\n}\n\n')),Object(l.b)("p",null,"Die Niveaus sind nicht sortiert; verwenden Sie die Orderbuch-Hilfsfunktionen der Klasse ",Object(l.b)("inlineCode",{parentName:"p"},"ta")," (",Object(l.b)("inlineCode",{parentName:"p"},"ta.bestBid"),", ",Object(l.b)("inlineCode",{parentName:"p"},"ta.sumBids"),", ...), um mit dem Buch zu arbeiten.\nDie historischen Bücher der Kerzen stammen aus ",Object(l.b)("inlineCode",{parentName:"p"},"depths()"),": ",Object(l.b)("inlineCode",{parentName:"p"},"depths()[i].data")," hat dasselbe Format, dort werden jedoch nur die größten Limit-Orders gespeichert."),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(); // The exchange, ticker, and timeframe parameters default to the current chart.\nconst closes = candles.map(c => c.close);\n")),Object(l.b)("h3",{id:"levelsexchange-settings"},Object(l.b)("inlineCode",{parentName:"h3"},"levels(exchange, settings?)")),Object(l.b)("p",null,"Die Level des ",Object(l.b)("strong",{parentName:"p"},"Liquiditäts-Screeners"),": die großen ruhenden Limit-Orders einer Börse, gefiltert mit denselben Einstellungen wie die Screener-Seite. Live-Daten, nicht an Kerzen gebunden. Ohne Plan sind die Nähe auf 1 %, die Lebensdauer auf 60 Minuten und das Ergebnis auf 200 Level begrenzt; mit Plan bis zu 2000 Level. Die größten Orders kommen zuerst. Zählt als eine Datenquellen-Anfrage."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'{\n "BTCUSDT": {\n "asks": {\n "109500": {\n "price": 109500,\n "quantity": 42.5, // size in the base asset\n "quantityUSDT": 4653750, // size in the quote currency\n "distance": 0.62, // from the current price, percent\n "duration": 184, // minutes the order has been standing\n "touches": 2,\n "currentTouches": 1,\n "filledPercent": 12.4,\n "strength": 95.5, // percent, see the screener\n "diversity": 11,\n "isContinuous": true,\n "date": "2026-10-10T06:12:03.000Z"\n },\n ...\n },\n "bids": { ... },\n "volume1hTotal": 183000000\n },\n ...\n}\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Einstellungen")," (alle optional):"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Einstellung"),Object(l.b)("th",{parentName:"tr",align:null},"Standard"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers")),Object(l.b)("td",{parentName:"tr",align:null},"alle Ticker"),Object(l.b)("td",{parentName:"tr",align:null},"nur diese Ticker der Börse")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"exclude")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"[]")),Object(l.b)("td",{parentName:"tr",align:null},"zu überspringende Ticker")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"type")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"all"')),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"all"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"bids"')," oder ",Object(l.b)("inlineCode",{parentName:"td"},'"asks"'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"nearness")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"5")),Object(l.b)("td",{parentName:"tr",align:null},"max. Abstand zum aktuellen Preis in Prozent")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"size")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"100000")),Object(l.b)("td",{parentName:"tr",align:null},"min. Ordergröße in der Notierungswährung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"lifespan")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0")),Object(l.b)("td",{parentName:"tr",align:null},"min. Minuten, die die Order steht")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"touches"),", ",Object(l.b)("inlineCode",{parentName:"td"},"currentTouches")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0")),Object(l.b)("td",{parentName:"tr",align:null},"min. Berührungen des Levels / der aktuellen Order")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"filled")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0")),Object(l.b)("td",{parentName:"tr",align:null},"min. ausgeführter Teil der Order in Prozent")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"strength"),", ",Object(l.b)("inlineCode",{parentName:"td"},"diversity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0")),Object(l.b)("td",{parentName:"tr",align:null},"min. Stärke (Prozent) und Diversität wie im Screener")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"continuousOnly")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},"Orders überspringen, die verschwanden und zurückkamen")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"volume1h")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0")),Object(l.b)("td",{parentName:"tr",align:null},"min. 1h-Volumen des Tickers in der Notierungswährung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"spotAndFutures")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},"nur Ticker, die es am Spot- und am Futures-Markt gibt")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"limit")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"500")),Object(l.b)("td",{parentName:"tr",align:null},"max. Anzahl Level, die größten zuerst (max. 2000)")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// the big orders around the price of the chart market as horizontal lines, labelled with the size and the lifespan\nconst candles = await source.ohlcv();\nconst lastDate = candles.at(-1).startTime;\nconst levels = await source.levels(currentExchange, { tickers: [currentTicker], nearness: 3, size: 300000, lifespan: 30 });\nconst own = levels[currentTicker] || { asks: {}, bids: {} };\nfor (const [type, color] of [["asks", "#ef5350"], ["bids", "#26a69a"]]) {\n for (const [price, level] of Object.entries(own[type])) {\n plot.horizontalLine(`${type} ${price}`, +price, color, 0.8, Math.min(4, 1 + level.quantityUSDT / 1e6));\n plot.text(`${type} ${price} label`, `${(level.quantityUSDT / 1e6).toFixed(2)}M · ${level.duration}m`, lastDate, +price, 10, color);\n }\n}\n')),Object(l.b)("h3",{id:"keylevelsexchange-settings"},Object(l.b)("inlineCode",{parentName:"h3"},"keyLevels(exchange, settings?)")),Object(l.b)("p",null,"Die Levels des ",Object(l.b)("strong",{parentName:"p"},"Key-Levels-Screeners"),": Open, High und Low des aktuellen und des vorherigen Tages, der Woche, des Monats und des Jahres für jeden Ticker einer Börse, mit dem Abstand jedes Levels zum aktuellen Preis. Live-Daten, nicht an Kerzen gebunden. Ohne Plan enthält das Ergebnis nur die Levels innerhalb von ±1 % vom Preis (der feste Bereich der Screener-Seite) und höchstens 100 Ticker; mit Plan ein beliebiger Abstandsbereich und bis zu 1000 Ticker. Die Ticker mit dem nächstgelegenen Level kommen zuerst. Zählt als eine Datenquellen-Anfrage."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'{\n "BTCUSDT": {\n "price": 79776.57, // aktueller Preis\n "updatedAt": 1788707880000,\n "bootstrapped": true, // false, solange die Historie des Tickers noch gesammelt wird\n "nearest": 0.08, // Abstand des nächsten Levels in Prozent\n "matches": 5, // Levels innerhalb des Abstandsbereichs\n "daily": { "start": 1788652800000, "open": 79700, "high": 79985, "low": 79710, "openApprox": false,\n "distance": { "open": -0.1, "high": 0.26, "low": -0.08 } }, // Prozent vom Preis, mit Vorzeichen\n "prevDay": { ... }, "weekly": { ... }, "prevWeek": { ... },\n "monthly": { ... }, "prevMonth": { ... }, "yearly": { ... }, "prevYear": null // null: noch keine Daten für die Periode\n },\n ...\n}\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Einstellungen")," (alle optional):"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Einstellung"),Object(l.b)("th",{parentName:"tr",align:null},"Standard"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers")),Object(l.b)("td",{parentName:"tr",align:null},"alle Ticker"),Object(l.b)("td",{parentName:"tr",align:null},"nur diese Ticker der Börse")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"exclude")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"[]")),Object(l.b)("td",{parentName:"tr",align:null},"zu überspringende Ticker")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"periods")),Object(l.b)("td",{parentName:"tr",align:null},"alle"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"daily"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"prevDay"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"weekly"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"prevWeek"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"monthly"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"prevMonth"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"yearly"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"prevYear"'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fields")),Object(l.b)("td",{parentName:"tr",align:null},"alle"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"open"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"high"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"low"'),": die zurückzugebenden Levels")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"distanceFrom"),", ",Object(l.b)("inlineCode",{parentName:"td"},"distanceTo")),Object(l.b)("td",{parentName:"tr",align:null},"keine"),Object(l.b)("td",{parentName:"tr",align:null},"Abstandsbereich vom Preis in Prozent mit Vorzeichen (z. B. ",Object(l.b)("inlineCode",{parentName:"td"},"-2")," und ",Object(l.b)("inlineCode",{parentName:"td"},"2"),"); nur Ticker mit einem Level innerhalb des Bereichs werden zurückgegeben. Ohne Plan ist der Bereich fest ±1 %")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"limit")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"200")),Object(l.b)("td",{parentName:"tr",align:null},"maximale Anzahl Ticker, das nächstgelegene Level zuerst (max. 1000; 100 ohne Plan)")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// the key levels of the chart market as horizontal lines\nconst candles = await source.ohlcv();\nconst lastDate = candles.at(-1).startTime;\nconst rows = await source.keyLevels(currentExchange, { tickers: [currentTicker], periods: ["daily", "prevDay", "weekly"] });\nconst own = rows[currentTicker];\nif (own) {\n for (const period of ["daily", "prevDay", "weekly"]) {\n const level = own[period];\n if (!level) continue;\n for (const [field, color] of [["high", "#ef5350"], ["low", "#26a69a"], ["open", "#90a4ae"]]) {\n if (level[field] == null) continue;\n plot.horizontalLine(`${period} ${field}`, level[field], color, 0.8, 1);\n plot.text(`${period} ${field} label`, `${period} ${field.toUpperCase()}`, lastDate, level[field], 10, color);\n }\n }\n}\n')),Object(l.b)("h3",{id:"levelsmetricsexchange-settings"},Object(l.b)("inlineCode",{parentName:"h3"},"levelsMetrics(exchange, settings?)")),Object(l.b)("p",null,"Die Historie der ",Object(l.b)("strong",{parentName:"p"},"starken Liquiditätslevel"),", die für die Seite ",Object(l.b)("strong",{parentName:"p"},"Metriken")," gesammelt wird: alle 5 Minuten nimmt der Server einen Schnappschuss der Liquiditäts-Screener-Level jeder Börse mit einer Dauer von mindestens 30 Minuten und einer Stärke von mindestens 80 % und bewahrt eine Woche davon auf. Die Quelle filtert die Schnappschüsse eines Zeitraums wie die Seite und liefert pro Schnappschuss die Anzahl und die $-Größe der passenden Level, die Aggregate je Ticker und den Lebenszyklus jedes Levels. Gesammelte Daten, nicht an Kerzen gebunden: ",Object(l.b)("inlineCode",{parentName:"p"},"series[].at")," muss mit den Kerzendaten abgeglichen werden. Ohne Abonnement beträgt der Zeitraum höchstens 24 Stunden und die Liste höchstens 100 Level; mit Abonnement bis zu 7 Tage und 1000 Level. Zählt als eine Datenquellen-Anfrage."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'{\n "exchange": "binanceFutures",\n "hours": 24,\n "snapshotMinutes": 5,\n "latestAt": 1792102098685,\n "summary": { "snapshots": 287, "uniqueLevels": 217, "uniqueTickers": 118, "activeNow": 180, "bidsNow": 102, "asksNow": 78, "usdNow": 119294436 },\n "series": [ // one point per snapshot, oldest first\n { "at": 1792015822555, "bids": 24, "asks": 21, "bidsUsd": 1851345, "asksUsd": 1228883, "tickers": 20 },\n ...\n ],\n "tickers": { // per ticker, over the period\n "BTCUSDT": { "now": 3, "nowUsd": 95710480, "snapshots": 63, "bids": 3, "asks": 0, "levels": 3,\n "maxUsd": 42347880, "maxDuration": 8220, "maxStrength": 100 },\n ...\n },\n "levels": [ // the lifecycle of every level, active ones first\n { "ticker": "BTCUSDT", "side": "bids", "price": 52050, "usd": 42347880, "quantity": 813.6, "distance": 19.8,\n "duration": 8220, "strength": 100, "continuous": 1, "firstSeen": 1792015822555, "lastSeen": 1792102098685,\n "snapshots": 63, "maxDuration": 8220, "maxStrength": 100, "active": true },\n ...\n ],\n "levelsTotal": 217\n}\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Einstellungen")," (alle optional):"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Einstellung"),Object(l.b)("th",{parentName:"tr",align:null},"Standard"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers")),Object(l.b)("td",{parentName:"tr",align:null},"alle Ticker"),Object(l.b)("td",{parentName:"tr",align:null},"nur diese Ticker der Börse")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"exclude")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"[]")),Object(l.b)("td",{parentName:"tr",align:null},"zu überspringende Ticker")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"hours")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"24")),Object(l.b)("td",{parentName:"tr",align:null},"Zeitraum in Stunden (max. 168; 24 ohne Abonnement)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"minDuration")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"30")),Object(l.b)("td",{parentName:"tr",align:null},"minimale Orderdauer in Minuten: ",Object(l.b)("inlineCode",{parentName:"td"},"30"),", ",Object(l.b)("inlineCode",{parentName:"td"},"60"),", ",Object(l.b)("inlineCode",{parentName:"td"},"120")," oder ",Object(l.b)("inlineCode",{parentName:"td"},"180"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"minStrength")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"80")),Object(l.b)("td",{parentName:"tr",align:null},"minimale Orderstärke in Prozent: ",Object(l.b)("inlineCode",{parentName:"td"},"80"),", ",Object(l.b)("inlineCode",{parentName:"td"},"90")," oder ",Object(l.b)("inlineCode",{parentName:"td"},"100"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"maxDistance")),Object(l.b)("td",{parentName:"tr",align:null},"keine"),Object(l.b)("td",{parentName:"tr",align:null},"maximale Entfernung der Order zum aktuellen Preis in Prozent, in jedem Schnappschuss geprüft")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"stableOnly")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"true"),": nur Orders, deren Menge nie gesprungen ist („Orders mit instabilen Mengen ausschließen“)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"limit")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"200")),Object(l.b)("td",{parentName:"tr",align:null},"maximale Anzahl Level in ",Object(l.b)("inlineCode",{parentName:"td"},"levels")," (max. 1000; 100 ohne Abonnement)")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// $ size of the strong levels of the chart market per candle\nconst candles = await source.ohlcv();\nconst data = await source.levelsMetrics(currentExchange, { tickers: [currentTicker], hours: 24, minDuration: 60, minStrength: 90, stableOnly: true });\nconst series = data.series; // oldest first\nlet j = 0;\nconst buy = [], sell = [];\nfor (let i = 0; i < candles.length; i++) {\n const end = candles[i + 1] ? candles[i + 1].startTime : candles[i].startTime + (candles[1].startTime - candles[0].startTime);\n while (j + 1 < series.length && series[j + 1].at < end) j++; // the last snapshot inside the candle\n const point = series[j] && series[j].at < end ? series[j] : null;\n buy.push(point ? point.bidsUsd : null);\n sell.push(point ? point.asksUsd : null);\n}\nplot.areaSeries("Buy levels ($)", buy, "#26a69a", 0.3, "#26a69a", 1, 1, 0);\nplot.areaSeries("Sell levels ($)", sell, "#ef5350", 0.3, "#ef5350", 1, 1, 0);\n')),Object(l.b)("h2",{id:"http-anfragen"},"HTTP-Anfragen"),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"http"))," sendet Anfragen an externe HTTP-APIs und gibt die Antwort zurück, sodass ein Indikator Daten nutzen kann, die in ",Object(l.b)("inlineCode",{parentName:"p"},"source")," nicht verfügbar sind: Ihr eigener Server, eine öffentliche REST-API, ein Anbieter von On-Chain-Metriken, ...\nWie bei ",Object(l.b)("inlineCode",{parentName:"p"},"source.*")," werden die Aufrufe als synchrone Funktionen geschrieben, ein ",Object(l.b)("inlineCode",{parentName:"p"},"await")," ist nicht nötig."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"get(url, options?)")),Object(l.b)("td",{parentName:"tr",align:null},"GET-Anfrage")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"post(url, body?, options?)")),Object(l.b)("td",{parentName:"tr",align:null},"POST-Anfrage. Ein Objekt oder Array als ",Object(l.b)("inlineCode",{parentName:"td"},"body")," wird als JSON gesendet (",Object(l.b)("inlineCode",{parentName:"td"},"Content-Type: application/json"),"), ein String wird unverändert gesendet")))),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"options")," ist ",Object(l.b)("inlineCode",{parentName:"p"},"{ headers: { name: value } }")," — bis zu ",Object(l.b)("strong",{parentName:"p"},"10")," eigene Header (zum Beispiel ",Object(l.b)("inlineCode",{parentName:"p"},"Authorization")," oder ",Object(l.b)("inlineCode",{parentName:"p"},"x-api-key"),")."),Object(l.b)("p",null,"Beide Methoden geben dasselbe Antwortobjekt zurück und ",Object(l.b)("strong",{parentName:"p"},"werfen nie eine Exception"),":"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'{\n ok: true, // Status 200–299\n status: 200, // HTTP-Status, 0 wenn die Anfrage nicht gesendet wurde\n headers: { "content-type": "application/json", ... },\n data: { ... }, // Antwortkörper als JSON geparst, null wenn der Körper kein JSON ist\n text: "...", // roher Antwortkörper\n error: null // Grund, wenn die Anfrage fehlgeschlagen ist: "timeout", "url not allowed", "too many requests", ...\n}\n')),Object(l.b)(b.b,{type:"warning",title:"Limits und Sicherheit",mdxType:"Callout"},Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Bis zu ",Object(l.b)("strong",{parentName:"li"},"3 Anfragen")," pro Skriptlauf und ",Object(l.b)("strong",{parentName:"li"},"60 Anfragen pro Minute")," pro Benutzer."),Object(l.b)("li",{parentName:"ul"},"Nur öffentliche ",Object(l.b)("inlineCode",{parentName:"li"},"http://")," / ",Object(l.b)("inlineCode",{parentName:"li"},"https://")," URLs. Anfragen an ",Object(l.b)("inlineCode",{parentName:"li"},"localhost"),", private Netzwerke und Cloud-Metadaten-Adressen werden abgelehnt, Weiterleitungen werden ",Object(l.b)("strong",{parentName:"li"},"nicht gefolgt")," (eine ",Object(l.b)("inlineCode",{parentName:"li"},"3xx"),"-Antwort wird unverändert zurückgegeben)."),Object(l.b)("li",{parentName:"ul"},"Anfragen werden von den MobChart-Proxy-Servern gesendet: die Ziel-API sieht die Proxy-Adresse und nie Ihre IP."),Object(l.b)("li",{parentName:"ul"},"Timeout ",Object(l.b)("strong",{parentName:"li"},"5 Sekunden"),", Anfragekörper bis ",Object(l.b)("strong",{parentName:"li"},"64 KB"),", Antwort bis ",Object(l.b)("strong",{parentName:"li"},"512 KB")," (größere Antworten schlagen mit ",Object(l.b)("inlineCode",{parentName:"li"},"response too large")," fehl)."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Host"),", ",Object(l.b)("inlineCode",{parentName:"li"},"Cookie"),", ",Object(l.b)("inlineCode",{parentName:"li"},"Proxy-*"),", ",Object(l.b)("inlineCode",{parentName:"li"},"X-Forwarded-*")," und andere Verbindungs-Header können nicht gesetzt werden, ",Object(l.b)("inlineCode",{parentName:"li"},"Set-Cookie")," wird nie zurückgegeben."),Object(l.b)("li",{parentName:"ul"},"Alarmprüfungen führen Ihr Skript regelmäßig auf dem Server aus: die API wird bei jeder Prüfung aufgerufen, beachten Sie die Ratenlimits der Ziel-API."),Object(l.b)("li",{parentName:"ul"},"Der Code eines öffentlichen Indikators (",Object(l.b)("inlineCode",{parentName:"li"},"isPublicCode = true"),") ist für alle sichtbar — legen Sie niemals API-Schlüssel in öffentlichen Code."))),Object(l.b)("p",null,"Mögliche Werte von ",Object(l.b)("inlineCode",{parentName:"p"},"error"),": ",Object(l.b)("inlineCode",{parentName:"p"},"invalid url"),", ",Object(l.b)("inlineCode",{parentName:"p"},"url not allowed"),", ",Object(l.b)("inlineCode",{parentName:"p"},"invalid headers"),", ",Object(l.b)("inlineCode",{parentName:"p"},"invalid body"),", ",Object(l.b)("inlineCode",{parentName:"p"},"body too large"),", ",Object(l.b)("inlineCode",{parentName:"p"},"response too large"),", ",Object(l.b)("inlineCode",{parentName:"p"},"timeout"),", ",Object(l.b)("inlineCode",{parentName:"p"},"too many requests"),", ",Object(l.b)("inlineCode",{parentName:"p"},"rate limit"),", ",Object(l.b)("inlineCode",{parentName:"p"},"busy"),", ",Object(l.b)("inlineCode",{parentName:"p"},"proxy unavailable"),", ",Object(l.b)("inlineCode",{parentName:"p"},"network error"),"."),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel (GET):")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'define("Fear & Greed", "Crypto Fear & Greed index", "offchart", true, true);\n\nconst res = http.get("https://api.alternative.me/fng/?limit=30");\nif (!res.ok) logger.log("request failed:", res.status, res.error);\n\n// res.data = { data: [{ value: "71", timestamp: "1757635200" }, ...] }\nconst byDay = {};\n(res.data?.data || []).forEach((row) => { byDay[Number(row.timestamp) * 1000] = Number(row.value); });\n\nconst candles = source.ohlcv();\nconst values = candles.map((c) => c ? byDay[c.startTime - (c.startTime % 86400000)] ?? null : null);\nplot.lineSeries("Fear & Greed", values, "#00C8FF");\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel (POST):")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst last = candles.at(-1);\n\nconst res = http.post(\n "https://example.com/api/signals",\n { exchange: currentExchange, ticker: currentTicker, close: last.close },\n { headers: { "x-api-key": "YOUR_KEY" } } // private code only\n);\nlogger.log("signal sent:", res.ok, res.status, res.data);\n')),Object(l.b)("h2",{id:"globale-variablen"},"Globale Variablen"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Variable"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"),Object(l.b)("th",{parentName:"tr",align:null},"Beispiel"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"currentExchange")),Object(l.b)("td",{parentName:"tr",align:null},"Aktuelle Börse im Chart"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"binance"),", ",Object(l.b)("inlineCode",{parentName:"td"},"binanceFutures"),", ",Object(l.b)("inlineCode",{parentName:"td"},"bybit"),", ",Object(l.b)("inlineCode",{parentName:"td"},"bybitFutures"),", ",Object(l.b)("inlineCode",{parentName:"td"},"okx"),", ",Object(l.b)("inlineCode",{parentName:"td"},"okxFutures"),", ",Object(l.b)("inlineCode",{parentName:"td"},"coinbase"),", ",Object(l.b)("inlineCode",{parentName:"td"},"bitfinex"),", ",Object(l.b)("inlineCode",{parentName:"td"},"bitfinexFutures"),", ",Object(l.b)("inlineCode",{parentName:"td"},"hyperliquid"),", ",Object(l.b)("inlineCode",{parentName:"td"},"hyperliquidFutures"),", ",Object(l.b)("inlineCode",{parentName:"td"},"asterFutures"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"currentTicker")),Object(l.b)("td",{parentName:"tr",align:null},"Aktueller Ticker im Chart (Format hängt von der Börse ab)"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"BTCUSDT"),", ",Object(l.b)("inlineCode",{parentName:"td"},"ADA-USD"),", ",Object(l.b)("inlineCode",{parentName:"td"},"BTC/USDC"),", ...")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"currentTimeframe")),Object(l.b)("td",{parentName:"tr",align:null},"Aktueller Zeitrahmen im Chart"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"1m"),", ",Object(l.b)("inlineCode",{parentName:"td"},"5m"),", ",Object(l.b)("inlineCode",{parentName:"td"},"15m"),", ...")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"exchanges")),Object(l.b)("td",{parentName:"tr",align:null},"Namen aller Börsen (eingefrorenes Array)"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'["binance", "binanceFutures", ...]'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers")),Object(l.b)("td",{parentName:"tr",align:null},"Ticker aller Börsen: ",Object(l.b)("inlineCode",{parentName:"td"},"tickers[currentExchange]")," ist die Liste der Chart-Börse (eingefroren)"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tickers.binance")," = ",Object(l.b)("inlineCode",{parentName:"td"},'["BTCUSDT", "ETHUSDT", ...]'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"heatmapStep")),Object(l.b)("td",{parentName:"tr",align:null},"Preisschritt der Orderbuch-Heatmap und der Cluster beim aktuellen Preis (die Genauigkeit, auf die der Server Preise rundet: 5 über 5000, 1 bei 1000-5000, 0.1 bei 100-1000, ...), aus dem letzten Schlusskurs des Charts; ",Object(l.b)("inlineCode",{parentName:"td"},"null"),", solange der Preis unbekannt ist (bekannt nach dem ersten ",Object(l.b)("inlineCode",{parentName:"td"},"source.ohlcv()")," des Chart-Markts)"),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"5"),", ",Object(l.b)("inlineCode",{parentName:"td"},"1"),", ",Object(l.b)("inlineCode",{parentName:"td"},"0.1"),", ",Object(l.b)("inlineCode",{parentName:"td"},"0.001"),", ...")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(currentExchange, currentTicker, currentTimeframe);\nconst closes = candles.map(c => c.close);\n")),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Ticker-Formate.")," Jede ",Object(l.b)("inlineCode",{parentName:"p"},"source"),"-Methode mit Börse und Ticker schickt den Ticker durch ",Object(l.b)("inlineCode",{parentName:"p"},"resolveTicker"),": aus dem übergebenen Format (",Object(l.b)("inlineCode",{parentName:"p"},"ETHUSDT"),", ",Object(l.b)("inlineCode",{parentName:"p"},"ETH-USD"),", ",Object(l.b)("inlineCode",{parentName:"p"},"ETH/USDC"),", ",Object(l.b)("inlineCode",{parentName:"p"},"ETH:USD"),", ",Object(l.b)("inlineCode",{parentName:"p"},"ETHF0:USTF0"),", ...) wird die Basiswährung gelesen und der Ticker im Format der angefragten Börse neu gebildet. ",Object(l.b)("inlineCode",{parentName:"p"},"ETH-USD")," funktioniert also für Binance, und ",Object(l.b)("inlineCode",{parentName:"p"},"currentTicker")," eines Binance-Charts funktioniert für Coinbase. Nur der Coin bleibt erhalten: es wird das Standard-Paar der Börse verwendet (USDT bei Binance, USD bei Coinbase, USDC bei Hyperliquid, ...), ein Coin, den die Börse nicht listet, liefert ein leeres Ergebnis mit einer Zeile im Log."),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// ein Coinbase-Ticker auf Binance Futures: wird zu ETHUSDT aufgelöst\nconst depths = source.depths("binanceFutures", "ETH-USD");\n// der Ticker eines Binance-Charts auf Coinbase: aus ETHUSDT wird ETH-USD\nconst spot = source.ohlcv("coinbase", currentTicker, currentTimeframe);\n')),Object(l.b)("h2",{id:"logging"},"Logging"),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"logger"))," dient zur Ausgabe von Informationen und zum Debuggen."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"log(...args)")),Object(l.b)("td",{parentName:"tr",align:null},"Fügt dem Log einen Eintrag hinzu (mit Begrenzungen für Länge und Anzahl)")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nlogger.log("First candle:", candles?.[0]);\n')),Object(l.b)(b.f,{src:"../../public/code_editor_log.png",mdxType:"Screenshot"}),Object(l.b)("h2",{id:"visualisierung"},"Visualisierung"),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"plot"))," ist für das Zeichnen grafischer Elemente und Datenreihen zuständig."),Object(l.b)("h3",{id:"geometrische-formen"},"Geometrische Formen"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"box(title, date1, price1, date2, price2, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(l.b)("td",{parentName:"tr",align:null},"Rechteck")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"square(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(l.b)("td",{parentName:"tr",align:null},"Quadrat")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"diamond(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(l.b)("td",{parentName:"tr",align:null},"Raute")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"triangle(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(l.b)("td",{parentName:"tr",align:null},"Dreieck")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"circle(title, date1, price1, radius = 10, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(l.b)("td",{parentName:"tr",align:null},"Kreis")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"text(title, value, date1, price1, fontSize, fill, opacity)")),Object(l.b)("td",{parentName:"tr",align:null},"Text im Chart")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"table(title, rows, options)")),Object(l.b)("td",{parentName:"tr",align:null},"Tabelle in einer Ecke des Charts, siehe ",Object(l.b)("a",{parentName:"td",href:"#tabellen"},"Tabellen"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"straightLine(title, date1, price1, date2, price2, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(l.b)("td",{parentName:"tr",align:null},"Gerade Linie")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"horizontalLine(title, price1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(l.b)("td",{parentName:"tr",align:null},"Horizontale Linie über das gesamte Chart")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"verticalLine(title, date1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(l.b)("td",{parentName:"tr",align:null},"Vertikale Linie über das gesamte Chart")))),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Parameter"),Object(l.b)("th",{parentName:"tr",align:null},"Datentyp"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"title")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")),Object(l.b)("td",{parentName:"tr",align:null},"Name des Elements (eindeutige Kennung im Chart)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"date1")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," (Zeitstempel, ms)"),Object(l.b)("td",{parentName:"tr",align:null},"Start-Zeitstempel")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"price1")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Startpreis (Koordinate der Y-Achse)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"date2")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," (Zeitstempel, ms)"),Object(l.b)("td",{parentName:"tr",align:null},"End-Zeitstempel (für Linien und Rechtecke)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"price2")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Endpreis (für Linien und Rechtecke)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"size")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Größe der Form (in Pixeln)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"radius")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Kreisradius (Standard 10)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fill")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")," (hex, z. B. ",Object(l.b)("inlineCode",{parentName:"td"},'"#FF0000"'),")"),Object(l.b)("td",{parentName:"tr",align:null},"Füllfarbe der Form")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"opacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Füllung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"stroke")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")," (hex, z. B. ",Object(l.b)("inlineCode",{parentName:"td"},'"#000000"'),")"),Object(l.b)("td",{parentName:"tr",align:null},"Linienfarbe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"strokeOpacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Linie")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"strokeWidth")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Linienbreite (in Pixeln)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"strokeDasharray")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"array")," (z. B. ",Object(l.b)("inlineCode",{parentName:"td"},"[5,5]"),")"),Object(l.b)("td",{parentName:"tr",align:null},"Stil der gestrichelten Linie")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fontSize")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")),Object(l.b)("td",{parentName:"tr",align:null},"Textgröße (in Pixeln)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"value")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")),Object(l.b)("td",{parentName:"tr",align:null},"Textwert (für die Methode ",Object(l.b)("inlineCode",{parentName:"td"},"text"),")")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'plot.text("Text object", "Hello world!", 1757699100000, 115000, 10, "#00C8FF", 0.5);\nplot.straightLine(`${namePrefix} Open`, level.timeStart, level.open, level.timeEnd, level.open, color);\nplot.circle(`${namePrefix} High`, level.timeStart, level.high, 3, color);\n')),Object(l.b)("p",null,"Es können nicht mehr als ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"3000"))," Formen im Chart angezeigt werden."),Object(l.b)("h3",{id:"datenreihen"},"Datenreihen"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"lineSeries(title, values, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(l.b)("td",{parentName:"tr",align:null},"Linienchart")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"barSeries(title, values, fill, opacity)")),Object(l.b)("td",{parentName:"tr",align:null},"Balkenchart")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"candleSeries(title, openValues, closeValues, highValues, lowValues, fill, opacity)")),Object(l.b)("td",{parentName:"tr",align:null},"Kerzen")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"areaSeries(title, values, fill, opacity, stroke, strokeOpacity, strokeWidth, base)")),Object(l.b)("td",{parentName:"tr",align:null},"Gefüllte Fläche zwischen der Linie und ",Object(l.b)("inlineCode",{parentName:"td"},"base")," (Standard: der untere Rand des Charts)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"bandSeries(title, upperValues, lowerValues, fill, opacity, stroke, strokeOpacity, strokeWidth, step)")),Object(l.b)("td",{parentName:"tr",align:null},"Gefülltes Band zwischen zwei Reihen, jede Kerze behält ihre eigene Farbe und Deckkraft")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"profile(title, values, options)")),Object(l.b)("td",{parentName:"tr",align:null},"Histogramm nach Preis über die sichtbaren Kerzen, wie das Volumenprofil, siehe ",Object(l.b)("a",{parentName:"td",href:"#profile"},"Profile"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"histogram(title, rows, options)")),Object(l.b)("td",{parentName:"tr",align:null},"Fertiges Preisprofil, als Profil gezeichnet, siehe ",Object(l.b)("a",{parentName:"td",href:"#histogramme"},"Histogramme"))))),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Parameter"),Object(l.b)("th",{parentName:"tr",align:null},"Datentyp"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"values"),", ",Object(l.b)("inlineCode",{parentName:"td"},"upperValues"),", ",Object(l.b)("inlineCode",{parentName:"td"},"lowerValues")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"(number \\| null)[]")),Object(l.b)("td",{parentName:"tr",align:null},"Ein Wert pro Kerze, ",Object(l.b)("inlineCode",{parentName:"td"},"null")," blendet die Kerze aus")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fill"),", ",Object(l.b)("inlineCode",{parentName:"td"},"stroke")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"string")," (hex) oder ",Object(l.b)("inlineCode",{parentName:"td"},"function")),Object(l.b)("td",{parentName:"tr",align:null},"Farbe oder eine Funktion, die die Farbe der Kerze zurückgibt: ",Object(l.b)("inlineCode",{parentName:"td"},"(value, i)")," für ",Object(l.b)("inlineCode",{parentName:"td"},"lineSeries"),", ",Object(l.b)("inlineCode",{parentName:"td"},"barSeries"),", ",Object(l.b)("inlineCode",{parentName:"td"},"candleSeries"),", ",Object(l.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(l.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," für ",Object(l.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"opacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," (0–1) oder ",Object(l.b)("inlineCode",{parentName:"td"},"function")),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Füllung, eine Funktion ",Object(l.b)("inlineCode",{parentName:"td"},"(value, i)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," für ",Object(l.b)("inlineCode",{parentName:"td"},"areaSeries")," / ",Object(l.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"base")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number")," ","|"," ",Object(l.b)("inlineCode",{parentName:"td"},"null")),Object(l.b)("td",{parentName:"tr",align:null},"Basisniveau von ",Object(l.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(l.b)("inlineCode",{parentName:"td"},"null")," = der untere Rand des Charts")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"step")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"boolean")),Object(l.b)("td",{parentName:"tr",align:null},"Stil von ",Object(l.b)("inlineCode",{parentName:"td"},"bandSeries"),": ",Object(l.b)("inlineCode",{parentName:"td"},"true")," = eine Spalte pro Kerze (Standard), ",Object(l.b)("inlineCode",{parentName:"td"},"false")," = ein durchgehendes Polygon")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("EMA", ta.ema(closes, 20), "#00C8FF");\n// every candle keeps its own color: green where the close is above the EMA, red below it\nplot.lineSeries("Close", closes, (v, i) => v > ema[i] ? colorBuy : colorSell);\nplot.barSeries("Premium %", premiumPercents, ((d) => d > 0 ? color1 : color2), 1);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\nplot.areaSeries("Volume", volumes, "#00C8FF", 0.3);\n// area colored per candle, more opaque on the bigger candles\nplot.areaSeries("Delta", deltas, (v, i) => v >= 0 ? colorBuy : colorSell, (v, i) => Math.min(1, Math.abs(v) / maxDelta));\n\n// pressure band between the close and 1% below it, colored and shaded by the imbalance ratio of the candle\nplot.bandSeries(\n "Bid pressure",\n closes,\n closes.map(c => c * 0.99),\n (upper, lower, i) => ratios[i] > 0 ? bidColor : askColor,\n (upper, lower, i) => Math.abs(ratios[i]) / 100\n);\n')),Object(l.b)("p",null,"Es können nicht mehr als ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"20"))," Datenreihen im Chart angezeigt werden."),Object(l.b)("h3",{id:"profile"},"Profile"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"plot.profile(title, values, options?)")," zeichnet ein Histogramm nach Preis, wie das eingebaute Volumenprofil. ",Object(l.b)("inlineCode",{parentName:"p"},"values[i]")," ist die Preiskarte der Kerze ",Object(l.b)("inlineCode",{parentName:"p"},"i")," von ",Object(l.b)("inlineCode",{parentName:"p"},"ohlcv()"),": ",Object(l.b)("inlineCode",{parentName:"p"},"{ price: value }")," oder ",Object(l.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," (das ",Object(l.b)("inlineCode",{parentName:"p"},"data")," eines ",Object(l.b)("inlineCode",{parentName:"p"},"clusters()"),"- oder ",Object(l.b)("inlineCode",{parentName:"p"},"liquidations()"),"-Datensatzes kann unverändert übergeben werden) oder ",Object(l.b)("inlineCode",{parentName:"p"},"null")," für eine Kerze ohne Zeilen. Die Zeilen der ",Object(l.b)("strong",{parentName:"p"},"im Chart sichtbaren")," Kerzen werden direkt im Chart je Preisschritt summiert, daher folgt das Profil dem Verschieben, Zoomen und Nachladen ohne neuen Lauf. Einzelwerte werden in einer Farbe gezeichnet (ein negativer Wert geht an ",Object(l.b)("inlineCode",{parentName:"p"},"fill2"),"), Paare teilen den Balken in Kauf- und Verkaufsteil und erlauben den Delta-Modus. ",Object(l.b)("inlineCode",{parentName:"p"},"profile()")," gibt keinen Alert-Handle zurück."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Option"),Object(l.b)("th",{parentName:"tr",align:null},"Standard"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"step")),Object(l.b)("td",{parentName:"tr",align:null},"Tickgröße des Charts"),Object(l.b)("td",{parentName:"tr",align:null},"Zeilenhöhe in Preiseinheiten, Preise werden darauf abgerundet")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"orient")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"right"')),Object(l.b)("td",{parentName:"tr",align:null},"Kante, von der die Balken wachsen, ",Object(l.b)("inlineCode",{parentName:"td"},'"right"')," oder ",Object(l.b)("inlineCode",{parentName:"td"},'"left"'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"width")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"30")),Object(l.b)("td",{parentName:"tr",align:null},"breiteste Zeile in Prozent der Chartbreite")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fill")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"#26a69a"')),Object(l.b)("td",{parentName:"tr",align:null},"Farbe des Werts bzw. des Kaufteils")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fill2")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"#ef5350"')),Object(l.b)("td",{parentName:"tr",align:null},"Farbe des Verkaufsteils")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"opacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0.6")),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Balken")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"delta")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"buy - sell")," statt der Summe zeichnen, nur bei Paaren")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"poc")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"true")),Object(l.b)("td",{parentName:"tr",align:null},"Linie an der Zeile mit dem größten Wert")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"valueArea")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"70")),Object(l.b)("td",{parentName:"tr",align:null},"Prozent der Summe um den POC mit voller Deckkraft, ",Object(l.b)("inlineCode",{parentName:"td"},"false")," zum Abschalten")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"valueAreaOpacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0.3")),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Zeilen außerhalb der Value Area")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"labels")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"true")),Object(l.b)("td",{parentName:"tr",align:null},"Zeilensummen auf den Balken, wenn Platz ist")))),Object(l.b)("p",null,"Grenzen: ",Object(l.b)("strong",{parentName:"p"},"3")," Profile pro Lauf, ",Object(l.b)("strong",{parentName:"p"},"300")," Zeilen pro Kerze, ",Object(l.b)("strong",{parentName:"p"},"200000")," Zeilen pro Profil. Zeilen darüber hinaus werden verworfen, der Lauf schreibt eine Notiz ins Log."),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// volume profile of the chart, the same picture as the built-in tool\nconst rows = await source.clusters();\nplot.profile("Volume", rows.map((r) => r?.data ?? null), { step: 5 });\n\n// only large trades, delta coloured, on the left edge\nconst minSize = input.number("Min trade size", 50, 0, 100000, 1);\nconst big = rows.map((r) => {\n if (!r?.data) return null;\n const out = {};\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n if (c.buy + c.sell >= minSize) out[price] = { buy: c.buy, sell: c.sell };\n }\n return out;\n});\nplot.profile("Large trades", big, { step: 5, delta: true, orient: "left" });\n')),Object(l.b)("h3",{id:"histogramme"},"Histogramme"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"plot.histogram(title, rows, options?)")," zeichnet ein Histogramm, das Sie bereits gebaut haben: ",Object(l.b)("strong",{parentName:"p"},"eine Preiskarte für den ganzen Chart"),", aus den Kerzen wird nichts summiert. Verwenden Sie ",Object(l.b)("inlineCode",{parentName:"p"},"profile()"),", wenn die Zeilen zu Kerzen gehören und das Bild dem sichtbaren Bereich folgen soll, und ",Object(l.b)("inlineCode",{parentName:"p"},"histogram()"),", wenn die Zeilen fertig sind: ein Orderbuch-Schnappschuss, vom Skript berechnete Level, Daten eines anderen Marktes."),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"rows")," hat dieselben Formate wie ein Kerzeneintrag von ",Object(l.b)("inlineCode",{parentName:"p"},"profile()"),": ",Object(l.b)("inlineCode",{parentName:"p"},"{ price: value }"),", ",Object(l.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," oder eine Liste von ",Object(l.b)("inlineCode",{parentName:"p"},"[price, buy, sell]"),"-Zeilen. Ein Einzelwert wird in einer Farbe gezeichnet (ein negativer Wert geht an ",Object(l.b)("inlineCode",{parentName:"p"},"fill2"),"), Paare teilen den Balken in Kauf- und Verkaufsteil und erlauben den Delta-Modus. Die Optionen sind dieselben wie bei ",Object(l.b)("inlineCode",{parentName:"p"},"profile()"),", siehe die Tabelle oben."),Object(l.b)("p",null,"Das Histogramm trägt das Datum der letzten Kerze des Laufs, und der Chart behält das ",Object(l.b)("strong",{parentName:"p"},"neueste")," Histogramm eines Titels, sodass Teilberechnungen über ältere Kerzen (Nachladen der Historie) das aktuelle nie ersetzen. Es wird bei jeder Aktualisierung des Skripts neu gezeichnet, ein Orderbuch-Histogramm folgt also dem Live-Buch. ",Object(l.b)("inlineCode",{parentName:"p"},"histogram()")," gibt keinen Alert-Handle zurück."),Object(l.b)("p",null,"Grenzen: ",Object(l.b)("strong",{parentName:"p"},"3")," Histogramme pro Lauf, ",Object(l.b)("strong",{parentName:"p"},"5000")," Zeilen. Zeilen darüber hinaus werden verworfen, der Lauf schreibt eine Notiz ins Log."),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel, das Orderbuch:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// the live order book as a profile on the right edge: bids in the buy colour, asks in the sell colour\nconst book = await source.orderbook();\nconst rows = {};\nfor (const [price, qty] of Object.entries(book.bids)) rows[price] = { buy: qty };\nfor (const [price, qty] of Object.entries(book.asks)) rows[price] = { sell: qty };\nplot.histogram("Order book", rows, { step: 5, width: 25, valueArea: false, poc: false });\n')),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel, eigene Level:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// your own histogram: cluster volume of the last 100 candles, recent candles weigh more\nconst rows = await source.clusters();\nconst weighted = {};\nrows.slice(-100).forEach((r, i, arr) => {\n if (!r?.data) return;\n const weight = (i + 1) / arr.length;\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n const cell = weighted[price] || (weighted[price] = { buy: 0, sell: 0 });\n cell.buy += (c.buy || 0) * weight;\n cell.sell += (c.sell || 0) * weight;\n }\n});\nplot.histogram("Weighted volume", weighted, { step: 5, orient: "left", delta: true });\n')),Object(l.b)("h3",{id:"tabellen"},"Tabellen"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"plot.table(title, rows, options?)")," zeichnet ein kleines Raster in einer Ecke des Chartbereichs: Zusammenfassungen über mehrere Zeitrahmen, Statistiken des geladenen Bereichs, Signalübersichten. ",Object(l.b)("inlineCode",{parentName:"p"},"rows")," ist ein Array von Zeilen, eine Zeile ein Array von Zellen, eine Zelle ein String, eine Zahl oder ",Object(l.b)("inlineCode",{parentName:"p"},"{ text, color, bg, align, bold }"),". Tabellen derselben Ecke werden der Reihe nach gestapelt. Eine Tabelle trägt das Datum der letzten Kerze des Laufs, und der Chart behält die ",Object(l.b)("strong",{parentName:"p"},"neueste")," Tabelle eines Titels, sodass Teilberechnungen über ältere Kerzen (Nachladen der Historie) die aktuelle nie ersetzen. Auf Charts schmaler als 500 px werden Tabellen nicht gezeichnet. Eine Tabelle kann mit der Maus verschoben werden: Die Position wird mit dem Workspace gespeichert und zurückgesetzt, wenn das Skript seine Option ",Object(l.b)("inlineCode",{parentName:"p"},"position")," ändert. ",Object(l.b)("inlineCode",{parentName:"p"},"table()")," gibt keinen Alert-Handle zurück."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Option"),Object(l.b)("th",{parentName:"tr",align:null},"Standard"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"position")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"top-right"')),Object(l.b)("td",{parentName:"tr",align:null},"Ecke des Bereichs: ",Object(l.b)("inlineCode",{parentName:"td"},'"top-right"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"top-left"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"bottom-right"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"bottom-left"'))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"header")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"false")),Object(l.b)("td",{parentName:"tr",align:null},"erste Zeile fett auf einem schattierten Band")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fontSize")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"11")),Object(l.b)("td",{parentName:"tr",align:null},"Textgröße in px, 8 bis 16")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"color"),", ",Object(l.b)("inlineCode",{parentName:"td"},"bg"),", ",Object(l.b)("inlineCode",{parentName:"td"},"border")),Object(l.b)("td",{parentName:"tr",align:null},"nach Thema"),Object(l.b)("td",{parentName:"tr",align:null},"Standardfarben für Text, Fläche und Raster; eine Zelle kann ",Object(l.b)("inlineCode",{parentName:"td"},"color")," und ",Object(l.b)("inlineCode",{parentName:"td"},"bg")," überschreiben")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"opacity")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"0.85")),Object(l.b)("td",{parentName:"tr",align:null},"Deckkraft der Fläche")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"align")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},'"left"')),Object(l.b)("td",{parentName:"tr",align:null},"Standardausrichtung der Zellen, ",Object(l.b)("inlineCode",{parentName:"td"},'"left"'),", ",Object(l.b)("inlineCode",{parentName:"td"},'"center"')," oder ",Object(l.b)("inlineCode",{parentName:"td"},'"right"'))))),Object(l.b)("p",null,"Grenzen: ",Object(l.b)("strong",{parentName:"p"},"3")," Tabellen pro Lauf, ",Object(l.b)("strong",{parentName:"p"},"50")," Zeilen, ",Object(l.b)("strong",{parentName:"p"},"10")," Spalten, ",Object(l.b)("strong",{parentName:"p"},"100")," Zeichen pro Zelle. Längerer Text wird mit Auslassungspunkten gekürzt, eine Spalte nimmt höchstens 30 % der Chartbreite ein."),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const candles = await source.ohlcv();\nconst closes = candles.map((c) => c.close);\nconst rsi = ta.rsi(closes, 14);\nconst last = rsi.at(-1);\nconst change = (closes.at(-1) / closes.at(-25) - 1) * 100;\n\nplot.table("Stats", [\n ["Metric", "Value"],\n ["RSI 14", { text: last.toFixed(1), color: last > 70 ? "#ef5350" : last < 30 ? "#26a69a" : undefined }],\n ["Change 24 bars", { text: change.toFixed(2) + "%", align: "right" }],\n ["Volume", candles.slice(-24).reduce((s, c) => s + c.volume, 0).toFixed(0)],\n], { position: "top-right", header: true });\n')),Object(l.b)("h2",{id:"technische-analyse"},"Technische Analyse"),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"ta"))," implementiert die ",Object(l.b)("inlineCode",{parentName:"p"},"ta.*"),"-Funktionen von PineScript v5. Pine rechnet Bar für Bar, hier nimmt jede Funktion ganze Serien (Arrays, ein Wert pro Kerze, älteste zuerst) und gibt eine Serie gleicher Länge zurück, die direkt geplottet werden kann. Solange die Periode nicht gefüllt ist, sind die Werte ",Object(l.b)("inlineCode",{parentName:"p"},"null"),", und ",Object(l.b)("inlineCode",{parentName:"p"},"null"),"-Eingaben werden wie Pines ",Object(l.b)("inlineCode",{parentName:"p"},"na")," weitergereicht. Pine-Funktionen, die implizit ",Object(l.b)("inlineCode",{parentName:"p"},"high"),", ",Object(l.b)("inlineCode",{parentName:"p"},"low"),", ",Object(l.b)("inlineCode",{parentName:"p"},"close")," oder ",Object(l.b)("inlineCode",{parentName:"p"},"volume")," lesen, erhalten diese Arrays als Argumente."),Object(l.b)("p",null,"Funktionen mit mehreren Serien (",Object(l.b)("inlineCode",{parentName:"p"},"bb"),", ",Object(l.b)("inlineCode",{parentName:"p"},"kc"),", ",Object(l.b)("inlineCode",{parentName:"p"},"macd"),", ",Object(l.b)("inlineCode",{parentName:"p"},"stoch"),", ",Object(l.b)("inlineCode",{parentName:"p"},"dmi"),", ",Object(l.b)("inlineCode",{parentName:"p"},"supertrend"),") geben ein Array mit benannten Eigenschaften zurück: ",Object(l.b)("inlineCode",{parentName:"p"},"const [middle, upper, lower] = ta.bb(closes, 20, 2)")," oder ",Object(l.b)("inlineCode",{parentName:"p"},"ta.bb(closes, 20, 2).upper"),"."),Object(l.b)("h3",{id:"hilfsfunktionen"},"Hilfsfunktionen"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"highest(values, length)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"lowest(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Höchster / niedrigster Wert über ",Object(l.b)("inlineCode",{parentName:"td"},"length")," Bars")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"highestbars(values, length)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"lowestbars(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Versatz (0 oder negativ) zum höchsten / niedrigsten Bar")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"max(values)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"min(values)")),Object(l.b)("td",{parentName:"tr",align:null},"Allzeithoch / -tief bis zu jedem Bar")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"range(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"highest - lowest"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"change(values, length = 1)")),Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"values[i] - values[i - length]"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"mom(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Momentum")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"roc(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Änderungsrate, %")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"cum(values)")),Object(l.b)("td",{parentName:"tr",align:null},"Laufende Summe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"rising(values, length)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"falling(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Wert liegt über / unter jedem der vorherigen ",Object(l.b)("inlineCode",{parentName:"td"},"length")," Werte")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"variance(values, length, biased = true)")),Object(l.b)("td",{parentName:"tr",align:null},"Varianz")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"stdev(values, length, biased = true)")),Object(l.b)("td",{parentName:"tr",align:null},"Standardabweichung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"dev(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Mittlere absolute Abweichung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"median(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Median")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"mode(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Häufigster Wert (bei Gleichstand der kleinste)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"percentile_linear_interpolation(values, length, percentage)")),Object(l.b)("td",{parentName:"tr",align:null},"Perzentil, lineare Interpolation zwischen den zwei nächsten Rängen")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"percentile_nearest_rank(values, length, percentage)")),Object(l.b)("td",{parentName:"tr",align:null},"Perzentil, Nearest-Rank-Methode")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"percentrank(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"% der vorherigen ",Object(l.b)("inlineCode",{parentName:"td"},"length")," Werte, die kleiner oder gleich dem aktuellen sind")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"correlation(series1, series2, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Korrelationskoeffizient")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"crossover(series1, series2)")),Object(l.b)("td",{parentName:"tr",align:null},"Kreuzung nach oben (jedes Argument kann eine Zahl sein: ",Object(l.b)("inlineCode",{parentName:"td"},"ta.crossover(rsi, 70)"),")")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"crossunder(series1, series2)")),Object(l.b)("td",{parentName:"tr",align:null},"Kreuzung nach unten")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"cross(series1, series2)")),Object(l.b)("td",{parentName:"tr",align:null},"Beliebige Kreuzung")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"barssince(condition)")),Object(l.b)("td",{parentName:"tr",align:null},"Bars seit ",Object(l.b)("inlineCode",{parentName:"td"},"condition")," (Array von Booleans) zuletzt true war")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"valuewhen(condition, values, occurrence = 0)")),Object(l.b)("td",{parentName:"tr",align:null},"Wert von ",Object(l.b)("inlineCode",{parentName:"td"},"values"),", als ",Object(l.b)("inlineCode",{parentName:"td"},"condition")," vor ",Object(l.b)("inlineCode",{parentName:"td"},"occurrence")," Vorkommen true war")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"pivothigh(values, leftbars, rightbars)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"pivotlow(...)")),Object(l.b)("td",{parentName:"tr",align:null},"Pivot-Wert auf dem bestätigenden Bar, der Pivot selbst liegt ",Object(l.b)("inlineCode",{parentName:"td"},"rightbars")," Bars früher")))),Object(l.b)("h3",{id:"gleitende-durchschnitte"},"Gleitende Durchschnitte"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"sma(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Einfacher gleitender Durchschnitt")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"ema(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Exponentieller gleitender Durchschnitt")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"rma(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Wilders gleitender Durchschnitt (für RSI / ATR)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"wma(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Gewichteter gleitender Durchschnitt")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"hma(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Hull Moving Average")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"alma(values, length, offset = 0.85, sigma = 6, floor = false)")),Object(l.b)("td",{parentName:"tr",align:null},"Arnaud Legoux Moving Average")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"swma(values)")),Object(l.b)("td",{parentName:"tr",align:null},"Symmetrisch gewichteter gleitender Durchschnitt über 4 Bars")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"vwma(values, volumes, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Volumengewichteter gleitender Durchschnitt")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"linreg(values, length, offset = 0)")),Object(l.b)("td",{parentName:"tr",align:null},"Lineare Regressionskurve")))),Object(l.b)("h3",{id:"oszillatoren"},"Oszillatoren"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"rsi(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Relative Strength Index")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"cmo(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Chande Momentum Oscillator")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"cog(values, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Center of Gravity")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"mfi(values, volumes, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Money Flow Index (",Object(l.b)("inlineCode",{parentName:"td"},"values")," meist hlc3)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tsi(values, shortLength, longLength)")),Object(l.b)("td",{parentName:"tr",align:null},"True Strength Index, -1..1")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"wpr(highs, lows, closes, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Williams %R")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"stoch(highs, lows, closes, period = 14, smoothK = 3, smoothD = 3)")),Object(l.b)("td",{parentName:"tr",align:null},"Stochastik ",Object(l.b)("inlineCode",{parentName:"td"},"[k, d]"),", ",Object(l.b)("inlineCode",{parentName:"td"},"smoothK = 1")," liefert den Rohwert")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"cci(values, length)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"cci(highs, lows, closes, length)")),Object(l.b)("td",{parentName:"tr",align:null},"Commodity Channel Index (in der zweiten Form vom typischen Preis)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"macd(values, fast = 12, slow = 26, signalPeriod = 9)")),Object(l.b)("td",{parentName:"tr",align:null},"MACD ",Object(l.b)("inlineCode",{parentName:"td"},"[macd, signal, histogram]"))))),Object(l.b)("h3",{id:"bänder-und-kanäle"},"Bänder und Kanäle"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"bb(values, length = 20, mult = 2)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"bollinger(...)")),Object(l.b)("td",{parentName:"tr",align:null},"Bollinger-Bänder ",Object(l.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"bbw(values, length, mult)")),Object(l.b)("td",{parentName:"tr",align:null},"Breite der Bollinger-Bänder ",Object(l.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"kc(values, highs, lows, closes, length = 20, mult = 2, useTrueRange = true)")),Object(l.b)("td",{parentName:"tr",align:null},"Keltner-Kanäle ",Object(l.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"kcw(values, highs, lows, closes, length, mult, useTrueRange)")),Object(l.b)("td",{parentName:"tr",align:null},"Breite der Keltner-Kanäle ",Object(l.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))))),Object(l.b)("h3",{id:"trend-und-volatilität"},"Trend und Volatilität"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"tr(highs, lows, closes, handleNa = false)")),Object(l.b)("td",{parentName:"tr",align:null},"True Range (",Object(l.b)("inlineCode",{parentName:"td"},"handleNa = true")," liefert ",Object(l.b)("inlineCode",{parentName:"td"},"high - low")," auf dem ersten Bar)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"atr(highs, lows, closes, period = 14)")),Object(l.b)("td",{parentName:"tr",align:null},"Average True Range")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"dmi(highs, lows, closes, diLength = 14, adxSmoothing = 14)")),Object(l.b)("td",{parentName:"tr",align:null},"Directional Movement ",Object(l.b)("inlineCode",{parentName:"td"},"[plus, minus, adx]"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"adx(highs, lows, closes, period = 14)")),Object(l.b)("td",{parentName:"tr",align:null},"Average Directional Index")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"sar(highs, lows, closes, start = 0.02, inc = 0.02, max = 0.2)")),Object(l.b)("td",{parentName:"tr",align:null},"Parabolic SAR")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"supertrend(highs, lows, closes, factor = 3, atrPeriod = 10)")),Object(l.b)("td",{parentName:"tr",align:null},"Supertrend ",Object(l.b)("inlineCode",{parentName:"td"},"[supertrend, direction]"),", direction ",Object(l.b)("inlineCode",{parentName:"td"},"-1")," = Aufwärtstrend, ",Object(l.b)("inlineCode",{parentName:"td"},"1")," = Abwärtstrend")))),Object(l.b)("h3",{id:"volumen"},"Volumen"),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"vwap(values, volumes, anchor?)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"vwap(highs, lows, closes, volumes, anchor?)")),Object(l.b)("td",{parentName:"tr",align:null},"Kumulativer VWAP (in der zweiten Form vom typischen Preis), startet neu auf Bars, auf denen ",Object(l.b)("inlineCode",{parentName:"td"},"anchor")," (Array von Booleans) true ist")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"obv(closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"On Balance Volume")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"accdist(highs, lows, closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"Accumulation / Distribution")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"iii(highs, lows, closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"Intraday Intensity Index")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"pvt(closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"Price-Volume Trend")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"nvi(closes, volumes)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"pvi(closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"Negative / Positive Volume Index")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"wad(highs, lows, closes)")),Object(l.b)("td",{parentName:"tr",align:null},"Williams Accumulation / Distribution")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"wvad(opens, highs, lows, closes, volumes)")),Object(l.b)("td",{parentName:"tr",align:null},"Williams Variable Accumulation / Distribution")))),Object(l.b)("h3",{id:"orderbuch-hilfsfunktionen"},"Orderbuch-Hilfsfunktionen"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"orderbook")," ist ",Object(l.b)("inlineCode",{parentName:"p"},"source.orderbook()")," oder ",Object(l.b)("inlineCode",{parentName:"p"},"source.depths()[i].data"),": ",Object(l.b)("inlineCode",{parentName:"p"},"{asks: {price: quantity}, bids: {price: quantity}}"),"."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"orderbookSide(orderbook, side)")),Object(l.b)("td",{parentName:"tr",align:null},"Eine Seite (",Object(l.b)("inlineCode",{parentName:"td"},"'bids'")," / ",Object(l.b)("inlineCode",{parentName:"td"},"'asks'"),") als ",Object(l.b)("inlineCode",{parentName:"td"},"[[price, quantity], ...]"),", sortiert mit dem besten Preis zuerst")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"bestBid(orderbook)")," / ",Object(l.b)("inlineCode",{parentName:"td"},"bestAsk(orderbook)")),Object(l.b)("td",{parentName:"tr",align:null},"Bester Bid- / Ask-Preis (",Object(l.b)("inlineCode",{parentName:"td"},"null")," bei leerem Buch)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"sumBids(orderbook, percent, price, inQuote)")),Object(l.b)("td",{parentName:"tr",align:null},"Kumulierte Bid-Menge zwischen ",Object(l.b)("inlineCode",{parentName:"td"},"price")," (Standard: bester Bid) und ",Object(l.b)("inlineCode",{parentName:"td"},"price * (1 - percent / 100)"),", ",Object(l.b)("inlineCode",{parentName:"td"},"inQuote = true")," summiert ",Object(l.b)("inlineCode",{parentName:"td"},"price * quantity"))),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"sumAsks(orderbook, percent, price, inQuote)")),Object(l.b)("td",{parentName:"tr",align:null},"Kumulierte Ask-Menge zwischen ",Object(l.b)("inlineCode",{parentName:"td"},"price")," (Standard: bester Ask) und ",Object(l.b)("inlineCode",{parentName:"td"},"price * (1 + percent / 100)"))))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst rsiValues = ta.rsi(closes, 14);\nplot.lineSeries("RSI", rsiValues, "#00C8FF");\n')),Object(l.b)("h2",{id:"alarme"},"Alarme"),Object(l.b)("p",null,"Nutzer können Alarme für Ihren Indikator über den Reiter ",Object(l.b)("strong",{parentName:"p"},"Alarme")," in den Indikator-Einstellungen im Chart erstellen.\nAlarme werden serverseitig regelmäßig geprüft, Benachrichtigungen werden an ",Object(l.b)("strong",{parentName:"p"},"Telegram")," und/oder eine vom Nutzer definierte ",Object(l.b)("strong",{parentName:"p"},"Webhook-URL")," gesendet."),Object(l.b)("h3",{id:"alarm-einstellungen--alertinput"},"Alarm-Einstellungen — ",Object(l.b)("inlineCode",{parentName:"h3"},"alertInput")),Object(l.b)("p",null,"Die Klasse ",Object(l.b)("strong",{parentName:"p"},Object(l.b)("inlineCode",{parentName:"strong"},"alertInput"))," deklariert Alarm-Einstellungen. Sie funktioniert genau wie ",Object(l.b)("inlineCode",{parentName:"p"},"input"),", aber die Felder werden im Reiter ",Object(l.b)("strong",{parentName:"p"},"Alarme")," angezeigt, und jeder Nutzer konfiguriert seine eigenen Werte für seinen Alarm."),Object(l.b)("p",null,"Skripte ohne ",Object(l.b)("inlineCode",{parentName:"p"},"alertInput"),"-Deklarationen können nicht für Alarme verwendet werden."),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(l.b)("td",{parentName:"tr",align:null},"Numerische Eingabe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(l.b)("td",{parentName:"tr",align:null},"Bereichseingabe")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(l.b)("td",{parentName:"tr",align:null},"Dropdown-Auswahl")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(l.b)("td",{parentName:"tr",align:null},"Farbauswahl")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(l.b)("td",{parentName:"tr",align:null},"Boolesche Eingabe")))),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const alertVolumeThreshold = alertInput.number("Volume threshold", 1000, 0, 10000000, 1);\n')),Object(l.b)("h3",{id:"alarme-auslösen--alertfire"},"Alarme auslösen — ",Object(l.b)("inlineCode",{parentName:"h3"},"alert.fire")),Object(l.b)("table",null,Object(l.b)("thead",{parentName:"table"},Object(l.b)("tr",{parentName:"thead"},Object(l.b)("th",{parentName:"tr",align:null},"Methode"),Object(l.b)("th",{parentName:"tr",align:null},"Beschreibung"))),Object(l.b)("tbody",{parentName:"table"},Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",{parentName:"tr",align:null},Object(l.b)("inlineCode",{parentName:"td"},"fire(title, message, date)")),Object(l.b)("td",{parentName:"tr",align:null},"Löst eine Alarm-Benachrichtigung aus")))),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Alle drei Parameter sind ",Object(l.b)("strong",{parentName:"li"},"erforderlich")," — ein Aufruf mit fehlendem ",Object(l.b)("inlineCode",{parentName:"li"},"title"),", ",Object(l.b)("inlineCode",{parentName:"li"},"message")," oder ",Object(l.b)("inlineCode",{parentName:"li"},"date")," wird übersprungen (eine Warnung wird ins Log geschrieben)."),Object(l.b)("li",{parentName:"ul"},"Halten Sie den ",Object(l.b)("strong",{parentName:"li"},"Titel des Alarms konstant"),", generieren Sie keine eindeutigen Titel. Jeder Titel löst nur einmal pro Durchlauf aus (maximal ",Object(l.b)("strong",{parentName:"li"},"20")," Titel pro Durchlauf)."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"date")," ist die ",Object(l.b)("inlineCode",{parentName:"li"},"startTime")," der Kerze, zu der das Signal gehört: Derselbe Titel benachrichtigt erst wieder, wenn er für eine ",Object(l.b)("strong",{parentName:"li"},"neuere")," Kerze auslöst. Signale von Kerzen, die älter sind als der Zeitpunkt, zu dem der Nutzer seinen Alarm erstellt hat, werden ignoriert (Anti-Spam).")),Object(l.b)("p",null,Object(l.b)("strong",{parentName:"p"},"Beispiel:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'if (candle.volume > alertVolumeThreshold) {\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n}\n')),Object(l.b)("h3",{id:"form-alarme--plotshapealert"},"Form-Alarme — ",Object(l.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(l.b)("p",null,"Alle geometrischen Formen (",Object(l.b)("inlineCode",{parentName:"p"},"box"),", ",Object(l.b)("inlineCode",{parentName:"p"},"square"),", ",Object(l.b)("inlineCode",{parentName:"p"},"diamond"),", ",Object(l.b)("inlineCode",{parentName:"p"},"triangle"),", ",Object(l.b)("inlineCode",{parentName:"p"},"circle"),", ",Object(l.b)("inlineCode",{parentName:"p"},"straightLine"),", ",Object(l.b)("inlineCode",{parentName:"p"},"horizontalLine"),", ",Object(l.b)("inlineCode",{parentName:"p"},"verticalLine"),", ",Object(l.b)("inlineCode",{parentName:"p"},"text"),") geben ein Handle mit einer Methode ",Object(l.b)("inlineCode",{parentName:"p"},".alert()")," zurück.\nDer Alarm wird automatisch mit dem ",Object(l.b)("inlineCode",{parentName:"p"},"date1")," der Form ausgelöst, sodass die Anti-Spam-Logik ohne zusätzlichen Code funktioniert — dies ist der empfohlene Weg für Signale pro Kerze."),Object(l.b)("p",null,"Zwei Formen:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'// simple: fires every time the shape is plotted for a new date\nplot.box(...).alert("High volume", `vol ${candle.volume}`);\n\n// callback: return nothing to skip, [title, message] to fire\nplot.box(...).alert((shape) => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n});\n')),Object(l.b)("p",null,"Der Callback erhält die Daten der Form (",Object(l.b)("inlineCode",{parentName:"p"},"date1"),", ",Object(l.b)("inlineCode",{parentName:"p"},"price1"),", ",Object(l.b)("inlineCode",{parentName:"p"},"date2"),", ",Object(l.b)("inlineCode",{parentName:"p"},"price2"),", ...)."),Object(l.b)("h3",{id:"reihen-alarme--plotseriesalert"},"Reihen-Alarme — ",Object(l.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(l.b)("p",null,"Datenreihen (",Object(l.b)("inlineCode",{parentName:"p"},"lineSeries"),", ",Object(l.b)("inlineCode",{parentName:"p"},"barSeries"),", ",Object(l.b)("inlineCode",{parentName:"p"},"candleSeries"),", ",Object(l.b)("inlineCode",{parentName:"p"},"areaSeries"),", ",Object(l.b)("inlineCode",{parentName:"p"},"bandSeries"),") geben ebenfalls das Handle ",Object(l.b)("inlineCode",{parentName:"p"},".alert()")," zurück.\nDer Callback erhält den ",Object(l.b)("strong",{parentName:"p"},"letzten Datenpunkt")," und das Datum der letzten Kerze; der Alarm wird mit diesem Datum ausgelöst."),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"lineSeries")," / ",Object(l.b)("inlineCode",{parentName:"li"},"barSeries")," / ",Object(l.b)("inlineCode",{parentName:"li"},"areaSeries")," — der Callback erhält den letzten ",Object(l.b)("strong",{parentName:"li"},"Wert")," (eine Zahl)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"candleSeries")," — der Callback erhält die letzte Kerze ",Object(l.b)("inlineCode",{parentName:"li"},"{open, close, high, low}")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"bandSeries")," — der Callback erhält das letzte ",Object(l.b)("inlineCode",{parentName:"li"},"{upper, lower}"))),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("RSI", rsiValues, color).alert((rsi, date) => {\n if (rsi > alertRsiThreshold) alert.fire("RSI high", `RSI ${rsi.toFixed(1)}`, latestCandle.startTime);\n});\n')),Object(l.b)("p",null,"Eine Bedingung, die wahr bleibt, benachrichtigt einmal pro ",Object(l.b)("strong",{parentName:"p"},"neuer Kerze"),". Für einmalige Signale verwenden Sie Kreuzungsbedingungen (",Object(l.b)("inlineCode",{parentName:"p"},"ta.crossover"),")."),Object(l.b)("h3",{id:"vollständiges-beispiel"},"Vollständiges Beispiel"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const title = "Volume alerts";\nconst description = "Shows boxes on high-volume candles";\ndefine(title, description, "onchart", true, true);\n\nconst color = style.color("Color", "#00C8FF");\nconst volumeThreshold = input.number("Volume threshold", 1000, 0, 10000000, 1);\nconst alertVolumeThreshold = alertInput.number("Alert volume threshold", 5000, 0, 10000000, 1);\nconst alertCloseThreshold = alertInput.number("Alert close threshold", 100000, 0, 10000000, 1);\n\nconst candles = source.ohlcv();\nconst latestCandle = candles.at(-1);\nconst closes = candles.map(c => c.close);\n\n// series alert: checks the latest close\nplot.lineSeries("Closes", closes, color).alert((close, date) => {\n if (close > alertCloseThreshold) alert.fire("Close above threshold", `close ${close}`, latestCandle.startTime);\n});\n\nfor (let i = 0; i < candles.length; i++) {\n const candle = candles[i];\n\n if (candle.volume > volumeThreshold) {\n const right = i < candles.length - 1 ? candles[i + 1].startTime : candle.startTime + 60000;\n\n // shape alert: checked against the user\'s alert threshold\n plot.box(`Volume ${i}`, candle.startTime, candle.high, right, candle.low, "#00C8FF", 0.3)\n .alert(() => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n });\n }\n}\n')),Object(l.b)("h2",{id:"beispiele-für-indikatoren"},"Beispiele für Indikatoren"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const title = "Your first indicator";\nconst description = "Shows closes lines on the chart";\nconst indicatorType = "onchart";\n\ndefine(title, description, indicatorType, true, true);\n\nconst color = input.color("Line Color", "#00C8FF");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nplot.lineSeries("Closes", closes, color);\n\n')),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'define("Example Indicator", "Demonstrates basic plotting", "onchart", true, true);\n\nconst color = input.color("Line Color", "#00FF99");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\n\nconst ema20 = ta.ema(closes, 20);\nplot.lineSeries("EMA 20", ema20, color);\n\n')),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const title = "Colored Volume Bars"; \nconst description = "Volumes colored based on candle direction."; \nconst indicatorType = "onchart"; \nconst isPublic = true; \nconst isPublicCode = true; \n\ndefine(title, description, indicatorType, isPublic, isPublicCode); \n\n// Get OHLC candles\nconst candles = source.ohlcv(); \n\nconst colorUp = style.color("Color 1", "#2BB462"); // Greenish color for rising prices\nconst colorDown = style.color("Color 2", "#FB4C51"); // Reddish color for falling prices\nconst volumes = candles.map(candle => candle.volume); \n\nplot.barSeries("Volume", volumes, (value, index) => {\n const currentCandle = candles[index]; \n return currentCandle.close >= currentCandle.open ? colorUp : colorDown; \n});\n\n')),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},"define('Coinbase Premium Index', 'Coinbase Premium Index', 'offchart', true, false);\n\nconst color1 = style.color(\"Color 1\", \"#2BB462\");\nconst color2 = style.color(\"Color 2\", \"#FB4C51\");\n\n// Get OHLC candles\nconst cbCandles = source.ohlcv('coinbase', 'BTC-USD');\nconst binanceCandles = source.ohlcv('binance', 'BTCUSDT');\n\n// Extract closes\nconst cbCloses = cbCandles.map(c => c.close);\nconst binanceCloses = binanceCandles.map(c => c.close);\n\n// --- Coinbase Premium Index calculation ---\nconst premiumPercent = cbCloses.map((cb, i) => {\n const b = binanceCloses[i];\n return ((cb - b) / b) * 100;\n});\n\n// Plot premium index\nplot.barSeries(\"Premium %\", premiumPercent, ((d) => d > 0 ? color1 : color2)) // Percentage difference\n\n")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const title = "Candles";\nconst description = "Simple candles draw";\nconst indicatorType = "offchart";\nconst isPublic = true;\nconst isPublicCode = true;\ndefine(title, description, indicatorType, isPublic, isPublicCode);\n\nconst colorBuy = style.color("Buy Color", "#2BB462");\nconst colorSell = style.color("Sell Color", "#7a3d3f");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst opens = candles.map(c => c.open);\nconst highs = candles.map(c => c.high);\nconst lows = candles.map(c => c.low);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\n\n')),Object(l.b)("p",null,'Order Book Pressure (Bänder des Bid-/Ask-Tiefen-Ungleichgewichts um den Preis, wie die "Order Book Pressure"-Overlays von Trading-Terminals):'),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-js"},'const title = "Order Book Pressure";\nconst description = "Bid / ask depth imbalance bands around the price";\ndefine(title, description, "onchart", true, true);\n\nconst minBidRatio = input.number("Min bid ratio %", 20, 0, 100, 1);\nconst minAskRatio = input.number("Min ask ratio %", 20, 0, 100, 1);\nconst depthFrom = input.select("Depth from", "0%", ["0%", "1%", "2.5%", "5%"]);\nconst depthTo = input.select("Depth to", "5%", ["1%", "2.5%", "5%", "10%"]);\n\nconst bidColor = style.color("Bid fill color", "#a5d6a7");\nconst askColor = style.color("Ask fill color", "#f1627e");\nconst extremeColor = style.color("Extreme color", "#ffff00");\nconst highlight = style.boolean("Highlight extremes", true);\nconst showRef = style.boolean("Show reference lines", true);\n\nconst alertMinRatio = alertInput.number("Alert min |ratio| %", 40, 0, 100, 1);\n\nconst bounds = [1, 2.5, 5, 10]; // depth bands in % from the close\nconst from = parseFloat(depthFrom);\nconst to = parseFloat(depthTo);\n\nconst candles = source.ohlcv();\nconst depths = source.depths();\nconst liveBook = source.orderbook();\n\n// orderbook of every candle: depths()[i] is the snapshot of candles[i] (the biggest limit orders), the latest candle uses the live book\nconst lastIndex = candles.length - 1;\nconst books = candles.map((c, i) => {\n if (!c) return null;\n if (i === lastIndex && ta.bestBid(liveBook)) return liveBook;\n return depths[i]?.data || null;\n});\nconst closes = candles.map(c => c ? c.close : null);\n\n// imbalance ratio of every band in % (positive = bids dominate, negative = asks dominate)\nconst ratios = bounds.map((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n return candles.map((c, i) => {\n const book = books[i];\n if (!c || !book) return null;\n const bid = ta.sumBids(book, upper, c.close) - ta.sumBids(book, lower, c.close);\n const ask = ta.sumAsks(book, upper, c.close) - ta.sumAsks(book, lower, c.close);\n const total = bid + ask;\n return total > 0 ? ((bid - ask) / total) * 100 : 0;\n });\n});\n\n// a stronger ratio -> a more opaque band, extreme ratios get the extreme color\nconst bandOpacity = (ratio) => Math.min(0.95, Math.abs(ratio || 0) / 70 * 0.95);\nconst bandColor = (ratio) => highlight && Math.abs(ratio || 0) >= 63 ? extremeColor : (ratio >= 0 ? bidColor : askColor);\n\nbounds.forEach((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n if (from > lower || upper > to) return; // the band is outside of the selected depth range\n\n const bidUpper = closes.map(c => c != null ? c * (1 - lower / 100) : null);\n const bidLower = closes.map(c => c != null ? c * (1 - upper / 100) : null);\n const askLower = closes.map(c => c != null ? c * (1 + lower / 100) : null);\n const askUpper = closes.map(c => c != null ? c * (1 + upper / 100) : null);\n\n if (showRef) {\n plot.lineSeries(`Bid ${upper}%`, bidLower, bidColor, 0.4);\n plot.lineSeries(`Ask ${upper}%`, askUpper, askColor, 0.4);\n }\n\n // bid pressure: the band is filled only on the candles where bids dominate by more than the min ratio\n plot.bandSeries(\n `Bid pressure ${lower}-${upper}%`,\n bidUpper.map((v, i) => ratios[b][i] >= minBidRatio ? v : null),\n bidLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // ask pressure\n plot.bandSeries(\n `Ask pressure ${lower}-${upper}%`,\n askUpper.map((v, i) => ratios[b][i] <= -minAskRatio ? v : null),\n askLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // alert on the latest candle\n const latestRatio = ratios[b][lastIndex];\n if (latestRatio != null && Math.abs(latestRatio) >= alertMinRatio) {\n alert.fire(`Pressure ${lower}-${upper}%`, `ratio ${latestRatio.toFixed(1)}%`, candles[lastIndex].startTime);\n }\n});\n\n')))}void 0!==p&&p&&p===Object(p)&&Object.isExtensible(p)&&!Object.prototype.hasOwnProperty.call(p,"__filemeta")&&Object.defineProperty(p,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/components/de/Scripting.mdx"}}),p.isMDXComponent=!0}}]); //# sourceMappingURL=component---src-components-de-scripting-mdx-78356e23d15efa21a174.js.map