지지/저항선은 기술적 분석을 처음 접할 때부터 알게 되는 기본적인 지식이다.
하지만 코딩을 통해 지지/저항선을 차트에 표시하는 것은 마냥 쉽지만은 않다.
사람이라면 적절한 지지/저항 포인트를 알아낼 수 있지만 컴퓨터는 그렇지 않기 때문이다.
아래 코드는 파인스크립트를 이용해 트레이딩뷰 차트에 지지/저항선을 자동으로 그려주는 코드다.
위 코드의 출처는 다음과 같다.
https://kr.tradingview.com/script/mCzX2Ym5/
Pivots High & Low — Dr-Bull 의 인디케이터
- Pivot Point + extended gorizontal Lines - Easy to see the high and low points
kr.tradingview.com
코드를 설명하면 다음과 같다.
//@version=4
study('Pivots High&Low', overlay=true)
study는 pinescipt version 4에서 indicator를 만들 때 쓰는 함수다. ' ' 안에 있는 것은 indicator의 이름이고, overlay=true를 설정해야 차트 위에 보이게 된다.
lenH = input(title='Length High', type=input.integer, defval=20, minval=1)
lenL = input(title='Length Low', type=input.integer, defval=20, minval=1)
lenH와 lenL는 사용자가 입력할 수 있는 변수로 몇개의 캔들을 검사할 것인지를 설정한다. 변수 이름은 바꾸어도 상관이 없다. len은 length의 약자로 길이를 의미한다. 이 또한 관습적인 표현 방식일 뿐 다르게 표현해도 무방하다. input 함수가 있는 이유는 사용자가 lenH, lenL 변수에 들어갈 값을 변경할 수 있게 하기 위함이다. 만약 변수 값을 변경할 생각이 없으면 input 없이 lenH = 20이라고 써도 된다. title은 사용자가 변수값을 변경하기 위해 설정에 들어갔을 때 보이는 변수의 이름이다. 참고로 코드상 변수의 이름과 트레이딩뷰 웹사이트에 보이는 변수의 이름은 서로 다른 것이다.
type = input.integer는 값을 input하는 경우 정수값만 받도록 하기 위한 코드다. Length 변수는 n번째 캔들의 값을 확인하기 위해 존재한다. 만약 유리수 입력이 허용될 경우 1.5번째 캔들 같은 존재하지 않는 캔들을 찾게 될 수도 있으므로 정수값만을 입력 받도록 설정한 것이다. 만약 유리수값을 입력 받으려면 interger 대신 float을 쓰면 된다.
defval과 minval은 각각 default value와 minimum value를 의미한다. 기본값과 최솟값을 의미하며 기본값은 20으로, 최솟값은 1로 설정됐다. 최댓값은 maxval을 쓰면 된다.
fun(src, len, isHigh, _style, _yloc, _color) =>
p = nz(src[len])
isFound = true
for i = 0 to len * 2
if isHigh and src[i] > p
isFound := false
if not isHigh and src[i] < p
isFound := false
if isFound
label.new(bar_index[len], p, tostring(p), style=_style, yloc=_yloc, color=_color)
line.new(bar_index[len], p, bar_index, p, extend=extend.right, color=_color)
fun(high, lenH, true, label.style_labeldown, yloc.abovebar, color.red)
fun(low, lenL, false, label.style_labelup, yloc.belowbar, color.lime)
마지막 단락에 있는 fun(high, lenH, true, label.style_labeldown, yloc.abovebar, color.red)을 먼저 보도록 하자. fun이라는 이름을 가진 함수는 총 6개의 변수를 입력 받았다. 각각 high, lenH, true, label.style_labeldown, yloc.abovebar, color.red다.
high는 캔들의 고가를, lenH는 검사할 캔들의 개수를, label.style과 yloc.abovebar는 차트에 보여질 라벨의 스타일과 위치, color.red는 지지저항선과 라벨의 색깔을 의미한다
라벨은 위 사진에서 12047.6, 12945.6과 같이 지지저항선의 가격을 표시해준다. 빨간색 라벨은 화살표가 아래를 향하고 있고 저항선의 상단에 위치한다. 초록색 라벨은 화살표가 위를 향하고 있고 지지선의 하단에 위치한다.
fun(high, lenH, true, label.style_labeldown, yloc.abovebar, color.red)
fun(low, lenL, false, label.style_labelup, yloc.belowbar, color.lime)
저항선(고점)을 판단하기 위해 high 값을 이용하는 함수에선 style_labeldown과 yloc.abovebar를 쓰고, 지지선을 판단하기 위해 low(저점) 값을 이용하는 함수에선 style_labelup과 yloc.belowbar를 쓰는 이유다. 각각 라벨의 화살표 방향과 라벨의 위치를 나타내고 있다.
그렇다면 fun 함수는 어떤식으로 작동할까?
fun(src, len, isHigh, _style, _yloc, _color) =>
p = nz(src[len])
isFound = true
for i = 0 to len * 2
if isHigh and src[i] > p
isFound := false
if not isHigh and src[i] < p
isFound := false
if isFound
label.new(bar_index[len], p, tostring(p), style=_style, yloc=_yloc, color=_color)
line.new(bar_index[len], p, bar_index, p, extend=extend.right, color=_color)
fun 함수 안에 있는 변수는 src, len, isHigh, _style, _yloc, _color 총 6개다. 이때 src는 source의 약자로 high, low와 같은 주가 데이터를 입력 받는다. len은 lenH와 lenL의 값을 입력 받는다. isHigh는 고점을 판별하는지 저점을 판별하는지를 알려주는 bool형 변수다. 이외 style, yloc, color는 라벨과 지지저항선의 스타일, 위치, 색깔을 정해준다.
p = nz(src[len])에서 nz는 NaN 값을 0으로 return 해주는 함수다. src[len]의 경우 현재 캔들로부터 몇 번째 캔들인지를 의미한다. 예를 들어 len이 20이라고 했을 때 high[20] 또는 low[20]은 현재 캔들 이전의 20번째 캔들의 고가 또는 저가를 의미한다. 하지만 차트는 무제한이 아니므로 20번째 이전 캔들이 존재하지 않을 수 있다. 이 경우 NaN, 즉 Not a Number가 출력되고 nz 함수는 이 NaN 값을 0으로 변환해 p에 할당한다. 반면 값이 존재하는 일반적인 경우에는 해당 값을 p에 할당한다. 정리하면 p는 현재 캔들의 이전 len번째 캔들의 고가 또는 저가의 수치를 할당 받는 변수다.
isFound는 고가 또는 저점, 즉 pivot point를 찾았는지를 알려주는 boolean 변수다. default 값은 true로 설정되어 있다.
그 이후 for문이 나오는데 for문은 i=0부터 len*2까지 반복한다. for문에 들어가면 우선 isHigh가 true인지, 그리고 src[i]가 p보다 큰지 작은지를 확인한다. isHigh가 true라는 뜻은 고점을 찾고 있다는 뜻이다. 반대로 not ifHigh는 현재 고점을 찾고 있지 않다, 즉 저점을 찾고 있음을 의미한다. 그리고 src[i]는 high[i]또는 low[i]를 의미한다. 처음에 i=0이므로 현재 캔들부터 이전 len*2번째 캔들까지를 확인한다.
고점(저항선의 pivot point)를 찾을 때는 high[0]부터 high[40]의 값들이 하나라도 p보다 크면 isFound에 false 값이 할당된다. 이때 p는 high[20]이며 high[20] 기준 앞뒤 캔들 총 39개 중 고가가 high[20]의 캔들의 고가보다 높은 캔들이 하나라도 있으면 isFound는 false가 되고 if isFound 조건문은 작동하지 않는다. if isFound가 작동하려면 isFound = true여야 하고 if isHigh and src[i]>p 조건을 만족하지 않아야 한다. 즉 high[20] 기준 앞뒤 캔들 총 39개의 고가 모두 high[20]의 고가보다 낮은 값이어어야 한다는 뜻이다. 이 경우 if isHigh and src[i] > p 조건문은 작동하지 않고 isFound는 true로 유지되어 if isFound 조건문이 작동한다.
if isFound 조건문이 작동하는 경우 label.new 함수와 line.new 함수가 작동한다.
label.new의 경우 x 좌표(캔들 위치), y 좌표(가격)를 입력 받는다. 그리고 라벨에 들어갈 text를 입력받는다. 이외 라벨 화살표의 방향(style), 라벨의 위치(line에 대한 위치), 색깔 등도 입력 받는다.
label.new(bar_index[len], p, tostring(p), style=_style, yloc=_yloc, color=_color)
여기서 bar_index[len]은 캔들의 위치를 의미한다. bar_index[20]은 현재 캔들로부터 이전 20번째 캔들을 의미한다. 그리고 tostring(p)를 이용해 캔들의 고가를 라벨에 입력한다. 이외는 라벨의 스타일, 색깔을 결정하는 코드다.
line.new(bar_index[len], p, bar_index, p, extend=extend.right, color=_color)
line.new의 경우도 마찬가지다. 다만 지지선이 오른쪽으로 쭉 연장되도록 extend 변수가 추가되었다.
[Copy and Paste용 코드]
//@version=4
study('Pivots High&Low', overlay=true)
lenH = input(title='Length High', type=input.integer, defval=20, minval=1)
lenL = input(title='Length Low', type=input.integer, defval=20, minval=1)
fun(src, len, isHigh, _style, _yloc, _color) =>
// len 이전 값 : src[len]
// nz : 값이 없으면 0으로 만들어준다.
p = nz(src[len])
isFound = true
for i = 0 to len * 2
// High를 구할 때는, p 보다 큰 값이 있는지 확인한다.
if isHigh and src[i] > p
// 더 큰 값이 있으면 src[len] 은 Pivot High가 아니다.
isFound := false
// Low를 구할 때는, p 보다 작은 값이 있는지 확인한다.
if not isHigh and src[i] < p
// 더 작은 값이 있으면 src[len] 은 Pivot Low가 아니다.
isFound := false
if isFound
// 새로 라벨을 생성한다.
// x 좌표는 bar_index[len] : 현재 bar에서 len 이전
label.new(bar_index[len], p, tostring(p), style=_style, yloc=_yloc, color=_color)
line.new(bar_index[len], p, bar_index, p, extend=extend.right, color=_color)
fun(high, lenH, true, label.style_labeldown, yloc.abovebar, color.red)
fun(low, lenL, false, label.style_labelup, yloc.belowbar, color.lime)
'Pine Script > Indicator' 카테고리의 다른 글
[Indicator] RSI Divergence Finder, 파인스크립트로 RSI 다이버전스 찾기 (0) | 2022.09.04 |
---|
댓글