목차
Conditional structures
Introduction
- Pine Script에서 사용하는 조건문은 if와 switch가 있습니다.
- Pine Script에서는 조건문의 local block에서 호출하지 못하는 내장함수가 있습니다.
- alertcondition(), barcolor(), fill(), hline(), indicator(), library(), plot(), plotbar(), plotcandle(), plotchar(), plotshape(),
- 예를 들어 다음 코드는 에러가 발생합니다.
-
//@version=5 indicator("", "", true) float v = 0 if close>open plot(v) else plot(v+1)
- plot은 조건문의 local block에서 호출하지 못합니다.
-
if 문
- if 문 형식
-
if <expression> <local_block> {else if <expression> <local_block>} [else <local_block>]
- { } 로 묶인 부분은 0번 이상 반복될 수 있고, [ ] 로 묶인 부분은 0번 또는 1번 등장할 수 있습니다.
- expression은 bool 유형이거나 해당 유형으로 자동 형변환이 가능해야합니다.
-
- if를 사용해서 value를 return 받기
-
[<declaration_mode>] [<type>] <identifier> = if <expression> <local_block> {else if <expression> <local_block>} [else <local_block>]
-
- 만약 다음과 같이 else가 생략된 경우에는 else로 갈 경우 na를 return 합니다.
-
x = if close > open close
-
- 중첩된 if 문 사용도 가능합니다.
-
하지만 보통 이렇게 중첩하는 것은 성능 측면에서 권장되지 않습니다. 가능하다면 아래와 같이 한 번에 작성하는 것이 더 좋은 선택입니다.if condition1 if condition2 if condition3 expression
-
if condition1 and condition2 and condition3 expression
-
switch 문
- swtich 문은 두 가지 형태로 존재합니다.
-
[[<declaration_mode>] [<type>] <identifier> = ]switch <expression> {<expression> => <local_block>} => <local_block>
-
[[<declaration_mode>] [<type>] <identifier> = ]switch {<expression> => <local_block>} => <local_block>
- { } 로 묶인 부분은 0번 이상 반복될 수 있고, [ ] 로 묶인 부분은 0번 또는 1번 등장할 수 있습니다.
-
- switch with an expression 예시
-
//@version=5 indicator("Switch using an expression", "", true) string maType = input.string("EMA", "MA type", options = ["EMA", "SMA", "RMA", "WMA"]) int maLength = input.int(10, "MA length", minval = 2) float ma = switch maType "EMA" => ta.ema(close, maLength) "SMA" => ta.sma(close, maLength) "RMA" => ta.rma(close, maLength) "WMA" => ta.wma(close, maLength) => runtime.error("No matching MA type found.") 또는 float(na) plot(ma)
- 조건에 만족하는 것이 없을 경우 runtime.error를 발생시키게 하거나, na를 반환시킬수 있습니다. 다른 리턴값하고 타입을 통일시 해주기 위해 float를 지정해줍니다.
-
- switch without an expression
-
//@version=5 strategy("Switch without an expression", "", true) bool longCondition = ta.crossover( ta.sma(close, 14), ta.sma(close, 28)) bool shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) switch longCondition => strategy.entry("Long ID", strategy.long) shortCondition => strategy.entry("Short ID", strategy.short)
- 여러 케이스 중에서 첫번째로 true가 되는 조건을 만족하는 케이스만 실행합니다.
- 즉, 다음과 같은 순서로 실행됩니다.
- longCondition이 true 인 경우: switch 문은 longCondition에 대한 케이스를 실행하고 (strategy.entry("Long ID", strategy.long)), 이후의 케이스는 무시합니다. 즉, shortCondition에 대한 케이스는 체크하지 않습니다.
- longCondition이 false이고 shortCondition이 true인 경우: switch 문은 shortCondition에 대한 케이스를 실행합니다 (strategy.entry("Short ID", strategy.short)).
- 두 조건 모두 false인 경우: 어떤 케이스도 실행되지 않습니다.
-
Matching local block type requirement
- 여러 로컬 블록이 구조에 사용되는 경우 모든 로컬 블록의 반환 값 유형이 일치해야 합니다.
- 이는 선언에서 변수에 값을 할당하기 위해 구조를 사용하는 경우에만 적용됩니다.
- 변수는 하나의 유형만 가질 수 있고 명령문이 해당 분기에서 호환되지 않는 두 유형을 반환하는 경우 변수 유형을 제대로 결정할 수 없기 때문입니다.
- 정상적으로 작동하는 코드
-
x = if close > open close else open
-
- 컴파일 오류 코드
-
// Compilation error! x = if close > open close else "open"
-
Loops
Introduction
- Pine Script에서는 다양한 내장함수들이 존재하여 많은 상황에서 loop는 불필요 합니다.
- 불필요한 예시
- 평균 구하기
- 잘못된 방법
-
//@version=5 indicator("Inefficient MA", "", true) MA_LENGTH = 10 sumOfCloses = 0.0 for offset = 0 to MA_LENGTH - 1 sumOfCloses := sumOfCloses + close[offset] inefficientMA = sumOfCloses / MA_LENGTH plot(inefficientMA)
-
- 올바른 방법
-
//@version=5 indicator("Efficient MA", "", true) thePineMA = ta.sma(close, 10) plot(thePineMA)
- ta.sma를 이용하면 손쉽게 이동평균선을 계산할 수 있습니다.
-
- 잘못된 방법
- 마지막 10개 막대에서 상승 막대수 계산하기
- 잘못된 방법
-
//@version=5 indicator("Inefficient sum") MA_LENGTH = 10 upBars = 0.0 for offset = 0 to MA_LENGTH - 1 if close[offset] > open[offset] upBars := upBars + 1 plot(upBars)
-
- 올바른 방법
-
//@version=5 indicator("Efficient sum") upBars = math.sum(close > open ? 1 : 0, 10) plot(upBars)
- math.sum(source,length) 를 지정해주면 지정된 개수만큼의 막대에 대해서 source를 더해줍니다.
- 여기서 close > open 이면 1 아니면 0이기 때문에 각각의 10개의 막대에 대해서 계산한뒤 더해주게 됩니다.
-
- 잘못된 방법
- 평균 구하기
- 이처럼 생각보다 loop가 필요한 경우는 거의 없습니다. 그렇다면 언제 필요할까요? (필요한 예시)
- arrays,matrices, maps 등을 조작할 때
- 현재 바에서만 알 수 있는 기준값을 사용하여 바를 분석하기 위해 과거를 되돌아 보는 것(내장된 함수를 사용하여 수행할 수 없는 과거 막대에 대한 계산을 수행하고 싶은 경우)
- 예를 들면 현재 바의 고점보다 과거 고점이 몇 개나 높은지 확인
- 현재 막대의 최고치는 스크립트가 실행 중인 막대에서만 알려져 있으므로 시간을 거슬러 올라가 과거 막대를 분석하려면 루프가 필요합니다.
- 여기서 잠깐 헷갈릴 수 있는 부분이 존재합니다. 이것도 그냥 math.sum으로 아래처럼 하면 되는거 아니야? 할 수 있습니다. 하지만 math.sum은 이제 막대개수만큼 sliding 방식으로 체크하는 방식이기 때문에 이제 시점을 과거로 옮겨서 그때 v>high를 체크하게 됩니다. v 자체는 이제 high이기 때문에 결국엔 high>high가 되는 것이게 되므로 아래 코드는 틀린 코드가 되는 것입니다. 결국 현재 막대에 대한 정보와 과거 막대와 비교하기 위해서는 loop가 반드시 필요하게 됩니다.
-
//@version=5 indicator("Efficient sum") v = high upBars = math.sum(v >high ? 1 : 0, 10) plot(upBars)
-
for 문
- 구조
-
[[<declaration_mode>] [<type>] <identifier> = ]for <identifier> = <expression> to <expression>[ by <expression>] <local_block_loop>
- { } 로 묶인 부분은 0번 이상 반복될 수 있고, [ ] 로 묶인 부분은 0번 또는 1번 등장할 수 있습니다.
- by <expression>은 루프가 반복될 때마다 루프 카운터가 증가하거나 감소하는 단계입니다. 시작값< 끝값 이면 기본값은 1이고 시작값>끝값 이면 기본값은 -1입니다.
-
- 예시(현재 막대의 고점보다 고점이 높았던 막대의 개수 구하기)
-
//@version=5 indicator("High Bars Count", overlay=true) // 현재 막대의 고점 currentHigh = high // 과거 10개 막대 중 현재 고점보다 높은 막대의 수를 계산 var int higherHighsCount = na higherHighsCount := 0 for i = 1 to 10 if high[i] > currentHigh higherHighsCount := higherHighsCount + 1 plot(higherHighsCount, title="Higher Highs Count")
-
while 문
- 구조
-
[[<declaration_mode>] [<type>] <identifier> = ]while <expression> <local_block_loop>
- { } 로 묶인 부분은 0번 이상 반복될 수 있고, [ ] 로 묶인 부분은 0번 또는 1번 등장할 수 있습니다.
-
- 예시(for문 예시를 바꿔, 더 이상 현재 고점보다 높은 고점이 없을때까지의 막대 개수 계산하기)
-
//@version=5 indicator("Count of Higher Highs Using While Loop", overlay=true) // 현재 막대의 고점 currentHigh = high // 현재 고점보다 높은 고점을 가진 이전 막대들의 수를 계산 int higherHighsCount = 0 int i = 1 while (i < 100 and high[i] > currentHigh) higherHighsCount := higherHighsCount + 1 i := i + 1 plot(higherHighsCount, title="Higher Highs Count Using While Loop")
- i<100은 무한루프를 방지하기 위함입니다.
-
- return 값이 있는 while 문 예시
-
//@version=5 indicator("") int n = input.int(10, "Factorial of", minval=0) factorial(int val = na) => int counter = val int fact = 1 result = while counter > 0 fact := fact * counter counter := counter - 1 fact // Only evaluate the function on the first bar. var answer = factorial(n) plot(answer)
-
'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 기본 문법 - 3 (Qualifiers, Types, Tuple) (0) | 2023.12.26 |
Pine Script v5 기본 문법 - 1 (스크립트 기본, 연산자, 변수선언) (0) | 2023.12.24 |
Pine Script v5 기초 (1) | 2023.12.24 |