목적함수 설계: 최적화하는 지표가 전략을 은밀하게 고른다
"환상 없는 백테스트" 시리즈의 일부입니다.
📄 이 글은 하나의 연구 논문으로 발전했습니다. 아래의 모든 숫자는 통제된 실측값을 구축하는 하나의 결정론적 스크립트에서 나옵니다 — 중간 신호대에 알려진 엣지가 있고 어디에나 팻테일 노이즈가 있는 합성 시장을 만든 다음, 여섯 가지 서로 다른 목적함수 아래에서 하나의 임계값 서치를 실행하고, 각 목적함수가 실제로 어떤 전략을 선택하는지를 아웃오브샘플에서 측정합니다. 논문은 objective-design.marketmaker.cc에서 온라인으로(인터랙티브 버전 + PDF) 읽을 수 있으며, 코드와 데이터는 github.com/suenot/objective-design-degeneracy에 있습니다.
당신은 최선의 전략을 원합니다. 그래서 서치를 돌립니다 — 임계값, 룩백, 스탑 거리를 스윕하고, 가장 높은 점수를 낸 설정을 남깁니다. 서치가 끝나고 승자를 건네줍니다. 합리적입니다. 표준적입니다. 이 세상의 모든 옵티마이저, 그리드 서치, 하이퍼파라미터 튜너가 하는 일입니다.
하지만 동사를 보십시오: 가장 높은 점수를 낸. 무엇에 대해 가장 높은가? 서치가 무언가를 승자로 옹립하기 전에, 당신은 극대화할 단 하나의 숫자 — 목적함수 — 를 건네줘야 했습니다. PnL. 샤프. 거래한 바에서만 계산한 샤프. 최대 낙폭 대비 수익률. 당신은 이 중 하나를 별생각 없이 타이핑했을 것이고, 그러면 서치는 백만 번의 평가를 당신이 요청한 그대로 정확히 수행하는 데 썼습니다.
그 하나의 선택은 형식적인 절차가 아닙니다. 그것이 결정의 전부입니다. 서치는 "좋은 전략"을 찾지 않습니다 — 추상적으로는 그런 것이 존재하지 않기 때문입니다. 서치는 당신이 고른 스칼라를 극대화하는 전략을 찾을 뿐이며, 서로 다른 스칼라는 동일한 데이터에서 완전히 다른 전략을 가리킵니다. 목적함수는 운전대를 쥔 은밀한 손이며, 대부분의 경우 아무도 그것을 보고 있지 않습니다.
이 글 전체를 하나의 표로 요약하면 다음과 같습니다. 하나의 임계값 서치, 진짜이며 알려진 엣지를 가진 하나의 합성 시장, 여섯 개의 목적함수 — 그리고 이들이 선택한 여섯 개의 전략을, 홀드아웃 데이터에서 측정한 것입니다:
| 목적함수 (서치가 극대화하는 것) | 평균 시장 노출도 | 인샘플 샤프 | 아웃오브샘플 샤프 | 퇴화한 승자 비율 |
|---|---|---|---|---|
| 원시 PnL | 0.859 | 1.76 | 1.61 | 0% |
| 전체 타임라인 샤프 | 0.740 | 1.82 | 1.71 | 0% |
| 거래당("활성") 샤프 | 0.286 | 1.00 | 0.70 | 57% |
| 노출 하한선 () | 0.740 | 1.82 | 1.71 | 0% |
| 거래 수 축소 (conf_k) | 0.523 | 1.54 | 1.31 | 20.7% |
| 견고한 목적함수 (하한선 + conf_k) | 0.675 | 1.78 | 1.70 | 0.2% |
독립적인 600개 시드, 각 바, 서치당 80개의 후보 임계값, 인샘플과 아웃오브샘플은 독립적으로 추출됨. 연율화 샤프(연 252기간). "퇴화"란 선택된 승자가 시장에 5% 미만의 시간 동안만 있거나, 0 이하의 아웃오브샘플 샤프를 기록하는 경우를 뜻합니다. 이 시장의 진짜 최적값은 아웃오브샘플 연율화 샤프 1.77입니다.
세 번째 행이 따끔할 때까지 읽으십시오. 거래당 샤프 — 거래한 바에서만 계산되는, 활동조건부 지표 전체 가족(거래당 샤프, 기대값, 반 타프의 SQN, 승률)을 대표하는 지표 — 는 아웃오브샘플에서 다른 절반보다 더 나쁜 전략을 선택하며, 57%의 빈도로 퇴화합니다. 이것은 미묘하게 더 나쁜 목적함수가 아닙니다. 이 데이터에서는 함정이며, 서치는 절반이 넘는 빈도로 그 함정에 걸어 들어갑니다. 이제 바로 위 행을 읽으십시오: 단순한 전체 타임라인 샤프는 결코 퇴화하지 않고 아웃오브샘플에서 1.71을 기록합니다. 이것이 전체 수리법의 결론을 미리 스포일러하는 것입니다 — 정직한 해법은 그저 전체 타임라인에서 측정하는 것뿐이며, 아래쪽 행들의 더 정교한 사후 보강책들은 잘해봐야 그 숫자와 같아질 뿐, 결코 넘어서지 못합니다. 이 글은 그 함정과 그 해법의 해부도이며, 실측값이 처음부터 끝까지 알려져 있으므로 "목적함수가 올바른 전략을 골랐는가?"는 의견이 아니라 사실이 됩니다.
1막 — 은밀한 결정: 굿하트의 법칙이 곧 서치다

