Test 2

indicator_template.pine

//@version=6
indicator("euroPRO Express • TV-Port (v6++) — FIP Layout • Card UI • Config FIBs • License", overlay=true, max_bars_back=5000)

// =================== Inputs / Card Controls ===================
session_day   = input.session("0700-2200", "Tag-Session")
session_night = input.session("2200-0700", "Nacht-Session (ĂĽber Mitternacht)")
tz            = input.string("Europe/Berlin", "Zeitzone")

// Zielbereiche (Nacht/Vortag) & Filter
ui_scope      = input.string("V", "Zielbereiche", options=["N","V"], tooltip="N = Nacht (22–07), V = Vortag (07–22).")
ui_showFilter = input.bool(true,  "Filter (MA/Fill anzeigen)", tooltip="Ein-/Ausblenden der Filterdarstellung (MA1–MA5 & Fill).")

// Filter-Längen
len_ma1 = input.int(34, "MA1 (WMA) Trend", minval=1)
len_ma2 = input.int(5 , "MA2 (WMA)",      minval=1)
len_ma3 = input.int(34, "MA3 (WMA)",      minval=1)
len_ma5 = input.int(8 , "MA5 (SMA(MA2-MA3))", minval=1)

// FIP Einstellungen
show_live_today = input.bool(true, "Heutige Session-Range (HL) anzeigen")
anchor_mode = input.string("PrevClose", "FIP Anker",
     options = ["PrevClose", "PrevMid(H/L)", "TodayOpen", "PrevLow", "PrevHigh"],
     tooltip = "Referenz, um die FIP-Level zu spiegeln.")

// =================== Konfigurierbare FIBO-Level ===================
fibs_pos_input = input.string("0,23.6,38.2,50,61.8,76.4,100,141.4,161.8,261.8,423.6", "FIBO Levels (oberhalb, +)", tooltip="Kommagetrennte Liste. 23.6 = 0.236, 423.6 = 4.236 usw.")
fibs_neg_input = input.string("-41.4,-61.8,-161.8,-323.6", "FIBO Levels (unterhalb, -)", tooltip="Kommagetrennte Liste. -61.8 = -0.618 usw.")



// Parser
f_parse_fibs(strlist, bool percentMode) =>
    string s = str.replace_all(strlist, " ", "")
    s := str.replace_all(s, ";", ",")
    s := str.replace_all(s, ",", ",")
    string[] parts = str.split(s, ",")
    float[] out = array.new_float()
    for i = 0 to array.size(parts) - 1
        string tok = array.get(parts, i)
        tok := str.replace_all(tok, ",", ".")
        float v = str.tonumber(tok)
        if not na(v)
            if percentMode
                v := v / 100.0
            array.push(out, v)
    out

float[] fib_pos = f_parse_fibs(fibs_pos_input, fibs_percent_mode)
float[] fib_neg = f_parse_fibs(fibs_neg_input, fibs_percent_mode)

// =================== Lightweight License (client-side) ===================
// Pine hat keine HTTP-Requests → für harte Paywall Invite-Only verwenden.
license_customer_id  = input.string("", "Lizenz-ID (nur Ziffern)")
license_key          = input.string("", "LizenzschlĂĽssel (letzte 6 Ziffern = PrĂĽfsumme)")
license_expires_ymd  = input.int(20991231, "Lizenz gĂĽltig bis (YYYYMMDD)")

const_saltA = 137
const_saltB = 9973
const_saltC = 7919
const_mod   = 1000000.0  // 6-stellige PrĂĽfsumme

f_digits_only(s) =>
    string out = ""
    int L = str.length(s)
    for i = 0 to L - 1
        string ch = str.substring(s, i, i + 1)
        float d = str.tonumber(ch)
        if not na(d)
            out += ch
    out

f_hash_digits(s) =>
    float h = 0.0
    string ds = f_digits_only(s)
    int L = str.length(ds)
    for i = 0 to L - 1
        float d = str.tonumber(str.substring(ds, i, i + 1))
        h := math.fmod(h * const_saltA + d * (i + const_saltB) + const_saltC, 1e12)
    h

f_expected_check(idStr, expiryYmd) =>
    float h1 = f_hash_digits(idStr)
    float h2 = f_hash_digits(str.tostring(expiryYmd))
    int chk  = int(math.round(math.fmod(h1 * 97.0 + h2 * 193.0 + const_saltA * const_saltB + const_saltC, const_mod)))
    chk

f_key_last6(keyStr) =>
    string k = f_digits_only(keyStr)
    int Lk = str.length(k)
    int start = math.max(Lk - 6, 0)
    string tail = str.substring(k, start, Lk)
    int val = int(str.tonumber(tail))
    val

