실전으로 배우는 전략 패턴 (Strategy Pattern) – 트레이딩 봇에서 OOP 활용하기 w.Python
2025. 4. 25. 08:00ㆍ프로그래밍 공부/Python
반응형
SMALL
전략 패턴이란?
전략 패턴(Strategy Pattern)은 알고리즘(전략)의 동적 교체를 가능하게 해주는 객체지향 디자인 패턴입니다.
행동(Behavior)을 캡슐화하고, 런타임 시에 객체에 전략을 주입해 변경 가능한 유연한 구조를 만들 수 있도록 도와줍니다.
“변화하는 부분을 분리하고, 고정된 부분은 그대로 두자”는 OOP 원칙의 대표 사례입니다.
https://github.com/99mini/trading 에서 소스코드를 확인할 수 있습니다.
구조 요약
trading-bot/
├── .venv/ # 가상환경
├── .gitignore
├── requirements.in # 의존성 명시
├── requirements.txt # 고정된 의존성
├── README.md
├── trading/ # 실시간 매매 모듈
│ ├── __init__.py
│ ├── base_trader.py # 트레이드 인터페이스 (추상 클레스)
│ └── binance_trader.py # 바이낸스 실거래 모듈
├── backtesting/ # 백테스팅 모듈
│ ├── __init__.py
│ └── backtester.py # 백테스팅 모듈
├── strategies/ # 전략 모듈
│ ├── __init__.py # strategy 진입점
│ ├── base_strategy.py # 전략 인터페이스 (추상 클래스)
│ ├── volatility_breakout.py # 변동성 전략
│ └── moving_average.py # 이평선 전략
└── scraping/
└── coin_scraping.py # 데이터 수집 헬퍼
전략 패턴 적용하기
전략 인터페이스 정의 (strategies/base_strategy.py)
from abc import ABC, abstractmethod
import pandas as pd
class BaseStrategy(ABC):
@abstractmethod
def generate_signal(self, data: pd.DataFrame) -> str:
pass
@abstractmethod
def prepare_data(self, raw_data: pd.DataFrame) -> pd.DataFrame:
pass
@abstractmethod
def __name__(self) -> str:
return self.__class__.__name__
모멘텀 전략 구현 (strategies/moving_average.py)
import pandas as pd
from .base_strategy import BaseStrategy
class MovingAverageStrategy(BaseStrategy):
def prepare_data(self, raw_data):
df = raw_data.copy()
df['MA20'] = df['close'].rolling(20).mean()
df['MA50'] = df['close'].rolling(50).mean()
return df.dropna()
def generate_signal(self, data):
latest = data.iloc[-1]
if latest['MA20'] > latest['MA50']:
return "buy"
return "sell"
def __name__(self):
return "MovingAverageStrategy"
백테스팅 클래스 구현 (backtesting/backtester.py)
import pandas as pd
from typing import Type
from strategies import BaseStrategy
class Backtester:
def __init__(self, strategy_cls: Type[BaseStrategy]):
self.strategy = strategy_cls()
self.historical_data = None
def load_data(self, data_path: str):
self.historical_data = pd.read_csv(data_path)
def run(self) -> dict:
processed_data = self.strategy.prepare_data(self.historical_data)
signals = []
for i in range(1, len(processed_data)):
window = processed_data.iloc[:i]
signal = self.strategy.generate_signal(window)
signals.append(signal)
# implement something
Backtester 클래스는 BaseStrategy 클래스를 주입받아 BaseStrategy에서 설계한 인터페이스만을 사용합니다. 개발자는 BaseStrategy의 인터페이스에 맞게 구체적인 구현(MovingAverageStrategy)을 작업하면 됩니다.
Main 함수
from strategies import MovingAverageStrategy
from backtesting import Backtester
backtester = Backtester(MovingAverageStrategy)
backtester.load_data(data_path)
results = backtester.run()
진입점이되는 main함수는 Backtester 클래스와 MovingAverageStrategy 클래스를 import해서 Backtester 클래스에 각 전략을 주입하는 방식으로 사용할 수 있습니다.
해당 개시글에서는 백테스팅 클래스가 Strategy를 주입받아 사용하지만 Trader 클래스를 Backtester 클래스와 유사하게 Strategy를 주입받아 구현하게 되면 전략 패턴을 더욱 적극 사용할 수 있게 될 것입니다.
전략 패턴의 장점
- 유연성: 전략을 객체로 주입받아 실행하므로, 다양한 전략을 손쉽게 교체하거나 추가할 수 있습니다.
- 재사용성: 동일한 전략 클래스를 실시간 매매와 백테스팅 모듈에서 모두 활용할 수 있어 코드 중복을 줄입니다.
- 유지보수 용이성: 전략 로직이 분리되어 있어, 특정 전략의 수정이 전체 시스템에 영향을 주지 않습니다.
- 테스트 용이성: 각 전략을 독립적으로 테스트할 수 있어, 전략의 성능을 정확히 평가할 수 있습니다.
반응형
LIST
'프로그래밍 공부 > Python' 카테고리의 다른 글
[Python] Collections 모듈: counter, most_common (0) | 2022.03.19 |
---|---|
[Python] 순열, 조합, 중복순열, 중복조합 (0) | 2021.09.30 |