1975년, 경제학자 찰스 굿하트는 자신이 남긴 다른 모든 것보다 오래 살아남은 한 문장을 썼습니다:
"관측된 어떠한 통계적 규칙성도, 통제 목적으로 그것에 압력이 가해지는 순간 붕괴하는 경향이 있다."
일반적으로 매릴린 스트래선의 것으로 여겨지는 더 간결한 파라프레이즈는 이렇습니다: 측정 지표가 목표가 되는 순간, 그것은 더 이상 좋은 측정 지표가 아니게 된다.
파라미터 서치는 굿하트의 법칙이 가장 순수한 형태로 나타나는 사례입니다. 목적함수가 측정 지표입니다. 서치가 바로 그 압력입니다 — 그 지표를 최대한 밀어 올리기 위한 수천, 수백만 번의 시도. 그리고 서치는 당신이 그 지표로 의도한 것이 무엇인지 조금도 신경 쓰지 않습니다. 오직 숫자에만 신경을 씁니다. 진짜로 거래 가능한 엣지와는 아무 상관 없이 그 숫자를 크게 만드는 방법이 있다면 — 드물게 거래하고, 대부분 가만히 있다가, 운 좋은 몇 개의 이상치를 잡는 것 — 서치는 그 방법을 찾아낼 것입니다. 최댓값을 찾는 것이 서치가 만들어진 단 하나의 목적이기 때문입니다.
이것은 AI 안전성 문헌이 **리워드 해킹(reward hacking)**이라 부르는 것과 동일한 실패입니다: 당신이 원하는 것의 *대리 지표(proxy)*를 최적화하는 에이전트는 그 대리 지표와 진짜 목표 사이의 모든 틈을 파고들 것입니다. 당신의 서치가 바로 그 에이전트입니다. "샤프 비율"이 그 대리 지표입니다. "다음 분기에 실제 돈으로 거래해도 믿을 수 있는 전략"이 진짜 목표입니다. 그 둘 사이의 틈, 그곳이 바로 이 학문 분야 전체가 살고 있는 곳입니다.
그 틈이 벌어지는 것을 지켜보려면, 진실을 알고 있는 세계가 필요합니다. 그래서 우리는 그런 세계를 만듭니다.
시장. 매 기간마다 예측자 (표준정규분포 신호)가 도착하고, 그 뒤를 이어 그것이 부분적으로 예측하는 수익률 가 나타납니다. 엣지는 진짜이지만 제한적입니다 — 중간 신호대 안에서만 존재하고, 그 밖에서는 사라집니다:
두 가지 설계 선택이 중요합니다. 첫째, 엣지는 중간 대역에 있습니다: 극단적인 신호는 예측 정보를 전혀 담고 있지 않으므로, 전략은 중간을 거래하고 꼬리는 건너뛰어야 합니다. 둘째, 노이즈 는 팻테일입니다(자유도 4의 스튜던트-, 실제 수익률이 실제로 가지는 종류의 두꺼운 꼬리) — 하지만 이 요소는 메커니즘이 아니라 현실성을 위해 존재합니다. 팻테일이 함정을 가능하게 만드는 요인이라고 말하고 싶은 유혹이 들며, 우리도 통제 실험을 돌리기 전까지는 정확히 그렇게 가정했습니다: 이 시장의 가우시안 노이즈 버전(결과에서 gaussian_control, 300개 시드)은 함정을 사실상 변함없이 재현합니다 — 거래당 목적함수는 가우시안 노이즈 하에서도 여전히 **55.7%**의 빈도로 퇴화하며(팻테일에서는 57.0%), 아웃오브샘플 샤프는 0.71입니다(팻테일에서는 0.70). 따라서 함정은 팻테일 때문이 아닙니다. 이것은 순수한 소표본-플러스-선택 효과입니다: 소수의 관측치로 계산한 샤프의, 약 20개의 저노출 임계값에 걸친 최댓값을 취하면, 운 좋은 어느 구석은 언제나 눈부셔 보이게 됩니다. 어떤 노이즈 분포든 이렇게 만듭니다; 단 몇 개의 바 동안만 시장에 있는 전략은 순전히 운만으로 몇 번의 유리한 움직임을 버텨내고 아무 의미도 없는 인샘플 수치를 기록할 수 있습니다. 우리가 팻테일을 유지하는 것은 함정에 그것이 필요해서가 아니라, 실제 수익률이 그것을 가지고 있기 때문입니다.
전략. 단일 파라미터 가족입니다. 신호의 크기가 임계값 미만일 때는 언제나 신호 방향으로 거래하고, 그렇지 않으면 플랫 상태를 유지합니다:
아주 작은 는 가장 작고 가장 평범한 신호에서만 거래합니다 — 희귀 거래 복권이며, 시장에 거의 있지 않습니다. 대역 가장자리 근처의 는 진짜 엣지 전체를 포착하며 노출도가 충분합니다. 거대한 는 엣지가 전혀 없고 노이즈만 더하는 대역 밖의 바까지 포함해 모든 것을 거래합니다.
def gen_dataset(T, rng, beta=0.30, band=1.0, tail_df=4):
s = rng.standard_normal(T)
edge = beta * np.where(np.abs(s) <= band, s, 0.0) # edge ONLY inside |s| <= 1
t = rng.standard_t(tail_df, T) / np.sqrt(tail_df / (tail_df - 2.0)) # fat tails, unit var
return s, edge + t
def simulate(s, r, theta):
pos = np.where(np.abs(s) <= theta, np.sign(s), 0.0) # trade the band, skip outliers
strat = pos * r
active = pos != 0.0
exposure = active.mean() # fraction of bars in a position
sharpe_full = strat.mean() / strat.std(ddof=1) # on the WHOLE timeline
sharpe_active = strat[active].mean() / strat[active].std(ddof=1) # on ONLY the active bars
return dict(exposure=exposure, n_trades=int(active.sum()),
sharpe_full=sharpe_full, sharpe_active=sharpe_active, pnl=strat.sum())
우리가 이 시장을 직접 만들었기 때문에, 진실을 직접 계산할 수 있습니다 — 600개 시드 전체에 걸쳐, 아웃오브샘플에서, 모든 임계값에서의 평균 성과를 말입니다. 진짜 최적값은 에 있습니다: 신호 대역의 가장자리 바로 지점이며, 약 **70%**의 시간 동안 시장에 있고(도출: 표준정규분포 신호가 안에 들어갈 확률은 입니다), 아웃오브샘플 연율화 샤프 1.77을 기록합니다. 이것이 모든 목적함수가 찾아내려 애쓰는 숫자입니다. 이것을 기억해 두십시오: θ≈1.04, OOS 샤프 1.77, 타임라인의 약 70%를 시장에 있음. 목적함수가 선택한 것이 이것과 거리가 멀다면, 그것은 시장이 어려워서가 아니라 목적함수가 실패한 것입니다.
2막 — 함정: 운 좋은 여덟 번의 거래, 샤프 21, 그리고 신기루

