목차
Qualifiers
Introduction
- Qualifiers를 이해해야 하는 이유는 qualifier가 맞지 않을 경우 오류가 발생할 수 있기 때문입니다.
- 오류 발생 예시
-
//@version=5 indicator("내 스크립트") series int l = 14 plot(ta.ema(close,l))
- 오류 발생
- Cannot call 'ta.ema' with argument 'length'='l'. An argument of 'series int' type was used but a 'simple int' is expected.
-
- 오류 발생 이유
- ta.ema의 경우 source에는 series qualifier/ length에는 simple qualifier가 지정되어야 합니다.
- 하지만 위의 예시에서는 l이 series로 지정이 되어 있어 발생하는 문제입니다.
- series를 simple로 작성하게 되면 문제없이 코드가 작동하게 됩니다.
- 따라서 qualifier를 이해하는 것은 오류를 파악하기 위해 중요하다고 할 수 있습니다. 특히 library의 경우 export를 할 때 입력인자에 대한 정확한 qualifier를 정의해 줘야 오류가 발생하지 않습니다.
- 오류 발생 예시
- qualifier 정의
- qualifier를 통해 스크립트 실행 시 값에 접근할 수 있을 때를 식별합니다.
- "const"로 설정된 값들은 컴파일 시점에 생성됩니다.
- "input"로 설정된 값들은 입력 시(즉, 스크립트의 "설정/입력" 탭에서 값을 변경할 때)에 사용할 수 있습니다.
- "simple"로 설정된 값들은 첫 번째 막대(스크립트 실행의 첫번째 막대)에서 생성됩니다.
- "series"로 설정된 값들은 스크립트 실행 전반에 걸쳐 변경될 수 있습니다.
- qualifier를 통해 스크립트 실행 시 값에 접근할 수 있을 때를 식별합니다.
- qualifier 특징
- 변수 선언에서 qualifier가 선언되지 않았다면 컴파일러는 보통 변수에 할당된 값에 기반하여 자동으로 qualifier을 추론할 수 있습니다.
- 예를 들어 , 변수가 각 막대마다 변경되는 값을 할당받으면, 컴파일러는 이를 series 타입으로 간주합니다.
- 기본적으로 가능한 가장 약한 qualifier로 할당하다가 더 강한 qualifier를 만나면 강한 qualfier로 변경되는 형태로 진행됩니다. (이는 qualifier가 선언되지 않았을 때를 말하는 것입니다. qualifier가 선언된 경우라면 현재 변수보다 강한 qualifier 변수를 지정할 수는 없습니다.)
- 참고 : qualfier가 선언되지 않은 경우
-
더보기
- 아래 예시에서는 모두 우선적으로 가능한 값들 중에서 가장 약한 qualfier인 const가 먼저 지정됩니다.
-
//@version=5 // The following global variables are all of the "const string" qualified type: //@variable The title of the indicator. INDICATOR_TITLE = "const demo" //@variable The title of the first plot. var PLOT1_TITLE = "High" //@variable The title of the second plot. const string PLOT2_TITLE = "Low" //@variable The title of the third plot. PLOT3_TITLE = "Midpoint between " + PLOT1_TITLE + " and " + PLOT2_TITLE indicator(INDICATOR_TITLE, overlay = true) plot(high, PLOT1_TITLE) plot(low, PLOT2_TITLE) plot(hl2, PLOT3_TITLE)
- PLOT3_TITLE의 경우 const 끼리 연산되기 때문에 또한 const가 되게 됩니다. (만약 연산되는 값들 중에 하나라도 const보다 강한 qualifier가 있다면 해당 qualifier로 변수의 qualifier가 변경되게 됩니다.)
-
- 만약 연산되는 값들 중에 더 강한 qualfier가 있다면 해당 qualifier로 변하게 됩니다.
-
//@version=5 indicator("qualifier") a = -1 // const b= bar_index // series a:=a+b // series plot(a)
-
- 아래 예시에서는 모두 우선적으로 가능한 값들 중에서 가장 약한 qualfier인 const가 먼저 지정됩니다.
-
- 참고 : qualfier가 선언된 경우
-
더보기
- 아래 예시를 보면 simple로 지정한 변수에 series로 지정한 변수를 지정하면 오류가 발생합니다. 이는 simple보다 series가 더 강한 qualifier이기 때문에 simple로 선언된 변수인 a로 더 강한 qualifier인 series로 지정된 b가 할당될 수 없습니다.
-
//@version=5 indicator("qualifier") simple float a = -1 series float b = 1 a:=b
- 오류발생
-
- 하지만 반대로 series로 지정한 변수에 simple로 지정한 값을 할당해 주면 오류가 발생하지 않습니다.
-
//@version=5 indicator("qualifier") simple float a = -1 series float b = 1 b:=a plot(a) plot(b)
-
- 아래 예시를 보면 simple로 지정한 변수에 series로 지정한 변수를 지정하면 오류가 발생합니다. 이는 simple보다 series가 더 강한 qualifier이기 때문에 simple로 선언된 변수인 a로 더 강한 qualifier인 series로 지정된 b가 할당될 수 없습니다.
-
- 참고 : qualfier가 선언되지 않은 경우
- 필요한 경우 변수의 qualifier를 더 강한 것으로 자동 변경할 수 있습니다. 하지만 더 낮은 qualifier로 변경할 수 없습니다.
- Type qualifier 계층은 "const" < "input" < "simple" < "series" 순서입니다.
- "const"가 가장 약하고 "series"가 가장 강합니다.
- const를 요구하는 변수나 매개변수에 input, simple, series로 선언된 변수를 전달할 수 없습니다.
- 반대로 series를 요구하는 변수나 매개변수에는 const, input, simple로 선언된 변수를 모두 전달할 수 있습니다. (자동으로 series qulifier로 변경됩니다.)
- "const" 및 "series" 값이 포함된 expression을 계산하면 qualifier 계층이 더 높은 "series" qualifier로 반환합니다.
- 어떤 변수에 대해 qualifier를 지정하지 않은 경우 어떤 내장 함수에 그 값이 입력인자로 사용될 경우, 내장 함수의 입력인자 qualifier 조건에 맞춰 알아서 변수의 qualifier가 변경됩니다. (즉, 변수에 명시적인 qualfier가 지정되지 않은 경우 컴파일러는 자동으로 가장 적합한 qualfier를 추론합니다.)
- 오류 난 위 코드에서는 l에 series라고 명시적으로 지정해 주어서 오류가 발생했습니다. 하지만 아무런 qualifier를 지정하지 않은 경우는 내장 함수의 조건에 맞춰서 입력인자가 알아서 변경되게 됩니다. (l이 ta.ema의 입력인자 조건에 맞춰서 simple로 변경되어 ta.ema(close, l) 안에 들어가게 됩니다.)
-
//@version=5 indicator("내 스크립트") l = 14 plot(ta.ema(close,l))
-
- 이러한 이유로 library에서 export 하는 함수(일종의 내장 함수를 만드는 것)에서는 입력인자에 대해 type을 반드시 지정해주어야 합니다.(위 함수처럼 qualifier를 지정하지 않더라도 자동으로 인식하도록 설정해 주기 위함입니다.) 또한 library에서는 type 지정 시 몇몇 주의할 점이 있습니다. 아래 예시들을 통해 살펴보도록 하겠습니다.
- 예시
-
더보기
- type 지정 안 한 경우
-
//@version=5 //@description A library with custom functions. library("CustomFunctions", overlay = true) //@function Calculates the length values for a ribbon of four EMAs by multiplying the `baseLength`. //@param baseLength The initial EMA length. Requires "simple int" because you can't use "series int" in `ta.ema()`. //@returns A tuple of length values. export ribbonLengths(baseLength) => length1 = baseLength length2 = baseLength * 2 [length1, length2] // Get a tuple of "simple int" length values. [len1, len2] = ribbonLengths(14) // Plot four EMAs using the values from the tuple. plot(ta.ema(close, len1), "EMA 1", color = color.red) plot(ta.ema(close, len2), "EMA 1", color = color.orange)
- 오류 발생 : All exported functions args should be typified
- library에서 exported function을 만들 때 반드시 type을 지정해야 한다는 것을 알 수 있습니다.
-
- int로 지정한 경우
-
//@version=5 //@description A library with custom functions. library("CustomFunctions", overlay = true) //@function Calculates the length values for a ribbon of four EMAs by multiplying the `baseLength`. //@param baseLength The initial EMA length. Requires "simple int" because you can't use "series int" in `ta.ema()`. //@returns A tuple of length values. export ribbonLengths(int baseLength) => length1 = baseLength length2 = baseLength * 2 [length1, length2] // Get a tuple of "simple int" length values. [len1, len2] = ribbonLengths(14) // Plot four EMAs using the values from the tuple. plot(ta.ema(close, len1), "EMA 1", color = color.red) plot(ta.ema(close, len2), "EMA 1", color = color.orange)
- 오류 발생
- Cannot call 'ta.ema' with argument 'length'='len1'. An argument of 'series int' type was used but a 'simple int' is expected.
- Cannot call 'ta.ema' with argument 'length'='len2'. An argument of 'series int' type was used but a 'simple int' is expected.
- library에서 입력인자에 int로 지정하면(type만 지정하면) series int(series 타입)로 자동인식하게 된다는 것을 알 수 있습니다.
- 참고 : libarary가 아니라면 int로 지정해도 series int로 인식하는 것이 아닌, 자동으로 함수 입력인자 qualifier에 맞춰지거나, 다른 qualifier연산에 맞춰지게 됩니다.
- 아래 코드에서 ta.ema의 l에는 simple만 들어갈 수 있는데 int l = 14로 하더라도 정상적으로 코드가 작동합니다. (따라서 library에서만 type만 지정하면 series 타입으로 지정된다는 것을 알 수 있습니다.)
-
//@version=5 indicator("내 스크립트") int l = 14 plot(ta.ema(close,l))
- 참고 : libarary가 아니라면 int로 지정해도 series int로 인식하는 것이 아닌, 자동으로 함수 입력인자 qualifier에 맞춰지거나, 다른 qualifier연산에 맞춰지게 됩니다.
-
- const int로 지정한 경우
-
//@version=5 //@description A library with custom functions. library("CustomFunctions", overlay = true) //@function Calculates the length values for a ribbon of four EMAs by multiplying the `baseLength`. //@param baseLength The initial EMA length. Requires "simple int" because you can't use "series int" in `ta.ema()`. //@returns A tuple of length values. export ribbonLengths(const int baseLength) => length1 = baseLength length2 = baseLength * 2 [length1, length2] // Get a tuple of "simple int" length values. [len1, len2] = ribbonLengths(14) // Plot four EMAs using the values from the tuple. plot(ta.ema(close, len1), "EMA 1", color = color.red) plot(ta.ema(close, len2), "EMA 1", color = color.orange)
- 오류 발생
- Cannot declare an exported function's parameters with the `const` keyword. Parameters in exported functions can only be of 'simple' or 'series' forms.
- library에서 exported function을 만들 때 파라미터에 const를 사용하면 안 된다는 것을 알 수 있습니다. 반드시 simple이나 series만 지정이 가능합니다.
-
- simple int로 지정한 경우
-
//@version=5 //@description A library with custom functions. library("CustomFunctions", overlay = true) //@function Calculates the length values for a ribbon of four EMAs by multiplying the `baseLength`. //@param baseLength The initial EMA length. Requires "simple int" because you can't use "series int" in `ta.ema()`. //@returns A tuple of length values. export ribbonLengths(simple int baseLength) => length1 = baseLength length2 = baseLength * 2 [length1, length2] // Get a tuple of "simple int" length values. [len1, len2] = ribbonLengths(14) // Plot four EMAs using the values from the tuple. plot(ta.ema(close, len1), "EMA 1", color = color.red) plot(ta.ema(close, len2), "EMA 1", color = color.orange)
- 코드가 정상적으로 작동합니다.
-
- type 지정 안 한 경우
-
- 예시
- 오류 난 위 코드에서는 l에 series라고 명시적으로 지정해 주어서 오류가 발생했습니다. 하지만 아무런 qualifier를 지정하지 않은 경우는 내장 함수의 조건에 맞춰서 입력인자가 알아서 변경되게 됩니다. (l이 ta.ema의 입력인자 조건에 맞춰서 simple로 변경되어 ta.ema(close, l) 안에 들어가게 됩니다.)
- 변수 선언에서 qualifier가 선언되지 않았다면 컴파일러는 보통 변수에 할당된 값에 기반하여 자동으로 qualifier을 추론할 수 있습니다.
const
- 설명
- "const" 키워드는 variables(변수)와 non-exported functions(내보내지 않은 함수)의 parameters(매개변수)에 "const" type qualifier를 명시적으로 할당합니다.
- 만약 내보내는 함수의 경우 컴파일시점에 바로 지정이 불가능하기 때문입니다.
- "const" qualifier가 있는 variables(변수)와 parameters(매개변수)는 컴파일 시점에 설정되고 스크립트 실행 중에 절대 변경되지 않는 값을 참조합니다.
- 변수를 "const" 키워드로 명시적으로 선언하면 type qualifier를 "const"로 제한하는데, 이는 variables(변수)가 더 강한 qualifier (예를 들면 input, simple, series)를 가진 값으로 초기화될 수 없음을 의미하며, 스크립트 실행 중에 변수에 할당된 값이 변경될 수도 없습니다.
- 가장 약하기 때문에 다른 input, simple, series값을 받아올 수 없습니다. 하지만 input, simple, series 키워드로 선언된 어떠한 변수에든 const로 선언된 변수는 지정가능합니다.
- "const" 키워드를 사용하여 type qualifier를 명시할 때, 허용되는 타입을 선언하기 위해 type keyword도 함께 사용해야 합니다.
- 아래는 "const" 변수로 지정이 가능한 값들입니다. (또한 const보다 강한 input, simple, series에 모두 할당가능한 값들입니다.)
- literal int: 1, -1, 42
- literal float: 1., 1.0, 3.14, 6.02E-23, 3e8
- literal bool: true, false
- literal color: #FF55C6, #FF55C6ff
- literal string: "A text literal", "Embedded single quotes 'text'", 'Embedded double quotes "text"'
- "const" 키워드는 variables(변수)와 non-exported functions(내보내지 않은 함수)의 parameters(매개변수)에 "const" type qualifier를 명시적으로 할당합니다.
- "const " syntax
-
[method ]<functionName>([const <paramType> ]<paramName>[ = <defaultValue>])
- parameters(매개변수)에 const 지정
- const로 정의된 변수들만 들어올 수 있습니다.
-
const <variableType> <variableName> = <variableValue>
- variables(변수)에 const 지정
- const로 정의된 변수 선언
-
- 예시
- parameters(매개변수)에 const 지정
-
//@version=5 indicator("custom plot title") //@function Concatenates two "const string" values. concatStrings(const string x, const string y) => const string result = x + y //@variable The title of the plot. const string myTitle = concatStrings("My ", "Plot") plot(close, myTitle)
-
- variables(변수)에 const 지정
-
//@version=5 indicator("can't assign input to const") //@variable A variable declared as "const float" that attempts to assign the result of `input.float()` as its value. // This declaration causes an error. The "input float" qualified type is stronger than "const float". const float myVar = input.float(2.0) plot(myVar)
- 하지만 이 예시는 오류가 발생합니다. myVar는 const로 지정했기 때문에 그보다 더 강한 qualifier인 input으로 지정될 수 없습니다.
-
- 위 예시들처럼 const를 사용할 때 float나 string처럼 type keyword가 함께 사용되어야 합니다.
- parameters(매개변수)에 const 지정
input
- input 내장함수 종류
- input(), input().bool(), input().color() , input.float(), input.int(), input().price(), input.source(), input.string(), input.symbol(), input.text_area(), input.time(), input.timeframe() 등 다양한 input 내장 함수들이 존재합니다.
input()
- input()
- 이 함수는 처음에 입력된 값을 토대로 자동으로 type을 감지하고 해당 입력 함수를 사용하게 되는 것입니다.
-
//@version=5 indicator("input", overlay=true) i_switch = input(true, "On/Off") plot(i_switch ? open : na) i_len = input(7, "Length") i_src = input(close, "Source") plot(ta.sma(i_src, i_len)) i_border = input(142.50, "Price Border") hline(i_border) bgcolor(close > i_border ? color.green : color.red) i_col = input(color.red, "Plot Color") plot(close, color=i_col) i_text = input("Hello!", "Message") l = label.new(bar_index, high, text=i_text) label.delete(l[1])
- 위와 같이 input을 설정해 두면 해당 지표/전략 설정 부분에서 값을 손쉽게 변경이 가능합니다.
input.bool()
- input.bool()
-
//@version=5 indicator("input.bool", overlay=true) i_switch = input.bool(true, "On/Off") plot(i_switch ? open : na)
-
input.color()
- input.color()
-
//@version=5 indicator("input.color", overlay=true) i_col = input.color(color.red, "Plot Color") plot(close, color=i_col)
-
input.float()
- input.float()
-
//@version=5 indicator("input.float", overlay=true) i_angle1 = input.float(0.5, "Sin Angle", minval=-3.14, maxval=3.14, step=0.02) plot(math.sin(i_angle1) > 0 ? close : open, "sin", color=color.green) i_angle2 = input.float(0, "Cos Angle", options=[-3.14, -1.57, 0, 1.57, 3.14]) plot(math.cos(i_angle2) > 0 ? close : open, "cos", color=color.red)
- step을 통해 아래와 같이 변경 크기를 지정해 줄 수 있습니다.
- options를 통해 다음과 같이 선택할 수 있는 범위를 제한해 줄 수 있습니다.
- step을 통해 아래와 같이 변경 크기를 지정해 줄 수 있습니다.
-
input.int()
- input.int()
-
//@version=5 indicator("input.int", overlay=true) i_len1 = input.int(10, "Length 1", minval=5, maxval=21, step=1) plot(ta.sma(close, i_len1)) i_len2 = input.int(10, "Length 2", options=[5, 10, 21]) plot(ta.sma(close, i_len2))
-
input.price()
- input.price()
-
//@version=5 indicator("input.price", overlay=true) price1 = input.price(title="Date", defval=42) plot(price1) price2 = input.price(54, title="Date") plot(price2)
- 차트를 보면 USDT 단위인 것을 확인할 수 있습니다.
- 차트를 보면 USDT 단위인 것을 확인할 수 있습니다.
-
- input.session()
-
//@version=5 indicator("input.session", overlay=true) i_sess_1 = input.session("1300-1700", "Session", options=["0930-1600", "1300-1700", "1700-2100"]) i_sess_2 = input.session("1700-2100", "Session") t_1 = time(timeframe.period, i_sess_1) bgcolor(time == t_1 ? color.green : na) t_2 = time(timeframe.period, i_sess_2) bgcolor(time == t_2 ? color.red : na)
- 사용자가 세션의 시작과 끝을 지정할 수 있도록 하는 두 개의 드롭다운을 추가하고 결과를 문자열로 반환합니다.
- 사용자가 세션의 시작과 끝을 지정할 수 있도록 하는 두 개의 드롭다운을 추가하고 결과를 문자열로 반환합니다.
-
input.source()
- input.source()
-
//@version=5 indicator("input.source", overlay=true) i_src = input.source(close, "Source") plot(i_src)
- defval에는 다음 사항이 들어갈 수 있습니다.
- open/high/low/close/hl2/hlc3/ohlc4/hlcc4
- defval에는 다음 사항이 들어갈 수 있습니다.
-
input.string()
- input.string()
-
//@version=5 indicator("input.string", overlay=true) i_text = input.string("Hello!", "Message") l = label.new(bar_index, high, i_text) label.delete(l[4])
-
input.symbol()
- input.symbol()
-
//@version=5 indicator("input.symbol", overlay=true) i_sym = input.symbol("BINANCE:ETCUSDT.P", "Symbol") s = request.security(i_sym, 'D', close) plot(s)
-
- 설정 변경
- 설정 변경
-
-
input.text_area()
- input.text_area()
-
//@version=5 indicator("input.text_area") i_text = input.text_area(defval = "Hello \nWorld!", title = "Message") plot(close)
- string에 비해 더 넓은 입력공간을 제공해 줍니다.
-
input.time()
- input.time()
-
//@version=5 indicator("input.time", overlay=true) i_date = input.time(timestamp("20 Jul 2023 00:00 +0300"), "Date") l = label.new(i_date, high, "Date", xloc=xloc.bar_time) label.delete(l[1])
-
input.timeframe()
- input.timeframe()
-
//@version=5 indicator("input.timeframe", overlay=true) i_res = input.timeframe('D', "Resolution", options=['D', 'W', 'M']) s = request.security("AAPL", i_res, close) plot(s)
- 만약 options가 없을 경우 아래와 같이 지정됩니다.
- 만약 options가 없을 경우 아래와 같이 지정됩니다.
-
simple
- 설명
- "simple" 키워드는 variables(변수)와 functions(함수)의 parameters(매개변수)에 "simple" type qualifier를 명시적으로 할당합니다.
- "simple" qualifer가 있는 variables(변수)와 parameters(매개변수)는 스크립트 실행 시작 시에 설정되고 이후에는 변경되지 않는 값을 참조할 수 있습니다.
- 라이브러리의 exported functions(내보낸 함수)에서 paramters(매개변수)를 오직 "simple" 또는 그보다 약한 type qualifier로만 허용하려면, 매개변수를 선언할 때 "simple" 키워드를 사용하는 것이 종종 필요합니다. 이는 라이브러리가 기본적으로 가능한 모든 매개변수를 "series"로 자동 지정하기 때문입니다.
- "simple" 인수를 받아들이도록 함수를 명시적으로 제한하는 것은, 해당 함수가 실행하는 연산에 따라, 일부 경우에 "simple" 값을 반환하게 할 수도 있으며, "series"인수를 허용하지 않는 내장 함수의 paramters(매개변수)와 함께 사용할 수 있게 합니다.
- variables(변수)를 "simple" 키워드로 명시적으로 선언하면 type qualifier를 "simple"로 제한하는데, 이는 스크립트가 다른 simple 보다 강한 qualifier인 "series"값을 할당할 수 없음을 의미합니다. (simple 보다 약한 const, input qulifier 값은 할당 가능합니다.)
- "simple" 키워드를 사용하여 type qualifier를 명시할 때, 허용되는 타입을 선언하기 위해 type keyword도 함께 사용해야 합니다.
- "simple" syntax
-
export [method ]<functionName>([[simple ]<paramType>] <paramName>[ = <defaultValue>])
- (라이브러리) parameters(매개변수)에 simple 지정 -> simple을 내보내기 위함.
-
[method ]<functionName>([simple <paramType> ]<paramName>[ = <defaultValue>])
- parameters(매개변수)에 simple 지정
-
simple <variableType> <variableName> = <variableValue></variableValue>
- variables(변수)에 simple 지정
-
- 예시
- parameters(매개변수)에 simple 지정
-
//@version=5 //@description A library with custom functions. library("CustomFunctions", overlay = true) //@function Calculates the length values for a ribbon of four EMAs by multiplying the `baseLength`. //@param baseLength The initial EMA length. Requires "simple int" because you can't use "series int" in `ta.ema()`. //@returns A tuple of length values. export ribbonLengths(simple int baseLength) => length1 = baseLength length2 = baseLength * 2 length3 = baseLength * 3 length4 = baseLength * 4 [length1, length2, length3, length4] // Get a tuple of "simple int" length values. [len1, len2, len3, len4] = ribbonLengths(14) // Plot four EMAs using the values from the tuple. plot(ta.ema(close, len1), "EMA 1", color = color.red) plot(ta.ema(close, len2), "EMA 1", color = color.orange) plot(ta.ema(close, len3), "EMA 1", color = color.green) plot(ta.ema(close, len4), "EMA 1", color = color.blue)
- ta.ema라이브러리는 simple int를 요구하기 때문에 series int 타입을 사용할 수 없습니다.
-
- variables(변수)에 simple 지정
-
//@version=5 indicator("can't change simple to series") //@variable A variable declared as "simple float" with a value of 5.0. simple float myVar = 5.0 // This reassignment causes an error. // The `close` variable returns a "series float" value. Since `myVar` is restricted to "simple" values, it cannot // change its qualifier to "series". myVar := close plot(myVar)
- simple qualifier을 받은 myVar에 series값을 지정해 주었기 때문에 오류가 발생합니다.
-
- parameters(매개변수)에 simple 지정
series
- 가장 강한 type qualifier입니다. series qualifier과 연산되는 모든 변수(const, input, simple)의 결과는 series qualifier가 됩니다. 가장 강한 type qualifier이기 때문입니다. (참고: const+input -> input / const+simple -> simple / simple + series -> series 더 강한 쪽으로 가게 됩니다.)
- 아래 예시를 보면 simple로 지정한 변수에 series로 지정한 변수를 지정하면 오류가 발생합니다. 이는 simple보다 series가 더 강한 qualifier이기 때문에 simple로 선언된 변수인 a로 더 강한 qualifier인 series로 지정된 b가 할당될 수 없습니다.
-
//@version=5 indicator("qualifier") simple float a = -1 series float b = 1 a:=b
- 오류발생
-
- 하지만 반대로 series로 지정한 변수에 simple로 지정한 값을 할당해 주면 오류가 발생하지 않습니다.
-
//@version=5 indicator("qualifier") simple float a = -1 series float b = 1 b:=a plot(a) plot(b)
-
- 아래 예시를 보면 simple로 지정한 변수에 series로 지정한 변수를 지정하면 오류가 발생합니다. 이는 simple보다 series가 더 강한 qualifier이기 때문에 simple로 선언된 변수인 a로 더 강한 qualifier인 series로 지정된 b가 할당될 수 없습니다.
Declaration modes (var / varip / 아무것도 지정 안 한 경우)
- Declaration modes는 qualifier 앞에 지정할 수 있는 값입니다.
- 보통 series qualifier 앞에서 가장 많이 사용됩니다. 이론상 값이 변경되는 것을 series로 생각하기 때문입니다. 하지만 simple qualifier 변수에도 값을 수정하는 것이 가능합니다.
-
//@version=5 indicator("qualifier") var simple int a = 0 a:=a+1 plot(a)
- 그럼 여기서 생각해 볼 수 있는데 a:=a+1 연산 때문에 simple이 series로 변경된 거 아니냐고 생각할 수 있습니다. 실험 결과 아닌 것을 확인할 수 있습니다. 즉 simple 또한 series처럼 declaration modes가 적용된다는 것을 확인할 수 있습니다. 하지만 정확하게는 series로 사용하는 것이 보다 올바른 표현방법입니다.
-
//@version=5 indicator("qualifier") var simple int a = 0 a:=a+1 var series int b = -1 a:=b
- 오류 발생 : Variable 'a' was declared with 'simple int' type. Cannot assign it expression of type 'series int'
- 즉, a는 a:=a+1 연산을 해도 그대로 simple임을 알 수 있습니다. 또한 simple의 경우에도 declaration modes가 적용된다는 것을 확인할 수 있습니다.
-
-
- 보통 series qualifier 앞에서 가장 많이 사용됩니다. 이론상 값이 변경되는 것을 series로 생각하기 때문입니다. 하지만 simple qualifier 변수에도 값을 수정하는 것이 가능합니다.
- Declaration modes에 들어갈 수 있는 값은 var, varip 또는 아무것도 지정 안 하는 것입니다.
- 아무것도 지정 안 한 경우 로컬(local) 변수로 동작하여서 변수는 매 bar마다 지정된 값으로 초기화하게 됩니다.
- 즉 만약 v = 0이라고 초기화한다면, 매 막대마다 스크립트가 실행될 텐데 그때마다 v=0이라고 다시 초기화가 되는 것입니다.
- var이나 varip인 경우는 첫 번째 막대에서만 v=0으로 초기화하고 다음부터 그 초기화 코드는 작동하지 않습니다.
- var이나 varip으로 지정하게 되면 초기화하는 코드는 데이터세트에서 제일 처음 바에서만 한 번만 초기화되게 됩니다.
- var과 varip의 차이점
- var과 varip는 백테스팅에서는 동일하게 작동하지만 실시간 매매에서는 다르게 동작합니다.
- var의 경우는 실시간 매매에서는 하나의 bar에 대해서 값의 업데이트가 딱 한 번만 진행되게 됩니다. 하지만 varip의 경우는 하나의 bar에서도 거래량이나 현재가격이 변화하면 해당 변수의 값이 계속해서 업데이트를 진행하게 됩니다.
- var과 varip의 차이 예시
- var
-
//@version=5 indicator("var") var int v = -1 v := v + 1 plot(v)
- var의 경우 실시간 봉에 대해서 해당하는 변수는 처음 딱 봉이 생성될 때 값이 업데이트되고 그다음 봉이 생길 때까지 값이 업데이트되지 않습니다.
- 하지만 if문 등 조건이 있는 경우 그 조건에 맞게 변할 때마다 var 변수더라도 그 조건에 맞는 값으로 실시간 변화하게 됩니다.
- 예를 들어 아래 코드와 같을 때 var 변수라고 하더라도 처음 봉이 만들어질 때 평가된 if문 조건이 아닌 계속해서 가격이 변화할 때마다 if문을 체크하고 다른 조건이 되면 그 값으로 표시되게 됩니다.
- (아래 두 코드를 비교하면 varip와 var을 정확하게 이해할 수 있을 것입니다.)
- 과거 데이터에 대해서는 동일하게 작동하지만 실시간 데이터에서는 하나의 봉에서 가격이 변화할 때마다 var인 경우는 if문중에서 조건에 맞는 결과를 표시하고 varip인 경우 가격이 변화할 때마다 조건문에 맞는 결과를 실행하게 됩니다.
- 즉 varip는 중복해서 값이 더해지고, var은 값이 하나의 봉에서 딱 한 번만 변화하게 됩니다.(근데 그 변화가 1이 더해질지 2가 더해질지 close가 open보다 큰지 작은지에 따라서 실시간으로 변화하게 되는 것입니다.)
-
//@version=5 indicator("", "", true) var float v = 0 if close>open v:=v+1 else v:=v+2 plot(v)
-
//@version=5 indicator("", "", true) varip float v = 0 if close>open v:=v+1 else v:=v+2 plot(v)
- (아래 두 코드를 비교하면 varip와 var을 정확하게 이해할 수 있을 것입니다.)
-
- varip
-
//@version=5 indicator("varip") varip int v = -1 v := v + 1 plot(v)
- 과거에서는 var과 동일하게 작동하지만 실시간 봉에서는 틱이 바뀔 때마다 계속해서 v가 같이 업데이트되는 것을 확인할 수 있습니다. var로 선언된 변수는 스크립트 실행 중 처음에 한 번만 초기화됩니다. 그 후 스크립트에서 변경된 값을 계속해서 유지가 됩니다.
-
- var
- var과 varip의 차이점
- 아무것도 지정 안 한 경우 로컬(local) 변수로 동작하여서 변수는 매 bar마다 지정된 값으로 초기화하게 됩니다.
Types
int / float / bool / color / string
- int
- 정수
- 1, -1, 750,...
- bar_index, time, timenow,...
- float
- 소수점이 있는 수
- 3.141592 , -3.0 , 6.02e23, 1.6e-19
- pine script의 float 값 내부 정밀도는 1e-16입니다.
- close, hlcc4, volume, ta.vwap, strategpy.position_size,...
- bool
- 참/ 거짓
- true / false
- bool 타입의 표현식이 na를 반환하면, 조건문과 연산자에서는 거짓(false)으로 처리됩니다.
- barstate.isfirst, timeframe.isdaily,...
- color
- 색상
- #000000 (검정색), #FF0000 (빨강색), #00FF00 (초록색), #0000FF (파랑색), #FFFFFF (흰색), #808080 (회색)
- color.green, color.red, color.orange, color.blue
- string
- 문자, 숫자, 기호, 공백 및 기타 문자들의 시퀀스
- "안녕하세요" , "hi" ,...
- + 연산자를 사용하여 문자열 값을 연결할 수 있습니다.
- str.format()과 같은 str.*() 내장함수를 사용하여 특수한 작업을 수행할 수 있습니다.
- syminfo.tickerid, syminfo.currency, timeframe.period,...
Collections
- arrays, matrices, maps 은 reference ID를 사용합니다. 이 ID의 타입은 컬렉션이 포함할 요소의 타입을 정의합니다.
- 예시
- array<int> : int요소를 포함하는 배열
- array<label> : label ID를 포함하는 배열
- array<UDT> : 사용자 정의 타입(UDT) 객체를 참조하는 ID를 포함하는 배열
- matrix<float> : float 요소를 포함하는 행렬
- matrix<UDT> : 사용자 정의 타입(UDT) 객체를 참조하는 ID를 포함하는 행렬
- map<string, float> : string 키와 float 값을 포함하는 맵
- map<int, UDT> : int 키와 사용자 정의 타입(UDT) 인스턴스 ID 값을 포함하는 맵
- 코드
-
a1 = array.new<int>(1, 10) array<int> a2 = array.new<int>(1, 10) a3 = array.from(10) array<int> a4 = array.from(10)
-
User-defined types
- type 키워드를 사용하여 사용자 정의 타입(UDTs)을 생성할 수 있습니다. UDTs는 다양한 필드를 포함할 수 있는 복합 타입입니다.
-
[export] type <UDT_identifier> <field_type> <field_name> [= <value>] ...
-
- 예시
- pivotPoint라는 UDT를 선언하는 예시입니다. 이 타입은 int 타입의 pivotTime 필드와 float 타입의 priceLevel 필드를 포함하여, 계산된 피벗에 대한 시간 및 가격정보를 보유합니다.
-
type pivotPoint int pivotTime float priceLevel
-
- 사용 예시
-
//@version=5 indicator("Pivot Point Example 1", overlay=true) type pivotPoint int pivotTime float priceLevel // 피벗 포인트 객체 생성 var pivot = pivotPoint.new(na, na) // 특정 조건에서 피벗 포인트 업데이트 if (bar_index % 10 == 0) // 매 10번째 바마다 pivot := pivotPoint.new(timenow, close) // 피벗 포인트 표시 plot(not na(pivot.pivotTime) ? pivot.priceLevel : na, color=color.red)
-
- pivotPoint라는 UDT를 선언하는 예시입니다. 이 타입은 int 타입의 pivotTime 필드와 float 타입의 priceLevel 필드를 포함하여, 계산된 피벗에 대한 시간 및 가격정보를 보유합니다.
void
- void 타입은 사용 가능한 결과를 반환하지 않는 함수가 반환하는 타입입니다.
- 예를 들어 alert() 함수는 알림 이벤트를 트리거 하지만 사용가능한 값을 반환하지는 않습니다.
- 스크립트에서 void 결과를 표현식에 사용하거나 변수에 할당할 수 없습니다. void 키워드는 Pine Script에 존재하지 않으며, void 타입의 변수를 선언할 수 없습니다.
'na' value
- Pine Script에서 na값은 not available의 약자로, 정의되지 않은 값 또는 사용할 수 없는 값을 나타내는 특별한 값입니다.
- 이는 Java의 null이나 Python의 None과 유사합니다.
- 자동 형변환
- 스크립트는 na 값을 거의 모든 타입으로 자동으로 변환할 수 있습니다. 그러나 컴파일러가 na값과 연관된 타입을 추론할 수 없는 경우도 있습니다.
- 예를 들어 myVar = na는 컴파일 오류를 일으키는데, 이는 컴파일러가 myVar 변수가 수치, 문자열 또는 다른 목적의 값 중 어떤 것을 참조할지 결정할 수 없기 때문입니다.
-
// Compilation error! myVar = na
- 명시적 타입 선언 필요
- 오류를 해결하기 위해 변수에 명시적으로 타입을 선언해야 합니다.
- 예시
-
float myVar = na
-
myVar = float(na)
-
- na 값 테스트
- na() 함수 사용
- 변수나 표현식에서 na 값을 테스트하려면 na() 함수를 호출합니다. 이 함수는 값이 정의되지 않은 경우 true를 반환합니다.
-
//@variable Is 0 if the `myVar` is `na`, `close` otherwise. float myClose = na(myVar) ? 0 : close
- == 연산자 사용 금지
- na 값의 동등성을 테스트하기 위해 == 연산자를 사용해서는 안됩니다. na 값은 정의되지 않았기 때문에 동등성을 결정할 수 없습니다.
-
//@variable Returns the `close` value. The script cannot compare the equality of `na` values, as they're undefined. float myClose = myVar == na ? 0 : close
- na() 함수 사용
- na 값 처리(nz)
- 스크립트에서 na 값을 처리하는 것은 계산 중 정의되지 않은 값이 결과에 전파되는 것을 방지하는데 중요합니다.
- nz() 함수를 사용하여 na 값이 있는 경우 대체 값을 사용합니다.
-
bool risingClose = close > nz(close[1], open)
- nz(close[1], open) : close[1] 값이 na라면 open으로 대체합니다.
-
- 예를 들면, math.max()를 사용할 때 math.max()는 na값과 비교할 수 없으므로 만약 na일 경우 0으로 대체하는 nz() 함수를 사용하여 초기 na값을 대체하여 비교할 수 있습니다.
- 잘못된 경우
-
//@version=5 indicator("na protection demo", overlay = true) //@variable The result of calculating the all-time high price with an initial value of `na`. var float allTimeHigh = na // Reassign the value of the `allTimeHigh`. // Returns `na` on all bars because `math.max()` can't compare the `high` to an undefined value. allTimeHigh := math.max(allTimeHigh, high) plot(allTimeHigh) // Plots `na` on all bars.
- 모든 바가 na로 plot 되게 됩니다. math.max(na, high)는 비교가 불가능하기 때문에 na를 반환하게 됩니다.
-
- 올바른 경우
-
//@version=5 indicator("na protection demo", overlay = true) //@variable The result of calculating the all-time high price with an initial value of `na`. var float allTimeHigh = na // Reassign the value of the `allTimeHigh`. // We've used `nz()` to prevent the initial `na` value from persisting throughout the calculation. allTimeHigh := math.max(nz(allTimeHigh), high) plot(allTimeHigh)
- na를 nz를 통해서 na일 경우 0으로 대체하도록 만들면, allTimeHigh가 올바르게 구해지게 됩니다.
-
- 잘못된 경우
Type templates
- Pine Script에서 Type templates은 Collection(배열, 행렬, 맵)이 포함할 수 있는 데이터 타입을 명시합니다.
- 배열과 행렬의 Type templates
- 단일 타입 식별자를 꺾쇠괄호 안에 넣어 구성합니다.
- <int> , <label> , <PivotPoint> (여기서 PivotPoint는 사용자 정의 타입(UDT)입니다.)
- 맵의 Type templates
- 두 개의 타입 식별자를 꺾쇠 괄호 안에 넣어 구성합니다.
- 첫 번째 식별자는 키의 타입을, 두 번째는 값의 타입을 지정합니다.
- <string, float> 은 문자열 키와 부동 소수점 값이 있는 맵을 위한 Type template입니다.
- Type templates 구성 가능한 타입들
- 기본 타입 : int, float, bool, color, string
- 특별한 타입 : line, linefill, box, polyline, label, table, chart.point
- 사용자 정의 타입(UDTs)
- 참고 사항
- 맵은 값으로 어떤 타입도 사용할 수 있지만, 키로는 기본 타입만을 받을 수 있습니다.
- 스크립트는 변수를 선언하거나 새 컬렉션 인스턴스를 생성할 때 타입 템플릿을 사용합니다.
-
//@version=5 indicator("Type templates demo") //@variable A variable initially assigned to `na` that accepts arrays of "int" values. array<int> intArray = na //@variable An empty matrix that holds "float" values. floatMatrix = matrix.new<float>() //@variable An empty map that holds "string" keys and "color" values. stringColorMap = map.new<string, color>()
-
Type casting
- Pine Script에서 Type casting은 값의 타입을 필요에 따라 자동으로 변환하는 메커니즘을 포함합니다.
- 기본 Type casting
- int에서 float으로의 자동 캐스팅 : 필요할 때 int 값이 float로 자동 변환됩니다.
- int와 float에서 bool으로의 자동 캐스팅: bool을 기대하는 함수 및 연산의 매개변수로 숫자 값을 전달할 때 Pine Script는 이를 자동으로 bool로 변환합니다.
- 하지만 이러한 자동 변환에 의존하지 않는 것이 좋습니다.
- 명시적 Type casting
- int(), float(), bool() 함수를 사용하여 명시적으로 타입을 변환합니다.
- 예를 들어 ta.sma() 함수 호출에서 const float 값을 int로 변환해야 할 때 int() 함수를 사용합니다.
- 종류
- int(), float(), bool(), color(), string(), line(), linefill(), label, box(), table() 등
Tuple
- Pine Script에서 튜플은 괄호 안에 쉼표로 구분된 표현식 집합입니다. 함수, 메소드 또는 다른 로컬 블록이 여러 값을 반환할 때, 스크립트는 튜플 형태로 이러한 값을 반환합니다.
- 튜플의 기본 사용법
- 합과 곱을 반환하는 사용자 정의 함수
-
calcSumAndProduct(float a, float b) => float sum = a + b float product = a * b [sum, product]
-
- 함수 호출로부터 반환된 값에 해당하는 여러 변수를 선언하기 위해 튜플 선언을 사용
-
[hlSum, hlProduct] = calcSumAndProduct(high, low)
-
- 합과 곱을 반환하는 사용자 정의 함수
- 타입 추론
- 튜플에서 변수의 타입을 명시적으로 정의할 수는 없으며, 컴파일러가 튜플의 변수와 관련된 타입을 자동으로 추론합니다.
- 다양한 타입 포함
- 튜플은 다양한 타입의 값을 포함할 수 있습니다. 예를 들어, int, float, bool, color, string 값을 포함하는 튜플을 반환하는 함수가 있을 수 있습니다.
- 튜플 예시
-
//@function Returns a tuple of OHLC values, rounded to the nearest tick. roundedOHLC() => [math.round_to_mintick(open), math.round_to_mintick(high), math.round_to_mintick(low), math.round_to_mintick(close)] [op, hi, lo, cl] = request.security(syminfo.tickerid, "D", roundedOHLC())
-
- 조건 구조에서의 튜플 반환
- if 및 switch 문과 같은 조건 구조의 로컬 블록은 튜플을 반환할 수 있습니다.
-
[v1, v2] = if close > open [high, close] else [close, low]
-
[v1, v2] = switch close > open => [high, close] => [close, low]
-
- 그러나 삼항 연산자에서는 튜플을 반환할 수 없습니다.
-
// Not allowed. [v1, v2] = close > open ? [high, close] : [close, low]
-
- if 및 switch 문과 같은 조건 구조의 로컬 블록은 튜플을 반환할 수 있습니다.
- 튜플 내 항목의 Type qualifier
- 함수에서 반환된 튜플 내의 모든 항목은 simple 또는 series의 qualifier입니다.
- 만약 튜플에 series 값이 포함된다면 튜플 내의 다른 모든 요소도 series qualifier가 됩니다.
-
//@version=5 indicator("Qualified types in tuples demo") makeTicker(simple string prefix, simple string ticker) => tId = prefix + ":" + ticker // simple string source = close // series float [tId, source] // Both variables are series now. [tId, source] = makeTicker("BATS", "AAPL") // Error cannot call 'request.security' with 'series string' tId. r = request.security(tId, "", source) plot(r)
'Algorithm Trading > Pine Script v5 기본' 카테고리의 다른 글
Pine Script v5 기본 개념 - 2 (Strategies) (1) | 2024.01.05 |
---|---|
Pine Script v5 기본 개념 - 1 (Alerts) (1) | 2023.12.26 |
Pine Script v5 기본 문법 - 2 (조건문, 반복문) (0) | 2023.12.25 |
Pine Script v5 기본 문법 - 1 (스크립트 기본, 연산자, 변수선언) (0) | 2023.12.24 |
Pine Script v5 기초 (1) | 2023.12.24 |