승률이 절반을 넘고 있었다
자동매매 성과를 보는 화면에 승률이 있다. 53.7%였다. 넉 달 내리 손실인 시스템의 숫자치고는 이상하게 멀쩡했다.
손익은 마이너스인데 승률은 절반을 넘는다. 이 조합 자체는 이상하지 않다. 이긴 거래가 조금씩 벌고 진 거래가 크게 잃으면 그렇게 된다. 그래서 나는 이것을 손익비 문제로 읽고 있었다. 이기는 횟수는 충분하니 한 번 이길 때 더 벌면 된다고.
지적은 다른 데서 왔다. 트레일링 스탑으로 끝난 거래를 승률에서 빼는 게 맞지 않냐는 것이었다. 어차피 세금 떼면 본전이라는 이유였다.
이긴 거래의 정체
트레일링 스탑은 이익이 난 종목이 고점에서 일정 폭 밀리면 파는 장치다. 손절과 달리 대개 플러스로 끝난다. 그래서 손익 부호로만 세면 거의 전부가 승리로 들어간다.
문제는 그 플러스의 크기였다. 청산 사유별로 건당 세후 손익을 갈라봤다.
- 목표가에 닿아 익절: 건당 +5,779원
- 트레일링 스탑: 건당 +1,181원
5분의 1이다. 그리고 손절은 건당 -10,915원이었다.
숫자를 나란히 놓으면 무엇을 세고 있었는지가 보인다. 손절 한 건을 메우려면 트레일링 청산이 아홉 건 필요하다. 그런데 승률 계산에서는 그 아홉 건과 익절 한 건이 같은 무게였다. 1승은 1승이니까.
세금이 그 위에 있었다
한국 주식은 팔 때 세금과 수수료가 붙는다. 이익이 작을수록 그 비중이 커진다.
트레일링 청산의 세전 이익 중 31.7%를 제세가 가져갔다. 익절 쪽은 8% 남짓이다. 같은 비용이 이익이 작은 쪽만 집중적으로 깎는다.
그래서 세전으로는 플러스인데 세후로는 마이너스가 되는 거래가 나온다. 화면에는 승리로 찍히고 계좌에서는 돈이 빠지는 거래다. 이것을 이겼다고 세고 있었다.
승과 패 두 칸으로는 담기지 않았다
고치는 방향은 두 가지가 있었다.
하나는 트레일링 청산을 손익 부호대로 두되 가중치를 주는 것이다. 기각했다. 가중치는 내가 정하는 값이라 근거가 없고, 근거 없는 숫자를 성과 지표에 넣으면 그 지표를 다시 못 믿는다.
다른 하나는 칸을 하나 더 만드는 것이다. 승과 패 사이에 무승부를 두고, 트레일링 청산은 손익 부호와 무관하게 무승부로 보낸다. 승률은 승과 패만으로 계산한다.
후자를 택했다. 트레일링 스탑은 목표에 닿은 것도 손절선에 걸린 것도 아니고 밀려서 접은 것이기 때문이다. 애초에 승패로 나눌 성격이 아니었다.
바뀐 결과는 이렇다.
- 이전: 수익 79 / 손실 68 = 승률 53.7%
- 이후: 수익 53 / 손실 64 / 무승부 30 = 승률 45.3%
8.4%p가 사라졌다. 거래는 한 건도 바뀌지 않았다. 세는 방법만 바꿨다.
무승부로 옮긴 30건 중 26건이 이전에는 승리 칸에 있었다. 승률이 절반을 넘었던 이유가 그것이다.
정의를 바꾸자 그 숫자를 쓰던 곳들이 못 따라왔다
여기서부터가 예상 밖이었다.
승률의 정의를 바꾸는 것은 함수 하나를 고치는 일로 보였다. 실제로는 그 값을 인용하는 화면이 네 군데 있었고, 세 라운드에 걸쳐 하나씩 튀어나왔다.
첫째, 연간 요약 카드가 승률에서 건수를 역산하고 있었다. 승률과 전체 건수를 곱해 이긴 건수를 구하는 방식이다. 분모에서 무승부가 빠지자 이 역산이 깨져서, 실제 53건인 것을 67건으로 표시했다.
둘째, 일간과 월간 카드가 옛 건수와 새 승률을 한 화면에 나란히 뒀다. 각각은 맞는 값인데 함께 보면 산수가 안 맞는다.
셋째, 알림 메시지의 요약문을 만드는 함수가 두 벌이었다. 자동으로 나가는 것과 수동으로 부르는 것이 이름만 다르고 하는 일이 같은 별개 함수였다. 두 라운드 내내 한쪽만 고쳐졌다.
넷 다 컴파일이 통과하고 테스트가 전부 초록인 채로 있었다. 타입이 맞고 계산이 맞았기 때문이다. 틀린 것은 그 값이 무엇을 뜻하는지였고, 그건 타입 검사에 걸리지 않는다.
접근을 바꾼 것이 효과를 냈다
되짚어보면 두 라운드를 같은 방식으로 실패했다. 지적받은 지점을 고치고, 다음 라운드에 다른 지점이 나오고, 또 고쳤다.
세 번째에 방식을 바꿨다. 고치기 전에 그 값을 화면에 그리는 지점을 전부 찾아 표로 만들고, 각각이 새 정의와 맞는지 하나씩 적었다. 그 라운드에서 네 번째 지점이 나왔다.
규칙을 하나 더 만들지는 않았다. 이미 비슷한 규칙이 여럿 있고, 그것들이 이번 일을 막지 못했다. 바뀐 것은 규칙이 아니라 일을 시작하는 방식이었다. 지적받은 곳부터 여는 대신 전수 목록부터 만든 것.
남은 것
세 문장으로 정리된다.
지표의 정의가 실적을 가릴 수 있다. 손익은 정직했다. 넉 달 내리 마이너스였다. 그 옆에서 승률만 절반을 넘고 있었고, 나는 그것을 손익비 문제로 읽어 잘못된 곳을 고치려 했다.
비용이 작은 이익만 집중적으로 깎는다. 이익 폭이 작은 거래는 세금을 넣는 순간 성격이 달라진다. 세전 숫자로 승패를 나누면 그 전환이 통째로 안 보인다.
정의를 바꾸면 그 값을 인용하는 코드는 따라오지 않는다. 그것들은 여전히 컴파일되고 여전히 테스트를 통과한다. 값의 의미가 바뀐 것을 알 방법이 코드 안에 없기 때문이다. 정의를 건드릴 때 고칠 목록은 그 정의를 쓰는 곳이 아니라 그 값을 보여주는 곳 전부다.