이제 나이브한 목적함수를 이 시장의 구체적인 하나의 추출 — 시드 6 — 에 풀어놓아 봅시다. 시드에 대해 솔직히 밝힙니다: 이것은 첫 번째 추출도, 무작위로 고른 것도 아닙니다. 우리는 극명하게 퇴화한 거래당 승자를 찾아 여러 시드를 훑어본 다음 이것을 골랐습니다. 정확히 그 메커니즘을 놓칠 수 없게 만들기 위해서입니다. 여기서 보여주는 결과는 철저하게 전형적입니다 — 3막이 확인해 주겠지만, 거래당 목적함수는 전체 시드의 56%에서 노출도 5% 미만의 복권을 고릅니다 — 하지만 시드 6의 크기는 그 분포의 극단 끝에 있습니다. 이것을 중앙값 사례가 아니라, 흔한 실패의 특히 극명한 사례로 읽으십시오. 우리는 거래당 샤프를 최적화합니다: 전략이 실제로 포지션을 보유한 바에서만 계산한 샤프 비율입니다. 이것은 보고하기에 대단히 자연스러운 것입니다. "거래할 때, 그 거래는 얼마나 좋았는가?" 스킬을 유휴 상태로부터 분리해 내는 것처럼 느껴집니다. 실제로는 그 반대입니다.
다음은 거래당 샤프가 시드 6에서 승자로 옹립한 전략입니다:
- 임계값 — 가장 미세한 신호에서만 거래합니다.
- 시장 노출도 0.4% — 99.6%의 시간 동안 플랫 상태입니다.
- 여덟 번의 거래. 여덟 번. 2000개의 바에 걸쳐서요.
- 인샘플 거래당 연율화 샤프: 21.09.
- 인샘플 전체 타임라인 샤프: 0.82.
- 아웃오브샘플 전체 타임라인 샤프: 0.13.
거래당 지표는 21.09를 기록합니다 — 실제 전략이 낸 적 없는 숫자이며, 펀드를 출시하게 만들 법한 종류의 수치입니다. 그리고 이것은 완전한 신기루입니다. 그 여덟 번의 거래는 우연히 몇 번의 유리한 움직임을 잡아냈습니다; 딱 그 여덟 개의 바에서만 측정하면, 평균 대 표준편차 비율은 천문학적입니다. 하지만 전체 타임라인 — 전략이 99.6%의 시간 동안 플랫 상태인 곳 — 에서는, 그 "엣지"가 사실상 아무것도 기여하지 않습니다: 인샘플 전체 타임라인 샤프는 0.82이고, 새 데이터에서는 0.13으로 무너집니다. 목적함수가 선택한 승자는, 거래의 모든 실질적 목적에서, 플랫 상태입니다.
그리고 그 임계값에는 진짜 엣지조차 없습니다. 시장을 떠올려 보십시오: 엣지는 대역 안에 있고, 는 신호가 가장 약한 정중앙에 자리합니다. 에서의 진짜 아웃오브샘플 곡선은 −0.01입니다 — 0과 구별할 수 없습니다(실측값 곡선에서 도출). 서치는 작지만 진짜인 엣지를 찾은 것이 아닙니다. 노이즈의 운 좋은 여덟 번의 추출을 찾아내고는 그것을 샤프 21로 보고한 것입니다.
이것이 축소판 함정입니다: 거래당 샤프는 전략이 최대한 드물게 거래하도록 보상합니다, 왜냐하면 발을 딛는 바가 적을수록 그중 몇 개가 운이 좋기가 더 쉬워지고, 이 지표는 "그런데 실제로 시장에 있었는가?"라는 질문을 단 한 번도 던지지 않기 때문입니다. 시드 6의 크기는 우리가 극명한 것을 찾아 나섰기에 취사선택된 것입니다 — 하지만 그 종류는 그렇지 않습니다. 600개 전체 시드에 걸쳐 거래당 샤프는 **57%**에서 퇴화한(거의 거래하지 않거나 아웃오브샘플에서 손실을 내는) 승자를 선택하며, 구체적으로 **56%**에서 노출도 5% 미만의 복권을 선택합니다. 전형적인 퇴화 선택은 시드 6의 샤프 21보다 훨씬 얌전합니다: 600개 시드 전체에 걸쳐 평균을 내면, 거래당 목적함수의 승자는 인샘플 거래당 샤프 4.58과 평균 노출도 0.286을 가집니다 — 여전히 대부분의 시간 동안 플랫이지만, 99.6% 플랫은 아닙니다. 시드 6은 메커니즘을 극적으로 보여줄 뿐이며, 당신을 걱정하게 만들어야 할 부분은 56%입니다. 절반이 넘는 빈도로, 이 흔한 지표는 당신에게 복권을 건네주고는 그것을 전략이라 부릅니다.
3막 — 통계적 진실: 여섯 개의 목적함수, 600개의 시드

