OPEN-SOURCE SCRIPT

HTF Candle Countdown Timer

152
//version=5
indicator("HTF Candle Countdown Timer", overlay=true)

// ============================================================================
// INPUTS - SETTINGS MENU
// ============================================================================

// --- Mode Selection ---
mode = input.string(title="Mode", defval="Auto", options=["Auto", "Custom"],
tooltip="Auto: Αυτόματη αντιστοίχιση timeframes\nCustom: Επιλέξτε το δικό σας timeframe")

// --- Custom Timeframe Selection ---
customTF = input.timeframe(title="Custom Timeframe", defval="15",
tooltip="Ενεργό μόνο σε Custom Mode")

// --- Table Position ---
tablePos = input.string(title="Table Position", defval="Bottom Right",
options=["Top Left", "Top Right", "Bottom Left", "Bottom Right"])

// --- Colors ---
textColor = input.color(title="Text Color", defval=color.white)
bgColor = input.color(title="Background Color", defval=color.black)
transparentBg = input.bool(title="Transparent Background", defval=false,
tooltip="Ενεργοποίηση διάφανου φόντου")

// --- Text Size ---
textSize = input.string(title="Text Size", defval="Normal",
options=["Auto", "Tiny", "Small", "Normal", "Large", "Huge"])

// ============================================================================
// FUNCTIONS
// ============================================================================

// Μετατροπή string position σε table position constant
getTablePosition(pos) =>
switch pos
"Top Left" => position.top_left
"Top Right" => position.top_right
"Bottom Left" => position.bottom_left
"Bottom Right" => position.bottom_right
=> position.bottom_right

// Μετατροπή string size σε size constant
getTextSize(size) =>
switch size
"Auto" => size.auto
"Tiny" => size.tiny
"Small" => size.small
"Normal" => size.normal
"Large" => size.large
"Huge" => size.huge
=> size.normal

// Αυτόματη αντιστοίχιση timeframes
getAutoTimeframe() =>
currentTF = timeframe.period
string targetTF = ""

if currentTF == "1"
targetTF := "15"
else if currentTF == "3"
targetTF := "30"
else if currentTF == "5"
targetTF := "60"
else if currentTF == "15"
targetTF := "240"
else if currentTF == "60"
targetTF := "D"
else if currentTF == "240"
targetTF := "W"
else
// Default fallback για μη-mapped timeframes
targetTF := "60"

targetTF

// Μετατροπή timeframe string σε λεπτά για σύγκριση
timeframeToMinutes(tf) =>
float minutes = 0.0

if str.contains(tf, "D")
multiplier = str.tonumber(str.replace(tf, "D", ""))
minutes := na(multiplier) ? 1440.0 : multiplier * 1440.0
else if str.contains(tf, "W")
multiplier = str.tonumber(str.replace(tf, "W", ""))
minutes := na(multiplier) ? 10080.0 : multiplier * 10080.0
else if str.contains(tf, "M")
multiplier = str.tonumber(str.replace(tf, "M", ""))
minutes := na(multiplier) ? 43200.0 : multiplier * 43200.0
else
minutes := str.tonumber(tf)

minutes

// Format countdown σε ώρες:λεπτά:δευτερόλεπτα ή λεπτά:δευτερόλεπτα
formatCountdown(milliseconds) =>
totalSeconds = math.floor(milliseconds / 1000)
hours = math.floor(totalSeconds / 3600)
minutes = math.floor((totalSeconds % 3600) / 60)
seconds = totalSeconds % 60

string result = ""

if hours > 0
result := str.format("{0,number,00}:{1,number,00}:{2,number,00}", hours, minutes, seconds)
else
result := str.format("{0,number,00}:{1,number,00}", minutes, seconds)

result

// Μετατροπή timeframe σε readable format
formatTimeframe(tf) =>
string formatted = ""

if str.contains(tf, "D")
formatted := tf + "aily"
else if str.contains(tf, "W")
formatted := tf + "eekly"
else if str.contains(tf, "M")
formatted := tf + "onthly"
else if tf == "60"
formatted := "1H"
else if tf == "240"
formatted := "4H"
else
formatted := tf + "min"

formatted

// ============================================================================
// MAIN LOGIC
// ============================================================================

// Επιλογή target timeframe βάσει mode
targetTimeframe = mode == "Auto" ? getAutoTimeframe() : customTF

// Validation: Έλεγχος αν το target timeframe είναι μεγαλύτερο από το τρέχον
currentTFMinutes = timeframeToMinutes(timeframe.period)
targetTFMinutes = timeframeToMinutes(targetTimeframe)

var string warningMessage = ""

if targetTFMinutes <= currentTFMinutes
warningMessage := "⚠ HTF < Current TF"
else
warningMessage := ""

// Υπολογισμός του χρόνου κλεισίματος του HTF candle
htfTime = request.security(syminfo.tickerid, targetTimeframe, time)
htfTimeClose = request.security(syminfo.tickerid, targetTimeframe, time_close)

// Υπολογισμός υπολειπόμενου χρόνου σε milliseconds
remainingTime = htfTimeClose - timenow

// Format countdown
countdown = warningMessage != "" ? warningMessage : formatCountdown(remainingTime)

// Format timeframe για εμφάνιση
displayTF = formatTimeframe(targetTimeframe)

// ============================================================================
// TABLE DISPLAY
// ============================================================================

// Δημιουργία table
var table countdownTable = table.new(
position=getTablePosition(tablePos),
columns=2,
rows=2,
bgcolor=transparentBg ? color.new(bgColor, 100) : bgColor,
frame_width=1,
frame_color=color.gray,
border_width=1)

// Update table content
if barstate.islast
// Header
table.cell(countdownTable, 0, 0, "Timeframe:",
text_color=textColor,
bgcolor=transparentBg ? color.new(bgColor, 100) : bgColor,
text_size=getTextSize(textSize))

table.cell(countdownTable, 1, 0, displayTF,
text_color=textColor,
bgcolor=transparentBg ? color.new(bgColor, 100) : bgColor,
text_size=getTextSize(textSize))

// Countdown
table.cell(countdownTable, 0, 1, "Countdown:",
text_color=textColor,
bgcolor=transparentBg ? color.new(bgColor, 100) : bgColor,
text_size=getTextSize(textSize))

table.cell(countdownTable, 1, 1, countdown,
text_color=warningMessage != "" ? color.orange : textColor,
bgcolor=transparentBg ? color.new(bgColor, 100) : bgColor,
text_size=getTextSize(textSize))

// ============================================================================
// END OF SCRIPT
// ============================================================================

Exención de responsabilidad

La información y las publicaciones que ofrecemos, no implican ni constituyen un asesoramiento financiero, ni de inversión, trading o cualquier otro tipo de consejo o recomendación emitida o respaldada por TradingView. Puede obtener información adicional en las Condiciones de uso.