앞으로 C++로 개발할 일이 많아질 것 같아 기본적인 문법들을 이해하고자 작성함.

 

# 접근지정자

접근 지정자에는 크게 public, private, protected가 있다. 접근지정자는 C++에서 클래스안의 멤버함수와 멤버변수에 접근 여부를 제어할 때 사용한다. public에 멤버함수나 멤버변수를 두면 클래스 외부를 포함한 모든 곳에서 접근가능하다. private에 멤버변수나 멤버변수를 두면 클래스 내부에서만 접근가능하고 외부에서는 접근할 수 없다. protected는 상속과 관련됨 (추가 이해 필요)

 

# this

C++에서 this는 클래스의 실제 인스턴스에 대한 주소를 가리키는 포인터다. 클래스의 모든 함수는 함수가 호출된 객체를 가리키는 this 포인터를 갖는다. 이는 컴파일러가 동작하는 과정에서 implicit하게 this 포인터를 사용가능하도록 만들기 때문이다. this 포인터는 크게 두 가지 측면으로 활용된다. 첫 번째는 멤버변수와 매개변수의 이름이 같을 때 구분할 수 있고, 두 번째는 함수에서 *this를 반환하는 방식으로 함수체이닝으로 코드를 간결하게 작성할 수 있다.

 

# auto

auto는 자료형을 자동으로 추론할 때 사용한다. 예를 들어 다음과 같다.

int main(void)
{
	int a = 5;
    int b = 21;
    auto sum = a + b;
}

별도의 int, float, double, char 등을 지정해주지 않아도 자동 타입추론을 통해 자료형을 할당한다.

 

 

# 람다함수

람다함수는 메모리 효율을 위해 사용한다. 일반 함수와 달리 함수명이 없는 것이 특징이다. 람다함수의 구조는 크게 4가지로 구성된다. [](){}()다. 역할을 먼저 설명하면 가장 첫번째인 []는 캡처, ()는 매개변수, {}는 함수동작, ()는 호출인자다. []인 캡처는 매개변수와 동일하게 값을 받아와 사용할 수 있다. call-by-value 또는 call-by-reference로 받아올 수 있다. call-by-value는 외부변수를 변경하지 않을때 사용하고 call-by-reference는 외부변수를 변경할 때 사용한다. 예를 들어 call-by-reference로 사용할 때는 다음과 같다.

 

int main(void)
{
	int r1 = 1;
    int r2 = 2;
    
    [r1, r2](int a, int b)
    {
    	cout << r1 + r2 + a + b << endl;
    }
}

 

call-by-reference로 사용할 때는 다음과 같다.

int main(void)
{
	int r1 = 1;
    int r2 = 2;
    
    [&r1, &r2](int a, int b)
    {
    	r1 = 2;
        r2 = 4;
        cout << r1 + r2 + a + b << endl;
    }
}

 

캡처는 이외에도 [=]를 통해 외부변수 전체를 복사해 가져올 수도 있고 [&]를 통해 외부변수 전체를 참조할 수도 있다.

 

람다함수 구조의 두 번째인 ()는 매개변수를 의미한다. 위 코드에서 (int a, int b)와 같다. 세 번째인 {}는 동작할 함수 동작이다. 위 코드 예시에서는 값을 더해주고 출력하는 것이다. 네 번째인 ()는 두 번째 매개변수와 다른 호출인자다. (int a, int b)에 실질적으로 넣어줄 값을 의미한다. 

 

문제 상황

Node JS에서 MySQL에 Update 쿼리를 날렸을 때 당최 쿼리가 반영되지 않았다. 나의 경우에는 HTML selectbox에서 A, B, C 값 중 하나를 선택하면 ajax를 이용해 MySQL에 업데이트하는 간단한 기능을 구현하고 싶었다. 하지만 업데이트 되지 않았고 결과를 출력해보니 아래와 같이 출력됐다.

 

OkPacket {
  fieldCount: 0,
  affectedRows: 0,
  insertId: 0,
  serverStatus: 2,
  warningCount: 0,
  message: '(Rows matched: 0  Changed: 0  Warnings: 0',
  protocol41: true,
  changedRows: 0
}

 

