// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © goodia
//@version=6
// import goodia/Mirpapa_Lib_HTF/3
// @description
// High Time Frame Handler Library:
// Provides utilities for working with High Time Frame (HTF) and chart (LTF) conversions and data retrieval.
library("Mirpapa_Lib_HTF", overlay = false)
////////////////////////////////////////////////////////////////////////////////
// ────────────────────────────────────────────────────────────────────────────
// HandlerHTF (inlined)
// @description
// High Time Frame Handler: Functions for converting and retrieving HTF values.
// ────────────────────────────────────────────────────────────────────────────
////////////////////////////////////////////////////////////////////////////////
export type HTFCache
string _timeframe
int _lastBarIndex
bool _isNewBar
int _barIndex
// 배열 기반 OHLCT 데이터 (0~3 offset)
array<float> _opens // [open, open[1], open[2], open[3]]
array<float> _highs // [high, high[1], high[2], high[3]]
array<float> _lows // [low, low[1], low[2], low[3]]
array<float> _closes // [close, close[1], close[2], close[3]]
array<int> _times // [time, time[1], time[2], time[3]]
// @function parseMinutesFromTF
// @description
// Parse a timeframe string into its equivalent number of minutes.
// @param _tf
// A timeframe string (examples: "1", "5", "15", "1D", "1W", "1M").
// @return
// Returns the integer number of minutes corresponding to the timeframe, or na if the string is not recognized.
parseMinutesFromTF(string _tf) =>
_tf == "1" ? 1 :
_tf == "3" ? 3 :
_tf == "5" ? 5 :
_tf == "15" ? 15 :
_tf == "30" ? 30 :
_tf == "60" ? 60 :
_tf == "120" ? 120 :
_tf == "240" ? 240 :
_tf == "1D" ? 1440 :
_tf == "1W" ? 10080 :
_tf == "1M" ? 43200 :
_tf == "12M" ? 525600 : na
// @function calHTFtoRatioLTF
// @description
// Calculate the ratio of a High Time Frame (HTF) to the current chart’s Lower Time Frame (LTF) in minutes.
// @param _chartTf
// The current chart’s timeframe string (examples: "5", "15", "1D").
// @param _htfTf
// The target High Time Frame string to compare against (examples: "60", "1D").
// @return
// Returns the rounded integer ratio of HTF minutes to chart minutes, or na if either conversion fails.
calHTFtoRatioLTF(string _chartTf, string _htfTf) =>
_chartMin = parseMinutesFromTF(_chartTf)
_htfMin = parseMinutesFromTF(_htfTf)
_chartMin > 0 and _htfMin > 0 ? math.round(_htfMin / _chartMin) : na
// @function IsChartTFcomparisonHTF
// @description
// Determine whether the given High Time Frame (HTF) is greater than or equal to the current chart timeframe.
// @param _chartTf
// The current chart’s timeframe string (examples: "5", "15", "1D").
// @param _htfTf
// The High Time Frame string to compare (examples: "60", "1D").
// @return
// Returns true if HTF minutes ≥ chart minutes, false otherwise or na if conversion fails.
export IsChartTFcomparisonHTF(string _chartTf, string _htfTf) =>
_chartMin = parseMinutesFromTF(_chartTf)
_htfMin = parseMinutesFromTF(_htfTf)
not na(_chartMin) and not na(_htfMin) and _htfMin >= _chartMin
// @function GetHTFrevised
// @description
// Retrieve a specific bar value from a Higher Time Frame (HTF) series.
// Supports current and historical OHLC values, based on a case identifier.
// @param _tf
// The target HTF string (examples: "60", "1D").
// @param _case
// A case string determining which OHLC value and bar offset to request:
// "b" → HTF bar_index
// "o" → HTF open
// "h" → HTF high
// "l" → HTF low
// "c" → HTF close
// "o1" → HTF open one bar ago
// "h1" → HTF high one bar ago
// "l1" → HTF low one bar ago
// "c1" → HTF close one bar ago
// … up to "o5", "h5", "l5", "c5" for five bars ago.
// @return
// Returns the requested HTF value or na if _case does not match any condition.
export GetHTFrevised(string _tf) =>
request.security(syminfo.tickerid, _tf, bar_index)
export GetHTFrevised(string _tf, string _case) =>
switch _case
"b" => request.security(syminfo.tickerid, _tf, bar_index)
"o" => request.security(syminfo.tickerid, _tf, open)
"h" => request.security(syminfo.tickerid, _tf, high)
"l" => request.security(syminfo.tickerid, _tf, low)
"c" => request.security(syminfo.tickerid, _tf, close)
"o1" => request.security(syminfo.tickerid, _tf, open[1])
"h1" => request.security(syminfo.tickerid, _tf, high[1])
"l1" => request.security(syminfo.tickerid, _tf, low[1])
"c1" => request.security(syminfo.tickerid, _tf, close[1])
"o2" => request.security(syminfo.tickerid, _tf, open[2])
"h2" => request.security(syminfo.tickerid, _tf, high[2])
"l2" => request.security(syminfo.tickerid, _tf, low[2])
"c2" => request.security(syminfo.tickerid, _tf, close[2])
"o3" => request.security(syminfo.tickerid, _tf, open[3])
"h3" => request.security(syminfo.tickerid, _tf, high[3])
"l3" => request.security(syminfo.tickerid, _tf, low[3])
"c3" => request.security(syminfo.tickerid, _tf, close[3])
"o4" => request.security(syminfo.tickerid, _tf, open[4])
"h4" => request.security(syminfo.tickerid, _tf, high[4])
"l4" => request.security(syminfo.tickerid, _tf, low[4])
"c4" => request.security(syminfo.tickerid, _tf, close[4])
"o5" => request.security(syminfo.tickerid, _tf, open[5])
"h5" => request.security(syminfo.tickerid, _tf, high[5])
"l5" => request.security(syminfo.tickerid, _tf, low[5])
"c5" => request.security(syminfo.tickerid, _tf, close[5])
=> na
// @function GetHTFfromLabel
// @description
// Convert a Korean HTF label into a Pine Script-recognizable timeframe string.
// Examples:
// "5분" → "5"
// "1시간" → "60"
// "일봉" → "1D"
// "주봉" → "1W"
// "월봉" → "1M"
// "연봉" → "12M"
// @param _label
// The Korean HTF label string (examples: "5분", "1시간", "일봉").
// @return
// Returns the Pine Script timeframe string corresponding to the label, or "1W" if no match is found.
export GetHTFfromLabel(string _label) =>
_label == "5분" ? "5" :
_label == "15분" ? "15" :
_label == "1시간" ? "60" :
_label == "4시간" ? "240" :
_label == "일봉" ? "1D" :
_label == "주봉" ? "1W" :
_label == "월봉" ? "1M" :
_label == "연봉" ? "12M" : "1W"
// @function GetHTFoffsetToLTFoffset
// @description
// Adjust an HTF bar index and offset so that it aligns with the current chart’s bar index.
// Useful for retrieving historical HTF data on an LTF chart.
// @param _offset
// The HTF bar offset (0 means current HTF bar, 1 means one bar ago, etc.).
// @param _chartTf
// The current chart’s timeframe string (examples: "5", "15", "1D").
// @param _htfTf
// The High Time Frame string to align (examples: "60", "1D").
// @return
// Returns the corresponding LTF bar index after applying HTF offset. If result is negative, returns 0.
export GetHTFoffsetToLTFoffset(int _offset, string _chartTf, string _htfTf) =>
ratio = calHTFtoRatioLTF(_chartTf, _htfTf)
_os = _chartTf == _htfTf ? _offset : _offset + 1
_result = bar_index - (ratio * _os)
_result := 0 > _result ? 0 : _result
_result
// @function UpdateHTFCache
// @description HTF 데이터 캐싱 (성능 최적화).\
// HTF의 OHLC 데이터를 배열로 캐싱하여 매 틱마다 request.security 호출 방지.\
// 새 bar 또는 bar_index 변경 시에만 업데이트, 그 외에는 기존 캐시 반환.\
// @param _cache 기존 캐시 데이터 (없으면 na)
// @param _tf 시간대 (예: "60", "1D")
// @returns HTFCache 업데이트된 캐시 데이터
export UpdateHTFCache(HTFCache _cache, string _tf) =>
_currentBarIndex = bar_index
_isNewBar = ta.change(time(_tf)) != 0
if na(_cache) or _cache._lastBarIndex != _currentBarIndex or _isNewBar
// 배열 생성 및 데이터 채우기
_opens = array.new<float>(4)
_highs = array.new<float>(4)
_lows = array.new<float>(4)
_closes = array.new<float>(4)
_times = array.new<int>(4)
// offset 0~3 데이터 개별 요청 (Pine Script 제약)
array.set(_opens, 0, GetHTFrevised(_tf, "o"))
array.set(_opens, 1, GetHTFrevised(_tf, "o1"))
array.set(_opens, 2, GetHTFrevised(_tf, "o2"))
array.set(_opens, 3, GetHTFrevised(_tf, "o3"))
array.set(_highs, 0, GetHTFrevised(_tf, "h"))
array.set(_highs, 1, GetHTFrevised(_tf, "h1"))
array.set(_highs, 2, GetHTFrevised(_tf, "h2"))
array.set(_highs, 3, GetHTFrevised(_tf, "h3"))
array.set(_lows, 0, GetHTFrevised(_tf, "l"))
array.set(_lows, 1, GetHTFrevised(_tf, "l1"))
array.set(_lows, 2, GetHTFrevised(_tf, "l2"))
array.set(_lows, 3, GetHTFrevised(_tf, "l3"))
array.set(_closes, 0, GetHTFrevised(_tf, "c"))
array.set(_closes, 1, GetHTFrevised(_tf, "c1"))
array.set(_closes, 2, GetHTFrevised(_tf, "c2"))
array.set(_closes, 3, GetHTFrevised(_tf, "c3"))
array.set(_times, 0, int(request.security(syminfo.tickerid, _tf, time)))
array.set(_times, 1, int(request.security(syminfo.tickerid, _tf, time[1])))
array.set(_times, 2, int(request.security(syminfo.tickerid, _tf, time[2])))
array.set(_times, 3, int(request.security(syminfo.tickerid, _tf, time[3])))
HTFCache.new(_tf, _currentBarIndex, _isNewBar, int(GetHTFrevised(_tf)), _opens, _highs, _lows, _closes, _times)
else
_cache
// @function GetTimeframeSettings
// @description 현재 차트 시간대에 맞는 중위/상위 시간대 자동 선택.\
// _currentTF: 현재 차트 시간대 (timeframe.period).\
// 1분~1월 차트별로 적절한 중위/상위 시간대 매핑.\
// 예: 5분 차트 → 중위 15분, 상위 60분.\
// 반환: [중위 시간대(string), 상위 시간대(string)].\
// @param _currentTF 현재 차트 시간대
// @param _midTF1m~_highTF1M 각 시간대별 중위/상위 시간대 설정
// @returns [string, string] [중위 시간대, 상위 시간대]
export GetTimeframeSettings(string _currentTF, string _midTF1m, string _highTF1m, string _midTF5m, string _highTF5m, string _midTF15m, string _highTF15m, string _midTF30m, string _highTF30m, string _midTF60m, string _highTF60m, string _midTF240m, string _highTF240m, string _midTF1D, string _highTF1D, string _midTF1W, string _highTF1W, string _midTF1M, string _highTF1M) =>
_midTimeframe = switch _currentTF
'1' => _midTF1m
'5' => _midTF5m
'15' => _midTF15m
'30' => _midTF30m
'60' => _midTF60m
'240' => _midTF240m
'1D' => _midTF1D
'1W' => _midTF1W
'1M' => _midTF1M
=> '240'
_highTimeframe = switch _currentTF
'1' => _highTF1m
'5' => _highTF5m
'15' => _highTF15m
'30' => _highTF30m
'60' => _highTF60m
'240' => _highTF240m
'1D' => _highTF1D
'1W' => _highTF1W
'1M' => _highTF1M
=> '1D'
[_midTimeframe, _highTimeframe]
// @function GetCachedData
// @description 캐시된 HTF 데이터에서 특정 offset의 OHLCT 값 조회.\
// 배열 기반 캐시에서 안전하게 데이터 추출.\
// @param _cache HTF 캐시 데이터
// @param _offset 조회할 offset (0~3)
// @param _type 데이터 타입 ("o", "h", "l", "c", "t")
// @returns float|int 요청된 데이터 값 (없으면 na)
export GetCachedData(HTFCache _cache, int _offset, string _type) =>
if na(_cache) or _offset < 0 or _offset > 3
na
else
switch _type
"o" => array.get(_cache._opens, _offset)
"h" => array.get(_cache._highs, _offset)
"l" => array.get(_cache._lows, _offset)
"c" => array.get(_cache._closes, _offset)
"t" => int(array.get(_cache._times, _offset))
=> na
// @function GetBoxDataFromCache
// @description 캐시된 HTF 데이터에서 박스 생성용 좌표 추출.\
// offset에 따른 시간과 가격 데이터를 한번에 반환.\
// @param _cache HTF 캐시 데이터
// @param _offset 조회할 offset (0~3)
// @returns [int, int, float, float] [leftTime, rightTime, high, low]
export GetBoxDataFromCache(HTFCache _cache, int _offset) =>
if na(_cache) or _offset < 0 or _offset > 3
[na, na, na, na]
else
_leftTime = array.get(_cache._times, _offset)
_rightTime = array.get(_cache._times, 0) // 현재 시간
_high = array.get(_cache._highs, _offset)
_low = array.get(_cache._lows, _offset)
[_leftTime, _rightTime, _high, _low]
Show all 293 lines