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 Range-Bound Trading (Sideway)
Được viết bởi thanhdt vào ngày 16/11/2025 lúc 21:43 | 10 lượt xem
Chiến lược Range-Bound Trading (Sideway): Hướng dẫn Python
Range-Bound Trading (hay còn gọi là Sideway Trading) là một chiến lược giao dịch hiệu quả khi thị trường không có xu hướng rõ ràng và giá dao động trong một vùng nhất định. Trong bài viết này, chúng ta sẽ tìm hiểu các chiến lược Range-Bound Trading thực sự hiệu quả và cách triển khai chúng bằng Python.
1. Hiểu về Range-Bound Trading
Range-Bound Trading là chiến lược giao dịch dựa trên giả định rằng giá sẽ tiếp tục dao động giữa mức hỗ trợ (support) và kháng cự (resistance) trong một khoảng thời gian. Khác với trend trading, range trading tận dụng sự dao động giá trong một vùng.
Đặc điểm của thị trường Range-Bound:
- Giá dao động giữa Support và Resistance: Giá liên tục test và bật lại từ các mức này
- Không có xu hướng rõ ràng: Giá không tạo higher highs/lower lows
- Volume thấp: Thường có volume thấp hơn so với thị trường có xu hướng
- Phù hợp với các cặp tiền tệ: Đặc biệt hiệu quả với các cặp tiền tệ chính
Công thức xác định Range:
import pandas as pd
import numpy as np
def identify_range(df, period=20):
"""
Xác định vùng range (support và resistance)
Parameters:
-----------
df : pd.DataFrame
DataFrame chứa OHLCV data
period : int
Số nến để xác định range
Returns:
--------
dict: Chứa support, resistance, và range width
"""
# Lấy giá cao và thấp trong khoảng thời gian
recent_highs = df['High'].rolling(window=period).max()
recent_lows = df['Low'].rolling(window=period).min()
# Xác định resistance (kháng cự) - giá cao nhất
resistance = recent_highs.max()
# Xác định support (hỗ trợ) - giá thấp nhất
support = recent_lows.min()
# Tính độ rộng của range
range_width = resistance - support
range_width_pct = (range_width / support) * 100
return {
'support': support,
'resistance': resistance,
'range_width': range_width,
'range_width_pct': range_width_pct,
'midpoint': (support + resistance) / 2
}
2. Các chiến lược Range-Bound Trading hiệu quả
2.1. Chiến lược Support/Resistance Cơ bản
Đặc điểm:
- Đơn giản, dễ triển khai
- Mua ở support, bán ở resistance
- Phù hợp với thị trường sideway rõ ràng
Quy tắc:
- Mua: Giá chạm hoặc gần support và bắt đầu tăng
- Bán: Giá chạm hoặc gần resistance và bắt đầu giảm
class BasicRangeStrategy:
"""Chiến lược Range-Bound cơ bản"""
def __init__(self, period=20, support_buffer=0.001, resistance_buffer=0.001):
"""
Parameters:
-----------
period : int
Số nến để xác định range
support_buffer : float
Buffer % để xác định vùng mua (0.001 = 0.1%)
resistance_buffer : float
Buffer % để xác định vùng bán
"""
self.period = period
self.support_buffer = support_buffer
self.resistance_buffer = resistance_buffer
def identify_range(self, df):
"""Xác định support và resistance"""
recent_highs = df['High'].tail(self.period)
recent_lows = df['Low'].tail(self.period)
resistance = recent_highs.max()
support = recent_lows.min()
return support, resistance
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 = df.copy()
df['Signal'] = 0
# Tính support và resistance cho mỗi nến
for i in range(self.period, len(df)):
window_df = df.iloc[i-self.period:i]
support, resistance = self.identify_range(window_df)
current_price = df.iloc[i]['Close']
prev_price = df.iloc[i-1]['Close']
# Vùng mua: giá gần support
support_zone = support * (1 + self.support_buffer)
if current_price <= support_zone and prev_price > current_price:
df.iloc[i, df.columns.get_loc('Signal')] = 1
# Vùng bán: giá gần resistance
resistance_zone = resistance * (1 - self.resistance_buffer)
if current_price >= resistance_zone and prev_price < current_price:
df.iloc[i, df.columns.get_loc('Signal')] = -1
return df['Signal']
2.2. Chiến lược Bollinger Bands trong Range (Hiệu quả cao)
Đặc điểm:
- Sử dụng Bollinger Bands để xác định vùng range
- Mua khi giá chạm dải dưới, bán khi chạm dải trên
- Giảm false signals đáng kể
Quy tắc:
- Mua: Giá chạm dải dưới Bollinger Bands trong vùng range
- Bán: Giá chạm dải trên Bollinger Bands trong vùng range
import pandas_ta as ta
class BollingerBandsRangeStrategy:
"""Chiến lược Range-Bound với Bollinger Bands"""
def __init__(self, bb_period=20, bb_std=2.0, range_period=50):
"""
Parameters:
-----------
bb_period : int
Period cho Bollinger Bands
bb_std : float
Độ lệch chuẩn cho Bollinger Bands
range_period : int
Period để xác định thị trường có phải range không
"""
self.bb_period = bb_period
self.bb_std = bb_std
self.range_period = range_period
def is_range_market(self, df):
"""
Kiểm tra xem thị trường có phải range không
Sử dụng ADX (Average Directional Index) - ADX < 25 = range
"""
if len(df) < self.range_period + 14:
return False
# Tính ADX
adx = ta.adx(df['High'], df['Low'], df['Close'], length=14)
if adx is None or len(adx) == 0:
return False
# Lấy giá trị ADX cuối cùng
current_adx = adx.iloc[-1, 0] if isinstance(adx, pd.DataFrame) else adx.iloc[-1]
# ADX < 25 thường được coi là thị trường range
return current_adx < 25
def generate_signals(self, df):
"""Tạo tín hiệu giao dịch"""
df = df.copy()
# Kiểm tra xem có phải range market không
if not self.is_range_market(df):
return pd.Series(0, index=df.index)
# Tính Bollinger Bands
bb = ta.bbands(df['Close'], length=self.bb_period, std=self.bb_std)
if bb is None:
return pd.Series(0, index=df.index)
df['BB_Upper'] = bb.iloc[:, 0] # BBU
df['BB_Middle'] = bb.iloc[:, 1] # BBM
df['BB_Lower'] = bb.iloc[:, 2] # BBL
df['Signal'] = 0
# Tín hiệu mua: Giá chạm hoặc dưới dải dưới
buy_condition = (
(df['Close'] <= df['BB_Lower']) |
((df['Close'] <= df['BB_Lower'] * 1.001) &
(df['Close'].shift(1) > df['BB_Lower'].shift(1)))
)
df.loc[buy_condition, 'Signal'] = 1
# Tín hiệu bán: Giá chạm hoặc trên dải trên
sell_condition = (
(df['Close'] >= df['BB_Upper']) |
((df['Close'] >= df['BB_Upper'] * 0.999) &
(df['Close'].shift(1) < df['BB_Upper'].shift(1)))
)
df.loc[sell_condition, 'Signal'] = -1
return df['Signal']
2.3. Chiến lược RSI trong Range (Nâng cao – Rất hiệu quả)
Đặc điểm:
- Kết hợp RSI với range trading
- Mua khi RSI oversold trong range, bán khi RSI overbought
- Tín hiệu mạnh, độ chính xác cao
Quy tắc:
- Mua: RSI < 30 (oversold) và giá gần support
- Bán: RSI > 70 (overbought) và giá gần resistance
class RSIRangeStrategy:
"""Chiến lược Range-Bound với RSI"""
def __init__(self, rsi_period=14, range_period=20,
oversold=30, overbought=70):
"""
Parameters:
-----------
rsi_period : int
Period cho RSI
range_period : int
Period để xác định range
oversold : float
Ngưỡng oversold (mặc định 30)
overbought : float
Ngưỡng overbought (mặc định 70)
"""
self.rsi_period = rsi_period
self.range_period = range_period
self.oversold = oversold
self.overbought = overbought
def calculate_rsi(self, prices):
"""Tính RSI"""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=self.rsi_period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=self.rsi_period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def identify_range(self, df):
"""Xác định support và resistance"""
recent_highs = df['High'].tail(self.range_period)
recent_lows = df['Low'].tail(self.range_period)
resistance = recent_highs.max()
support = recent_lows.min()
return support, resistance
def generate_signals(self, df):
"""Tạo tín hiệu giao dịch"""
df = df.copy()
# Tính RSI
df['RSI'] = self.calculate_rsi(df['Close'])
df['Signal'] = 0
for i in range(self.range_period, len(df)):
window_df = df.iloc[i-self.range_period:i]
support, resistance = self.identify_range(window_df)
current_price = df.iloc[i]['Close']
current_rsi = df.iloc[i]['RSI']
# Tính vị trí giá trong range (0 = support, 1 = resistance)
range_position = (current_price - support) / (resistance - support)
# Tín hiệu mua: RSI oversold và giá gần support
if (current_rsi < self.oversold and
range_position < 0.3): # Trong 30% dưới của range
df.iloc[i, df.columns.get_loc('Signal')] = 1
# Tín hiệu bán: RSI overbought và giá gần resistance
if (current_rsi > self.overbought and
range_position > 0.7): # Trong 30% trên của range
df.iloc[i, df.columns.get_loc('Signal')] = -1
return df['Signal']
2.4. Chiến lược Stochastic Oscillator trong Range (Rất hiệu quả)
Đặc điểm:
- Sử dụng Stochastic để xác định điểm vào lệnh
- Phù hợp với thị trường range
- Tín hiệu rõ ràng và dễ theo dõi
Quy tắc:
- Mua: Stochastic < 20 (oversold) và giá trong vùng range
- Bán: Stochastic > 80 (overbought) và giá trong vùng range
class StochasticRangeStrategy:
"""Chiến lược Range-Bound với Stochastic Oscillator"""
def __init__(self, stoch_k=14, stoch_d=3,
range_period=20, oversold=20, overbought=80):
"""
Parameters:
-----------
stoch_k : int
Period %K cho Stochastic
stoch_d : int
Period %D cho Stochastic
range_period : int
Period để xác định range
oversold : float
Ngưỡng oversold
overbought : float
Ngưỡng overbought
"""
self.stoch_k = stoch_k
self.stoch_d = stoch_d
self.range_period = range_period
self.oversold = oversold
self.overbought = overbought
def calculate_stochastic(self, df):
"""Tính Stochastic Oscillator"""
stoch = ta.stoch(df['High'], df['Low'], df['Close'],
k=self.stoch_k, d=self.stoch_d)
if stoch is None:
return None, None
stoch_k = stoch.iloc[:, 0] # %K
stoch_d = stoch.iloc[:, 1] # %D
return stoch_k, stoch_d
def identify_range(self, df):
"""Xác định support và resistance"""
recent_highs = df['High'].tail(self.range_period)
recent_lows = df['Low'].tail(self.range_period)
resistance = recent_highs.max()
support = recent_lows.min()
return support, resistance
def generate_signals(self, df):
"""Tạo tín hiệu giao dịch"""
df = df.copy()
# Tính Stochastic
stoch_k, stoch_d = self.calculate_stochastic(df)
if stoch_k is None:
return pd.Series(0, index=df.index)
df['Stoch_K'] = stoch_k
df['Stoch_D'] = stoch_d
df['Signal'] = 0
for i in range(self.range_period, len(df)):
window_df = df.iloc[i-self.range_period:i]
support, resistance = self.identify_range(window_df)
current_price = df.iloc[i]['Close']
current_stoch_k = df.iloc[i]['Stoch_K']
current_stoch_d = df.iloc[i]['Stoch_D']
# Kiểm tra giá có trong range không
if current_price < support or current_price > resistance:
continue
# Tín hiệu mua: Stochastic oversold và %K cắt lên %D
if (current_stoch_k < self.oversold and
current_stoch_k > current_stoch_d and
df.iloc[i-1]['Stoch_K'] <= df.iloc[i-1]['Stoch_D']):
df.iloc[i, df.columns.get_loc('Signal')] = 1
# Tín hiệu bán: Stochastic overbought và %K cắt xuống %D
if (current_stoch_k > self.overbought and
current_stoch_k < current_stoch_d and
df.iloc[i-1]['Stoch_K'] >= df.iloc[i-1]['Stoch_D']):
df.iloc[i, df.columns.get_loc('Signal')] = -1
return df['Signal']
3. Bot Auto Trading Range-Bound 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 RangeBoundTradingBot:
"""Bot auto trading sử dụng chiến lược Range-Bound"""
def __init__(self, exchange_name: str, api_key: str, api_secret: str,
strategy_type: str = 'rsi_range'):
"""
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 ('basic', 'bb_range', 'rsi_range', 'stoch_range')
"""
# 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%
def _init_strategy(self, strategy_type: str):
"""Khởi tạo chiến lược"""
if strategy_type == 'basic':
return BasicRangeStrategy()
elif strategy_type == 'bb_range':
return BollingerBandsRangeStrategy()
elif strategy_type == 'rsi_range':
return RSIRangeStrategy()
elif strategy_type == 'stoch_range':
return StochasticRangeStrategy()
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) -> float:
"""Tính toán kích thước vị thế"""
max_position_value = balance * self.max_position_size
position_size = max_position_value / price
return position_size
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':
# Kiểm tra stop loss
if current_price <= self.stop_loss:
print(f"[{datetime.now()}] Stop Loss triggered @ {current_price}")
self.close_position(current_price)
return
# Kiểm tra take profit
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
if side == 'long':
self.stop_loss = price * (1 - self.stop_loss_pct)
self.take_profit = price * (1 + self.take_profit_pct)
print(f"[{datetime.now()}] Position opened: {side} @ {price}")
def close_position(self, price: float):
"""Đóng vị thế"""
if self.position:
# Tính toán lợi nhuận
if self.position == 'long':
pnl_pct = ((price - self.entry_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: # Đã đóng vị thế
time.sleep(check_interval)
continue
# Tạo tín hiệu
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']
amount = self.calculate_position_size(available_balance, current_price)
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)
# Đợi đến lần kiểm tra tiếp theo
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 Range-Bound
4.1. Hàm Backtest
def backtest_range_strategy(df, strategy, initial_capital=10000):
"""
Backtest chiến lược Range-Bound
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 = []
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
trades.append({
'type': 'buy',
'date': df.index[i],
'price': price,
'capital': capital
})
elif signal == -1 and position > 0: # Bán
capital = position * price
pnl = ((price - entry_price) / entry_price) * 100
trades.append({
'type': 'sell',
'date': df.index[i],
'price': price,
'capital': capital,
'pnl': pnl
})
position = 0
# Tính toán metrics
if position > 0: # Đóng vị thế cuối cùng
final_price = df['Close'].iloc[-1]
capital = position * final_price
total_return = ((capital - initial_capital) / initial_capital) * 100
winning_trades = [t for t in trades if t.get('pnl', 0) > 0]
losing_trades = [t for t in trades if t.get('pnl', 0) < 0]
win_rate = len(winning_trades) / len([t for t in trades if 'pnl' in t]) * 100 if 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
# Tính số ngày trong range
range_days = len(df) / 24 # Giả sử timeframe là 1h
return {
'initial_capital': initial_capital,
'final_capital': capital,
'total_return': total_return,
'total_trades': len([t for t in trades if 'pnl' in t]),
'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,
'range_days': range_days
}
# Ví dụ sử dụng
import yfinance as yf
# Lấy dữ liệu
data = yf.download('EURUSD=X', period='6mo', interval='1h')
df = pd.DataFrame(data)
df.columns = [col.lower() for col in df.columns]
# Chạy backtest
strategy = RSIRangeStrategy(rsi_period=14, range_period=20)
results = backtest_range_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ố Range-Bound Strategy
5.1. Tìm tham số tối ưu
from itertools import product
def optimize_range_parameters(df, strategy_class, param_ranges):
"""
Tối ưu hóa tham số Range-Bound Strategy
Parameters:
-----------
df : pd.DataFrame
Dữ liệu lịch sử
strategy_class : class
Lớp chiến lược
param_ranges : dict
Phạm vi tham số cần tối ưu
Returns:
--------
dict: Tham số tối ưu và kết quả
"""
best_params = None
best_score = -float('inf')
best_results = None
# Tạo tất cả các tổ hợp tham số
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))
# Tạo chiến lược với tham số mới
strategy = strategy_class(**param_dict)
# Backtest
results = backtest_range_strategy(df, strategy)
# Đánh giá (kết hợp return và win rate)
score = results['total_return'] * (results['win_rate'] / 100)
if score > best_score:
best_score = score
best_params = param_dict
best_results = results
return {
'best_params': best_params,
'best_score': best_score,
'results': best_results
}
# Ví dụ tối ưu hóa
param_ranges = {
'rsi_period': [10, 14, 21],
'range_period': [15, 20, 30],
'oversold': [25, 30, 35],
'overbought': [65, 70, 75]
}
optimization_results = optimize_range_parameters(df, RSIRangeStrategy, 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 Range-Bound Trading
6.1. Position Sizing động
class RangeRiskManager:
"""Quản lý rủi ro cho chiến lược Range-Bound"""
def __init__(self, max_risk_per_trade=0.02, max_portfolio_risk=0.1):
self.max_risk_per_trade = max_risk_per_trade
self.max_portfolio_risk = max_portfolio_risk
def calculate_position_size(self, account_balance, entry_price,
support, resistance):
"""
Tính toán kích thước vị thế dựa trên range width
Parameters:
-----------
account_balance : float
Số dư tài khoản
entry_price : float
Giá vào lệnh
support : float
Mức hỗ trợ
resistance : float
Mức kháng cự
Returns:
--------
float: Kích thước vị thế
"""
range_width = resistance - support
stop_loss_distance = range_width * 0.1 # Stop loss = 10% range width
risk_amount = account_balance * self.max_risk_per_trade
position_size = risk_amount / stop_loss_distance
return position_size
def calculate_stop_loss_take_profit(self, entry_price, support, resistance,
side='long'):
"""
Tính stop loss và take profit dựa trên range
Parameters:
-----------
entry_price : float
Giá vào lệnh
support : float
Mức hỗ trợ
resistance : float
Mức kháng cự
side : str
'long' hoặc 'short'
Returns:
--------
tuple: (stop_loss, take_profit)
"""
range_width = resistance - support
if side == 'long':
# Stop loss dưới support một chút
stop_loss = support - (range_width * 0.05)
# Take profit gần resistance
take_profit = resistance - (range_width * 0.1)
else: # short
# Stop loss trên resistance một chút
stop_loss = resistance + (range_width * 0.05)
# Take profit gần support
take_profit = support + (range_width * 0.1)
return stop_loss, take_profit
6.2. Xác định thị trường Range
def detect_range_market(df, period=50, adx_threshold=25):
"""
Phát hiện thị trường có phải range không
Parameters:
-----------
df : pd.DataFrame
Dữ liệu OHLCV
period : int
Period để tính toán
adx_threshold : float
Ngưỡng ADX (ADX < threshold = range market)
Returns:
--------
bool: True nếu là range market
"""
if len(df) < period + 14:
return False
# Tính ADX
adx = ta.adx(df['High'], df['Low'], df['Close'], length=14)
if adx is None or len(adx) == 0:
return False
current_adx = adx.iloc[-1, 0] if isinstance(adx, pd.DataFrame) else adx.iloc[-1]
# Kiểm tra độ biến động giá
price_range = df['High'].tail(period).max() - df['Low'].tail(period).min()
price_mean = df['Close'].tail(period).mean()
volatility = (price_range / price_mean) * 100
# Range market nếu ADX thấp và volatility không quá cao
return current_adx < adx_threshold and volatility < 5
7. Kết luận: Chiến lược Range-Bound nào hiệu quả nhất?
Đánh giá các chiến lược:
- Support/Resistance Cơ bản
- ✅ Đơn giản, dễ triển khai
- ❌ Nhiều false signals
- ⭐ Hiệu quả: 3/5
- Bollinger Bands Range
- ✅ Giảm false signals đáng kể
- ✅ Phù hợp nhiều thị trường
- ⭐ Hiệu quả: 4/5
- RSI Range
- ✅ Tín hiệu mạnh, độ chính xác cao
- ✅ Kết hợp tốt với range trading
- ⭐ Hiệu quả: 4.5/5
- Stochastic Range
- ✅ Tín hiệu rõ ràng, dễ theo dõi
- ✅ Phù hợp với range market
- ⭐ Hiệu quả: 4.5/5
Khuyến nghị:
- Cho người mới bắt đầu: Bollinger Bands Range Strategy
- Cho trader có kinh nghiệm: RSI Range hoặc Stochastic Range
- Cho scalping: RSI Range với khung thời gian ngắn (M15, M30)
Lưu ý quan trọng:
- Xác định đúng Range: Chỉ trade khi thị trường thực sự trong range
- Quản lý rủi ro: Luôn đặt stop loss và take profit
- Tránh trade khi breakout: Khi giá breakout khỏi range, đóng lệnh ngay
- Backtest kỹ lưỡng: Kiểm tra chiến lược trên dữ liệu lịch sử
- Theo dõi và điều chỉnh: Range có thể thay đổi, cần cập nhật support/resistance
- Không trade trong tin tức: Range trading không phù hợp với thời điểm có tin tức lớn
8. Tài liệu tham khảo
- Range Trading Strategies – 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ư.