쿼리는 에러없이 실행되었지만 중요한 것은 Rows matched: 0 Changed: 0이라고 출력된 부분이다. 분명 쿼리 실행 이전, selectbox에서 값도 잘 받아왔고 쿼리문도 문제 없이 작성했지만 결과에 반영 되지 않았다. 직접 MySQL Workchbench로 값을 수정하면 반영이 잘되었고, 권한 문제도 없었기에 원인을 더욱 찾지 못해 아까운 시간 하루를 시간을 낭비했다.

 

에러 해결 방법

원인은 쿼리였다. 늘 사용했었고 다른 기능 구현에도 원활히 실행 됐었기에 문제가 없을 것이라 생각했다. 사용했던 쿼리는 다음과 같다.

const query = `UPDATE users SET column = ? WHERE username = ?`
return new Promise((resolve, reject) => {
	db.query(query, [value, username], (error, result) => {
    	if (error)
        	throw (error);
        else
        	reject(true);
    })
})

하지만 위와 같은 구문을 사용할 것이 아니라 아래와 같이 변경할 컬럼과 값, 조건문과 조건값을 별도의 변수에 담은 뒤 입력해주어야 한다.

const values = {'column': value};
const condition = {'username': username};
const query = `UPDATE users SET ? WHERE ?`;
return new Promise((resolve, reject) => {
    db.query(query, [values, condition], (error, result) =>{
        if (error)
            throw (error);
        else
            resolve(true);
    })
})

 

위와 같은 구문을 사용해 Update 문을 실행하면 아래와 같이 업데이트가 이루어지는 것을 확인할 수 있다.

 

 

애석하게도 원인의 본질적인 문제는 찾진 못했다. 다만 SQL Injection 방지를 위해 '?'를 사용해 쿼리를 실행하는 prepared statement와 관련이 있는 것으로 보인다. 구글에서 해결 방법을 찾기 어려워 혹시나 하는 마음으로 ChatGPT에게 질의한 결과로 얻은 해결방법이었다. 에러는 해결했지만 마음 한 구석에 세상의 발전에 대한 환희감과 동시에 인간의 지위에 대한 박탈감을 느꼈다. 단순히 이 문제에 대한 해답만이 아니라 여러 학문에 대한 답과 철학적인 질문들에도 막힘없는 대답을 들을 수 있었기 때문이다. ChatGPT가 열어갈 미래와 변화할 사회 모습이 궁금해지는 대목이다.

문제 상황

Node JS 다루다 보면 자주 마주치는 오류라고 한다. property가 없어서 발생한다고 하지만 분명 값이 있었기에 당최 그 이유를 알 수 없었다. 내가 이 오류를 마주한 구문은 try catch이었다. try와 catch 각각의 return 구문이 있었고, 신기하게도 try에서도 return되고 catch에서도 return 되는 기이한 현상이었다. 또 이와 더불어 console.log에 값이 두 개씩 찍힌다는 것도 문제였다. 하나는 올바른 값이 들어 있지만 하나는 값 없이 undefined만 출력됐다. 어디가 문제인지, 무엇이 문제인지, 무엇을 모르는지 올바르게 떠올리지 못해 거의 하루를 낭비했다.

 

나의 경우는 HTML 쪽이 문제였다. 정확히는 form에서 submit이 실행될 때 이벤트를 듣고 있는 addEventListener 함수가 문제였다. 생각지도 못했다. 아래와 같이 addEventListener 함수를 한 번 호출했지만 계속해서 두 번씩 호출되고 있었고 이 때문에 console.log 값이 두 번씩 찍혔다.

"use strict";

const name = document.querySelector("#name"),
    email = document.querySelector("#email"),
    submitBtn = document.querySelector("#submit");

submitBtn.addEventListener("click", findUsername);

 

해결 방법

