실버를 넘고, 0.0063 앞에서 멈추다 (월드퀀트 브레인 7편)
퀀트 트레이딩 플랫폼 WorldQuant BRAIN에서 알파를 쌓아 점수를 올리는 공개 기록. 6편에서 네 번째 알파를 찾아 제출했다. 이번 편은 그 알파가 점수판에 반영되며 실버로 올라선 이야기, 그리고 다섯 번째 알파를 거의 다 잡았다가 마지막 한 걸음 앞에서 멈춘 이야기다.
0. 한 줄 요약
네 번째 알파가 반영되며 브론즈를 넘어 실버가 됐다. 이어서 찾은 다섯 번째 후보는 통과 기준의 두 가지 문(수익성 일관성, 효율성)을 다 넘었는데, 세 번째 문인 자기상관에서 딱 0.0063만큼 모자라 스무 번 넘게 조정하고도 끝내 넘지 못했다.
1. 반영을 기다리는 하루
6편 끝에서 만든 네 번째 알파는 곧바로 낼 수 있는 게 아니었다. 점수는 하루 상한이 있어서, 강한 알파는 날짜를 나눠 내는 게 유리하다. 그래서 하루를 기다렸다가 냈다.
내는 것과 점수판에 찍히는 것 사이에도 시차가 있다. 매일 새벽(미국 동부 기준) 점수가 갱신되는데, 알파를 그 갱신 시각에 딱 맞춰 내지 못하면 다음 날 갱신을 기다려야 한다. 이번에도 그랬다. 갱신 시각을 살짝 넘겨 낸 탓에, 반영까지 갱신 시각으로부터 20분 가까이 걸렸다. 그 20분 동안 점수를 몇 번이고 다시 확인했다. 마침내 숫자가 바뀌었을 때, 점수는 5,546에서 7,464로 뛰었고 등급은 브론즈에서 실버로 올라갔다. 다음 문턱인 골드까지 2,536점이 남았다.
2. 막힌 길을 다시 보다: 배치로 훑기
다섯 번째 알파를 찾으러 나서면서, 이번엔 방식을 하나 바꿨다. 지금까지는 후보 하나하나를 손으로 설계해서 시험했는데, 이 저장소에는 애초에 "배치 마이너"라는 도구가 있었다. 여러 개의 정형화된 틀(템플릿)에 여러 데이터 필드를 자동으로 대입해서, 한 번에 수십 개씩 시험해 주는 도구다. 이번 세션에서 처음으로 제대로 써봤다.
펀더멘털 데이터셋에는 재무제표 항목이 886개 있다. 그중 자산, 부채, 매출원가 같은 것들을 하나씩 넣어 돌려봤다. 그런데 이 도구에 손봐야 할 구멍이 하나 있었다. 대입할 틀이 다섯 가지인데, 한 번에 시험할 개수 상한을 필드 개수와 똑같이 주면, 첫 번째 틀만 필드 수만큼 다 써버리고 나머지 네 개 틀은 단 한 번도 실행되지 않는다는 것. 이 사실을 뒤늦게 알아챘다. 그러니까 처음 34개 필드를 스캔했다고 생각했던 게, 사실은 "필드를 단순히 순위 매기기"라는 틀 하나만 시험한 것이었다.
3. 우연히 만난 함정과, 그걸 피하는 법
이 틀들을 마저 돌리다가 눈에 띄는 숫자 하나를 봤다. "중단영업 유동자산"이라는, 회사가 사업 일부를 접거나 팔 때만 생기는 회계 항목이었다. 단독으로 돌렸더니 수익성 일관성 지표가 1.07까지 나왔다. 이번 세션 최고치였다.
그런데 3편에서 배운 교훈이 떠올랐다. 화려한 숫자는 의심부터 해야 한다는 것. 이 항목은 대부분 회사에서 값이 없거나 0이다. 사업을 접는 회사만 값이 있다. 그러니 종목을 줄여서(유동성 좋은 대형주만) 다시 재봤다. 1.07이던 지표가 0.37로 무너졌다. 소수의 특이 종목에 몰려 있던 우연이었다. 그 함정을 확인하고 그대로 폐기했다.
4. 그룹 안에서 줄 세우기
여러 재무 항목을 이 틀 저 틀로 계속 시험하다가, 하나의 패턴이 뚜렷이 보이기 시작했다. 어떤 항목을 "전체 시장에서 줄 세우기"보다 "같은 업종 안에서 줄 세우기"로 바꾸면, 유독 특정 부류의 항목에서 지표가 꾸준히 올라갔다. 부채, 매출원가, 유동성 같은 항목들이 그랬다. 이유를 짐작해보면, 업종마다 원래 감당할 수 있는 부채 수준이 다르다. 전체 시장과 비교하면 그 차이가 잡음이 되지만, 같은 업종 동료와 비교하면 진짜 신호가 드러난다.
스물일곱 개 항목을 이 방식으로 재봤다. 주식 거래 회전율과 장기 이연수익이 1.03으로 가장 높았고, 장기부채 신규발행이 1.01, 장기부채 잔액이 0.92로 뒤를 이었다. 반면 기업가치나 자기자본 같은 밸류에이션 항목들은 이 방식을 써도 전혀 오르지 않았다. 업종 내 비교가 통하는 항목과 안 통하는 항목이 갈렸다.
5. 유동성과 경쟁사 스필오버의 만남
"같은 업종 안에서 유동비율로 줄 세우기"(현금성 자산이 단기 부채 대비 넉넉한 순서, 뒤집어서 유동성 나쁜 쪽을 위로)를 4편, 6편에서 검증된 경쟁사 수익률 신호와 곱해봤다. 결과는 수익성 일관성 지표 1.33, 효율성 지표 1.02. 두 문 다 넘었다.
세 번째 문인 자기상관을 확인했다. 0.7189. 기준은 0.7. 겨우 0.019 차이로 막혔다.
6. 스무 번의 미세조정과 마지막 0.0063
이때부터 이 알파 하나를 붙들고 스무 번 넘게 손봤다. 경쟁사 신호를 평균 내는 기간을 21일에서 하나씩 줄여봤다. 19일로 줄이자 자기상관이 0.7141로 내려갔다. 18일에서는 0.7093, 17일에서는 0.7063까지 내려갔다. 줄일수록 상관이 낮아지는 뚜렷한 추세였다. 그런데 16일로 더 줄이자 이번엔 효율성 지표가 0.95로 떨어지며 다른 문에서 막혔다. 17일이 두 요구사항이 겹치는 유일한 지점이었고, 그 지점에서도 0.0063이 모자랐다.
다른 손잡이도 다 당겨봤다. 평활의 정도를 바꿔봐도, 비중 상한을 조정해봐도, 업종을 더 잘게 나누거나 더 크게 묶어봐도, 경쟁사 신호를 아예 빼고 다른 재료로 바꿔봐도 소용없었다. 경쟁사 신호를 빼면 자기상관은 낮아지지만 그 대신 알파 자체가 약해져서 다른 문에서 막혔다.
한 번은 지름길처럼 보이는 방법을 썼다가 완전히 헛수고를 한 적도 있다. 신호를 극단적으로 증폭하거나 눌러서 두 재료의 비중을 재조정해보려 했는데, 최종적으로 순위를 매기는 함수 바로 안쪽에서 그 조정을 하니 아무 효과가 없었다. 순위를 매기는 함수는 크기가 아니라 순서만 본다. 순서를 그대로 보존하는 조정은 아무리 해도 결과가 똑같다. 이 사실을 시뮬레이션 네 번을 날리고서야 깨달았다. 조정의 효과를 보려면 순위를 매기기 전, 값들을 실제로 곱하거나 더하는 단계에서 손을 대야 했는데, 그렇게 하니 이번엔 극단값에 신호 전체가 휘둘려서 지표가 0.03까지 주저앉았다.
결국 이 조합, "유동비율의 업종 내 순위 곱하기 경쟁사 스필오버"는 자기상관의 벽 앞에서 멈췄다. 스무 번이 넘는 조정과 쉰 번이 넘는 시뮬레이션을 들였으니, 이 정확한 조합에 대해서는 충분히 확인했다고 본다.
7. 왜 하필 자기상관이었을까
돌아보면 짚이는 게 있다. 경쟁사 수익률 신호는 이미 세 번째 알파와 네 번째 알파에 각각 다른 형태로 들어가 있었다. 첫 알파는 이 신호를 안 썼지만, 세 번째와 네 번째가 이미 썼다. 자기상관 기준은 "지금까지 내가 낸 모든 알파와 얼마나 닮았는가"를 재는 것이라, 같은 재료를 세 번째로 또 쓰면 두 알파 모두와의 닮음이 겹쳐서 쌓인다. 세 번째 알파 때는 이 신호 하나만 썼으니 닮음이 0.138로 낮았고, 네 번째 때는 다른 재료와 섞어 써서 0.43까지 올랐고, 이번엔 세 번째로 쓰면서 0.72 언저리까지 올라간 것으로 보인다. 같은 좋은 재료라도, 서랍에서 몇 번째로 꺼내 쓰느냐에 따라 대가가 달라진다는 뜻이다.
8. 이번 편에서 배운 것
- 점수 반영에는 시차가 있다. 갱신 시각을 살짝 넘겨 내면, 그날치가 아니라 다음 갱신을 기다려야 한다.
- 자동화 도구도 검증하고 써야 한다. 배치 마이너의 다섯 개 틀 중 네 개가 한 번도 실행되지 않고 있었다. 도구를 믿기 전에 실제로 뭘 하고 있는지 확인해야 한다.
- 업종 안에서 비교하면 보이는 게 있다. 전체 시장 비교로는 죽어 있던 신호가, 같은 업종끼리 비교하니 살아났다. 다만 이 효과는 부채/유동성 계열에만 통했고 밸류에이션에는 안 통했다.
- 좋은 재료도 계속 쓰면 값이 떨어진다. 검증된 신호를 세 번째로 재사용하니 자기상관이 누적돼 벽이 됐다. 같은 재료의 반복 사용에는 대가가 있다.
- 순위 함수 안에서의 조정은 순서를 안 바꾼다. 순위를 매기는 함수 바로 안에서 크기만 조정하는 건 아무 효과가 없다. 조정은 순위를 매기기 전 단계에서 해야 하고, 그마저도 극단값 관리가 필요하다.
- 충분히 시도한 뒤엔 멈출 줄도 알아야 한다. 스무 번의 조정 끝에도 안 되면, 그건 아직 못 찾은 방법이 아니라 이 조합 자체의 한계일 수 있다. 다만 그 판단은 충분히 시도한 뒤에만 내려야 한다.
다음 편에서는 이번에 찾은 다른 유망한 재료(장기 이연수익, 신규 부채발행)로 다섯 번째 알파를 다시 노린다. 경쟁사 신호를 또 쓸지, 아니면 완전히 다른 재료로 갈지가 이번 사냥에서 얻은 가장 큰 질문이다.
기술 메모 (부록)
- 점수 현황 (07-02): SILVER, 7,464점, rank 20,520, 알파 4개 반영. Gold(10,000)까지 2,536점.
- group_rank(field, subindustry) 실측 순위 (27개 필드, USA TOP3000): 최고 fnd6_cshtr(주식거래회전율)/fnd6_drlt(이연수익LT) 1.03, fnd6_dltis(장기부채신규발행) 1.01, debt_lt(장기부채) 0.92, cogs(매출원가) 0.88, debt_st 0.86, debt 0.84, current_ratio(플립) 0.81. 레버리지/유동성/영업규모 계열에서 val_rank(단순 횡단면 랭크) 대비 +0.07 to 0.13 uplift 확인, 밸류에이션 계열(enterprise_value/equity/cashflow_op)엔 uplift 없음(0.24 to 0.30 정체).
- 5호 후보 (미제출, self-corr로 최종 실패):
rank(-group_rank(current_ratio, subindustry)) * rank(winsorize(ts_mean(ts_backfill(rel_ret_comp,5),21),std=4)), USA/TOP3000/delay1/decay6/INDUSTRY/trunc0.02 → Sharpe 1.33, Fitness 1.02, sub-universe 0.83, self-corr 0.7189(한도 0.7). 경쟁사 스필오버 윈도우를 21→17일로 좁히며 self-corr 0.7189→0.7141→0.7093→0.7063 선형감소 확인(윈도우16에서 Fitness 0.95로 게이트 이탈). decay/truncation/SUBINDUSTRY와 SECTOR중립화/comp-free 대체파트너/signed_power 재가중 전부 무효 확인, 20개 이상 배치, 55회 이상 시뮬 투자 후 확정 마감. - 배치마이너 버그:
scripts/mine.py --template-set value는 5개 템플릿(val_rank/val_rankneg/val_tsrank/val_grp/val_improve) 순환인데--max를 필드수와 같게 주면 template-major 순회상 첫 템플릿만 캡을 다 쓰고 나머지 4개는 미실행. 강한 필드에 나머지 템플릿을 별도 지정 실행해서 우회. - sub-universe 함정 재확인:
fnd6_acdo(중단영업 유동자산) 단독 S1.07/F0.90이 TOP1000에서 0.37로 붕괴(부호 flip -1.09로 정상 검증됨). 대부분 종목 결측/0인 희소 회계항목의 전형적 집중 과적합. - signed_power 함정:
rank(signed_power(x,p))는 단조변환이라 rank() 직후 감싸면 순서 불변=사실상 no-op. 가중치를 바꾸려면 rank() 이전 곱셈/합 단계에서 적용해야 하나, 원시값(zscore) 곱은 극단값에 취약해 신호가 붕괴할 수 있음(실측 0.03). - 자기상관 누적 관찰: comp(경쟁사 스필오버) 엔진 재사용 횟수와 self-corr 상관관계. 3호(단독 사용) 0.138, 4호(신뢰도가중 콤보) 0.43, 5호후보(유동비율 콤보, 3번째 사용) 0.72대로 상승. 같은 강엔진을 반복 재사용할수록 상관 누적 위험 증가.