บทนำ
การเทรดความผันผวน (Volatility Trading) เป็นหนึ่งในกลยุทธ์ขั้นสูงที่นักเทรดระดับมืออาชีพใช้ในการสร้างผลตอบแทนจากการเคลื่อนไหวของราคาสินทรัพย์โดยไม่จำเป็นต้องรู้ทิศทางที่แน่นอน ในบทความนี้ผมจะพาทุกท่านเจาะลึกถึงหลักการทำงานของ Greeks (Delta, Gamma, Theta, Vega, Rho) วิธีการคำนวณ และการสร้างระบบ Backtesting ที่เชื่อถือได้สำหรับกลยุทธ์ Volatility Arbitrage
จากประสบการณ์การพัฒนาระบบ Quantitative Trading มากว่า 8 ปี ผมพบว่าการเข้าใจ Greeks อย่างลึกซึ้งคือกุญแจสำคัญในการบริหารความเสี่ยงและสร้างผลตอบแทนที่ยั่งยืน โดยเฉพาะในตลาดที่มีความผันผวนสูงอย่างตลาดคริปโตหรือตลาดฟิวเจอร์ส
---
ความเข้าใจพื้นฐานเกี่ยวกับ Volatility
Volatility คืออะไร
Volatility หรือความผันผวน คือการวัดอัตราการเปลี่ยนแปลงของราคาสินทรัพย์ในช่วงเวลาที่กำหนด ในทางคณิตศาสตร์เราใช้ **Standard Deviation** ในการคำนวณ:
σ = √(Σ(Ri - μ)² / N)
โดยที่:
- σ (Sigma) = ความผันผวน (Volatility)
- Ri = ผลตอบแทนในช่วง i
- μ = ผลตอบแทนเฉลี่ย
- N = จำนวนข้อมูล
Historical Volatility vs Implied Volatility
**Historical Volatility (HV)** คำนวณจากข้อมูลราคาในอดีต ใช้สำหรับวัดความผันผวนที่เกิดขึ้นจริง
**Implied Volatility (IV)** คำนวณย้อนกลับจากราคาตราสารอนุพันธ์ (Derivatives) โดยใช้ Black-Scholes Model ซึ่งสะท้อนความคาดหวังของตลาดต่อความผันผวนในอนาคต
ส่วนต่างระหว่าง IV และ HV คือ **Volatility Risk Premium** ซึ่งเป็นหัวใจสำคัญของกลยุทธ์ Volatility Arbitrage
---
Greeks: เครื่องมือวัดความเสี่ยงของออปชัน
Greeks คือตัวแปรที่ใช้วัดความอ่อนไหวของราคาออปชันต่อปัจจัยต่างๆ ในตลาด ซึ่งประกอบด้วย 5 ตัวหลัก:
1. Delta (Δ) - ความอ่อนไหวต่อราคาสินทรัพย์
Delta วัดการเปลี่ยนแปลงของราคาออปชันเมื่อราคาสินทรัพย์อ้างอิง (Underlying Asset) เปลี่ยนแปลง 1 หน่วย
Delta (Call) = N(d1)
Delta (Put) = N(d1) - 1
import numpy as np
from scipy.stats import norm
def calculate_delta(S, K, T, r, sigma, option_type='call'):
"""
คำนวณ Delta ของออปชัน
S: ราคาปัจจุบันของสินทรัพย์อ้างอิง
K: Strike Price
T: เวลาที่เหลือ (ปี)
r: อัตราดอกเบี้ยปลอดความเสี่ยง
sigma: ความผันผวน
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
if option_type == 'call':
delta = norm.cdf(d1)
else:
delta = norm.cdf(d1) - 1
return delta
ตัวอย่างการใช้งาน
Delta ของ Call Option
call_delta = calculate_delta(S=100, K=100, T=30/365, r=0.05, sigma=0.2, option_type='call')
print(f"Call Delta: {call_delta:.4f}") # ผลลัพธ์: ~0.5248
Delta ของ Put Option
put_delta = calculate_delta(S=100, K=100, T=30/365, r=0.05, sigma=0.2, option_type='put')
print(f"Put Delta: {put_delta:.4f}") # ผลลัพธ์: ~-0.4752
2. Gamma (Γ) - อัตราการเปลี่ยนแปลงของ Delta
Gamma วัดอัตราการเปลี่ยนแปลงของ Delta เมื่อราคาสินทรัพย์อ้างอิงเปลี่ยนแปลง 1 หน่วย
def calculate_gamma(S, K, T, r, sigma):
"""
คำนวณ Gamma ของออปชัน
Gamma เหมือนกันสำหรับ Call และ Put
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))
return gamma
ตัวอย่างการใช้งาน
gamma = calculate_gamma(S=100, K=100, T=30/365, r=0.05, sigma=0.2)
print(f"Gamma: {gamma:.6f}") # ผลลัพธ์: ~0.0242
Gamma จะสูงสุดเมื่อออปชันอยู่ At-The-Money (ATM)
และจะลดลงเมื่อออปชันอยู่ In-The-Money (ITM) หรือ Out-Of-The-Money (OTM)
3. Theta (Θ) - การสึกกร่อนของมูลค่าตามเวลา
Theta วัดการเปลี่ยนแปลงของราคาออปชันเมื่อเวลาผ่านไป 1 วัน
def calculate_theta(S, K, T, r, sigma, option_type='call'):
"""
คำนวณ Theta ของออปชัน (ต่อวัน)
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
first_term = -(S * norm.pdf(d1) * sigma) / (2 * np.sqrt(T))
if option_type == 'call':
theta = (first_term - r * K * np.exp(-r * T) * norm.cdf(d2)) / 365
else:
theta = (first_term + r * K * np.exp(-r * T) * norm.cdf(-d2)) / 365
return theta
ตัวอย่างการใช้งาน
call_theta = calculate_theta(S=100, K=100, T=30/365, r=0.05, sigma=0.2, option_type='call')
put_theta = calculate_theta(S=100, K=100, T=30/365, r=0.05, sigma=0.2, option_type='put')
print(f"Call Theta (ต่อวัน): {call_theta:.4f}") # ผลลัพธ์: ~-0.0167
print(f"Put Theta (ต่อวัน): {put_theta:.4f}") # ผลลัพธ์: ~-0.0093
Theta ของ Put มักจะน้อยกว่า Call เพราะ Put มีค่า Intrinsic Value
จากดอกเบี้ยที่ได้รับเมื่อถือเงินสดแทนหุ้น
4. Vega (Ν) - ความอ่อนไหวต่อความผันผวน
Vega วัดการเปลี่ยนแปลงของราคาออปชันเมื่อ Implied Volatility เปลี่ยนแปลง 1%
def calculate_vega(S, K, T, r, sigma):
"""
คำนวณ Vega ของออปชัน (% ต่อ 1% IV change)
Vega เหมือนกันสำหรับ Call และ Put
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
vega = S * norm.pdf(d1) * np.sqrt(T) / 100
return vega
ตัวอย่างการใช้งาน
vega = calculate_vega(S=100, K=100, T=30/365, r=0.05, sigma=0.2)
print(f"Vega: {vega:.4f}") # ผลลัพธ์: ~0.1212
หมายความว่า ถ้า IV เพิ่มขึ้น 1% ราคาออปชันจะเพิ่มขึ้น ~0.12 บาท
5. Rho (ρ) - ความอ่อนไหวต่ออัตราดอกเบี้ย
Rho วัดการเปลี่ยนแปลงของราคาออปชันเมื่ออัตราดอกเบี้ยปลอดความเสี่ยงเปลี่ยนแปลง 1%
def calculate_rho(S, K, T, r, sigma, option_type='call'):
"""
คำนวณ Rho ของออปชัน (% ต่อ 1% การเปลี่ยนแปลงของ r)
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == 'call':
rho = K * T * np.exp(-r * T) * norm.cdf(d2) / 100
else:
rho = -K * T * np.exp(-r * T) * norm.cdf(-d2) / 100
return rho
ตัวอย่างการใช้งาน
call_rho = calculate_rho(S=100, K=100, T=30/365, r=0.05, sigma=0.2, option_type='call')
print(f"Call Rho: {call_rho:.4f}") # ผลลัพธ์: ~0.0126
---
กลยุทธ์ Volatility Trading หลัก
กลยุทธ์ที่ 1: Volatility Arbitrage
กลยุทธ์นี้ใช้ประโยชน์จากส่วนต่างระหว่าง Implied Volatility และ Historical Volatility
class VolatilityArbitrageStrategy:
def __init__(self, symbol, entry_iv_threshold=30, exit_iv_threshold=20):
self.symbol = symbol
self.entry_iv_threshold = entry_iv_threshold # IV ที่จะเข้า Order
self.exit_iv_threshold = exit_iv_threshold # IV ที่จะออก Order
self.position = None
self.entry_iv = None
def calculate_hv(self, prices, window=20):
"""คำนวณ Historical Volatility"""
returns = np.diff(np.log(prices))
hv = np.std(returns[-window:]) * np.sqrt(252) * 100
return hv
def calculate_iv(self, option_price, S, K, T, r):
"""คำนวณ Implied Volatility โดยใช้ Newton-Raphson"""
def black_scholes_call(S, K, T, r, sigma):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
sigma = 0.2 # Initial guess
for _ in range(100):
price = black_scholes_call(S, K, T, r, sigma)
vega = S * norm.pdf((np.log(S/K) + (r + 0.5*sigma**2)*T) /
(sigma*np.sqrt(T))) * np.sqrt(T)
diff = option_price - price
if abs(diff) < 1e-6:
break
sigma += diff / (vega * 100)
return sigma * 100 # Return as percentage
def generate_signal(self, current_price, option_price, strike, expiry_days):
"""สร้างสัญญาณเข้า/ออก Order"""
T = expiry_days / 365
r = 0.05 # Risk-free rate
# คำนวณ IV
iv = self.calculate_iv(option_price, current_price, strike, T, r)
# สร้างสัญญาณ
if self.position is None:
if iv >= self.entry_iv_threshold:
self.position = 'long_volatility'
self.entry_iv = iv
return 'BUY', iv
else:
if iv <= self.exit_iv_threshold:
self.position = None
return 'SELL', iv
return 'HOLD', iv
ตัวอย่างการใช้งาน
strategy = VolatilityArbitrageStrategy(
symbol='SPY',
entry_iv_threshold=30,
exit_iv_threshold=20
)
ทดสอบสัญญาณ
signal, iv = strategy.generate_signal(
current_price=450,
option_price=15,
strike=450,
expiry_days=30
)
print(f"Signal: {signal}, IV: {iv:.2f}%")
กลยุทธ์ที่ 2: Delta Hedged Strategy
กลยุทธ์นี้ใช้ Delta ในการป้องกันความเสี่ยงจากการเคลื่อนไหวของราคา โดยเปิดสถานะสินทรัพย์อ้างอิงในทิศทางตรงข้าม
class DeltaHedgedStrategy:
def __init__(self, target_delta=0):
self.target_delta = target_delta
self.position_pnl = []
def calculate_hedge_ratio(self, option_delta, option_size, underlying_price):
"""คำนวณจำนวนสินทรัพย์อ้างอิงที่ต้องซื้อ/ขายเพื่อ Delta Hedge"""
total_option_delta = option_delta * option_size
shares_to_hedge = -total_option_delta / self.target_delta
return shares_to_hedge
def rebalance(self, current_price, strike, T, r, sigma,
current_shares, option_position):
"""
Rebalance สถานะเพื่อรักษา Delta Neutral
"""
# คำนวณ Delta ปัจจุบัน
current_delta = calculate_delta(current_price, strike, T, r, sigma, 'call')
# คำนวณ Delta ของสถานะทั้งหมด
total_delta = (current_delta * option_position +
current_shares / current_price)
# คำนวณ Delta ที่ต้องการ
desired_delta = self.target_delta * (option_position + 1)
# คำนวณการเปลี่ยนแปลง
delta_diff = desired_delta - total_delta
shares_to_trade = delta_diff * current_price
return shares_to_trade, total_delta
def backtest_single_period(self, price_path, strike, T, r, sigma, initial_shares=0):
"""
ทดสอบกลยุทธ์ในช่วงเวลาหนึ่ง
"""
results = []
current_shares = initial_shares
for i in range(len(price_path) - 1):
S = price_path[i]
S_next = price_path[i + 1]
T_remaining = T - (i / 252) # ลดเวลาตามวันที่ผ่านไป
if T_remaining <= 0:
break
# คำนวณ Delta ปัจจุบัน
current_delta = calculate_delta(S, strike, T_remaining, r, sigma, 'call')
# Rebalance
shares_to_trade, total_delta = self.rebalance(
S, strike, T_remaining, r, sigma, current_shares, 1
)
# คำนวณ P&L
underlying_pnl = current_shares * (S_next - S)
option_price = max(S_next - strike, 0) - max(S - strike, 0)
total_pnl = underlying_pnl + option_price
self.position_pnl.append(total_pnl)
results.append({
'price': S,
'delta': current_delta,
'shares': current_shares,
'pnl': total_pnl
})
# อัปเดตสถานะ
current_shares += shares_to_trade
return results
ทดสอบกลยุทธ์
strategy = DeltaHedgedStrategy(target_delta=0)
np.random.seed(42)
price_path = 100 + np.cumsum(np.random.randn(30) * 0.5)
results = strategy.backtest_single_period(
price_path=price_path,
strike=100,
T=30/365,
r=0.05,
sigma=0.2
)
กลยุทธ์ที่ 3: Gamma Scalping
กลยุทธ์นี้ใช้ประโยชน์จาก Theta Decay โดยการเปิดสถานะที่มี Gamma สูงและ Rebalance สม่ำเสมอ
class GammaScalpingStrategy:
def __init__(self, target_gamma_exposure=0.5):
self.target_gamma_exposure = target_gamma_exposure
self.transaction_costs = 0.001 # 0.1% ต่อครั้ง
def calculate_gamma_exposure(self, delta, gamma, position_size, underlying_price):
"""
คำนวณ Dollar Gamma Exposure (GEX)
GEX = Gamma * Position_Size * Underlying_Price^2
"""
gex = gamma * position_size * underlying_price**2 / 100
return gex
def optimal_rebalance_frequency(self, gamma, volatility, transaction_cost):
"""
คำนวณความถี่ที่เหมาะสมในการ Rebalance
โดยใช้สมการของ Marion และ Mastron:
Optimal Frequency ∝ √(Γ * σ² / TC)
"""
optimal_freq = np.sqrt(gamma * volatility**2 / transaction_cost)
return optimal_freq
def simulate_gamma_scalp(self, S0, mu, sigma, T, K, r, rebalance_days=5):
"""
จำลองกลยุทธ์ Gamma Scalping
"""
np.random.seed(42)
n_steps = int(T * 252)
dt = T / n_steps
# สร้างราคา
prices = [S0]
for _ in range(n_steps):
z = np.random.randn()
S_next = prices[-1] * np.exp((mu - 0.5*sigma**2)*dt + sigma*np.sqrt(dt)*z)
prices.append(S_next)
# ติดตามผล
portfolio_values = []
hedge_ratio = 0
cumulative_theta = 0
cumulative_gamma_pnl = 0
for i in range(0, n_steps, rebalance_days):
S = prices[i]
T_remaining = T - i/252
if T_remaining <= 0:
break
# คำนวณ Greeks
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T_remaining) / (sigma*np.sqrt(T_remaining))
delta = norm.cdf(d1)
gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T_remaining))
theta = -(S * norm.pdf(d1) * sigma) / (2 * np.sqrt(T_remaining)) / 365
# คำนวณ Theta P&L
theta_pnl = theta * rebalance_days
cumulative_theta += theta_pnl
# คำนวณ Gamma P&L
S_next = prices[min(i + rebalance_days, len(prices)-1)]
gamma_pnl = 0.5 * gamma * S**2 * ((S_next - S)/S)**2 * 100
cumulative_gamma_pnl += gamma_pnl
# Rebalance Hedge
hedge_ratio = -delta
portfolio_values.append({
'day': i,
'price': S,
'delta': delta,
'gamma': gamma,
'theta_pnl': theta_pnl,
'gamma_pnl': gamma_pnl
})
return portfolio_values, cumulative_theta, cumulative_gamma_pnl
ทดสอบกลยุทธ์
strategy = GammaScalpingStrategy()
results, total_theta, total_gamma = strategy.simulate_gamma_scalp(
S0=100,
mu=0.05,
sigma=0.2,
T=30/365,
K=100,
r=0.05,
rebalance_days=3
)
print(f"Total Theta P&L: {total_theta:.4f}")
print(f"Total Gamma P&L: {total_gamma:.4f}")
print(f"Net P&L: {total_theta + total_gamma:.4f}")
---
ระบบ Backtesting สำหรับ Volatility Strategies
การสร้าง Backtesting Engine
```python
import pandas as pd
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
class VolatilityBacktester:
def __init__(self, initial_capital=100000, transaction_cost=0.001):
self.initial_capital = initial_capital
self.transaction_cost = transaction_cost
self.results = []
def load_market_data(self, filepath):
"""โหลดข้อมูลตลาดจาก CSV"""
df = pd.read_csv(filepath)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp', inplace=True)
return df
def generate_synthetic_data(self, S0, mu, sigma, days, trading_days=252):
"""สร้างข้อมูลสังเคราะห์สำหรับทดสอบ"""
dates = pd.date_range(start='2023-01-01', periods=days, freq='D')
n = len(dates)
dt = 1 / trading_days
drift = (mu - 0.5 * sigma**2) * dt
diffusion = sigma * np.sqrt(dt)
returns = np.random.normal(drift, diffusion, n)
prices = S0 * np.exp(np.cumsum(returns))
# เพิ่ม Volatility Clustering (GARCH-like effect)
volatility_regime = np.random.choice([0.5, 1.5], n, p=[0.7, 0.3])
prices = prices * volatility_regime.cumprod()
df = pd.DataFrame({
'open': prices * (1 + np.random.uniform(-0.01, 0.01, n)),
'high': prices * (1 + np.random.uniform(0, 0.02, n)),
'low': prices * (1 - np.random.uniform(0, 0.02, n)),
'close': prices,
'volume': np.random.randint(1000000, 10000000, n)
}, index=dates)
return df
def calculate_portfolio_metrics(self, portfolio_value, risk_free_rate=0.05):
"""คำนวณ Portfolio Metrics"""
returns = np.diff(portfolio_value) / portfolio_value[:-1]
# Annualized Return
total_days = len(portfolio_value)
annual_return = (portfolio_value[-1] / portfolio_value[0]) ** (252/total_days) - 1
# Annualized Volatility
annual_volatility = np.std(returns) * np.sqrt(252)
# Sharpe Ratio
excess_return = annual_return - risk_free_rate
sharpe_ratio = excess_return / annual_volatility if annual_volatility > 0 else 0
# Maximum Drawdown
cumulative = portfolio_value / portfolio_value[0]
running_max = np.maximum.accumulate(cumulative)
drawdown = (cumulative - running_max) / running_max
max_drawdown = drawdown.min()
# Calmar Ratio
calmar_ratio = annual_return / abs(max_drawdown) if max_drawdown != 0 else 0
return {
'total_return': (portfolio_value[-1] - portfolio_value[0]) / portfolio_value[0],
'annual_return': annual_return,
'annual_volatility': annual_volatility,
'sharpe_ratio': sharpe_ratio,
'max_drawdown': max_drawdown,
'calmar_ratio': calmar_ratio,
'win_rate': len(returns[returns > 0]) / len(returns)
}
def run_backtest(self, strategy, market_data, params):
"""Run Backtest"""
capital = self.initial_capital
portfolio_value = [capital]
position = 0
trades = []
for i in range(len(market_data) - 1):
current_price = market_data['close'].iloc[i]
next_price = market_data['close'].iloc[i + 1]
# สร้างสัญญาณ
signal, iv = strategy.generate_signal(
current_price=current_price,
option_price=params.get('option_premium', current_price * 0.05),
strike=params.get('strike', current_price),
expiry_days=params.get('expiry_days', 30)
)
# ดำเนินการตามสัญญาณ
if signal == 'BUY' and position == 0:
shares = capital * params.get('position_size', 0.1) / current_price
cost = shares * current_price * (1 + self.transaction_cost)
position = shares
capital -=
แหล่งข้อมูลที่เกี่ยวข้อง
บทความที่เกี่ยวข้อง