addEventListener 함수가 두 번씩 호출되고 console.log가 두 번씩 출력되는 이유는 아래와 같이 HTML의 form에서 onsubmit="return false;"이 빠져있다면 addEventListener가 두 번씩 호출되기 때문이다. 정확히는 onsubmit이 form에서 submit이 실행되면 발생하는 이벤트 핸들러로 기본값이 true로 되어 있기 때문에 addEventLitener와 중복되어 두 번씩 실행되는 것이다. 

<form class="login-form" action="/find-username" method="post">
    <h4>이름과 이메일을 입력해주세요.</h4>
    <input id="name" type="name" placeholder="이름"/>
    <input id="email" type="email" placeholder="이메일"/><br><br>
    <input type="submit" id="submit" value="확인">

따라서 위와 달리 onsubmit="return false;"를 추가해주면 더 이상 console.log에서 두 번 출력되지 않고 값도 undefined로 출력되지 않는다. 

<form class="login-form" action="/find-username" method="post" onsubmit="return false;">
    <h4>이름과 이메일을 입력해주세요.</h4>
    <input id="name" type="name" placeholder="이름"/>
    <input id="email" type="email" placeholder="이메일"/><br><br>
    <input type="submit" id="submit" value="확인">

RuntimeError: CUDA error: device-side assert triggered

Traceback (most recent call last):
  File "main.py", line 70, in <module>
    trainer.train()
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\transformers\trainer.py", line 463, in train
    tr_loss += self._training_step(model, inputs, optimizer)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\transformers\trainer.py", line 580, in _training_step
    outputs = model(**inputs)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\nn\modules\module.py", line 1051, in _call_impl
    return forward_call(*input, **kwargs)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\transformers\modeling_bert.py", line 1284, in forward
    loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\nn\modules\module.py", line 1051, in _call_impl
    return forward_call(*input, **kwargs)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\nn\modules\loss.py", line 1121, in forward
    ignore_index=self.ignore_index, reduction=self.reduction)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\nn\functional.py", line 2824, in cross_entropy
    return torch._C._nn.cross_entropy_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)
RuntimeError: CUDA error: device-side assert triggered

 

에러를 해결하는 과정에서 pytorch 버전 변경, cuda 버전 변경, 환경변수 설정 등을 잘해주라는 답변으로 인해 시간을 다소 낭비했다. 나의 경우는 pre-trained 모델 로딩할 때 매개변수로 num_labels를 입력해주어야 한다는 것을 알지 못해 발생한 문제였다. 아래와 같이 데이터셋의 라벨 개수와 맞도록 입력해주면 된다.

 

model = BertForSequenceClassification.from_pretrained(MODEL_NAME, num_labels=4).to(device)

(만약 위와 같이 num_labels를 설정해주어도 에러가 발생한다면 라벨의 인덱스를 확인해 0부터 시작하는지 확인해야 한다. 1부터 시작하도록 설정했더니 위와 같은 에러가 또 발생했었음)

 

다음은 위 에러를 조우하기 전 발생했던 에러다. 

RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`

 

Traceback (most recent call last):
  File "main.py", line 65, in <module>
    trainer.train()
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\transformers\trainer.py", line 463, in train
    tr_loss += self._training_step(model, inputs, optimizer)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\transformers\trainer.py", line 592, in _training_step
    loss.backward()
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\_tensor.py", line 255, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph, inputs=inputs)
  File "C:\Users\roytravel\anaconda3\envs\kochat\lib\site-packages\torch\autograd\__init__.py", line 149, in backward
    allow_unreachable=True, accumulate_grad=True)  # allow_unreachable flag
RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`

 

이는 아래 환경변수 설정으로 해결하였다.

import os
os.environ['CUDA_LAUNCH_BLOCKING'] = "1"
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

최근, 향후 창업을 준비하고자 몇몇 세미나를 듣고 있다. 이번이 세 번째다. 어제는 (2022.07.26(화) 16:00~18:00) 스타트업 해외진출 관련하여 마곡, 서울창업허브 (M+)에서 "Awake, It's time to innovation Asia"라는 주제로 세미나를 들었다. 연사는 엑센트리벤처스의 윤우근 이사회 의장이다. 엑센트리는 런던베이스 엑셀러레이터로, 스타트업이 런던쪽에 랜딩할 수 있도록 자본 지원과 프로그램을 제공한다고 한다. 오늘 세미나의 핵심 내용은 간단했다. 스타트업의 해외 진출을 위해선 6~7가지로 요약할 수 있었다.

 

