Reinforcement Learning — ترید با RL
Q-Learning، PPO، DQN.
یادگیری تقویتی در ترید — Q-Learning، DQN، PPO
هدف یادگیری
پس از مطالعه این درس خواهید توانست:
- مسئله ترید را در قالب فرمال Markov Decision Process (MDP) تعریف کنید
- معادله بلمن و آپدیت Q-Learning را دستی محاسبه کنید
- تفاوت معماری DQN و Q-Learning جدولی را توضیح دهید
- الگوریتم PPO و مفهوم clipping را با فرمول شرح دهید
- محیط ترید برای RL را طراحی کرده و تابع پاداش مناسب انتخاب کنید
---
۱. ترید بهعنوان Markov Decision Process
ترید در بازارهای مالی را میتوان بهصورت یک MDP با چهارتایی (S, A, P, R) فرمال کرد:
- S (State Space): مجموعه حالتهای بازار — قیمت، حجم، اندیکاتورها، موقعیت فعلی پرتفولیو
- A (Action Space): فضای اقدام — {خرید، فروش، نگهداری} یا برای اقدام پیوسته {−1 تا +1} بهعنوان وزن موقعیت
- P (Transition Probability): احتمال انتقال از حالت s به s' با اقدام a — در بازار ذاتاً تصادفی است
- R (Reward Function): تابع پاداش — معمولاً تغییر ارزش پرتفولیو منهای هزینه معاملاتی
مثال عددی — تعریف حالت برای BTC/USDT:
s_t = [close_t / close_{t-1} - 1, # بازده قیمتی نرمالشده
volume_t / MA(volume, 20), # نسبت حجم به میانگین ۲۰ دورهای
RSI_14 / 100, # RSI نرمالشده به [0,1]
position_t] # موقعیت فعلی: {-1, 0, +1}
بازده تجمعی با Discount Factor:
عامل RL هدفش بیشینه کردن بازده تجمعی تخفیفیافته است:
G_t = R_{t+1} + γ·R_{t+2} + γ²·R_{t+3} + ...
= Σ_{k=0}^{∞} γ^k · R_{t+k+1}
با γ = 0.99 برای استراتژی swing (افق بلندمدتتر) در برابر γ = 0.90 برای scalping، عامل وزندهی پاداشهای آینده را کنترل میکنیم. هر چه γ به ۱ نزدیکتر باشد، عامل «صبورتر» است.
---
۲. Q-Learning — معادله بلمن و آپدیت جدولی
Q-Learning یک الگوریتم model-free و off-policy است که تابع ارزش-اقدام Q(s,a) را یاد میگیرد — یعنی نیازی به مدل انتقال محیط ندارد.
معادله بلمن برای Q بهینه:
Q(s, a) = E[R_{t+1} + γ · max_{a'} Q(s_{t+1}, a') | s_t=s, a_t=a]
قانون آپدیت Q-Learning:
Q(s_t, a_t) ← Q(s_t, a_t) + α · [R_{t+1} + γ·max_{a'}Q(s_{t+1}, a') - Q(s_t, a_t)]
|_____________TD Target_____________| |__TD Error__|
جایی که α نرخ یادگیری است و TD Error خطای تفاضل زمانی نامیده میشود.
مثال محاسباتی گامبهگام:
فرض کنید:
- Q(s_t, Buy) = 0.40
- R_{t+1} = +0.02 (قیمت ۲٪ رشد کرد — پاداش مثبت)
- max Q(s_{t+1}, a') = 0.60
- α = 0.10, γ = 0.95
TD Target = 0.02 + 0.95 × 0.60 = 0.02 + 0.57 = 0.59
TD Error = 0.59 - 0.40 = 0.19
Q_new(s_t, Buy) = 0.40 + 0.10 × 0.19 = 0.419
آپدیت Q برای Buy اقدام را ۰.۰۱۹ واحد افزایش داد — عامل یاد گرفت که در این حالت خرید بهتر از آن چیزی بود که فکر میکرد.
محدودیت بنیادی — Curse of Dimensionality:
Q-Learning کلاسیک فضای حالت را در یک جدول ذخیره میکند. اگر State یک بردار ۱۰ بعدی پیوسته باشد، جدول Q بهطور نمایی رشد میکند و عملاً غیرممکن میشود. این همان مشکلی بود که DQN برای حل آن طراحی شد.
---
۳. DQN — شبکه عصبی بهجای جدول
Deep Q-Network (DQN) از یک شبکه عصبی بهعنوان function approximator برای Q استفاده میکند:
Q(s, a; θ) ≈ Q*(s, a)
شبکه ورودی s را میگیرد و برای همه اقدامات a مقدار Q را بهصورت موازی خروجی میدهد.
نوآوری اول: Experience Replay
بهجای آموزش آنلاین (هر گام یک آپدیت)، تجربیات (s, a, r, s') را در یک Replay Buffer ذخیره میکنیم:
python
replay_buffer = deque(maxlen=100_000)
هر گام:
replay_buffer.append((s_t, a_t, r_{t+1}, s_{t+1}, done))هر N گام، یک batch تصادفی برای آموزش:
batch = random.sample(replay_buffer, batch_size=64)این کار دو مشکل را حل میکند:
۱. Correlation: تجربیات متوالی همبسته هستند — نمونهبرداری تصادفی این همبستگی را میشکند
۲. Sample Efficiency: هر تجربه میتواند چندین بار در آموزش استفاده شود
نوآوری دوم: Target Network
یک شبکه هدف جداگانه با وزنهای θ⁻ داریم که با تأخیر آپدیت میشود:
Loss(θ) = E[(R + γ·max_{a'}Q(s', a'; θ⁻) - Q(s, a; θ))²]
هر C گام (معمولاً C = 1000) وزنهای Target Network کپی میشوند: θ⁻ ← θ
اگر Target Network نداشتیم، هم هدف و هم پیشبینی با هر آپدیت تغییر میکردند — مثل تیراندازی به یک هدف متحرک — و یادگیری diverge میشد.
معماری شبکه برای ترید (LSTM + Dense):
Input Layer: [N_features × T_lookback]
↓
LSTM Layer (64 units) ← برای گرفتن وابستگی زمانی در سری قیمتی
↓
Dense Layer (128) + ReLU
↓
Dense Layer (64) + ReLU
↓
Output Layer: [N_actions] # مثلاً [Q_buy, Q_sell, Q_hold]
Dueling DQN — پیشرفت معماری:
Dueling DQN تابع Q را به دو جزء تجزیه میکند:
Q(s, a; θ) = V(s; θ_v) + A(s, a; θ_a) - (1/|A|)·Σ_{a'} A(s, a'; θ_a)
- V(s): ارزش ذاتی حالت (مستقل از اقدام انتخابی)
- A(s,a): مزیت نسبی هر اقدام در آن حالت
این تفکیک بهویژه در بازارهای sideways مفید است — عامل یاد میگیرد که در حالتهای neutral، هیچ اقدامی مزیت خاصی ندارد، بدون اینکه نیاز باشد تکتک Q مقادیر را ارزیابی کند.
---
۴. PPO — بهینهسازی سیاست با Clipping
PPO از خانواده Policy Gradient است و مستقیماً سیاست π(a|s; θ) را بهینه میکند — نه تابع ارزش را.
تابع هدف استاندارد Policy Gradient:
J(θ) = E_t[log π_θ(a_t|s_t) · A_t]
که A_t (Advantage) برتری اقدام انتخابی نسبت به میانگین را نشان میدهد:
A_t = R_t - V(s_t) # شکل ساده
A_t = Σ_{l=0}^{T} (γλ)^l · δ_{t+l} # GAE (Generalized Advantage Estimation)
مشکل TRPO و راهحل PPO:
بهروزرسانیهای بزرگ در Policy Gradient میتوانند سیاست را به شکل فاجعهباری خراب کنند. TRPO با یک KL-divergence constraint این را کنترل کرد اما محاسباتی بسیار سنگین بود. PPO همین هدف را با یک Clipped Objective سادهتر حل کرد:
L^CLIP(θ) = E_t[ min( r_t(θ)·A_t , clip(r_t(θ), 1-ε, 1+ε)·A_t ) ]
جایی که:
r_t(θ) = π_θ(a_t|s_t) / π_{θ_old}(a_t|s_t) # نسبت سیاست جدید به قدیم
با ε = 0.2، نسبت r_t در بازه [0.8, 1.2] کلیپ میشود.
مثال عددی PPO:
فرض کنید:
- A_t = +0.50 (اقدام خرید مفید بوده)
- r_t = 1.35 (سیاست جدید این اقدام را ۳۵٪ بیشتر احتمال میدهد)
term1 = r_t · A_t = 1.35 × 0.50 = 0.675
term2 = clip(1.35, 0.8, 1.2) × 0.50 = 1.20 × 0.50 = 0.600
L^CLIP = min(0.675, 0.600) = 0.600
کلیپ کردن از gradient خیلی بزرگ جلوگیری کرد — سیاست نمیتواند بیش از ۲۰٪ شیفت کند.
PPO برای فضای پیوسته:
در ترید با تخصیص سرمایه پیوسته، خروجی شبکه یک توزیع گاوسی است:
π_θ(a|s) = N(μ_θ(s), σ_θ(s))
عامل وزن موقعیت دقیق (مثلاً ۰.۳۷ از سرمایه) را تعیین میکند، نه فقط یک انتخاب باینری خرید/فروش.
---
۵. طراحی محیط ترید و تابع پاداش
اسکلت محیط با OpenAI Gym:
python
class CryptoTradingEnv(gym.Env):
def __init__(self, df, initial_balance=10_000, fee=0.001):
self.observation_space = spaces.Box(
low=-np.inf, high=np.inf, shape=(n_features,), dtype=np.float32
)
self.action_space = spaces.Box(-1.0, 1.0, shape=(1,)) # پیوسته
self.fee = fee # کارمزد ۰.۱٪
def _compute_reward(self):
raw_return = (self.balance - self.prev_balance) / self.prev_balance
cost = abs(self.position_delta) * self.fee
return raw_return - cost
مقایسه توابع پاداش:
| تابع پاداش | مزیت | عیب |
|---|---|---|
| بازده ساده PnL_t | ساده | ریسک نادیده گرفته میشود |
| نسبت شارپ rolling | ریسک تنظیمشده | محاسبه پیچیدهتر است |
| Sortino Ratio | فقط downside جریمه میشود | نیاز به تنظیم بیشتر |
| MDD-penalized | از drawdown جلوگیری میکند | وزن penalty حساس است |
رویکرد پیشرفته — پاداش تنظیمشده با ریسک:
R_t = (PnL_t - cost_t) - λ · max(0, -PnL_t)²
پارامتر λ کنترل میکند که عامل چقدر نسبت به ضرر ریسکگریز باشد. با λ = 2.0 ضررهای بزرگ بهصورت چهارگوشی جریمه میشوند.
نرمالسازی State — جلوگیری از Data Leakage:
python
صحیح: rolling normalization
s_normalized = (s - rolling_mean(window=100)) / (rolling_std(window=100) + 1e-8)
غلط: نرمالسازی با کل داده — اطلاعات آینده وارد گذشته میشود!
s_wrong = (s - df.mean()) / df.std()---
۶. چالشهای کوانتی و ملاحظات عملی
Non-Stationarity — اصلیترین چالش:
بازارهای کریپتو non-stationary هستند — رژیمهای بازار (bull، bear، sideways) توزیع داده را تغییر میدهند. مدلی که روی داده ۲۰۲۱ آموزش دیده، در رژیم ۲۰۲۳ عملکرد متفاوتی خواهد داشت.
راهحلهای رایج:
- Walk-Forward Training: هر ۳۰ روز، fine-tune روی داده جدید
- Meta-RL (MAML): عامل یاد میگیرد که سریع با رژیم جدید adapt شود
- Regime Detection: قبل از RL، رژیم بازار شناسایی و به State اضافه شود
هزینههای معاملاتی — محاسبه واقعبینانه:
در بکتست باید هزینههای واقعی مدل شوند:
total_cost = spread_cost + taker_fee + slippage
≈ 0.0005 + 0.0010 + 0.0002
= 0.0017 per trade (0.17%)
با فرض ۵۰ معامله در ماه:
monthly_drag = 50 × 0.17% = 8.5%
این عدد نشان میدهد چرا high-frequency RL استراتژیها با هزینههای واقعی اغلب unprofitable هستند — هر الگوریتمی باید این سد را پشت سر بگذارد.
Reward Shaping در برابر Sparse Reward:
در ترید، پاداش اغلب sparse است — سود واقعی فقط در بسته شدن پوزیشن مشخص میشود. Reward Shaping با دادن سیگنالهای intermediate یادگیری را سرعت میبخشد:
R_shaped = R_actual + F(s_{t+1}) - F(s_t)
جایی که F یک تابع shaping potential است (مثلاً unrealized PnL). شرط Ng et al. تضمین میکند که policy بهینه تغییر نکند.
Hyperparameter Sensitivity — مقادیر رایج:
| پارامتر | DQN | PPO |
|---|---|---|
| Learning Rate | 1e-4 تا 5e-4 | 3e-4 تا 1e-3 |
| Batch Size | 32–128 | 64–2048 |
| γ (Discount) | 0.95–0.99 | 0.99 |
| Replay Buffer | 50k–1M | N/A |
| ε-greedy (exploration) | 1.0→0.01 | entropy coeff |
---
نتیجهگیری
یادگیری تقویتی در ترید یکی از پیچیدهترین و جذابترین حوزههای کوانت مالی است. هر سه الگوریتم رویکرد متفاوتی دارند:
- Q-Learning: پایه نظری محکم با معادله بلمن، اما محدود به فضاهای گسسته کوچک
- DQN: با Experience Replay و Target Network مشکل مقیاسپذیری را حل میکند
- PPO: با Clipped Objective انعطافپذیرترین الگوریتم برای فضاهای پیوسته است
خلاصه نقطهای:
- مسئله ترید را با MDP فرمال کنید: (S, A, P, R) را دقیق تعریف کنید
- معادله بلمن پایه ریاضی همه الگوریتمهای value-based است
- DQN با Experience Replay correlation بین نمونهها را میشکند
- Target Network از divergence در آموزش جلوگیری میکند
- PPO با clip(r_t, 1-ε, 1+ε) بهروزرسانیهای مخرب را محدود میکند
- تابع پاداش بحرانیترین تصمیم طراحی است — پاداش اشتباه، رفتار اشتباه میسازد
- هزینه ۰.۱۷٪ در هر معامله با ۵۰ ترید ماهانه = ۸.۵٪ drag ماهانه
- Non-stationarity بازار اصلیترین چالش تعمیمپذیری مدلهاست
- از نرمالسازی با کل داده اجتناب کنید تا data leakage نداشته باشید