하나의 시드는 아무것도 증명하지 못합니다; 그것은 그저 예시일 뿐입니다. 목적함수를 측정하려면 그것이 많은 독립적인 시장에 걸쳐 평균적으로 무엇을 선택하는지 물어야 하고, 그 선택을 서치가 한 번도 본 적 없는 데이터에서 채점해야 합니다. 그래서: 600개의 시드, 각각 시장의 독립적인 추출; 각각에 대해, 각 목적함수 아래에서 80개 임계값 서치를 실행; 무엇을 골랐든 그 노출도, 인샘플과 아웃오브샘플 샤프, 그리고 그 선택이 퇴화했는지 여부를 기록합니다.
| 목적함수 | 평균 노출도 | 인샘플 샤프 | 아웃오브샘플 샤프 | IS→OOS 하락폭(절댓값) | 퇴화 비율 |
|---|---|---|---|---|---|
| 원시 PnL | 0.859 | 1.76 | 1.61 | 0.15 | 0.0% |
| 전체 타임라인 샤프 | 0.740 | 1.82 | 1.71 | 0.11 | 0.0% |
| 거래당 샤프 | 0.286 | 1.00 | 0.70 | 0.30 | 57% |
| 노출 하한선 () | 0.740 | 1.82 | 1.71 | 0.11 | 0.0% |
| conf_k 축소 () | 0.523 | 1.54 | 1.31 | 0.23 | 20.7% |
| 견고한 목적함수 (하한선 + conf_k) | 0.675 | 1.78 | 1.70 | 0.08 | 0.2% |
"IS→OOS 하락폭" 열은 인샘플에서 아웃오브샘플로 넘어갈 때 연율화 샤프가 절대적으로 떨어진 폭입니다(예: 은 0.30의 하락입니다), 퍼센트가 아닙니다. 그리고 "노출 하한선" 행이 "전체 타임라인 샤프"와 바이트 단위로 완전히 동일하다는 점에 주목하십시오: 이것은 우연이 아니며, 5막에서 그 이유를 설명합니다.
세 가지 사실이 눈에 띄며, 각각이 하나의 교훈입니다.
거래당 샤프는 퇴화하는 유일한 나이브 목적함수입니다. 평균 노출도는 0.286입니다 — 대부분의 시간 동안 플랫인 전략을 선택한다는 뜻입니다 — 그리고 인샘플 샤프 1.00은 아웃오브샘플 0.70으로 0.30만큼 떨어지며, 전체 중 가장 나쁩니다. 단서를 눈여겨보십시오: 인샘플 수치(1.00)조차 인상적이지 않은데도, 단일 시드에서는 기꺼이 21이라는 거래당 수치를 보고할 것입니다. 운 좋은 구간들이 무작위 방향을 가리키기 때문에 평균은 씻겨 나가며; 아웃오브샘플까지 살아남는 것은 겨우 0.70이고, 개별 선택의 57%는 완전히 쓰레기입니다.
노출도를 인식하는 목적함수는 본질적으로 안전합니다. 원시 PnL과 전체 타임라인 샤프는 결코 퇴화하지 않습니다(0.0%). 그 이유는 구조적입니다: 둘 다 전체 타임라인에 걸쳐 측정되므로, 99.6%의 시간 동안 플랫인 전략은 이들 아래에서 거의 아무것도 벌지 못합니다. 드물게 거래해서 전체 타임라인 지표를 속일 수는 없습니다 — 플랫 상태로 있는 것은 직접적이고 자동적으로 페널티를 받습니다. 플랫 바가 분모에 들어가기 때문입니다. 이것이 이 글에서 가장 중요한 단 하나의 아이디어이며, 6막에서 다시 다룹니다.
원시 PnL은 안전하지만 최적은 아닙니다 — 과다 노출됩니다. 자세히 보십시오: 원시 PnL의 평균 노출도는 0.859로 전체 중 가장 높으며, 아웃오브샘플 샤프(1.61)는 전체 타임라인 샤프(1.71)와 진짜 최적값(1.77)보다 한 단계 낮습니다. PnL은 시장에 있는 것 자체를 보상하므로, 서치는 를 너무 높게 밀어붙입니다(시드 6에서, 원시 PnL은 최적값 1.04 대신 를 고릅니다), 엣지가 전혀 없고 노이즈만 더하는 대역 밖 바들을 끌어들이면서 말입니다. 이것은 폭발하지는 않습니다 — 하지만 거래당 함정과는 반대 방향으로 진짜 최적값을 지나쳐 표류합니다. 다른 목적함수, 다른 편향, 같은 교훈: 지표가 전략을 골랐습니다.
아직 논의하지 않은 두 행 — 노출 하한선과 conf_k — 이 바로 수리법입니다. 그것이 다음 막입니다.
4막 — 여덟 번의 거래를 결코 신뢰할 수 없는 이유

함정을 수리하기 전에, 여덟 번의 거래가 아무 의미 없는 샤프 21을 만들어내는 이유를 정확히 짚어볼 가치가 있습니다 — 해법이 그 이유로부터 직접 따라 나오기 때문입니다.
샤프 비율은 추정치이고, 추정치에는 오차 막대가 있습니다. 앤드루 로(Andrew Lo)의 2002년 결과는 가장 관대한 가정(IID 가우시안 수익률) 하에서, 개의 관측치로부터 추정한 샤프 비율의 표준오차를 제시합니다:
오차는 오직 의 속도로만 줄어듭니다. 여기에 함정 사례를 대입해 봅시다. 시드 6의 거래당 샤프는 연율화 이며, 이는 개의 바로 계산한 관측치당 에 해당합니다. 표준오차는
(로의 공식에서 도출). 점추정치는 입니다; 1-시그마 오차 막대는 대략 정도입니다 — 이것을 정교하게 보정된 신뢰구간이 아니라 예시적인 크기 규모(order of magnitude)로 읽으십시오. 이 공식은 IID 가우시안 수익률을 가정하는데, 우리의 팻테일 노이즈는 그것을 위반하기 때문입니다. 그렇더라도, 메시지는 명백합니다: "샤프 21"이라는 숫자는 너무 넓어서 사실상 아무 정보도 담고 있지 않은 분포에서 뽑은 숫자입니다 — 그리고 이것은 관대한 계산일 뿐입니다. Mertens의 확장이 보여주듯, 팻테일과 왜도는 표준오차를 더욱더 부풀리기만 하기 때문입니다. 희귀 거래 백테스트의 샤프는 모든 방향에서 동시에 그 점값보다 덜 신뢰할 만합니다: 관측치가 너무 적고, 분포도 틀렸습니다.
이것이 바로 **최소 트랙 레코드 길이(Minimum Track Record Length)**가 공식화하는 것입니다(Bailey & López de Prado, 2012). 이것은 질문을 뒤집습니다 — 신뢰도 에서 이 정도 크기의 샤프를 믿어도 되기까지 몇 개의 관측치가 필요한가? —
"소수 거래 백테스트를 덜 신뢰하라"는 말을 명시적이고 확인 가능한 거래 수로 바꿔줍니다. 목적함수 설계에 대한 깊은 요점은 이것입니다: 좋은 목적함수는 내부에서부터 최소 트랙 레코드를 강제해야 합니다, 승자가 여덟 개의 관측치에 기대고 있다는 것을 사람이 사후에 알아채도록 내버려 두는 대신 말입니다. 거래당 샤프는 그 반대로 행동합니다 — 관측치 개수를 최소값 쪽으로 밀어붙임으로써 극대화됩니다. 최적값이 "가능한 한 적은 거래"에 자리하는 목적함수는, 구조상, 자기 자신의 가장 신뢰할 수 없는 추정치를 찾아 헤매는 목적함수입니다.
함정 안에는 두 가지 실패가 복합적으로 작용하며, 둘 다 이름을 붙이면 고치는 방법도 알 수 있습니다. 첫째, 소표본 노이즈: 여덟 개의 관측치로는 어떤 비율도 확정할 수 없습니다. 둘째, 선택: 그 여덟 개의 바는 우리에게 주어진 것이 아닙니다 — 서치가 그것들에 착지한 임계값을 선택했으며, 부분적으로는 그것들이 운이 좋았기 때문입니다. 서치는 극대화기입니다; 그것은 언제나 노이즈가 우연히 신호처럼 보이는 공간의 구석을 찾아낼 것입니다. 더 나은 점추정치로는 이것을 이길 수 없습니다. "최선"이 의미하는 바를 바꿔서 운 좋은 구석이 최댓값이 되지 않도록 해야 합니다.
5막 — 수리법: 노출 하한선과 거래 수 축소