첫 번째로는 스타트업의 핵심기술이 글로벌 IP(Intellectual Property)로 보호받고 있어야 하는 것이다. 그 이유는 대기업의 기술 탈취가 심하기 때문이라 한다. 법정 공방에서도 중소기업 vs 대기업 구도에서 중소기업의 패소율이 84%에 달하며 대기업은 0.2%이란 수치를 볼 수 있었다. 보통 선진국에서는 약자 보호 시스템이 마련되어 있지만 우리나라는 그렇지 않다는 것이다. 그렇기에 핵심 기술이 글로벌 IP로 보호받고 있어야 해외진출이 가능하다 말한다. 두 번째는 전 세계에 핵심 기술을 알릴 홍보맨이 반드시 필요하다는 것이다. 홍보맨은 CEO만큼 제품이나 서비스를 잘 알고 있는 사람이여야 하며, 투자유치를 위해 계속해서 IR도 함께 해야 한다고 한다. 쓰는 시점에서 헷갈리는 데, IR은 대표의 역할인지 홍보맨의 역할인지 아니면 아무나 해도 상관 없는지 헷갈린다. IR에 대해 들으며 들었던 생각으론 가급적이면 외부 자본을 차입하지 않고 외부 자본에 독립적인 기업을 만들 수 있다면 가장 좋지 않을까 하는 생각이 들었다. 세 번째는 영어라고 말한다. 더 말하지 않아도 필요성을 절감한다. 창업 직전에는 어느 정도 네이티브와 비즈니스 영어를 문제 없이 구사하는 것을 목표로 하고 있다.

 

네 번째는 현지 모임에서 동양인, 한국인을 찾아 일원이 되어야 한다고 말한다. 런던 스타트업은 주로 60%~70%가 서양인이라 우리도 그렇듯 어느정도 차별이 있을 수 있기 때문이라 말한다.  다섯 번째는 정부지원 등 각종 프로그램을 타고 해외로 진출하는 것이 그나~마 성공 확률이 높다고 말한다. 여섯 번째는 현지 밴처캐피털이나 CEO와 밋업을 하는 것이라 말하고, 일곱 번째는 잠재적 고객과의 만남이라고 한다. 또 중요한 것은 Global standard 수립이라는 것이다. 삼성과 SK케미칼과 같이 1,2차 벤더사가 되기 위해서는 회계나 법률적인 부분을 6개월간 수정을 거쳐 일종의 표준화를 시키는 과정이 있다는 것이다. 여기까지가 들었던 핵심 내용이다.

 

이외의 내용으론 몇몇이 있었는데 그 중 첫 번째는 유니콘 기업 관련 산업이었다. 전세계 유니콘 기업이 약 1,170(?)개가 있고 미국 629개, 중국 173개, 인도 68개, 영국 44, 독일 29, 프랑스 24, 이스라엘 22 등등이 있다고 한다. 이러한 유니콘 기업은 대부분 헬스케어, 전기차, 빅데이터, 바이오이지만 한국에는 이러한 기업이 없고, 따라서 기회가 있다고 한다. 두 번째는 창업은 돌파구라고 말하며 창업은 돈이 아니라 소명의식이 필요하다 말한다. 절감한다. 소명의식의 예로는 사회공헌이나 고용창출이 있다고 말했다. 고용창출은 생각해본 적 없었지만 유니콘 기업 하나가 많은 고용창출을 하여 사회에 도움이 된다고 한다.

 