// AblaufprĂĽfung (Berlin-Zeit)
t_bln_license = request.security(syminfo.tickerid, "1", time("1", "0000-2359", tz), barmerge.gaps_off, barmerge.lookahead_off)
int today_ymd = year(t_bln_license) * 10000 + month(t_bln_license) * 100 + dayofmonth(t_bln_license)
bool not_expired = today_ymd <= license_expires_ymd

int expected = f_expected_check(license_customer_id, license_expires_ymd)
int provided = f_key_last6(license_key)
bool license_ok = (not_expired and expected == provided)

// Hinweis-Overlay bei fehlender Lizenz
var label licWarn = na
if barstate.islast
    if not license_ok
        if na(licWarn)
            licWarn := label.new(bar_index, close, xloc=xloc.bar_index, yloc=yloc.price,
                                 text="Lizenz ungĂĽltig oder abgelaufen.\nBitte gĂĽltige Daten eingeben.",
                                 style=label.style_label_center, color=color.new(color.red, 0), textcolor=color.white, size=size.large)
        else
            label.set_x(licWarn, bar_index),
            label.set_text(licWarn, "Lizenz ungĂĽltig oder abgelaufen.\nBitte gĂĽltige Daten eingeben.")
    else
        if not na(licWarn)
            label.delete(licWarn), licWarn := na

// =================== Session-Engine (M1 backbone) ===================
tfSess = "1"
in_day_m1     = request.security(syminfo.tickerid, tfSess, not na(time(timeframe.period, session_day,   tz)), barmerge.gaps_off, barmerge.lookahead_off)
in_night_m1   = request.security(syminfo.tickerid, tfSess, not na(time(timeframe.period, session_night, tz)), barmerge.gaps_off, barmerge.lookahead_off)
day_start_m1  = in_day_m1 and not in_day_m1[1]
day_end_m1    = not in_day_m1 and in_day_m1[1]
night_start_m1= in_night_m1 and not in_night_m1[1]

// M1 Basiserien global
close_m1 = request.security(syminfo.tickerid, tfSess, close, barmerge.gaps_off, barmerge.lookahead_off)
open_m1  = request.security(syminfo.tickerid, tfSess, open,  barmerge.gaps_off, barmerge.lookahead_off)
high_m1  = request.security(syminfo.tickerid, tfSess, high,  barmerge.gaps_off, barmerge.lookahead_off)
low_m1   = request.security(syminfo.tickerid, tfSess, low,   barmerge.gaps_off, barmerge.lookahead_off)

// =================== Range-Tracking ===================
var float day_hi_m1        = na
var float day_lo_m1        = na
var float prev_day_hi      = na
var float prev_day_lo      = na
var float prev_day_close   = na
var float prev_day_range   = na
var float today_open_m1    = na

if day_start_m1
    prev_day_hi    := day_hi_m1
    prev_day_lo    := day_lo_m1
    today_open_m1  := open_m1
    day_hi_m1      := high_m1
    day_lo_m1      := low_m1
else if in_day_m1
    day_hi_m1 := na(day_hi_m1) ? high_m1 : math.max(day_hi_m1, high_m1)
    day_lo_m1 := na(day_lo_m1) ? low_m1  : math.min(day_lo_m1, low_m1)

if day_end_m1
    prev_day_close := close_m1[1]
    prev_day_range := (not na(day_hi_m1) and not na(day_lo_m1)) ? (day_hi_m1 - day_lo_m1) : prev_day_range

// Nacht (22–07)
var float night_hi_m1      = na
var float night_lo_m1      = na
var float prev_night_range = na

if night_start_m1
    prev_night_range := (not na(night_hi_m1) and not na(night_lo_m1)) ? (night_hi_m1 - night_lo_m1) : prev_night_range
    night_hi_m1 := high_m1
    night_lo_m1 := low_m1
else if in_night_m1
    night_hi_m1 := na(night_hi_m1) ? high_m1 : math.max(night_hi_m1, high_m1)
    night_lo_m1 := na(night_lo_m1) ? low_m1  : math.min(night_lo_m1, low_m1)

if day_start_m1 and na(prev_night_range) and not na(night_hi_m1) and not na(night_lo_m1)
    prev_night_range := night_hi_m1 - night_lo_m1

// =================== Filter (Chart-TF) ===================
ma1 = ta.wma(close, len_ma1)
ma2 = ta.wma(close, len_ma2)
ma3 = ta.wma(close, len_ma3)
ma4 = ma2 - ma3
ma5 = ta.sma(ma4, len_ma5)
bull = close >= ma1 and ma4 >= ma5
bear = close <  ma1 and ma4 <  ma5

showFilter = ui_showFilter and license_ok

p_ma2 = plot(showFilter ? ma2 : na, display=display.none)
p_ma3 = plot(showFilter ? ma3 : na, display=display.none)
fillColor = showFilter ? (bear ? color.new(color.red, 60) : color.new(color.blue, 50)) : na
fill(p_ma2, p_ma3, color=fillColor)
bgCol = showFilter ? (bear ? color.new(color.red, 88) : bull ? color.new(color.blue, 88) : na) : na
bgcolor(bgCol)
plot(showFilter ? ma1 : na, "MA1 Trend", color=bull ? color.new(color.blue, 50) : color.new(color.red, 0), linewidth=2)

