최초 프로젝트 업로드 (Script Auto Commit)
This commit is contained in:
288
analyze_optimization.py
Normal file
288
analyze_optimization.py
Normal file
@@ -0,0 +1,288 @@
|
||||
# analyze_optimization.py
|
||||
# 24.69% 수익률 개선을 위한 심층 분석
|
||||
|
||||
import re
|
||||
from typing import Dict, List, Tuple
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def parse_all_trades(log_path: str) -> Tuple[List[Dict], List[Dict]]:
|
||||
"""BUY와 SELL 거래 모두 파싱"""
|
||||
buys = []
|
||||
sells = []
|
||||
|
||||
with open(log_path, 'r', encoding='utf-16', errors='ignore') as f:
|
||||
for line in f:
|
||||
# BUY 패턴
|
||||
buy_match = re.search(
|
||||
r'\[(\d{4}-\d{2}-\d{2})\]\s+BUY:\s+(.+?)\s+@\s+([\d,]+)\s+/\s+([\d,]+)주\s+\(SL:\s+([\d,]+)\)',
|
||||
line
|
||||
)
|
||||
if buy_match:
|
||||
date, ticker, price, shares, sl = buy_match.groups()
|
||||
buys.append({
|
||||
'date': date,
|
||||
'ticker': ticker.strip(),
|
||||
'price': int(price.replace(',', '')),
|
||||
'shares': int(shares.replace(',', '')),
|
||||
'stop_loss': int(sl.replace(',', ''))
|
||||
})
|
||||
|
||||
# SELL 패턴
|
||||
sell_match = re.search(
|
||||
r'\[(\d{4}-\d{2}-\d{2})\]\s+SELL\s+\(([^)]+)\):\s+(.+?)\s+@\s+[\d,]+\s+/\s+[\d,]+주\s+\(([+-]?\d+\.\d+)%\)',
|
||||
line
|
||||
)
|
||||
if sell_match:
|
||||
date, exit_reason, ticker, return_pct = sell_match.groups()
|
||||
sells.append({
|
||||
'date': date,
|
||||
'exit_reason': exit_reason,
|
||||
'ticker': ticker.strip(),
|
||||
'return_pct': float(return_pct)
|
||||
})
|
||||
|
||||
return buys, sells
|
||||
|
||||
|
||||
def analyze_trailing_stop_lt10pct(sells: List[Dict]) -> None:
|
||||
"""TRAILING_STOP_LT10PCT 상세 분석"""
|
||||
ts_lt10 = [s for s in sells if s['exit_reason'] == 'TRAILING_STOP_LT10PCT']
|
||||
|
||||
print("\n" + "="*80)
|
||||
print("📉 TRAILING_STOP_LT10PCT 상세 분석 (104회, 평균 -1.53%)")
|
||||
print("="*80)
|
||||
|
||||
# 손익 분포
|
||||
profits = [s['return_pct'] for s in ts_lt10]
|
||||
wins = [p for p in profits if p > 0]
|
||||
losses = [p for p in profits if p < 0]
|
||||
|
||||
print(f"\n1️⃣ 손익 분포:")
|
||||
print(f" - 수익 거래: {len(wins)}회 (승률 {len(wins)/len(ts_lt10)*100:.1f}%)")
|
||||
print(f" - 손실 거래: {len(losses)}회 (패율 {len(losses)/len(ts_lt10)*100:.1f}%)")
|
||||
print(f" - 평균 수익: {sum(wins)/len(wins) if wins else 0:.2f}%")
|
||||
print(f" - 평균 손실: {sum(losses)/len(losses) if losses else 0:.2f}%")
|
||||
|
||||
# 손실 구간 분포
|
||||
loss_ranges = {
|
||||
'0~-3%': [p for p in losses if -3 <= p < 0],
|
||||
'-3~-5%': [p for p in losses if -5 <= p < -3],
|
||||
'-5~-7%': [p for p in losses if -7 <= p < -5],
|
||||
'-7% 이하': [p for p in losses if p < -7]
|
||||
}
|
||||
|
||||
print(f"\n2️⃣ 손실 구간 분포:")
|
||||
for range_name, range_data in loss_ranges.items():
|
||||
if range_data:
|
||||
print(f" - {range_name}: {len(range_data)}회 ({len(range_data)/len(losses)*100:.1f}%)")
|
||||
|
||||
# 수익 구간 분포
|
||||
profit_ranges = {
|
||||
'0~3%': [p for p in wins if 0 < p <= 3],
|
||||
'3~5%': [p for p in wins if 3 < p <= 5],
|
||||
'5~7%': [p for p in wins if 5 < p <= 7],
|
||||
'7% 이상': [p for p in wins if p > 7]
|
||||
}
|
||||
|
||||
print(f"\n3️⃣ 수익 구간 분포:")
|
||||
for range_name, range_data in profit_ranges.items():
|
||||
if range_data:
|
||||
print(f" - {range_name}: {len(range_data)}회 ({len(range_data)/len(wins)*100 if wins else 0:.1f}%)")
|
||||
|
||||
|
||||
def analyze_profit_flow(sells: List[Dict]) -> None:
|
||||
"""익절 후 추가 수익 흐름 분석"""
|
||||
print("\n" + "="*80)
|
||||
print("💰 익절 전략 효율성 분석")
|
||||
print("="*80)
|
||||
|
||||
profit_takes = [s for s in sells if 'PROFIT_TAKE' in s['exit_reason']]
|
||||
trailing_stops = [s for s in sells if 'TRAILING_STOP' in s['exit_reason']]
|
||||
|
||||
print(f"\n1️⃣ 익절(PROFIT_TAKE) 현황:")
|
||||
print(f" - 거래 횟수: {len(profit_takes)}회")
|
||||
print(f" - 평균 수익: {sum(s['return_pct'] for s in profit_takes)/len(profit_takes):.2f}%")
|
||||
|
||||
print(f"\n2️⃣ 트레일링 스탑 현황:")
|
||||
print(f" - LT10PCT: {len([s for s in sells if s['exit_reason'] == 'TRAILING_STOP_LT10PCT'])}회 (평균 -1.53%)")
|
||||
print(f" - 10-30PCT: {len([s for s in sells if s['exit_reason'] == 'TRAILING_STOP_10_30PCT'])}회 (평균 9.49%)")
|
||||
print(f" - GT30PCT: {len([s for s in sells if s['exit_reason'] == 'TRAILING_STOP_GT30PCT'])}회 (평균 9.12%)")
|
||||
|
||||
print(f"\n3️⃣ 문제점:")
|
||||
print(f" - PROFIT_TAKE 이후 남은 절반이 TRAILING_STOP_LT10PCT로 손실 청산")
|
||||
print(f" - 104회 × -1.53% = 약 -159% 누적 손실")
|
||||
print(f" - 이 손실만 0%로 만들어도 총 수익률 +6~8% 증가 가능")
|
||||
|
||||
|
||||
def suggest_improvements() -> None:
|
||||
"""개선 방안 제시"""
|
||||
print("\n" + "="*80)
|
||||
print("🎯 총 수익률 개선 방안 (24.69% → 30~35% 목표)")
|
||||
print("="*80)
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("방안 1: TRAILING_STOP_LT10PCT 비율 완화 (즉시 적용 가능)")
|
||||
print("="*70)
|
||||
print("""
|
||||
현재: SELL_TRAILING_STOP_LOW_PCT = 0.07 (7% 하락)
|
||||
문제: 104회 거래 중 대부분이 이 설정으로 -1.53% 손실
|
||||
|
||||
개선안:
|
||||
SELL_TRAILING_STOP_LOW_PCT = 0.10 # 7% → 10% 완화
|
||||
|
||||
예상 효과:
|
||||
- 104회 중 40~50%가 손실 → 소폭 수익으로 전환
|
||||
- 평균 -1.53% → +0.5~1.0%로 개선
|
||||
- 총 수익률 +5~7% 증가 (24.69% → 30~31%)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("방안 2: 익절 비율 축소 (더 많이 남겨서 큰 수익 노리기)")
|
||||
print("="*70)
|
||||
print("""
|
||||
현재: SELL_PROFIT_TAKE_RATIO = 0.5 (50% 매도)
|
||||
문제: 절반 매도 후 남은 절반이 손실로 청산되면 전체 수익 감소
|
||||
|
||||
개선안 A (공격적):
|
||||
SELL_PROFIT_TAKE_RATIO = 0.33 # 1/3만 매도
|
||||
|
||||
개선안 B (중도):
|
||||
SELL_PROFIT_TAKE_RATIO = 0.4 # 40% 매도
|
||||
|
||||
예상 효과:
|
||||
- 큰 수익(20~30%) 구간 진입 빈도 증가
|
||||
- TRAILING_STOP_10_30PCT/GT30PCT 비중 증가
|
||||
- 총 수익률 +3~5% 증가 (24.69% → 28~30%)
|
||||
|
||||
리스크:
|
||||
- 하락 시 손실폭 증가 가능 (단, MDD 모니터링 필요)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("방안 3: 2단계 익절 전략 (안정성 + 수익성)")
|
||||
print("="*70)
|
||||
print("""
|
||||
현재: 15% 수익 시 50% 매도 → 나머지는 트레일링
|
||||
문제: 단일 익절 후 바로 트레일링으로 넘어가 손실 가능성
|
||||
|
||||
개선안:
|
||||
1차 익절: 12% 도달 시 30% 매도
|
||||
2차 익절: 20% 도달 시 추가 30% 매도
|
||||
3차: 나머지 40%는 트레일링 (10~15% 여유)
|
||||
|
||||
구현:
|
||||
SELL_PROFIT_TAKE_FIRST_PCT = 0.12
|
||||
SELL_PROFIT_TAKE_FIRST_RATIO = 0.3
|
||||
SELL_PROFIT_TAKE_SECOND_PCT = 0.20
|
||||
SELL_PROFIT_TAKE_SECOND_RATIO = 0.3
|
||||
# 나머지 40%는 트레일링
|
||||
|
||||
예상 효과:
|
||||
- 익절 구간 분산으로 리스크 감소
|
||||
- TRAILING_STOP_LT10PCT 비중 감소
|
||||
- 총 수익률 +4~6% 증가 (24.69% → 29~31%)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("방안 4: 조건부 트레일링 (수익률별 차등 적용)")
|
||||
print("="*70)
|
||||
print("""
|
||||
현재: 모든 거래에 동일한 트레일링 적용
|
||||
문제: 소폭 수익(5~10%) 구간에서 7% 하락은 너무 타이트
|
||||
|
||||
개선안:
|
||||
# 수익률 10% 미만: 트레일링 비활성화 (HOLD or 고정 익절)
|
||||
# 수익률 10~20%: 10% 트레일링
|
||||
# 수익률 20% 이상: 7% 트레일링 (현재 유지)
|
||||
|
||||
의사코드:
|
||||
if profit_pct < 0.10:
|
||||
# 트레일링 없음, 손절선(-7%)만 적용
|
||||
pass
|
||||
elif profit_pct < 0.20:
|
||||
trailing_pct = 0.10
|
||||
else:
|
||||
trailing_pct = 0.07
|
||||
|
||||
예상 효과:
|
||||
- TRAILING_STOP_LT10PCT 거래 104회 중 60~70% 감소
|
||||
- 평균 손실 -1.53% → 제거
|
||||
- 총 수익률 +6~8% 증가 (24.69% → 31~33%)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("방안 5: STOP_LOSS 추가 완화 (손실 -8.46% 개선)")
|
||||
print("="*70)
|
||||
print("""
|
||||
현재: SELL_STOP_LOSS_PCT = 0.07 (7% 손절)
|
||||
문제: 22회 거래에서 평균 -8.46% 손실 (총 -186% 손실)
|
||||
|
||||
개선안:
|
||||
SELL_STOP_LOSS_PCT = 0.10 # 7% → 10% 완화
|
||||
|
||||
예상 효과:
|
||||
- 22회 중 30~40%가 손절 회피
|
||||
- 평균 -8.46% → -6~7%로 개선
|
||||
- 총 수익률 +2~3% 증가 (24.69% → 27%)
|
||||
|
||||
리스크:
|
||||
- 급락 종목 손실폭 증가 가능
|
||||
- MDD 5~7% 증가 가능 (허용 범위 확인 필요)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("🏆 종합 추천: 복합 전략 (방안 1+2+4)")
|
||||
print("="*70)
|
||||
print("""
|
||||
1단계 (즉시 적용):
|
||||
SELL_TRAILING_STOP_LOW_PCT = 0.10 # 7% → 10%
|
||||
SELL_PROFIT_TAKE_RATIO = 0.4 # 50% → 40%
|
||||
|
||||
2단계 (strategy.py 수정 필요):
|
||||
수익률 10% 미만: 트레일링 비활성화
|
||||
수익률 10~20%: 10% 트레일링
|
||||
수익률 20% 이상: 7% 트레일링
|
||||
|
||||
예상 최종 성과:
|
||||
현재: 24.69%
|
||||
개선 후: 32~37% (+30~50% 증가)
|
||||
승률: 현재 대비 +5~8%
|
||||
MDD: 현재 대비 +2~3% (허용 범위)
|
||||
""")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("⚡ 우선순위:")
|
||||
print("="*70)
|
||||
print("""
|
||||
Priority 1: SELL_TRAILING_STOP_LOW_PCT = 0.10 (즉시 적용)
|
||||
→ 예상 효과: +5~7% 수익률 증가
|
||||
|
||||
Priority 2: SELL_PROFIT_TAKE_RATIO = 0.4 (즉시 적용)
|
||||
→ 예상 효과: +3~5% 수익률 증가
|
||||
|
||||
Priority 3: 조건부 트레일링 (strategy.py 수정)
|
||||
→ 예상 효과: +6~8% 수익률 증가
|
||||
|
||||
총 예상 개선: +14~20% → 최종 38~45% 목표 (매우 공격적)
|
||||
현실적 목표: +10~15% → 최종 35~40%
|
||||
""")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
log_path = 'clean_backtest.log'
|
||||
|
||||
print("="*80)
|
||||
print("📊 24.69% 수익률 개선을 위한 심층 분석")
|
||||
print("="*80)
|
||||
|
||||
buys, sells = parse_all_trades(log_path)
|
||||
print(f"\n총 {len(buys)}회 매수, {len(sells)}회 매도 분석")
|
||||
|
||||
analyze_trailing_stop_lt10pct(sells)
|
||||
analyze_profit_flow(sells)
|
||||
suggest_improvements()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user