세 번째는 지금은 산업간의 경계가 모호한 빅테크의 시대라고 말한다. 단계를 밟아가면 느릴 수 있다고 말한다. 뛰어넘어야 관심받고 투자 받는다고 한다. 중국이 현금 사용하다가 곧 바로 QR로 넘어간 것을 예를 들어 줬다. 네 번째부턴 맥락이 잘 기억이 나질 않는데 초기엔 VC 심사역을 만나는 것은 도움이 되지 않는다는 것이다. 엔젤이나 LLC(?)를 만나야 한다고 한다. 또 한국 법인과 해외 법인을 함께 만들라 한다. 해외법인만 설립하면 지원받기 힘들다는 이야길 하셨다.

  • 이후로 생각나는 대로 적자면 정부에선 예산 사용에 관심 있지 스타트업이 잘 되는 것 관심이 없다.
  • 현지서 피봇 기다려주는 엑셀러레이터 별로 없다. 하지만 최근 피봇까지 도와주는 몇몇이 생겨났다. 찾아서 그 프로그램 타고 글로벌 진출해라.
  • 한 나라에 특화된 산업 거의 없다. 장벽 거의 허물었다.
  • 희석된 지분에 대해 VC가 바라보는 관점은 Co-founder에게 많으면 +고 단순 엔지니어에게 많으면 -다. 한 질문자가 표면적으로라도 지분 조정을 해야할까요 하는 질문으로 미루어 서류상으로 무언가가 되나보다. 연사께서 CEO가 67.4%를 가져야 한다고 말한다. 어떤 배경에서 이런 수치가 나온 것인지 검색해보니 주총에서 보통 결의사항과 특별 결의사항이 있는데 이 중 특별 결의사항을 통과시키기 위해 2/3의 지분이 있어야 한다는 것이다. 결론적으론 안정적인 경영을 위한 것이다.
  • 홍보 담당자는 스타트업 초기에 채용은 부담스러울 수 있기에 스케일 업이 필요 할 때 채용하는 것이 적합하다.
  • 국내 글로벌 진출 프로그램관련해서 무역협회~, 중소기업~ 두 가지 추천해주셨는데 잘 듣지 못했다.
  • 엑센트리 벤처스에서 하는 것은 기업 특징에 따라 다르지만, 크게 두 가지로 첫 번째론 잠재 고객이 누굴까 깊이 고민해서 BM을 재구성해주는 것과 두 번째는 해외 투자자의 관점으로 어떤 것을 수정하면 조금이라도 더 투자를 받을 수 있을지를 도와준다고 한다

한 마디로 super().__init__()은 부모 클래스의 속성 및 메소드를 가져오는 것이다.

class A():
    def __init__(self):
        print ('[*] This is class A')

class B(A):
    def __init__(self):
        super().__init__()
        
if __name__ == "__main__":
    b = B()
(base) C:\github>python test.py
[*] This is class A

 

부모 클래스의 속성 가져오기

A 클래스에 self.name이라는 속성을 추가하였다. 상속을 받는 B 클래스에서는 self.name을 가져와서 사용할 수 있다.

class A():
    def __init__(self):
        self.name = "roytravel"
        print ('[*] This is class A')

class B(A):
    def __init__(self):
        super().__init__()
        print (self.name)
        
if __name__ == "__main__":
    b = B()
(base) C:\github>python test.py
[*] This is class A
roytravel

 

부모 클래스의 메소드 가져오기

A 클래스에 print_name이라는 메소드를 추가하였다. 이후 B 클래스에서 super를 통해 A 클래스의 메소드에 접근할 수 있다.

class A():
    def __init__(self):
        self.name = "roytravel"
        print ('[*] This is class A')
    
    def print_name(self):
        print (self.name)

class B(A):
    def __init__(self):
        super().__init__()
        super().print_name()
        
if __name__ == "__main__":
    b = B()
(base) C:\github>python test.py
[*] This is class A
roytravel

 

 

스토캐스틱 개념과 특징

가격 등락의 중심으로 가격이 회귀하려는 성질을 의미한다. 아래의 그림에서보면 지지선인 1000원과 저항선인 2000원의 채널 사이에 있는 1500원으로 회귀하려는 성질이 스토캐스틱이라 할 수 있다.