우리에게는 이름 붙인 두 가지 질병이 있습니다 — 너무 드물게 거래한다와 너무 적은 관측치에 기댄다 — 그래서 각각을 겨냥한 두 가지 치료법을 씁니다.
치료법 1: 노출 하한선. 가능한 가장 단순한 해법입니다. 적어도 의 시간 동안 시장에 있지 않은 전략은 무조건 기각합니다 — 거의 거래하지 않으면, 점수는 가 되고 서치는 당신을 선택할 수 없습니다. 하지만 무엇에 하한선을 씌우는지에는 정직한 미묘함이 있으며, 이것이 이 글 전체의 조용한 교훈입니다. 독립적인 목적함수로서 우리는 전체 타임라인 샤프에 하한선을 씌웠는데, 이 시장에서는 그것이 아무것도 바꾸지 않습니다: 전체 타임라인 샤프 자체의 승자는 이미 노출도 약 74%에 있으므로, 20% 하한선은 단 한 번도 걸리지 않습니다. 이것이 바로 위 표들의 "노출 하한선" 행과 "전체 타임라인 샤프" 행이 바이트 단위로 완전히 동일한 이유입니다 — 이미 안전한 지표에 하한선을 볼트로 고정하면, 그저 전체 샤프를 다시 도출한 것에 불과합니다. 하한선이 눈에 보이는 작업을 하는 것은 오직 그것이 지키지 않으면 구석으로 질주할 지표를 지키고 있을 때뿐입니다: 아래의 견고한 목적함수에서처럼 거래당 지표가 그렇습니다. 다시 말해, "노출도를 요구하는 것"과 "전체 타임라인에서 측정하는 것"은, 이 데이터에서는, 같은 개입을 가리키는 두 개의 이름입니다.
치료법 2: 거래 수 축소 — "conf_k". 거래당 지표에 발이 묶여 있고 하드 컷오프 대신 부드러운 보정을 원할 때를 위한 것입니다: 샤프가 기대고 있는 거래 수만큼 연속적으로 할인합니다. 를 곱합니다. 여기서 은 거래 수이고 는 고정된 "신뢰 상수" — 서치 이전에 선택하는, 거래 수와 동등한 사전 강도입니다:
일 때 점수는 원시 샤프가 아무리 크더라도 0으로 짓눌립니다; 일 때 점수는 원시 샤프로 수렴합니다. 이것은 MinTRL 및 4막의 표준오차와 동일한 보정 논리입니다 — 소표본 추정치를 표본 크기의 감소함수로 0을 향해 축소시키는 것 — 다만 사후 필터로 적용하는 대신 목적함수 안으로 직접 접어 넣은 것입니다. 가장 가까운 이름 붙은 선례는 반 타프(van Tharp)의 시스템 퀄리티 넘버(System Quality Number)()로, 이 역시 거래당 품질 지표를 거래 수 에 따라 척도화합니다 — 다만 함수 형태는 다릅니다(은 무한히 커지는 반면, 는 1에서 포화됩니다). 형태상 우리 것은 베이지안 정밀도-가중 / 경험적 베이즈 스타일의 축소이며; 문헌에서 가져온 이름 붙은 추정량이 아니라 이 문제를 위한 우리의 구성물입니다.
def obj_active_sharpe(m): # the trap: Sharpe on only the active bars
return m["sharpe_active"]
def _shrink(n, conf_k): # trade-count shrinkage n / (n + k)
return n / (n + conf_k) if (n + conf_k) > 0 else 0.0
def obj_confk(m, conf_k=40.0): # few trades -> little credit
return m["sharpe_active"] * _shrink(m["n_trades"], conf_k)
def obj_robust(m, e_min=0.20, conf_k=40.0): # both cures at once
if m["exposure"] < e_min: # floor: reject strategies that barely trade
return -np.inf
return m["sharpe_active"] * _shrink(m["n_trades"], conf_k)
이제 정직한 부분입니다: 얼마나 많은 하한선, 얼마나 많은 축소가 필요할까요? 둘 다 스윕하고 표면 전체를 읽으십시오. 각 셀은 200개 시드(2차원 스윕을 저렴하게 유지하기 위한 600개의 3분의 1 부분집합)에 걸친 평균 아웃오브샘플 샤프이며, 그 옆에 퇴화 비율이 표시되어 있습니다:
| \ conf_k | |||
|---|---|---|---|
| 0.00 | 0.66 (59.5%) | 1.26 (22.5%) | 1.47 (11.5%) |
| 0.05 | 1.43 (10.0%) | 1.53 (6.0%) | 1.60 (4.0%) |
| 0.10 | 1.64 (1.5%) | 1.65 (1.0%) | 1.67 (1.0%) |
| 0.20 | 1.71 (0.0%) | 1.71 (0.0%) | 1.71 (0.0%) |
| 0.35 | 1.73 (0.0%) | 1.73 (0.0%) | 1.73 (0.0%) |
평균 아웃오브샘플 연율화 샤프, 괄호 안은 퇴화 비율. 왼쪽 위 셀 은 원시 거래당 샤프입니다 — 하한선 없음, 축소 없음: OOS 0.66, 퇴화 59.5%. 이것은 3막의 거래당 행(0.70 / 57%)과 동일한 목적함수입니다; 작은 차이는 순전히 시드 집합 때문입니다 — 이 스윕은 200개 시드를 쓰고, 몬테카를로는 600개 전체를 썼습니다. 같은 지표, 더 작은 표본.
이 표면은 세 가지 읽기로 깔끔한 이야기를 들려줍니다.
각 치료법은 단독으로도 작동합니다. 맨 위 행을 따라 오른쪽으로 이동하면(축소를 추가하고, 하한선 없음): OOS는 로 상승하고 퇴화는 로 떨어집니다. 왼쪽 열을 따라 아래로 이동하면(하한선을 추가하고, 축소 없음): OOS는 로 상승하고 퇴화는 로 떨어집니다. 어느 다이얼이든 단독으로 돌리면 독립적으로 아웃오브샘플 성과를 끌어올리고 퇴화를 없앱니다. 노출 하한선이 여기서 더 강력한 단일 지렛대인데, 함정을 정의하는 특징 — 거의 0에 가까운 노출도 — 을 정면으로 공격하기 때문입니다.
두 치료법을 합치면 고원에 도달합니다 — 그리고 그 고원은 그저 전체 타임라인 샤프일 뿐입니다. 에 이르면 행은 모든 축소 수준에서 OOS 1.71, **퇴화 0%**로 평평해집니다; 까지 밀어붙이면 1.73으로 조금씩 나아갑니다. 하지만 그 1.71이 무엇인지 유심히 보십시오: 이것은 하한선도 축소도 전혀 없이 3막에서 단순한 전체 타임라인 샤프가 기록한 것과 정확히 같은 점수입니다. 잘해봐야, 사후 보강책들은 전체 타임라인 샤프를 넘어서지 못합니다 — 그것을 재구성할 뿐입니다. 그리고 완전히 수리된 견고한 목적함수조차 거기에 딱 도달하지는 못합니다: 600개 시드 전체에 걸쳐 OOS 1.70에 잔여 퇴화 **0.17%**로 착지하며, 전체 샤프의 1.71 / 0%보다 아주 살짝 낮습니다 — 더 단순한 지표에 의해 약하게 지배당하는 것입니다. 적당한 중간 설정, 과 은 OOS 1.65, **퇴화 1%**에 도달합니다 — 거래당 지표가 강제된다면 유용하지만, 그것을 선호할 이유는 결코 되지 않습니다.
정확한 숫자는 스케일에 의존합니다 — 모양이야말로 결과입니다. 이 시장을 완전히 수리하는 구체적인 값 , 은 이 데이터 생성 과정에 맞춰 튜닝된 것입니다; 거래 빈도와 꼬리 두께가 다른 시장에서는 고원이 다른 곳에 자리합니다. 일반화되는 것은 좌표가 아니라 표면입니다: 양방향 모두에서의 단조 상승, 0으로 몰리는 퇴화, 진실에 자리한 고원. 자신만의 좌표는 위와 정확히 같은 방식으로 스윕해서 찾아야 합니다.
두 치료법을 함께 적용해 — 하한선 0.20에 conf_k 40을 더한 견고한 목적함수 — 시드 6으로 돌아가 봅시다. 함정은 , 여덟 번의 거래, 전체 타임라인 OOS 샤프 0.13을 승자로 옹립했습니다. 견고한 목적함수는 대신 를 선택합니다: 시장 노출도 0.66, 447번의 거래, 아웃오브샘플 연율화 샤프 1.77. 이 는 진짜 최적값 보다 한 그리드 포인트 아래에 있으므로, 정중앙에 정확히 안착하기보다는 거의 최적이고 노출도가 충분한 임계값을 되찾은 것입니다 — 그 단일 시드의 아웃오브샘플 샤프(1.77)는 우연히 모집단 최적값과 일치합니다. 같은 데이터, 같은 서치, 같은 80개의 후보 임계값. 오직 "최선"의 정의만 바뀌었을 뿐인데, 그것이 승자를 플랫한 여덟-거래 신기루에서 진짜이며 노출도가 충분한 엣지로 옮겨 놓았습니다 — 그리고 시사하는 바가 있게도, 이것은 바로 이 시드에서 단순한 전체 타임라인 샤프가 고르는 것과 정확히 같은 임계값입니다.
스윕이 명시적으로 드러내는 한 가지 경고: 이 시장에서는 conf_k 단독으로는 충분하지 않습니다. 하한선 없이 일 때, 시드 전체에 걸쳐 퇴화는 여전히 22.5%입니다 — 그리고 구체적으로 시드 6에서, conf_k 단독은 , 35번의 거래, 아웃오브샘플 샤프 −0.06을 고릅니다. 35번의 거래는 의 축소를 견뎌내고도 승리하기에 충분한 점수를 남깁니다. 그 마지막 틈을 메우는 것은 노출 하한선입니다. 왜냐하면 그것은 거래 수를 대리 지표로 신뢰하는 대신, 함정의 진짜 특징 — 플랫 상태라는 것 — 을 직접 겨냥하기 때문입니다.
6막 — 더 깊은 교훈: 전체 타임라인에서 측정하라

