안녕하십니까 오늘은 제가 읽었던 "추세매매 절대원칙" 이라는 책에서 "추세"란 무엇일까 하여 개발 해보고 싶어 작성한 추세 파악 지표에 대해서 알려드릴까 합니다.


기본적으로 추세란 무엇일까요?

추세란, 데이터, 현상 등이 일정한 방향으로 움직이는 경향을 말합니다.

추세는 시장의 중요한 개념으로, 금융시장에서는 특히 가격의 지속적인 방향성을 나타냅니다.

  • (추세를 파악하면 시장의 흐름을 예측하고 적절한 투자 결정을 내리는 데 큰 도움이 됩니다.)

그러면 우리는 이 추세를 알아내기 위해서 어떠한 지표를 사용할 수 있을까요?

예시로는 Super Trend, 이동평균선, 거래량, 추세선, RSI 등 여러가지가 있는데요, 저는 오늘 "이동평균선""이평선"을 통해서 추세 파악을 하는 지표를 만들어볼까 합니다.

자, 그러면 해당 지표를 개발하기 위해서는 가장 먼저 이평선에 대하여 알아봐야겠죠?


이평선(이동평균선)이란?

이동평균선은 특정 기간 동안의 가격 데이터를 평균 내어 계산한 값을 시간에 따라 연결한 선입니다.

이동평균선은 가격의 변동성을 줄이고, 주된 추세를 더 명확하게 보여주는 도구로 사용됩니다. 주식, 외환, 암호화폐 등 다양한 금융 시장에서 활용되며, 기술적 분석의 핵심 지표 중 하나입니다.

간단하게 이평선을 설명해보았습니다. 그러면 이 이평선이 왜 추세를 나타내고, 왜 중요한지를 알아봐야겠죠?


이평선은 왜 추세를 나타내고, 왜 중요할까?

이평선이 중요한 이유

  • 가격의 방향성 파악: 이동평균선은 시장의 방향성을 시각적으로 나타내어, 상승, 하락, 또는 횡보 추세를 쉽게 파악할 수 있게 합니다.
  • 노이즈 제거: 가격의 단기적 변동성을 평균화하여, 장기적인 추세를 더 명확히 보여줍니다.
  • 심리적 지지와 저항 역할: 이동평균선은 종종 투자자들 사이에서 지지선(가격이 이동평균선 아래로 내려가지 않는 경우)이나 저항선(가격이 이동평균선을 넘지 못하는 경우)으로 인식됩니다.

우리가 중요하게 봐야할 것은 "이평선의 가격의 방향성 파악" 입니다.

과거의 데이터을 사용하여 이동평균선을 그린다는 것은 거의 모두가 아는 사실 일 것 입니다.

말 그대로 (최근의)과거 데이터를 사용한다는 것 이지요.

잡다한 긴 말 때려치우고 근거를 드려보겠습니다.

1. 수학적 근거: 평균의 특성과 노이즈 제거

이동평균선은 가격의 평균값을 계산한 결과입니다. 이는 가격 변동에서 다음과 같은 특성을 제공합니다:

  • 데이터의 안정화: 가격은 단기적으로 급등락할 수 있지만, 이동평균은 이러한 변동성을 평균화하여 노이즈를 제거합니다.
    • 노이즈가 제거되면 가격의 방향성과 변화 추세가 명확히 드러납니다.
  • 경향성의 확인: 평균값은 가격이 오랜 기간 동안 어떤 방향으로 움직였는지를 나타냅니다.
    • 상승 중이라면 평균값도 상승하고, 하락 중이라면 평균값도 하락합니다.
    • 즉, 가격의 중심적인 움직임을 반영하기 때문에 추세의 지표로 사용됩니다.

2. 시장 구조적 요인: 수요와 공급의 균형

  • 시장은 추세를 형성하는 경향이 있음: 시장에서 가격은 수요와 공급의 불균형으로 인해 특정 방향(상승 또는 하락)으로 움직입니다.
    • 상승 추세: 매수자가 우위 → 평균 가격도 상승
    • 하락 추세: 매도자가 우위 → 평균 가격도 하락
  • 지속성의 원칙: 시장은 관성(momentum)을 가지며, 한 번 형성된 추세는 외부 충격이 없는 한 지속되는 경향이 있습니다. 이동평균선은 이러한 추세를 따라가며 이를 시각적으로 나타냅니다.