위 그림을 보면 직관적으로 1000원에 사서 2000원에 팔면 되는 것으로 보인다. 하지만 실제로는 가격의 최고점과 최저점을 예측하기 어렵기 때문에 상승확률이 높은 1500원 이하에서 매수하고 하락 확률이 높은 1500원 이상에서 매도하는 전략을 짜면 더 빈번한 수익을 얻을 수 있다.

 

스토캐스틱 구성

크게 %K, %D라는 2가지 요소로 구성된다.

%K

어렵지 않다. 1000원과 2000원 사이를 파동으로 볼 수 있다. %K는 쉽게 말해 현재 가격이 파동의 몇 퍼센트의 위치에 와있느냐는 것이다. 1000원을 파동의 시작으로보면 1200원은 파동시작의 20%지점에 있다 볼 수 있다. 따라서 %K = 20%이다. 일반적으로 %K가 20% 이하면 침체고 80% 이상이면 과열로 분석한다.

%D

한 마디로 그냥 이동평균선이 아니라 %K의 이동평균선이다.

Slow %D 5는 %K의 5일 이동평균선이라는 것이다.

이동평균선을 알고 있다면, %K가 %D로부터 수렴과 발산 계속 할 것이라는 알 수 있다. 수렴과 발산이 이루어지다보면 %K와 %D 사이에서 골든크로스와 데드크로스가 나오게 된다.

 

스토캐스틱의 종류

스토캐스틱은 크게 2가지 종류인 Stochastic fast, Stochastic slow가 있다. 차이점은 Stochastic fast는 5일간의 가격 변동(%K 5)과 %K의 3일 이평선으로 이루어진(%D 3)차트이다. 하지만 fast의 경우 가격변동에 민감하다. 때문에 이를 보완하고자 Stochastic slow를 사용한다.

 

Stochastic slow는 12일간의 가격 평균인 %K 12를 사용하고, %K의 이동평균선은 5일 평균으로 사용한다. 때문에 fast에 비해 더 완만한 곡선을 보여주는 것이 특징이다.

 

스토캐스틱 사용법

이더리움 1일 봉

스토캐스틱을 활용한 매매법은 빨간지점에서 사고 파란지점에서 팔면된다. 빨간지점은 12일간의 가격 평균보다 5일간의 이동평균선이 더 내려 왔기 때문에 상승(회귀)할 것이라 예측할 수 있다. 반면 파란지점은 12일간의 가격 평균이 5일간의 이동평균선보다 더 높기 때문에 하락(회귀)할 것이라 예측할 수 있다.

 

스토캐스틱에서는 과열은 80, 침체는 20을 기준으로 한다. 따라서 %K가 과열되면 매도, %K가 침체되면 매수하는 전략을 취한다.

 

또한 스토캐스틱은 골든크로스와 데드크로스를 활용한 매매전략을 취할 수 있다. 아래와 같이 5일 이동평균선이 12일간의 가격 평균보다 낮았다가 변화하려는 시점에 매수하고, 5일 이동평균선이 12일간의 가격 평균보다 높다가 변화하는 시점에 매도하는 것이다.

 

하지만 이런 스토캐스틱을 활용한 매매법이 수익률 측면에서 유리하다 볼 수 없다. 단순히 추세 전환의 시작점을 찾을 때 유용하고, 매매 선택지를 줄여주는 효과가 있다. 주로 횡보장이나 추세가 없는 박스권에서 적중률이 높은 편이다.

 

스토캐스틱을 통해 아래의 항목에 활용 가능하다.

  • 다이버전스를 이용한 추세전환 분석
  • 과매수/과매도 판단
  • %K/%d 선의 교차 지점을 통해 진입 시점 판단

 

 

Reference

[1] https://monstock.tistory.com/173

[2] https://monstock.tistory.com/174?category=862767

[3] https://m.blog.naver.com/whtjdcks0414/221418132334

삼각수렴 개념

삼각수렴은 코인이나 주식 차트에서 볼 수 있는 하나의 캔들패턴으로 지지선과 저항선을 그었을 때 삼각형으로 수렴하는 패턴의 차트를 말한다.

 

삼각수렴 생성 배경