수리법에서 한 발 물러서서, 실제로 안전한 목적함수와 함정을 갈라놓은 것이 무엇이었는지 살펴봅시다. 그것은 정교함이 아니었습니다. 원시 PnL과 전체 타임라인 샤프는 거래당 샤프보다 더 단순하며, 하한선도, 축소도, 튜닝도 전혀 없이 결코 퇴화하지 않았습니다 — 600개 시드에 걸쳐 0%.
가르는 선은 단 하나의 속성입니다: 그 지표가 어떤 윈도우를 측정하는가? 거래당 샤프는 전략이 서기로 선택한 바만을 측정합니다 — 서치가 마음대로 줄일 수 있는 자기선택적 윈도우입니다. 전체 타임라인 샤프와 총 PnL은 플랫 바를 포함한 전체 타임라인을 측정합니다. 그리고 드물게 거래해서 전체 타임라인 지표를 크게 만들 수는 없습니다. 플랫으로 앉아 있는 매 시간이 아무것도 벌지 못하는 채로 분모에 들어가기 때문입니다. 노출 하한선과 conf_k는, 결국, 전체 타임라인 지표가 공짜로 가지고 있는 노출도 인식 능력을 거래당 지표에 사후 보강하는 방법일 뿐입니다 — 그리고 스윕은 이미 그 사후 보강의 한계를 알려주었습니다: 잘해봐야 전체 타임라인 샤프와 같아질 뿐(OOS 1.70 대 1.71), 결코 넘어서지 못합니다. 윈도우를 자유롭게 선택할 수 있다면, 전체 타임라인을 선택하고 사후 보강 자체를 건너뛰십시오.
그러니 설계 원칙을 명확히 말하면 다음과 같습니다:
운 좋은 희귀 거래로 속일 수 없도록 목적함수를 설계하십시오. 대략적인 선호 순서로 세 가지 도구가 있습니다:
- 전체 타임라인에서 측정하십시오. 거의 결코 벗어나서는 안 되는 기본값입니다. 전체 타임라인 샤프와 총 수익률은 구조상 노출도를 인식합니다 — 플랫 바도 카운트되므로 유휴 상태는 자동으로 페널티를 받습니다. "우리가 활동 중이었던 바에서만" 계산한 지표를 보고하고 있다는 것을 깨달았다면, 멈추고 그 바들을 선택할 자유를 가진 서치가 무엇을 할지 자문해 보십시오.
- 노출도를 요구하십시오. 활동조건부 지표를 반드시 써야 한다면, 노출도에 하한선을 씌워 서치가 거의 거래하지 않는 전략을 선택하지 못하게 하십시오. 이것이 이 특정 함정에 맞서는 가장 강력한 단일 지렛대입니다.
- 거래 수로 축소하십시오. 어떤 비율이든 로 할인해서, 소수의 관측치에 기댄 샤프가 수천 개에 기댄 샤프의 일부만큼만 credit을 받도록 하십시오. 이것은 최소 트랙 레코드 길이를 목적함수 수준에서 강제하는 것입니다: 적은 관측치에서 나온 숫자는 신뢰할 수 없으며(4막), 정직한 목적함수는 사람이 나중에 그것을 알아채도록 믿는 대신 그 신뢰할 수 없음을 미리 가격에 반영합니다.
이 중 어떤 것도 서치를 더 똑똑하게 만들지 않습니다. 목표를 정직하게 만들 뿐이며, 그래서 서치가 언제나 하는 일 — 최댓값을 찾는 것 — 을 정확히 수행할 때, 그 최댓값이 당신이 실제로 원하는 전략이 되도록 합니다.
정직성에 관한 노트
세 가지 유보 조항을 솔직하게 밝힙니다. 통제된 연구는 오직 자신의 한계를 명명함으로써만 그 결론을 얻을 자격을 갖추기 때문입니다.
- 시장은 합성 데이터이며, 의도적으로 그렇게 만들었습니다. 표준정규분포 신호, 에 국한된 선형 엣지, 팻테일 스튜던트-() 노이즈 — 시장 현실성이 아니라 통제된 실측값을 위해 선택된 것입니다. 우리는 오직 어떤 전략이 옳은지 아는 데이터에서 목적함수를 돌려봄으로써만 목적함수가 잘못된 전략을 고른다는 것을 증명할 수 있습니다. 실제 시장은 비정상적이고, 자기상관되어 있으며, 레짐이 전환됩니다. 팻테일은 우리가 유지한 현실적인 요소이지만 — 자연스러운 첫 직관과는 반대로, 그리고 바로 이 글의 이전 초안과도 반대로 — 함정을 작동시키는 것은 팻테일이 아닙니다: 가우시안 노이즈 통제 실험(300개 시드)은 여기서의 **57.0%**에 비해 **55.7%**의 빈도로 퇴화하며, 아웃오브샘플 샤프는 0.70에 비해 0.71입니다. 함정은 두꺼운 꼬리가 있든 없든 살아남는 소표본-플러스-선택 인공물입니다. 이 글의 결과물은 진단과 수리 패턴이지, 전략도 아니고 보편 상수도 아닙니다.
- 수리 값들은 스케일에 의존합니다. 함정을 완전히 닫는 구체적인 하한선 과 축소 은 이 데이터 생성 과정 — 거래 빈도, 꼬리 두께, 엣지 크기 — 에 맞춰진 것입니다. 다른 데이터에서는 고원이 이동합니다. 전이되는 것은 스윕 표면의 모양(양쪽 다이얼에서의 단조 상승, 0으로 향하는 퇴화, 진실에 자리한 고원)과 자신만의 좌표를 찾는 방법입니다: 둘 다 스윕하고 표면을 읽으십시오, 숫자를 그대로 복사하지 마십시오.
- conf_k는 우리의 구성물이지, 이름 붙은 추정량이 아닙니다. 거래 수 축소 는 이 문제를 위해 우리가 만든 베이지안 정밀도-가중 / 경험적 베이즈 스타일의 장치입니다; 그 근거는 검증된 로/Mertens 표준오차 결과와 Bailey–López de Prado의 MinTRL에 뿌리를 두고 있으며, 가장 가까운 이름 붙은 친척은 반 타프의 시스템 퀄리티 넘버(, 다른 함수 형태)이지만, 그 자체가 문헌에 어떤 이름으로 등장한다고 주장하지는 않습니다. 그것의 동반 치료법 — 노출 하한선, 전체 타임라인 측정 — 은 정밀하게 서술된 표준 관행입니다. 그리고 여기서 어떤 목적함수가 이미 안전했는지 눈여겨보십시오: 원시 PnL과 전체 타임라인 샤프는 결코 수리가 필요하지 않았습니다. 처음부터 노출도를 인식하기 때문입니다 — 어찌나 그런지, 전체 타임라인 샤프에 하한선을 씌우는 것은 그저 전체 타임라인 샤프로 환원됩니다. 그 승자가 이미 어떤 합리적인 하한선도 통과하기 때문입니다. 함정은 구체적으로 거래당 / 활성 샤프이며 — 완전히 수리된 거래당 목적함수조차 전체 타임라인 샤프와 같아질 뿐(OOS 1.70 대 1.71), 결코 넘어서지 못합니다. 가장 중요한 교훈은 수리법이 아닙니다; 애초에 전체 타임라인에서 측정하라는 것입니다.
핵심 요점
- 목적함수는 형식적인 절차가 아니라 결정 그 자체입니다. 서치는 "좋은 전략"을 찾지 않습니다 — 당신이 건네준 어떤 스칼라든 그것의 극대화기를 찾을 뿐이며, 서로 다른 스칼라는 동일한 데이터에서 완전히 다른 전략을 선택합니다. 목적함수를 선택하는 것이 곧 전략을 선택하는 것입니다; 그 이후의 모든 것은 부기(bookkeeping)일 뿐입니다. 이것이 굿하트의 법칙입니다: 당신의 지표가 서치의 목표가 되는 순간, 서치는 그 지표와 당신이 의도한 것 사이의 모든 틈을 파고들 것입니다.
- 거래당 샤프는 함정입니다. 전략이 거래하는 바에서만 측정되며, 최대한 드물게 거래함으로써 극대화됩니다 — 관측치가 적을수록, 몇 번의 운 좋은 움직임이 비율을 부풀리기가 더 쉬워집니다(가우시안 통제 실험은 팻테일이 필요하지 않다는 것을 확인해 줍니다; 이것은 소표본-플러스-선택 효과입니다). 600개 시드 전체에 걸쳐 **56%**에서 노출도 5% 미만의 복권을 고르고 **57%**에서 퇴화합니다; 전형적인 퇴화 선택은 평균적으로 인샘플 거래당 샤프 4.58을 기록합니다. 의도적으로 극명하게 고른 한 시드에서는 인샘플 거래당 샤프 21.09를 기록한 여덟-거래, 노출도 0.4% 전략을 승자로 옹립했다가, 전체 타임라인 아웃오브샘플 샤프 0.13으로 무너졌습니다. 여덟 개의 관측치로 만든 비율은 연율화 ±7.7 정도의 표준오차를 가집니다(4막) — 그것은 결코 정보가 아니었습니다.
- 노출도를 인식하는 목적함수는 본질적으로 안전합니다. 원시 PnL과 전체 타임라인 샤프는 결코 퇴화하지 않았습니다(0%). 전체 타임라인을 측정하고 유휴 상태가 자동으로 페널티를 받기 때문입니다. 드물게 거래해서 전체 타임라인 지표를 속일 수는 없습니다. 원시 PnL의 유일한 결함은 반대 방향의 편향입니다 — 과다 노출됩니다(평균 노출도 0.859, OOS 1.61 대 진짜 1.77), 시장에 더 많이 있기 위해 를 최적값 너머로 표류시킵니다.
- 수리법은 효과가 있습니다 — 하지만 그것은 그저 전체 타임라인 샤프로 돌아가게 할 뿐입니다. 노출 하한선과 거래 수(conf_k) 축소는 각각 독립적으로 아웃오브샘플 샤프를 끌어올리고 퇴화를 0을 향해 몰아갑니다; 함께 쓰면 고원에 도달합니다. 하지만 그 고원은 바로 전체 타임라인 샤프입니다: 퇴화는 에서의 **59.5%**에서 에 이르러 **0%**로 떨어지고 OOS 샤프는 0.66에서 1.71로 상승합니다 — 이는 단순한 전체 샤프가 아무 도움 없이 기록하는 것과 정확히 같은 숫자이며, 완전히 수리된 견고한 목적함수는 실제로 거기서 아주 살짝 못 미치게 착지합니다(OOS 1.70, 퇴화 0.17%: 약하게 지배당함). 시드 6에서 견고한 목적함수는 거의 최적이고 노출도가 충분한 임계값을 되찾습니다(, 진짜 보다 한 그리드 포인트 아래; 447번의 거래; OOS 샤프 1.77). conf_k를 전체 타임라인 측정보다 나은 업그레이드가 아니라, 거래당 지표가 강제될 때를 위한 대안으로 취급하십시오. 정확한 좌표는 스케일에 의존합니다; 표면의 모양이 전이 가능한 결과입니다.
- 운 좋은 희귀 거래로 속일 수 없도록 목적함수를 설계하십시오. 선호 순서대로: 전체 타임라인에서 측정하라(기본값), 노출도를 요구하라(가장 강력한 단일 지렛대), 거래 수로 축소하라(목적함수 수준의 최소 트랙 레코드 길이). 이 중 어느 것도 서치를 더 영리하게 만들지 않습니다 — 목표를 정직하게 만들 뿐이며, 그래서 서치가 필연적으로 찾아내는 최댓값이 당신이 실제로 거래할 전략이 되도록 합니다.
파라미터 서치는 순종적인 지니입니다. 당신이 의도한 소원이 아니라, 당신이 표현한 그대로의 소원을 정확히 들어줍니다 — 그리고 "이 지표를 극대화하라"가 바로 그 소원입니다. 그것을 거래당 샤프로 표현하면, 여덟 번의 운 좋은 거래를 불러내고는 그것을 행운이라 부를 것입니다. 플랫으로 앉아 있는 것이 벌을 받고 소수의 거래는 소수의 credit만 얻도록 표현하면, 같은 지니가, 같은 데이터에서, 당신에게 진짜 엣지를 건네줍니다. 당신이 배치하는 전략은 목적함수를 타이핑하는 그 순간 이미 선택된 것입니다. 그것을 의도적으로 선택하십시오.
전체 실험 — 합성 시장, 여섯 개의 목적함수, 600-시드 몬테카를로, 그리고 수리-스윕 표면, 이 글의 모든 숫자를 하나의 결정론적 스크립트에서 재현할 수 있음 — 은 objective-design.marketmaker.cc의 자매 논문에 있으며, 코드와 데이터는 github.com/suenot/objective-design-degeneracy에 있습니다.
이것은 우리의 다른 연구들이 서로 다른 각도에서 싸우고 있는 동일한 전쟁의 한 전선입니다. 디플레이티드 샤프 비율은 다중 검정 이후 서치의 승자의 값을 매깁니다 — 이 글이 목적함수가 애초에 올바른 전략을 골랐는지를 묻는 곳에서, DSR은 그것이 고른 전략이 운만으로 만들어낼 수 있는 것을 이기는지를 묻습니다. 곧 나올 백테스트 과적합 확률(PBO) 연구는 리샘플링 측면에서 동일한 선택 편향을 공략하며, 승자가 아니라 절차의 값을 매깁니다. 그리고 미래 참조 편향 분류는 가짜 샤프를 만들어내는 또 다른 거대한 원천 — 미래로부터의 누출 — 을 목록화하는데, 이는 완전히 다른 메커니즘을 통해 동일한 증상(라이브에서 죽어버리는 화려한 백테스트)을 만들어냅니다. 목적함수 설계, 디플레이션, 과적합 확률, 미래 참조: 하나의 학문 분야를 가리키는 네 개의 이름입니다 — 자기 자신의 백테스트에 속지 않는 것 말입니다.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.