float today_hi_series = (show_live_today and in_day_m1 and license_ok) ? day_hi_m1 : na
float today_lo_series = (show_live_today and in_day_m1 and license_ok) ? day_lo_m1 : na
plot(today_hi_series, "Heute High", color=color.new(color.blue, 50), style=plot.style_linebr)
plot(today_lo_series, "Heute Low",  color=color.new(color.red,   40), style=plot.style_linebr)

// =================== Zeitfenster (07:00–22:00) ===================
t_bln_day = request.security(syminfo.tickerid, tfSess, time("1", "0000-2359", tz), barmerge.gaps_off, barmerge.lookahead_off)
year_bln  = year(t_bln_day)
month_bln = month(t_bln_day)
day_bln   = dayofmonth(t_bln_day)
tsStart   = timestamp(tz, year_bln, month_bln, day_bln, 7,  0)
tsEnd     = timestamp(tz, year_bln, month_bln, day_bln, 22, 0)

// =================== Draw-Logic & Zielbereiche (N/V) ===================
var bool did_draw_today = false
if day_start_m1
    did_draw_today := false
    prev_day_hi := day_hi_m1
    prev_day_lo := day_lo_m1

should_draw_now = license_ok and (day_start_m1 or (in_day_m1 and not did_draw_today))

var line[]  proj_lines = array.new_line()
f_clear_all() =>
    while array.size(proj_lines) > 0
        line.delete(array.pop(proj_lines))

if should_draw_now
    f_clear_all()

    range_selected = ui_scope == "N" ? prev_night_range : prev_day_range
    float anchor = switch anchor_mode
        "PrevClose"     => prev_day_close
        "PrevMid(H/L)"  => (not na(prev_day_hi) and not na(prev_day_lo)) ? (prev_day_hi + prev_day_lo) / 2.0 : na
        "TodayOpen"     => today_open_m1
        "PrevLow"       => prev_day_lo
        "PrevHigh"      => prev_day_hi
        => na

    bool ok = not na(anchor) and not na(range_selected) and range_selected > 0

    if ok
        color colBlue = color.new(color.blue, 0)
        color colOrca = color.new(color.black, 0)
        int   wThin   = 1
        int   wOrca   = 2

        // Positive Levels (inkl. 0/100)
        for i = 0 to array.size(fib_pos) - 1
            float mul = array.get(fib_pos, i)
            float level = anchor + mul * range_selected
            bool isOrca = (mul == 0.0) or (math.abs(mul - 1.0) < 0.000001)
            color col = isOrca ? colOrca : colBlue
            int   w   = isOrca ? wOrca : wThin
            array.push(proj_lines, line.new(tsStart, level, tsEnd, level, xloc=xloc.bar_time, extend=extend.none, color=col, width=w))

        // Negative Levels (unterhalb)
        for i = 0 to array.size(fib_neg) - 1
            float mulN = array.get(fib_neg, i)
            float levelN = anchor + mulN * range_selected
            array.push(proj_lines, line.new(tsStart, levelN, tsEnd, levelN, xloc=xloc.bar_time, extend=extend.none, color=colBlue, width=wThin))

        did_draw_today := true

// =================== Minimal Card-UI (Statusanzeige) ===================
var table card = table.new(position.top_right, 6, 2, border_width=1)
f_cell(c, r, txt, bgcol, txtcol) =>
    table.cell(card, c, r, txt, text_color=txtcol, bgcolor=bgcol, text_halign=text.align_center, text_valign=text.align_center)

if barstate.islast
    color colLic = license_ok ? color.new(color.green, 60) : color.new(color.red, 20)
    f_cell(0, 0, "euroPRO",        color.new(color.blue, 80), color.white)
    f_cell(1, 0, "Lizenz",         color.new(color.gray, 85), color.white)
    f_cell(3, 0, "Zielbereiche",   color.new(color.gray, 85), color.white)
    f_cell(5, 0, "Filter",         color.new(color.gray, 85), color.white)

    f_cell(1, 1, license_ok ? "OK" : "NEIN", colLic, color.white)

    color colN = ui_scope == "N" ? color.new(color.blue, 60) : color.new(color.gray, 90)
    color colV = ui_scope == "V" ? color.new(color.blue, 60) : color.new(color.gray, 90)
    f_cell(3, 1, "N", colN, color.white)
    f_cell(4, 1, "V", colV, color.white)

    color colFilt = ui_showFilter ? color.new(color.blue, 60) : color.new(color.gray, 90)
    f_cell(5, 1, "Filter", colFilt, color.white)

{{LICENSE_KEY}}