Bài viết gần đây
-
-
So sánh Flutter và React Native
Tháng mười một 17, 2025 -
So sánh Flutter và React Native
Tháng mười một 17, 2025 -
Chiến lược RSI 30–70 trong Bot Auto Trading Python
Tháng mười một 17, 2025 -
Chiến Lược Giao Dịch News Filter sử dụng API Python
Tháng mười một 17, 2025
| Chiến lược MACD + RSI kết hợp trong Bot Auto Trading
Được viết bởi thanhdt vào ngày 16/11/2025 lúc 22:58 | 105 lượt xem
Chiến lược MACD + RSI kết hợp trong Bot Auto Trading: Hướng dẫn Python
Kết hợp MACD (Moving Average Convergence Divergence) và RSI (Relative Strength Index) là một trong những chiến lược trading hiệu quả nhất. MACD giúp xác định xu hướng và momentum, trong khi RSI xác định vùng overbought/oversold. Khi kết hợp cả hai, chúng ta có thể giảm false signals đáng kể và tăng độ chính xác của tín hiệu. Trong bài viết này, chúng ta sẽ tìm hiểu các cách kết hợp MACD + RSI hiệu quả và cách triển khai chúng bằng Python.
1. Hiểu về MACD và RSI
MACD (Moving Average Convergence Divergence)
MACD là chỉ báo động lượng theo xu hướng, bao gồm:
- MACD Line: EMA(12) – EMA(26)
- Signal Line: EMA(9) của MACD Line
- Histogram: MACD Line – Signal Line
Tín hiệu MACD:
- Bullish: MACD Line cắt lên Signal Line (golden cross)
- Bearish: MACD Line cắt xuống Signal Line (death cross)
- Divergence: Giá và MACD di chuyển ngược hướng
RSI (Relative Strength Index)
RSI là chỉ báo động lượng đo lường tốc độ và độ lớn của biến động giá, dao động từ 0 đến 100:
- RSI < 30: Vùng oversold (quá bán)
- RSI > 70: Vùng overbought (quá mua)
- RSI 30-70: Vùng trung tính
Tại sao kết hợp MACD + RSI?
- MACD xác định xu hướng: Cho biết thị trường đang tăng hay giảm
- RSI xác định điểm vào: Cho biết khi nào nên vào lệnh
- Giảm false signals: Cả hai phải đồng thuận mới vào lệnh
- Tăng độ chính xác: Kết hợp momentum và overbought/oversold
import pandas as pd
import numpy as np
import pandas_ta as ta
def calculate_macd(prices, fast=12, slow=26, signal=9):
"""
Tính toán MACD
Parameters:
-----------
prices : pd.Series
Chuỗi giá đóng cửa
fast : int
Period EMA nhanh (mặc định 12)
slow : int
Period EMA chậm (mặc định 26)
signal : int
Period Signal line (mặc định 9)
Returns:
--------
pd.DataFrame: Chứa MACD, Signal, Histogram
"""
macd = ta.macd(prices, fast=fast, slow=slow, signal=signal)
if macd is None:
return None
return pd.DataFrame({
'MACD': macd.iloc[:, 0],
'Signal': macd.iloc[:, 1],
'Histogram': macd.iloc[:, 2]
})
def calculate_rsi(prices, period=14):
"""
Tính toán RSI (Relative Strength Index)
Parameters:
-----------
prices : pd.Series
Chuỗi giá đóng cửa
period : int
Chu kỳ tính toán (mặc định 14)
Returns:
--------
pd.Series
Giá trị RSI
"""
delta = prices.diff()
# Tách gain và loss
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
# Tính RS và RSI
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
2. Các chiến lược MACD + RSI kết hợp hiệu quả
2.1. Chiến lược MACD Crossover + RSI Oversold/Overbought
Đặc điểm:
- Đơn giản, dễ triển khai
- MACD xác định xu hướng, RSI xác định điểm vào
- Phù hợp với thị trường có xu hướng rõ ràng
Quy tắc:
- Mua: MACD cắt lên Signal VÀ RSI < 50 (hoặc đang tăng từ oversold)
- Bán: MACD cắt xuống Signal VÀ RSI > 50 (hoặc đang giảm từ overbought)
class MACDRSICrossoverStrategy:
"""Chiến lược MACD Crossover kết hợp RSI"""
def __init__(self, macd_fast=12, macd_slow=26, macd_signal=9,
rsi_period=14, rsi_oversold=30, rsi_overbought=70):
"""
Parameters:
-----------
macd_fast : int
Period EMA nhanh cho MACD
macd_slow : int
Period EMA chậm cho MACD
macd_signal : int
Period Signal line cho MACD
rsi_period : int
Period cho RSI
rsi_oversold : float
Ngưỡng oversold cho RSI
rsi_overbought : float
Ngưỡng overbought cho RSI
"""
self.macd_fast = macd_fast
self.macd_slow = macd_slow
self.macd_signal = macd_signal
self.rsi_period = rsi_period
self.rsi_oversold = rsi_oversold
self.rsi_overbought = rsi_overbought
def calculate_indicators(self, df):
"""Tính toán các chỉ báo"""
# Tính MACD
macd_data = calculate_macd(df['Close'],
fast=self.macd_fast,
slow=self.macd_slow,
signal=self.macd_signal)
if macd_data is None:
return None
df['MACD'] = macd_data['MACD']
df['MACD_Signal'] = macd_data['Signal']
df['MACD_Histogram'] = macd_data['Histogram']
# Tính RSI
df['RSI'] = calculate_rsi(df['Close'], period=self.rsi_period)
return df
def generate_signals(self, df):
"""
Tạo tín hiệu giao dịch
Returns:
--------
pd.Series: 1 = Mua, -1 = Bán, 0 = Giữ
"""
df = self.calculate_indicators(df.copy())
if df is None:
return pd.Series(0, index=df.index)
df['Signal'] = 0
# Tín hiệu mua: MACD cắt lên Signal + RSI hỗ trợ
buy_condition = (
(df['MACD'] > df['MACD_Signal']) & # MACD trên Signal
(df['MACD'].shift(1) <= df['MACD_Signal'].shift(1)) & # Vừa cắt lên
(df['RSI'] < 70) & # RSI không quá overbought
(df['RSI'] > df['RSI'].shift(1)) # RSI đang tăng
)
df.loc[buy_condition, 'Signal'] = 1
# Tín hiệu bán: MACD cắt xuống Signal + RSI hỗ trợ
sell_condition = (
(df['MACD'] < df['MACD_Signal']) & # MACD dưới Signal
(df['MACD'].shift(1) >= df['MACD_Signal'].shift(1)) & # Vừa cắt xuống
(df['RSI'] > 30) & # RSI không quá oversold
(df['RSI'] < df['RSI'].shift(1)) # RSI đang giảm
)
df.loc[sell_condition, 'Signal'] = -1
return df['Signal']
2.2. Chiến lược MACD Histogram + RSI Divergence (Hiệu quả cao)
Đặc điểm:
- Sử dụng MACD Histogram để xác định momentum
- Kết hợp với RSI Divergence để phát hiện đảo chiều
- Tín hiệu mạnh, độ chính xác cao
Quy tắc:
- Mua: MACD Histogram tăng + RSI Bullish Divergence
- Bán: MACD Histogram giảm + RSI Bearish Divergence
class MACDHistogramRSIDivergenceStrategy:
"""Chiến lược MACD Histogram kết hợp RSI Divergence"""
def __init__(self, macd_fast=12, macd_slow=26, macd_signal=9,
rsi_period=14, lookback=5):
"""
Parameters:
-----------
macd_fast : int
Period EMA nhanh cho MACD
macd_slow : int
Period EMA chậm cho MACD
macd_signal : int
Period Signal line cho MACD
rsi_period : int
Period cho RSI
lookback : int
Số nến để tìm divergence
"""
self.macd_fast = macd_fast
self.macd_slow = macd_slow
self.macd_signal = macd_signal
self.rsi_period = rsi_period
self.lookback = lookback
def calculate_indicators(self, df):
"""Tính toán các chỉ báo"""
# Tính MACD
macd_data = calculate_macd(df['Close'],
fast=self.macd_fast,
slow=self.macd_slow,
signal=self.macd_signal)
if macd_data is None:
return None
df['MACD'] = macd_data['MACD']
df['MACD_Signal'] = macd_data['Signal']
df['MACD_Histogram'] = macd_data['Histogram']
# Tính RSI
df['RSI'] = calculate_rsi(df['Close'], period=self.rsi_period)
return df
def detect_rsi_divergence(self, prices, rsi):
"""
Phát hiện RSI Divergence
Returns:
--------
str: 'bullish', 'bearish', hoặc None
"""
if len(prices) < self.lookback * 2:
return None
# Tìm đỉnh và đáy
from scipy.signal import find_peaks
# Tìm đỉnh giá
price_peaks, _ = find_peaks(prices.values, distance=self.lookback)
price_troughs, _ = find_peaks(-prices.values, distance=self.lookback)
# Tìm đỉnh và đáy RSI
rsi_peaks, _ = find_peaks(rsi.values, distance=self.lookback)
rsi_troughs, _ = find_peaks(-rsi.values, distance=self.lookback)
# Bullish Divergence: Giá tạo lower low, RSI tạo higher low
if len(price_troughs) >= 2 and len(rsi_troughs) >= 2:
price_low1 = prices.iloc[price_troughs[-2]]
price_low2 = prices.iloc[price_troughs[-1]]
rsi_low1 = rsi.iloc[rsi_troughs[-2]]
rsi_low2 = rsi.iloc[rsi_troughs[-1]]
if price_low2 < price_low1 and rsi_low2 > rsi_low1:
return 'bullish'
# Bearish Divergence: Giá tạo higher high, RSI tạo lower high
if len(price_peaks) >= 2 and len(rsi_peaks) >= 2:
price_high1 = prices.iloc[price_peaks[-2]]
price_high2 = prices.iloc[price_peaks[-1]]
rsi_high1 = rsi.iloc[rsi_peaks[-2]]
rsi_high2 = rsi.iloc[rsi_peaks[-1]]
if price_high2 > price_high1 and rsi_high2 < rsi_high1:
return 'bearish'
return None
def generate_signals(self, df):
"""Tạo tín hiệu giao dịch"""
df = self.calculate_indicators(df.copy())
if df is None:
return pd.Series(0, index=df.index)
df['Signal'] = 0
for i in range(self.lookback * 2, len(df)):
window_prices = df['Close'].iloc[i-self.lookback*2:i+1]
window_rsi = df['RSI'].iloc[i-self.lookback*2:i+1]
# Phát hiện divergence
divergence = self.detect_rsi_divergence(window_prices, window_rsi)
current_histogram = df.iloc[i]['MACD_Histogram']
prev_histogram = df.iloc[i-1]['MACD_Histogram']
# Tín hiệu mua: Bullish divergence + MACD Histogram tăng
if (divergence == 'bullish' and
current_histogram > prev_histogram and
current_histogram > 0):
df.iloc[i, df.columns.get_loc('Signal')] = 1
# Tín hiệu bán: Bearish divergence + MACD Histogram giảm
elif (divergence == 'bearish' and
current_histogram < prev_histogram and
current_histogram < 0):
df.iloc[i, df.columns.get_loc('Signal')] = -1
return df['Signal']
2.3. Chiến lược MACD Zero Line + RSI Overbought/Oversold (Nâng cao – Rất hiệu quả)
Đặc điểm:
- MACD cắt zero line xác định xu hướng chính
- RSI overbought/oversold xác định điểm vào
- Tín hiệu mạnh và đáng tin cậy
Quy tắc:
- Mua: MACD cắt lên zero line + RSI < 40 (oversold recovery)
- Bán: MACD cắt xuống zero line + RSI > 60 (overbought rejection)
class MACDZeroLineRSIStrategy:
"""Chiến lược MACD Zero Line kết hợp RSI"""
def __init__(self, macd_fast=12, macd_slow=26, macd_signal=9,
rsi_period=14, rsi_oversold=40, rsi_overbought=60):
"""
Parameters:
-----------
macd_fast : int
Period EMA nhanh cho MACD
macd_slow : int
Period EMA chậm cho MACD
macd_signal : int
Period Signal line cho MACD
rsi_period : int
Period cho RSI
rsi_oversold : float
Ngưỡng oversold cho RSI
rsi_overbought : float
Ngưỡng overbought cho RSI
"""
self.macd_fast = macd_fast
self.macd_slow = macd_slow
self.macd_signal = macd_signal
self.rsi_period = rsi_period
self.rsi_oversold = rsi_oversold
self.rsi_overbought = rsi_overbought
def calculate_indicators(self, df):
"""Tính toán các chỉ báo"""
# Tính MACD
macd_data = calculate_macd(df['Close'],
fast=self.macd_fast,
slow=self.macd_slow,
signal=self.macd_signal)
if macd_data is None:
return None
df['MACD'] = macd_data['MACD']
df['MACD_Signal'] = macd_data['Signal']
df['MACD_Histogram'] = macd_data['Histogram']
# Tính RSI
df['RSI'] = calculate_rsi(df['Close'], period=self.rsi_period)
return df
def generate_signals(self, df):
"""Tạo tín hiệu giao dịch"""
df = self.calculate_indicators(df.copy())
if df is None:
return pd.Series(0, index=df.index)
df['Signal'] = 0
# Tín hiệu mua: MACD cắt lên zero line + RSI oversold recovery
buy_condition = (
(df['MACD'] > 0) & # MACD trên zero line
(df['MACD'].shift(1) <= 0) & # Vừa cắt lên
(df['RSI'] < self.rsi_overbought) & # RSI không quá overbought
(df['RSI'] > self.rsi_oversold) & # RSI đang recovery từ oversold
(df['RSI'] > df['RSI'].shift(1)) # RSI đang tăng
)
df.loc[buy_condition, 'Signal'] = 1
# Tín hiệu bán: MACD cắt xuống zero line + RSI overbought rejection
sell_condition = (
(df['MACD'] < 0) & # MACD dưới zero line
(df['MACD'].shift(1) >= 0) & # Vừa cắt xuống
(df['RSI'] > self.rsi_oversold) & # RSI không quá oversold
(df['RSI'] < self.rsi_overbought) & # RSI đang rejection từ overbought
(df['RSI'] < df['RSI'].shift(1)) # RSI đang giảm
)
df.loc[sell_condition, 'Signal'] = -1
return df['Signal']
2.4. Chiến lược MACD + RSI Multi-Timeframe (Rất hiệu quả)
Đặc điểm:
- Phân tích MACD và RSI trên nhiều khung thời gian
- Tín hiệu mạnh và đáng tin cậy nhất
- Phù hợp cho swing trading và position trading
Quy tắc:
- Mua: MACD(4h) bullish + RSI(1h) oversold recovery
- Bán: MACD(4h) bearish + RSI(1h) overbought rejection
class MultiTimeframeMACDRSIStrategy:
"""Chiến lược MACD + RSI đa khung thời gian"""
def __init__(self, macd_fast=12, macd_slow=26, macd_signal=9,
rsi_period=14):
"""
Parameters:
-----------
macd_fast : int
Period EMA nhanh cho MACD
macd_slow : int
Period EMA chậm cho MACD
macd_signal : int
Period Signal line cho MACD
rsi_period : int
Period cho RSI
"""
self.macd_fast = macd_fast
self.macd_slow = macd_slow
self.macd_signal = macd_signal
self.rsi_period = rsi_period
def analyze_multiple_timeframes(self, exchange, symbol):
"""
Phân tích MACD và RSI trên nhiều khung thời gian
Parameters:
-----------
exchange : ccxt.Exchange
Exchange object
symbol : str
Trading pair (e.g., 'BTC/USDT')
Returns:
--------
dict: MACD và RSI values cho các timeframe
"""
timeframes = {
'1h': '1h',
'4h': '4h',
'1d': '1d'
}
analysis = {}
for tf_name, tf_code in timeframes.items():
# Lấy dữ liệu OHLCV
ohlcv = exchange.fetch_ohlcv(symbol, tf_code, limit=100)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
df.columns = [col.capitalize() for col in df.columns]
# Tính MACD
macd_data = calculate_macd(df['Close'],
fast=self.macd_fast,
slow=self.macd_slow,
signal=self.macd_signal)
# Tính RSI
rsi = calculate_rsi(df['Close'], period=self.rsi_period)
if macd_data is not None:
analysis[tf_name] = {
'macd': macd_data['MACD'].iloc[-1],
'macd_signal': macd_data['Signal'].iloc[-1],
'macd_histogram': macd_data['Histogram'].iloc[-1],
'rsi': rsi.iloc[-1] if not rsi.empty else None
}
return analysis
def generate_signals(self, analysis):
"""
Tạo tín hiệu từ phân tích đa khung thời gian
Parameters:
-----------
analysis : dict
Kết quả phân tích từ analyze_multiple_timeframes
Returns:
--------
int: 1 = Mua, -1 = Bán, 0 = Giữ
"""
if '4h' not in analysis or '1h' not in analysis:
return 0
macd_4h = analysis['4h']['macd']
macd_signal_4h = analysis['4h']['macd_signal']
rsi_1h = analysis['1h']['rsi']
if rsi_1h is None:
return 0
# Tín hiệu mua: MACD(4h) bullish + RSI(1h) oversold recovery
if (macd_4h > macd_signal_4h and # MACD(4h) bullish
macd_4h > 0 and # MACD trên zero line
rsi_1h < 50 and # RSI(1h) không overbought
rsi_1h > 30): # RSI(1h) recovery từ oversold
return 1
# Tín hiệu bán: MACD(4h) bearish + RSI(1h) overbought rejection
if (macd_4h < macd_signal_4h and # MACD(4h) bearish
macd_4h < 0 and # MACD dưới zero line
rsi_1h > 50 and # RSI(1h) không oversold
rsi_1h < 70): # RSI(1h) rejection từ overbought
return -1
return 0
3. Bot Auto Trading MACD + RSI hoàn chỉnh
3.1. Bot với Quản lý Rủi ro và Position Management
import ccxt
import pandas as pd
import numpy as np
import time
from datetime import datetime
from typing import Dict, Optional
class MACDRSITradingBot:
"""Bot auto trading sử dụng chiến lược MACD + RSI"""
def __init__(self, exchange_name: str, api_key: str, api_secret: str,
strategy_type: str = 'crossover'):
"""
Khởi tạo bot
Parameters:
-----------
exchange_name : str
Tên sàn (binance, coinbase, etc.)
api_key : str
API key
api_secret : str
API secret
strategy_type : str
Loại chiến lược ('crossover', 'divergence', 'zero_line', 'multi_tf')
"""
# Kết nối exchange
exchange_class = getattr(ccxt, exchange_name)
self.exchange = exchange_class({
'apiKey': api_key,
'secret': api_secret,
'enableRateLimit': True,
})
# Chọn chiến lược
self.strategy = self._init_strategy(strategy_type)
# Quản lý vị thế
self.position = None
self.entry_price = None
self.stop_loss = None
self.take_profit = None
# Cài đặt rủi ro
self.max_position_size = 0.1 # 10% vốn
self.stop_loss_pct = 0.02 # 2%
self.take_profit_pct = 0.04 # 4%
self.risk_reward_ratio = 2.0
def _init_strategy(self, strategy_type: str):
"""Khởi tạo chiến lược"""
if strategy_type == 'crossover':
return MACDRSICrossoverStrategy()
elif strategy_type == 'divergence':
return MACDHistogramRSIDivergenceStrategy()
elif strategy_type == 'zero_line':
return MACDZeroLineRSIStrategy()
elif strategy_type == 'multi_tf':
return MultiTimeframeMACDRSIStrategy()
else:
raise ValueError(f"Unknown strategy type: {strategy_type}")
def get_market_data(self, symbol: str, timeframe: str = '1h', limit: int = 100):
"""Lấy dữ liệu thị trường"""
ohlcv = self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
df.columns = [col.capitalize() for col in df.columns]
return df
def calculate_position_size(self, balance: float, price: float, stop_loss: float) -> float:
"""Tính toán kích thước vị thế dựa trên rủi ro"""
risk_amount = balance * 0.01 # Risk 1% mỗi lệnh
risk_per_unit = abs(price - stop_loss)
if risk_per_unit == 0:
return 0
position_size = risk_amount / risk_per_unit
return position_size
def calculate_stop_loss_take_profit(self, entry_price: float, side: str):
"""Tính stop loss và take profit"""
if side == 'long':
stop_loss = entry_price * (1 - self.stop_loss_pct)
risk = entry_price - stop_loss
take_profit = entry_price + (risk * self.risk_reward_ratio)
else: # short
stop_loss = entry_price * (1 + self.stop_loss_pct)
risk = stop_loss - entry_price
take_profit = entry_price - (risk * self.risk_reward_ratio)
return stop_loss, take_profit
def place_order(self, symbol: str, side: str, amount: float,
order_type: str = 'market'):
"""Đặt lệnh giao dịch"""
try:
if side == 'buy':
order = self.exchange.create_market_buy_order(symbol, amount)
else:
order = self.exchange.create_market_sell_order(symbol, amount)
print(f"[{datetime.now()}] {side.upper()} {amount} {symbol} @ {order['price']}")
return order
except Exception as e:
print(f"Error placing order: {e}")
return None
def check_stop_loss_take_profit(self, current_price: float):
"""Kiểm tra stop loss và take profit"""
if self.position is None:
return
if self.position == 'long':
if current_price <= self.stop_loss:
print(f"[{datetime.now()}] Stop Loss triggered @ {current_price}")
self.close_position(current_price)
return
if current_price >= self.take_profit:
print(f"[{datetime.now()}] Take Profit triggered @ {current_price}")
self.close_position(current_price)
return
def open_position(self, symbol: str, side: str, price: float, amount: float):
"""Mở vị thế"""
order = self.place_order(symbol, side, amount)
if order:
self.position = side
self.entry_price = price
# Đặt stop loss và take profit
self.stop_loss, self.take_profit = self.calculate_stop_loss_take_profit(
price, side
)
print(f"[{datetime.now()}] Position opened: {side} @ {price}")
print(f"Stop Loss: {self.stop_loss}, Take Profit: {self.take_profit}")
def close_position(self, price: float):
"""Đóng vị thế"""
if self.position:
if self.position == 'long':
pnl_pct = ((price - self.entry_price) / self.entry_price) * 100
else: # short
pnl_pct = ((self.entry_price - price) / self.entry_price) * 100
print(f"[{datetime.now()}] Position closed. P&L: {pnl_pct:.2f}%")
self.position = None
self.entry_price = None
self.stop_loss = None
self.take_profit = None
def run(self, symbol: str, timeframe: str = '1h', check_interval: int = 300):
"""
Chạy bot
Parameters:
-----------
symbol : str
Trading pair
timeframe : str
Khung thời gian
check_interval : int
Thời gian chờ giữa các lần kiểm tra (giây)
"""
print(f"[{datetime.now()}] Bot started for {symbol}")
while True:
try:
# Lấy dữ liệu thị trường
df = self.get_market_data(symbol, timeframe)
current_price = df['Close'].iloc[-1]
# Kiểm tra stop loss và take profit
if self.position:
self.check_stop_loss_take_profit(current_price)
if self.position is None:
time.sleep(check_interval)
continue
# Tạo tín hiệu
if isinstance(self.strategy, MultiTimeframeMACDRSIStrategy):
analysis = self.strategy.analyze_multiple_timeframes(
self.exchange, symbol
)
signal = self.strategy.generate_signals(analysis)
else:
signals = self.strategy.generate_signals(df)
signal = signals.iloc[-1]
# Xử lý tín hiệu
if signal == 1 and self.position != 'long':
# Tín hiệu mua
balance = self.exchange.fetch_balance()
available_balance = balance['USDT']['free'] if 'USDT' in balance else balance['total']['USDT']
stop_loss, _ = self.calculate_stop_loss_take_profit(current_price, 'long')
amount = self.calculate_position_size(
available_balance, current_price, stop_loss
)
if amount > 0:
self.open_position(symbol, 'long', current_price, amount)
elif signal == -1 and self.position == 'long':
# Tín hiệu bán
self.close_position(current_price)
time.sleep(check_interval)
except KeyboardInterrupt:
print(f"[{datetime.now()}] Bot stopped by user")
break
except Exception as e:
print(f"[{datetime.now()}] Error: {e}")
time.sleep(check_interval)
4. Backtesting Chiến lược MACD + RSI
4.1. Hàm Backtest
def backtest_macd_rsi_strategy(df, strategy, initial_capital=10000):
"""
Backtest chiến lược MACD + RSI
Parameters:
-----------
df : pd.DataFrame
Dữ liệu OHLCV
strategy : Strategy object
Đối tượng chiến lược
initial_capital : float
Vốn ban đầu
Returns:
--------
dict: Kết quả backtest
"""
# Tạo tín hiệu
signals = strategy.generate_signals(df.copy())
df['Signal'] = signals
# Tính toán vị thế và lợi nhuận
capital = initial_capital
position = 0
entry_price = 0
trades = []
stop_loss_pct = 0.02
take_profit_pct = 0.04
for i in range(len(df)):
price = df['Close'].iloc[i]
signal = df['Signal'].iloc[i]
if signal == 1 and position == 0: # Mua
position = capital / price
entry_price = price
stop_loss = entry_price * (1 - stop_loss_pct)
take_profit = entry_price * (1 + take_profit_pct)
trades.append({
'type': 'buy',
'date': df.index[i],
'entry_price': price,
'stop_loss': stop_loss,
'take_profit': take_profit,
'capital': capital
})
elif signal == -1 and position > 0: # Bán
capital = position * price
pnl = ((price - entry_price) / entry_price) * 100
if trades:
trades[-1]['exit_price'] = price
trades[-1]['pnl'] = pnl
trades[-1]['capital'] = capital
position = 0
# Kiểm tra stop loss và take profit
if position > 0 and trades:
last_trade = trades[-1]
if 'exit_price' not in last_trade:
if price <= last_trade['stop_loss']:
capital = position * price
pnl = ((price - entry_price) / entry_price) * 100
last_trade['exit_price'] = price
last_trade['pnl'] = pnl
last_trade['exit_reason'] = 'stop_loss'
position = 0
elif price >= last_trade['take_profit']:
capital = position * price
pnl = ((price - entry_price) / entry_price) * 100
last_trade['exit_price'] = price
last_trade['pnl'] = pnl
last_trade['exit_reason'] = 'take_profit'
position = 0
# Đóng vị thế cuối cùng nếu còn
if position > 0:
final_price = df['Close'].iloc[-1]
capital = position * final_price
if trades and 'exit_price' not in trades[-1]:
pnl = ((final_price - entry_price) / entry_price) * 100
trades[-1]['exit_price'] = final_price
trades[-1]['pnl'] = pnl
trades[-1]['exit_reason'] = 'end_of_data'
# Tính toán metrics
completed_trades = [t for t in trades if 'pnl' in t]
total_return = ((capital - initial_capital) / initial_capital) * 100
winning_trades = [t for t in completed_trades if t.get('pnl', 0) > 0]
losing_trades = [t for t in completed_trades if t.get('pnl', 0) < 0]
win_rate = len(winning_trades) / len(completed_trades) * 100 if completed_trades else 0
avg_win = np.mean([t['pnl'] for t in winning_trades]) if winning_trades else 0
avg_loss = np.mean([t['pnl'] for t in losing_trades]) if losing_trades else 0
return {
'initial_capital': initial_capital,
'final_capital': capital,
'total_return': total_return,
'total_trades': len(completed_trades),
'winning_trades': len(winning_trades),
'losing_trades': len(losing_trades),
'win_rate': win_rate,
'avg_win': avg_win,
'avg_loss': avg_loss,
'profit_factor': abs(avg_win / avg_loss) if avg_loss != 0 else 0,
'trades': trades
}
# Ví dụ sử dụng
import yfinance as yf
# Lấy dữ liệu
data = yf.download('BTC-USD', period='1y', interval='1h')
df = pd.DataFrame(data)
df.columns = [col.lower() for col in df.columns]
# Chạy backtest
strategy = MACDRSICrossoverStrategy()
results = backtest_macd_rsi_strategy(df, strategy, initial_capital=10000)
print(f"Total Return: {results['total_return']:.2f}%")
print(f"Win Rate: {results['win_rate']:.2f}%")
print(f"Total Trades: {results['total_trades']}")
print(f"Profit Factor: {results['profit_factor']:.2f}")
5. Tối ưu hóa tham số MACD + RSI Strategy
5.1. Tìm tham số tối ưu
from itertools import product
def optimize_macd_rsi_parameters(df, strategy_class, param_ranges):
"""
Tối ưu hóa tham số MACD + RSI Strategy
"""
best_params = None
best_score = -float('inf')
best_results = None
param_names = list(param_ranges.keys())
param_values = list(param_ranges.values())
for params in product(*param_values):
param_dict = dict(zip(param_names, params))
try:
strategy = strategy_class(**param_dict)
results = backtest_macd_rsi_strategy(df, strategy)
# Đánh giá: kết hợp return, win rate và profit factor
score = (results['total_return'] * 0.4 +
results['win_rate'] * 0.3 +
results['profit_factor'] * 10 * 0.3)
if score > best_score:
best_score = score
best_params = param_dict
best_results = results
except:
continue
return {
'best_params': best_params,
'best_score': best_score,
'results': best_results
}
# Ví dụ tối ưu hóa
param_ranges = {
'macd_fast': [10, 12, 14],
'macd_slow': [24, 26, 28],
'macd_signal': [7, 9, 11],
'rsi_period': [12, 14, 16],
'rsi_oversold': [25, 30, 35],
'rsi_overbought': [65, 70, 75]
}
optimization_results = optimize_macd_rsi_parameters(
df, MACDRSICrossoverStrategy, param_ranges
)
print("Best Parameters:", optimization_results['best_params'])
print("Best Score:", optimization_results['best_score'])
6. Quản lý rủi ro với MACD + RSI
6.1. Dynamic Stop Loss dựa trên MACD Histogram
class MACDRSIRiskManager:
"""Quản lý rủi ro cho chiến lược MACD + RSI"""
def __init__(self, max_risk_per_trade=0.01, base_stop_loss_pct=0.02):
self.max_risk_per_trade = max_risk_per_trade
self.base_stop_loss_pct = base_stop_loss_pct
def calculate_dynamic_stop_loss(self, entry_price, macd_histogram, side='long'):
"""
Tính stop loss động dựa trên MACD Histogram
MACD Histogram lớn = momentum mạnh = stop loss rộng hơn
"""
# Normalize histogram (giả sử histogram trong khoảng -1 đến 1)
normalized_hist = np.clip(macd_histogram / entry_price, -0.01, 0.01)
# Điều chỉnh stop loss dựa trên momentum
if abs(normalized_hist) > 0.005: # Momentum mạnh
stop_loss_multiplier = 1.5
elif abs(normalized_hist) > 0.002: # Momentum trung bình
stop_loss_multiplier = 1.2
else: # Momentum yếu
stop_loss_multiplier = 1.0
if side == 'long':
stop_loss = entry_price * (1 - self.base_stop_loss_pct * stop_loss_multiplier)
else:
stop_loss = entry_price * (1 + self.base_stop_loss_pct * stop_loss_multiplier)
return stop_loss
def calculate_position_size(self, account_balance, entry_price, stop_loss):
"""Tính toán kích thước vị thế"""
risk_amount = account_balance * self.max_risk_per_trade
risk_per_unit = abs(entry_price - stop_loss)
if risk_per_unit == 0:
return 0
position_size = risk_amount / risk_per_unit
return position_size
7. Kết luận: Chiến lược MACD + RSI nào hiệu quả nhất?
Đánh giá các chiến lược:
- MACD Crossover + RSI
- ✅ Đơn giản, dễ triển khai
- ✅ Phù hợp nhiều thị trường
- ⭐ Hiệu quả: 4/5
- MACD Histogram + RSI Divergence
- ✅ Tín hiệu mạnh, độ chính xác cao
- ❌ Phức tạp hơn, cần phát hiện divergence
- ⭐ Hiệu quả: 4.5/5
- MACD Zero Line + RSI
- ✅ Tín hiệu rõ ràng, dễ theo dõi
- ✅ Phù hợp với xu hướng mạnh
- ⭐ Hiệu quả: 4.5/5
- MACD + RSI Multi-Timeframe
- ✅ Tín hiệu đáng tin cậy nhất
- ✅ Phù hợp swing/position trading
- ⭐ Hiệu quả: 5/5
Khuyến nghị:
- Cho người mới bắt đầu: MACD Crossover + RSI Strategy
- Cho trader có kinh nghiệm: MACD Zero Line + RSI hoặc Multi-Timeframe
- Cho scalping: MACD Crossover + RSI với khung thời gian ngắn (M15, M30)
Lưu ý quan trọng:
- Xác nhận từ cả hai chỉ báo: Cả MACD và RSI phải đồng thuận
- Quản lý rủi ro: Luôn đặt stop loss và take profit
- Backtest kỹ lưỡng: Kiểm tra chiến lược trên nhiều thị trường khác nhau
- Tối ưu hóa tham số: Tìm tham số phù hợp với từng thị trường
- Theo dõi và điều chỉnh: Thị trường thay đổi, chiến lược cũng cần thay đổi
- Tránh trade trong tin tức: MACD và RSI có thể bị ảnh hưởng bởi tin tức
8. Tài liệu tham khảo
- MACD Indicator – Investopedia
- RSI Indicator – Investopedia
- Technical Analysis of the Financial Markets – John J. Murphy
- Python for Finance – Yves Hilpisch
- Pandas TA Documentation
Lưu ý: Trading có rủi ro. Hãy luôn backtest kỹ lưỡng và bắt đầu với số vốn nhỏ. Bài viết này chỉ mang tính chất giáo dục, không phải lời khuyên đầu tư.