지난 글에서 나는 내가 만든 자동매매 프로그램이 하루 종일 한 주도 안 사던 날 이야기를 했다. 그때 배운 게 있었다. 봇이 안 사는 건 고장이 아니라, 종목 하나를 사기까지 통과해야 하는 조건이 여러 개라 그런 거라고. 그래서 나는 그 조건들을 하나씩 열어보기로 했다.
그런데 솔직히 그날, 나는 그 교훈을 다 이해하고도 좀 답답했다. 종목은 넘치는데 매수가 0건. 이 조건들, 내가 걸어놓긴 했는데 이렇게까지 빡빡하게 걸릴 줄은 몰랐던 것이다. 대체 뭐가 이렇게 죄다 막고 있나. 차단 로그를 뒤졌고, 맨 윗줄에서 이걸 봤다.
목차
🧭 [REGIME 변경] NEUTRAL → BEAR | breadth=0.0% (최근 240s hit=0/80)
프로그램이 그날 아침, 시장을 통째로 약세장으로 찍어두고 있었다. 그러고는 개별 종목을 보기도 전에, 제일 먼저 "오늘은 살 장이 아니다"라고 정해버린 것이다. 봇이 종목을 사기 전에 확인하는 여러 조건 중에, 이 시장 국면 판정(regime)이 제일 위에 있다. 그리고 이건, 다름 아닌 내가 일부러 그렇게 만들어둔 것이었다.
내가 만들어놓고, 내가 답답해했다
로그를 보고 나서야 아, 하고 이해가 됐다. 이 판정은 내가 작정하고 넣은 것이다. 약세장이면 매수 조건을 확 조이라고, 내가 그렇게 시켜서 만들었다. 그런데 막상 그게 하루 종일 한 건도 안 통과시키는 걸 보니, 내가 만든 규칙인데도 순간 못 견뎌서 "왜 이렇게까지 안 사?" 하고 있었던 것이다.
웃긴 일이다. 규율이 갖고 싶어서 봇한테 손을 넘긴 건데, 정작 그 규율이 세게 작동하니까 내가 먼저 답답해했다. 6편에서 봇이 안 산다고 봇을 의심했던 그 버릇, 그대로였다. 머리로는 "이게 맞다" 하면서도 손은 여전히 뭐라도 사고 싶어 하는 것.
그런데 왜 하필 시장부터 봤나
이 프로그램이 종목보다 시장을 먼저 보게 만든 이유는, 저 로그의 숫자 하나에 다 들어 있다. breadth=0.0% (hit=0/80). 봇은 내가 걸어둔 80개 종목을 계속 지켜보다가, 그중 지금 실제로 강한 게 몇 개인지(hit)를 센다. 80개 중 강한 게 하나도 없으면 hit=0, 그 비율(breadth)이 0%다. 시장의 폭이 이렇게 죽어 있으면 국면을 약세장으로 바꾼다.
강한 종목이 여기저기서 나와줘야 장이지, 딱 하나만 튀는 건 시장이 아니라 그 종목의 외로운 반란일 뿐이다. 나는 이걸 시장의 폭이라는 한 숫자로 보게 만들어뒀다. 개별 종목을 아무리 잘 골라도, 이 숫자가 죽어 있으면 그 아래는 아예 확인할 필요도 없도록.
나는 하락장에서 유독 많이 데었다
내가 시장 판정을 굳이 맨 앞에 둔 건, 하락장에서 오래 데어봤기 때문이다.
이상하게도 나는 강세장보다 약세장에서 훨씬 많이 매매했다. 확률로만 따지면 강세장에서 사는 게 유리한데, 정작 손이 바빠지는 건 하락장이었다. 이유는 하나였다. 약세장에서 손실이 조금 나면, 그걸 그 약세장 안에서 당장 만회하고 싶었다. 그 조바심에 매매 횟수만 늘었다.
그런데 약세장은 만만한 곳이 아니다. 눌림이 깊고, 나와줘야 할 반등이 따박따박 안 나온다. 강세장에선 내가 산 자리가 깨져도 이내 반등이 나와서 익절할 여지라도 있는데, 약세장은 그 힘 자체가 약하다. 지지가 깨지면 그냥 더 깨진다. 손절을 제때 못 하면 그대로 물리는 것이다. 만회하겠다고 들어간 매매가 계좌를 더 깎아먹는 걸, 나는 몇 번이고 반복했다.
오래 지켜보고 나서야 나는 이걸 알았다. 장세가 약하면, 한 번 더 깨지는 걸 보고 들어가거나 아예 안 들어가는 게 계좌엔 오히려 플러스일 때가 많다는 것. (테마주나 혼자 강한 종목은 예외다. 그건 시장과 따로 논다.) 손으로는 이걸 알면서도 못 지켰다. 그래서 프로그램을 만들 때, 이 판단을 개별 종목보다 위에 둔 것이다. 내가 끝내 손으로 못 지키던 걸, 봇한테는 맨 앞에 박아버렸다.
약세장으로 찍히면, 아예 조건을 조여버렸다
판정만 해두고 평소처럼 사게 두면 소용없었다. 그건 결국 손매매 때랑 똑같으니까. 그래서 약세장으로 찍히는 순간, 매수 조건 자체가 더 빡세게 걸리도록 만들었다. 그날 하루 종일 아무것도 안 산 게 바로 이 설정 때문이었다.
✅ BEAR min_cluster_heat=2 ✅ [REGIME 튜닝] BEAR pullback_weight_mul=1.3 → 약세장 눌림 강화
첫 줄은 약세장에선 여러 종목이 같이 강해야만 매수가 열린다는 뜻이다. 혼자 튀는 종목 하나로는 안 산다. 둘째 줄은 약세장에선 강하게 튀어 오르는 걸 쫓는 돌파 엔진(고점을 강하게 뚫을 때 사는 방식)보다, 눌렀다 다시 오는 걸 잡는 눌림 엔진(고점 근처에서 눌렸다 다시 뚫을 때 사는 방식) 쪽에 무게를 더 준다는 뜻이다. 약한 장에서 튀는 건 가짜일 때가 많으니까.
이렇게까지 조여둔 게, 그날 나를 답답하게 만든 범인이었다. 근데 로그를 다 보고 나니 할 말이 없었다. 앞에서 데인 그대로였다. 약세장에 강세장 기준을 들이대면 물린다는 것, 그게 바로 나였으니까. 답답했지만, 프로그램은 내가 시킨 대로 정확히 일한 것뿐이었다.
정작 이걸 코드로 옮길 땐 한참 헤맸다
관점은 뚜렷했는데, 이걸 코드로 만드는 건 또 다른 문제였다. 부끄러운 얘기지만 처음엔 이걸 어떻게 짜야 할지 감도 안 잡혔다. 시장이 약하다는 걸 사람은 그냥 느끼는데, 기계한테는 그 "약하다"를 숫자로 정해줘야 했다.
시장의 폭을 어떻게 세는지부터 한참 헤맸다. 80개 중 강한 게 몇 개인지 센다는 게 말은 쉬운데, "강하다"의 기준을 뭘로 잡을지, 몇 초를 볼지, 몇 %에서 약세장으로 자를지. 저 로그 한 줄의 hit=0/80이라는 단순한 숫자 뒤에, 값을 바꿔가며 헤맨 새벽이 여러 번 있었다. 시장을 보는 눈은 내 안에 있었는데, 그걸 기계가 셀 수 있는 숫자로 번역하는 게 그렇게 어려울 줄은 몰랐다.
무엇을 사느냐보다, 지금이 살 장이냐
이걸 만들고 나서 내 원칙은 한 칸 위로 올라갔다. 1편에서 나는 "언제 사느냐보다 언제 사지 않느냐"가 중요하다고 했다. 시장 판정은 그 위에 있다. 무엇을 사느냐보다, 지금이 애초에 살 장이냐가 먼저라는 것. 아무리 좋은 종목도 나쁜 시장에선 안 산다.
혹시 지금 만든 자동매매 프로그램이 하락장에서 자꾸 물린다면, 종목 고르는 조건부터 뜯기 전에 시장의 폭을 조건에 한번 넣어보는 걸 생각해봐도 좋을 듯하다. 감시하는 종목 중 몇 %가 실제로 강한지, 그 숫자 하나만 봐도 지금이 살 장인지 아닌지가 갈린다. 참고로 내 봇에는 지수 20일선을 기준으로 시장을 보는 또 다른 판정 방식도 있는데, 그건 성격이 좀 달라서 다음에 따로 풀겠다.
그 아래에서, 또 하나가 기다린다
시장 판정이 "오늘은 살 만한 장이다"라고 통과시켜도, 그걸로 끝이 아니다. 그 바로 아래에서 또 다른 조건이 종목을 붙잡는다. 6편 로그에서 잠깐 스쳐 지나갔던 것, 여럿이 같이 강할 때만 통과되는 조건이다.
나는 내가 만든 규칙에 내가 답답해했다. 근데 돌아보면 그 답답함이야말로, 내가 손으로 매매할 때 늘 지던 그 자리였다. 봇은 그걸 대신 지켜주고 있었을 뿐이다. 그 다음 이야기는, 다음 글에서 하려 한다.
이 글은 내가 직접 만든 프로그램의 개발 기록일 뿐, 특정 종목이나 매매 방식을 권하는 글이 아니다. 투자 판단과 그 결과는 각자의 몫이다.
댓글 쓰기