본문 바로가기

Quant

Parameter Optimization

블로그 포스팅을 안 하다가 이제 다시 꾸준히 작성해보려 한다.

개발을 안 했던거는 아니고, 지난 1년동안 시스템 트레이딩을 개발했지만

늘 열심히 했던 것도 아니고, 결과도 불투명했고, 방향도 못 잡아서 공개하기 부끄러운 부분이 있었다.

 

그래도, 최근 열심히 한 덕에 방향을 잡았고 결과까지 노력하는 과정도 이제 남겨보려 한다.

아직 아는 것보다 모르는 게 더 많고, 실수도 많지만 어차피 블로그 아무도 안 보는데 일기처럼 남겨볼까 한다.

오랜만에 진심으로 열심히 하고 좋아하는게 생겨서 좋다.


현재 단계는 Data ETL, Trading Bot, Back Testing 프로세스를 구축했고

실시간 데이터를 확보하며 Quant 전략을 보강하는 단계이다.

오늘은 그 보강 단계 중 Parameter Optimization 과정을 정리해보려 한다.

 

 

시스템에 사용되는 인자는 많지만, 전략에 영향을 주는 독립변수(X) 4개를 임의로 추출했다.

- base_market_cap : 시가총액

- buy_rsi : RSI 기반 매수 시점

- sell_rsi : RSI 기반 매도 시점

- threshold: 손절가 (0.97이면 3% 이상 시 손절)

 

이를 기반으로 확인할 수 있는 종속변수(Y)는 아래와 같다. (거래일 31일 기준 데이터)

- total_trades: 총 거래 횟수

- wining_trades: 수익률 0% 이상인 거래 횟수

- win_rate : winnning_trades / total_trades

- total_profit: *수익률 

 

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

file_path = 'parameter-optimization.csv'  # 파일 경로를 지정하세요
df = pd.read_csv(file_path)

 

 

1) Pairplot 활용 변수 간 관계 시각화

# Pairplot을 활용한 관계 분석
sns.pairplot(df, hue="base_market_cap", vars=["buy_rsi", "sell_rsi", "threshold", "total_profit"])
plt.show()

까만색이 base_market_cap이 3,000억인 경우이다.

전반적으로 base_market_cap이 3,000억 이상인 경우를 필터링 할 때 수익률이 좋아 보인다.

 

2) Correlation heatmap 시각화

# 상관관계 Heatmap
plt.figure(figsize=(10, 6))
sns.heatmap(df.corr(), annot=True, cmap="coolwarm", fmt=".2f")
plt.title("Correlation Heatmap")
plt.show()

 

수익률에 집중을 하면

1) base_market_cap : 0.56 (높을 수록 수익률 ▲)

2) buy_rsi & thres_hold : 0.33 & 0.35 (낮을 수록 수익률 ▲)

 

독립 변수는 아니지만 total_trades가 낮을 수록 total_profit이 높다.

- 1) 같은 종목 샀팔 샀팔 해서 좋을 게 없다

- 2) 매매 횟수가 많을수록 sleepage 만 증가하지, 줄이는게 좋다 (트레이더 친구 의견이랑은 반대이다)

 

3) Boxplot 활용

# Boxplot을 활용한 base_market_cap 별 total_profit 분포
plt.figure(figsize=(10, 6))
sns.boxplot(x="base_market_cap", y="total_profit", data=df)
plt.title("Total Profit Distribution by Base Market Cap")
plt.show()

- 확실히 1)의 결과와 같이 거래대금이 높을 수록 좋다.

 

- buy_rsi의 경우도 낮은게 좋아 보인다.

- 그런데 최대치는 비슷해서, 큰 의미는 없는 듯 하다.

- sell_rsi의 경우 79, 80이 82보다 좋은 것은 명확해 보인다.

- 79, 80의 차이가 경미해서 조금 더 파악이 필요하다.

 

plt.figure(figsize=(10, 6))
sns.boxplot(x="threshold", y="total_profit", data=df)
plt.title("Total Profit Distribution by threshold")
plt.show()

# Scatterplot을 활용한 threshold vs total_profit
plt.figure(figsize=(10, 6))
sns.scatterplot(x="threshold", y="total_profit", hue="base_market_cap", data=df, palette="viridis")
plt.title("Threshold vs Total Profit")
plt.show()

- 손절 %는 높은게 좋다. (0.97이면 3%, 0.985면 1.5%)

 

 


실제 결과는?

# total_profit을 기준으로 내림차순 정렬 (큰 값이 위로)
df_sorted = df.sort_values(by="total_profit", ascending=False)

df_sorted.iloc[:10

 

  base_market_cap buy_rsi sell_rsi threshold total_trades wining_trades win_rate total_profit
1 300000000000 75 80 0.970 79 31 39.24 41.98
2 300000000000 78 79 0.970 81 32 39.51 41.41
3 300000000000 75 79 0.970 79 31 39.24 41.35
4 300000000000 72 82 0.970 77 31 40.26 40.92
5 300000000000 72 79 0.970 75 28 37.33 40.06
6 300000000000 78 80 0.970 80 31 38.75 39.78
7 300000000000 72 80 0.970 75 30 40.00 39.50
8 250000000000 75 80 0.970 82 32 39.02 39.37
9 300000000000 72 79 0.975 73 28 38.36 38.48
10 300000000000 78 82 0.970 80 31 38.75 38.28

 

상위 10위 내 거래대금은 모두 3,000억

상위 5위 내 손절가 비율은 모두 3%

 

buy_rsi & sell_rsi는 더 자세히 보면

- 1위는 75/80이고, 분석 수치를 극대화한 것(72, 82)은 4위이다.

- 2, 3위는 굳이 선택할 필요는 없을 듯 하다.

 

  Before After
base_market_cap 250000000000 300000000000
buy_rsi 75 75
sell_rsi 80 80
thresghold 0.97 0.97

 

처음에 직관으로 설정했던 수치들이 대부분 맞았고,

거래대금도 scoring 로직에 별도로 추가할 필요 없이, filtering만 처리해도 될 듯 하다.


TODO

- paramter optimization 작업 시 소요 시간이 매우 오래 걸린다.

- 연산량이 많은 작업이고, for문을 4중 5중 중첩(Grid search 적용)해서 여러 개 돌리니 시간이 오래 걸린다.

- 리팩토링을 통해 연산 효율화 작업은 진행했기에, 더 근본적인 속도 개선 작업이 필요하다 (비동기, 멀티 프로세스 등)

'Quant' 카테고리의 다른 글

BackTesting : 디버깅 🐛  (2) 2025.02.05
BackTesting : 매매 내역 분석  (0) 2025.02.03
Quant : Backtesting - 재무제표 기반  (0) 2022.04.27
Quant : Visualization - Seaborn  (0) 2022.04.13
Quant : Visualization - Matplotlib  (0) 2022.04.13