가격이 어느 지점에 도달할 때 매도세와 매수세의 균형이 이루어지는 지점에서 생긴다. 엘리엇 파동이론에 따르면 삼각수렴은 마지막 파동의 이전 파동과 복합조정의 마지막파동에서 나온다고 설명되어 있다. 마지막 파동의 이전 파동이란 5파 이전인 4파 횡보조정이나 C파 이전인 B파 횡보조정을 의미한다. 복합조정의 마지막 파동이란 WXY의 Y 또는 WXYXZ의 Z파동을 의미한다. 엘리엇 파동이론에서는 4파에서 삼각수렴할 경우 5파동이 추진파동으로 삼각수렴 입구 크기만큼 나오며, 이 추진파동의 예측범위를 벗어날 경우 5파동이 연장된다고 한다.

 

삼각수렴 종류

삼각수렴의 종류는 크게 3가지가 있다. 상승 삼각수렴, 하강 삼각수렴, 대칭 삼각수렴이다. 어센딩 트라이앵글, 디센딩 트라이앵글, 시메티컬 트라이앵글이라고도 한다.

 

 

각 삼각수렴 별 특징

상승 삼각수렴

일반적으로 상승방향으로 가격이 향한다. 이유는 저점이 높아지기 때문인데, 이는 하단에서 매수세가 들어오고 있다는 의미이기 때문이다. 즉, 상승 삼각수렴 패턴은 고점은 일정한 가격대를 유지하지만, 저점은 높아지는 패턴이라 할 수 있다. 다른 용어로 짝궁댕이, 쌍바닥, W패턴, 하이힐 패턴이라고도 한다.

 

하강 삼각수렴

일반적으로 하락방향으로 가격이 향한다. 저점 추세선은 일직선을 유지하고 고점 추세선이 하락하는 패턴이다. 

 

대칭 삼각수렴

방향성이 정해져 있지 않다. 대칭 삼각수렴은 매도 세력과 매수 세력이 비슷한 힘을 가지고 수렴되는 패턴이다. 수렴되었을 때 더 강한 힘 방향으로 주가가 움직인다.

 

삼각수렴의 특징

삼각수렴의 경우 두드러진 특징이 가격이 수렴하면서 거래량또한 감소한다는 것이다. 줄어든 거래량은 방향성을 가지고 삼각수렴의 한 변을 돌파할 때 폭발적으로 증가하게 되며 이는 추세가 진행되는 것을 의미한다. 

만약 삼각수렴 이후 추세선 돌파시 눈에 띄는 거래량이 발생하지 않을 경우 아래와 같이 삼각수렴 패턴이 아니라 휩쏘일 가능성도 있다. 따라서 삼각수렴 이후 추세선 돌파시 눈에 띄는 거래량이 있는지 확인하고 매수/매도를 해야한다.

또 다른 삼각 수렴 패턴의 특징으로는 차트 상 가장 많이 발생된다는 것이다. 삼각 수렴은 일봉이나 주봉보다 간격이 짧은 1시간 이내의 차트에서 주로 발견된다. 때문에 단타 트레이더가 사용하기에 적합하다. 하지만 일반적으로 초보자들이 많이 하는 실수 중 하나가 분봉 패턴에서 삼각수렴의 패턴을 보고 이탈시 매수/매도 전략을 사용하기도 한다. 하지만 이는 사실 썩 좋지 않은 방법에 속한다. 분봉패턴의 삼각수렴은 정확하지 않음이 그 이유이며, 옳다고 하여도 스캘핑식 접근을 해야하기에 큰 수익을 기대하기 어렵기 때문이다.

 

삼각수렴의 경우 통상적으로 3개의 고점과 3개의 저점이 나타나는 것이 특징이며 그 이상 나타날 경우 패턴의 완성도가 높다고 판단할 수 있다. 추세선을 돌파할 경우 삼각수렴 패턴의 최초 상승/하락 폭이므로 패턴의 시작점을 정확히 파악하는 것이 중요하다.

 

 

삼각수렴 판단 방법

삼각수렴에 진입할 경우 입구의 볼륨이 가장 크고 입구부터 해서 점점 거래량이 줄어드는 양상을 띤다. 때문에 거래량을 보는 트레이더들은 거래량 감소를 보고 수렴 진입여부를 판단한다.

 

 