3. 심리적 근거: 군중 행동과 지지/저항 역할

  • 군중 심리에 의한 자가 실현적 성격:
    • 이동평균선은 많은 시장 참여자들이 추세를 판단하는 기준으로 사용합니다.
    • 트레이더들은 이동평균선을 보고 매수/매도 결정을 내리며, 그 결과 이동평균선은 실제로 가격의 추세를 형성하거나 강화하게 됩니다.
    • 예: 가격이 이평선 위에 있다면 상승 추세로 간주하고 매수, 아래에 있다면 매도로 이어져 추세를 유지.
  • 지지선 및 저항선 역할:
    • 가격이 이동평균선 근처에 다가오면, 투자자들은 이를 지지 또는 저항으로 인식하여 매매 활동을 증가시킵니다.
    • 이는 이동평균선이 가격의 변곡점을 결정하는 데 중요한 역할을 함을 의미합니다.

4. 기간의 선택에 따른 다양한 추세 해석

이동평균선은 기간(단기, 중기, 장기)에 따라 가격의 추세를 다르게 해석할 수 있습니다.

  • 단기 이동평균선: 최근 가격 변화를 민감하게 반영 → 단기적 추세를 나타냄.
  • 장기 이동평균선: 전체적인 시장의 방향성을 나타냄 → 장기적 추세를 확인.
  • 두 선이 교차할 때(예: 골든 크로스, 데드 크로스)는 새로운 추세의 시작으로 해석.

이러한 다층적인 해석은 투자자들이 추세를 다각도로 분석하고, 이를 매매 전략에 통합할 수 있도록 돕습니다.


5. 기술적 분석과의 통합적 역할

  • 가격 대비 상대적 위치 파악: 이동평균선은 현재 가격이 평균적인 가격 수준에 비해 얼마나 높은지 또는 낮은지를 확인하는 데 유용합니다.
    • 가격이 이동평균선 위에 있으면 상승 추세로, 아래에 있으면 하락 추세로 해석.
  • 다른 지표와의 조합: 이동평균선은 MACD, RSI와 같은 다른 기술적 지표와 결합하여 추세의 강도와 변화를 더 명확히 판단하는 데 사용됩니다.

6. 경제학적 근거: 평균 회귀와 추세 추종

  • 평균 회귀(Mean Reversion): 가격은 이동평균선으로 되돌아가려는 성향이 있습니다.
    • 극단적으로 과매수 또는 과매도된 상황에서, 가격은 평균값으로 회귀하려는 경향을 보입니다.
    • 이동평균선은 이러한 평균 회귀의 중심 축 역할을 합니다.
  • 추세 추종(Trend Following): 한 번 형성된 추세는 계속해서 이어질 가능성이 높으며, 이동평균선은 이를 확인하고 추적하는 데 도움을 줍니다.

자, 이제 이러한 많은 근거가 나와있는 상황에서 과연 이동평균선을 의심할 수 있을까요? 아직도 당신이 이동평균선을 의심하고 있다면. 안타까운거죠.

자, 이렇게 여러 긴 설명이 끝났으니 바로 개발에 들어가보려 합니다.

긴글을 읽어주신 여러분에게 감사를 표합니다.

개발

먼저, 저는 개발을 할 때 여러 경우의 수에 대한 대비를 하는 것이 옳다고 생각하며 그것을 생각하는 것을 즐깁니다.

그래서 이동평균선이 하나만 있는가에 대해서 먼저 생각을 합니다.

아니죠. 이동평균선(Moving Average)은 여러가지 있습니다. 예를 들어서 EMA, SMA, RMA, WMA 등 여러가지가 있지요. 저는 이 지표를 만들 때 해당 지표를 몇가지 넣어 사용자가 여러 경우의 수를 생각할 수 있게 생각하려 합니다.

바로 코드를 공개해드리겠습니다.

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cth_release

//@version=5
indicator("추세 파악 지표", overlay=true)