삼각수렴 대응 방법

1. 공격적 매매방법

엘리엇 파동 ABCD 파동까지 단타 후 E 파동을 기다리며 파동이 나온 이후 여러 시그널에 따라 진입 후 손절은 반대쪽 변으로 잡는 방법이다. 하지만 리스크가 다소 크기 때문에 손절라인을 잡을 것을 권한다.

 

2. 보수적 매매방법

엘리엇 파동 ABCDE 파동까지 나온 후 거래량과 함께 삼각수렴을 돌파하는 흐름이 나올 경우 진행 방향에 따라 매매하는 방법이다. 추세추종 매매이기에 손절위험이 적으나 진입가격 측면에서 불리한 것이 특징이다.

 

3. flag-based 매매방법

flag-based라는 용어는 임의로 만든 것으로, 상승 깃발형과 하락 깃발형을 기준으로 거래량을 동반해서 돌파하는 방향으로 매매하는 방법이다.

 

위의 1, 2, 3번 매매 법의 공통적인 주의점은 이평선이나 스토캐스틱 등의 시그널이 돌파방향과 일치하는지 확인해야 한다.

 

4. 비매매

매매 기회는 수 없이 많으므로 차트에 대한 이해가 없을 경우 매매를 지양할 것.

 

 

Reference

[1] http://wiki.hash.kr/index.php/삼각수렴

[2] https://tailong.tistory.com/375

[3] https://m.blog.naver.com/kkumchartist/222261897266

[4] https://kiwoom-wang.tistory.com/743

[5] https://tradingwong.tistory.com/90

파이썬 코드를 작성하는데 있어 이따금씩 실수하는 것은 리스트나 딕셔너리 등에 요소를 추가할 때 콤마(,)를 붙이지 않는 것이다.

 

만약 아래와 같이 콤마를 붙이지 않을 경우 아래와 같이 리스트 내부의 요소가 결합되는 것을 확인할 수 있다.

 

위와 같은 것을 문자열 리터럴 결합이라 부르고 파이썬 내부적으로 의도적이고 문서화 되어 있는 동작으로,

 

디버깅 하는데 있어서 오랜 시간이 걸릴 수도 있으므로 주의가 필요하다.

 

따라서 이러한 문제를 피할 수 있는 코드 스타일을 체화 하는 것이 필요하다. 그 방법은 마지막 요소에 항상 콤마(,)를 붙이는 것이다.

 

파이썬 내부적으로는 아래와 같이 쉼표 배치 문제를 해결할 수 있도록 끝에 콤마(,) 이후에 요소가 없더라도 정상적으로 동작하도록 설계해두었다.

 

사용 배경

객체지향 프로그래밍의 중요한 개념 중 하나는 데이터 은닉이며, 필요에 따라 특정 정보에 대한 은닉을 위해 접근 제한자를 사용한다.

 

 

접근 제한자

접근 제한자는 크게 public, protected, private 세 종류가 있다.

 

public

  • 외부 클래스가 자유롭게 접근하여 사용 가능
  • 연산자를 이용하여 아무곳에나 액세스 가능

 

private

  • 오직 클래스 내부에서만 접근 가능하며 클래스 외부의 객체나 함수에서 직접 접근 불가
  • 클래스 내부의 멤버 함수 또는 friend 함수만 클래스의 private 멤버에 접근 가능.

 

protected

  • 클래스 외부에선 protected 멤버에 접근할 수 없음. 하지만 해당 클래스의 하위 클래스에서는 접근할 수 있음.

* 하위 클래스: ex) 파생 클래스, 자식 클래스

 

 

 

* C++ 클래스 내에 멤버에 대한 접근 제한자를 두지 않으면 기본적으로 private임 (자바는 public이 default)

* C/C++ 구조체 멤버에 대한 기본적인 접근 제한자는 public임

 

 

Reference


[1] https://yeolco.tistory.com/115

[2] https://saack.tistory.com/46

 

+ Recent posts