type10 = input.string(defval = "SMA", title = "ma 10 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type20 = input.string(defval = "SMA", title = "ma 20 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type50 = input.string(defval = "SMA", title = "ma 50 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type100 = input.string(defval = "SMA", title = "ma 100 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type140 = input.string(defval = "SMA", title = "ma 140 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type200 = input.string(defval = "SMA", title = "ma 200 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")

ma(source, length, _type) =>
    switch _type
        "SMA" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

ma10 = ma(close, 10, type10)
ma20 = ma(close, 20, type20)
ma50 = ma(close, 50, type50)
ma100 = ma(close, 100, type100)
ma140 = ma(close, 140, type140)
ma200 = ma(close, 200, type200)

upTrend1 = ma10[1] < ma10
upTrend2 = ma20[1] < ma20
upTrend3 = ma50[1] < ma50
upTrend4 = ma100[1] < ma100
upTrend5 = ma140[1] < ma140
upTrend6 = ma200[1] < ma200

downTrend1 = ma10[1] > ma10
downTrend2 = ma20[1] > ma20
downTrend3 = ma50[1] > ma50
downTrend4 = ma100[1] > ma100
downTrend5 = ma140[1] > ma140
downTrend6 = ma200[1] > ma200

plot(ma10, "MA 10", upTrend1 ? color.green : downTrend1 ? color.red : color.gray)
plot(ma20, "MA 20", upTrend2 ? color.green : downTrend2 ? color.red : color.gray)
plot(ma50, "MA 50", upTrend3 ? color.green : downTrend3 ? color.red : color.gray)
plot(ma100, "MA 100", upTrend4 ? color.green : downTrend4 ? color.red : color.gray)
plot(ma140, "MA 140", upTrend5 ? color.green : downTrend5 ? color.red : color.gray)
plot(ma200, "MA 200", upTrend6 ? color.green : downTrend6 ? color.red : color.gray)

코드가 .. 더러운 것은 이해해주시길 바랍니다.

간단하게 말해서, MA선을 짧은 것 부터, 긴 것대로 이전봉과 현재봉의 가격을 비교 후 이전봉보다 가격이 높다면 상향세, 낮다면 하향세를 표시하도록 해봤습니다.

해당 코드를 추가하면 이런식으로 좀 선이 많은 코드가 추가 될 것 입니다.

저는 이 사용자의 눈 아픈 고통을 좀 덜어주려 합니다. 바로 Donchian 채널을 사용하여 추세와, 고점과 저점만 보여주는 것 입니다!

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cth_release

//@version=5
indicator("추세 파악 지표", overlay=true)

type10 = input.string(defval = "SMA", title = "ma 10 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type20 = input.string(defval = "SMA", title = "ma 20 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type50 = input.string(defval = "SMA", title = "ma 50 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type100 = input.string(defval = "SMA", title = "ma 100 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type140 = input.string(defval = "SMA", title = "ma 140 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type200 = input.string(defval = "SMA", title = "ma 200 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")

ma(source, length, _type) =>
    switch _type
        "SMA" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

ma10 = ma(close, 10, type10)
ma20 = ma(close, 20, type20)
ma50 = ma(close, 50, type50)
ma100 = ma(close, 100, type100)
ma140 = ma(close, 140, type140)
ma200 = ma(close, 200, type200)

upTrend1 = ma10[1] < ma10
upTrend2 = ma20[1] < ma20
upTrend3 = ma50[1] < ma50
upTrend4 = ma100[1] < ma100
upTrend5 = ma140[1] < ma140
upTrend6 = ma200[1] < ma200

downTrend1 = ma10[1] > ma10
downTrend2 = ma20[1] > ma20
downTrend3 = ma50[1] > ma50
downTrend4 = ma100[1] > ma100
downTrend5 = ma140[1] > ma140
downTrend6 = ma200[1] > ma200

// plot(ma10, "MA 10", upTrend1 ? color.green : downTrend1 ? color.red : color.gray)
// plot(ma20, "MA 20", upTrend2 ? color.green : downTrend2 ? color.red : color.gray)
// plot(ma50, "MA 50", upTrend3 ? color.green : downTrend3 ? color.red : color.gray)
// plot(ma100, "MA 100", upTrend4 ? color.green : downTrend4 ? color.red : color.gray)
// plot(ma140, "MA 140", upTrend5 ? color.green : downTrend5 ? color.red : color.gray)
// plot(ma200, "MA 200", upTrend6 ? color.green : downTrend6 ? color.red : color.gray)

upTrend = (upTrend1 ? 1 : 0) + (upTrend2 ? 1 : 0) + (upTrend3 ? 1 : 0) + (upTrend4 ? 1 : 0) + (upTrend5 ? 1 : 0) + (upTrend6 ? 1 : 0)
downTrend = (downTrend1 ? 1 : 0) + (downTrend2 ? 1 : 0) + (downTrend3 ? 1 : 0) + (downTrend4 ? 1 : 0) + (downTrend5 ? 1 : 0) + (downTrend6 ? 1 : 0)

length = input.int(20, minval = 1, group = "Donchian 채널")
lower =  ta.lowest(length)
upper =  ta.highest(length)
basis =  math.avg(upper, lower)
plot(basis,     "Basis", color.yellow)
u = plot(upper, "Upper", color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d)
l = plot(lower, "Lower", color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d)
fill(u, l, color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d, title = "Background")

이렇게 코드를 추가해준다면,

이렇게 우리의 눈을 조금 더 편하게 해주는 지표가 탄생할 것 입니다.

하지만 약간 뭔가 더 부족한 느낌 입니다. 그래서 무엇이 더 이 지표를 보는 사람이 더 편하게 볼 수 있을지, 생각을 하는 도중 전 캔들의 고점과, 저점에 대하여 평균을 구해 이평선을 그려넣는 것 입니다. (이것으로 손절 및 추세에 대한 정보를 얻을 것)

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cth_release

//@version=5
indicator("추세 파악 지표", overlay=true)

type10 = input.string(defval = "SMA", title = "ma 10 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type20 = input.string(defval = "SMA", title = "ma 20 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type50 = input.string(defval = "SMA", title = "ma 50 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type100 = input.string(defval = "SMA", title = "ma 100 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type140 = input.string(defval = "SMA", title = "ma 140 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")
type200 = input.string(defval = "SMA", title = "ma 200 type", options = ["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group = "추세 파악 관련")

ma(source, length, _type) =>
    switch _type
        "SMA" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

ma10 = ma(close, 10, type10)
ma20 = ma(close, 20, type20)
ma50 = ma(close, 50, type50)
ma100 = ma(close, 100, type100)
ma140 = ma(close, 140, type140)
ma200 = ma(close, 200, type200)

upTrend1 = ma10[1] < ma10
upTrend2 = ma20[1] < ma20
upTrend3 = ma50[1] < ma50
upTrend4 = ma100[1] < ma100
upTrend5 = ma140[1] < ma140
upTrend6 = ma200[1] < ma200

downTrend1 = ma10[1] > ma10
downTrend2 = ma20[1] > ma20
downTrend3 = ma50[1] > ma50
downTrend4 = ma100[1] > ma100
downTrend5 = ma140[1] > ma140
downTrend6 = ma200[1] > ma200

// plot(ma10, "MA 10", upTrend1 ? color.green : downTrend1 ? color.red : color.gray)
// plot(ma20, "MA 20", upTrend2 ? color.green : downTrend2 ? color.red : color.gray)
// plot(ma50, "MA 50", upTrend3 ? color.green : downTrend3 ? color.red : color.gray)
// plot(ma100, "MA 100", upTrend4 ? color.green : downTrend4 ? color.red : color.gray)
// plot(ma140, "MA 140", upTrend5 ? color.green : downTrend5 ? color.red : color.gray)
// plot(ma200, "MA 200", upTrend6 ? color.green : downTrend6 ? color.red : color.gray)

upTrend = (upTrend1 ? 1 : 0) + (upTrend2 ? 1 : 0) + (upTrend3 ? 1 : 0) + (upTrend4 ? 1 : 0) + (upTrend5 ? 1 : 0) + (upTrend6 ? 1 : 0)
downTrend = (downTrend1 ? 1 : 0) + (downTrend2 ? 1 : 0) + (downTrend3 ? 1 : 0) + (downTrend4 ? 1 : 0) + (downTrend5 ? 1 : 0) + (downTrend6 ? 1 : 0)

length = input.int(20, minval = 1, group = "Donchian 채널")
lower =  ta.lowest(length)
upper =  ta.highest(length)
basis =  math.avg(upper, lower)
plot(basis,     "Basis", color.yellow)
u = plot(upper, "Upper", color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d)
l = plot(lower, "Lower", color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d)
fill(u, l, color = upTrend == 6 ? color.rgb(76, 175, 79, 68) : downTrend == 6 ? color.rgb(255, 82, 82, 69) : #fbfcfc1d, title = "Background")

highMaLength = input.int(10, "고점 평균 길이", group = "util")
lowMaLength = input.int(10, "저점 평균 길이", group = "util")

plot(ta.ema(high, highSmaLength), "고점 평균", color.blue, 2)
plot(ta.ema(low, lowSmaLength), "저점 평균", color.red, 2)

네. 간단합니다.



나머지 설명은 아래 지표 Release에서 확인해주세요!

Market Trend Identification Indicators by cth_release — TradingView
# It is an indicator for trend identification. Overview When you add the indicator, the Donchian Channel, the high-point moving average line, and the low-point moving average line are displayed. These elements can help you identify trends. Uptrend: If the background of the Donchian Channel appears green, it indicates a basic uptrend. Furthermore, if the price is above the high-point moving average line, it confirms a strong uptrend. Downtrend: If the background of the Donchian Channel …

안녕하십니까! 저는 2005년생 신입 개발자 최태혁 이라고 합니다!

주로 블록체인, 웹 사이트 관련으로 개발을 하며, 투자에 큰 관심을 두고 있습니다!

저와 같이 투자에 대한 이야기, 개발에 대한 이야기를 나누고 싶으시다면! 아래의 링크로 디스코드로 와서 이야기 해보아요!

(100회 초대 코드 만료 되었다면 다른 최신 게시글에서 클릭 해주세요!)

어둠의 cth 교단 Discord 서버에 가입하세요!
Discord에서 어둠의 cth 교단 커뮤니티를 확인하세요. 41명과 어울리며 무료 음성 및 텍스트 채팅을 즐기세요.

(정신 놓고 채팅하는 곳이고.. 예의와 범절이 없을 수도 있으니 그냥 편하게 이야기를 나누고 싶으신 분들만 와주시길 바랍니다!)

긴 글 읽어주셔서 감사합니다!