LSTM — شبکه عصبی حافظه بلند-کوتاه مدت
LSTM (Long Short-Term Memory) با سه Gate مجزا — Forget، Input و Output — مشکل Vanishing Gradient شبکههای RNN استاندارد را حل میکند. در معاملات الگوریتمی، LSTM وابستگیهای بلندمدت در دادههای OHLCV را حفظ کرده و به مدل اجازه میدهد رویدادهای مهم چندین هفته پیش — مانند شکست سطح حمایت یا تصمیم بانک مرکزی — را هنگام تولید سیگنال در نظر بگیرد.
چگونه LSTM یاد میگیرد؟ — سه Gate کنترلی
عملکرد واقعی LSTM در بازارهای مالی
کلاسبندی روند (H4)
(OHLCV + اندیکاتور)
(کندل)
سیگنال Buy
مشخصات فنی پیادهسازی ExpertNevees
- OHLCV: Open, High, Low, Close, Volume — 60 کندل آخر
- RSI(14): اندیکاتور قدرت نسبی
- ATR(14): اندازهگیری نوسان بازار
- EMA(20) & EMA(50): میانگینهای متحرک نمایی
- نرمالسازی: MinMaxScaler برای هر ویژگی
- شکل تانسور: [Batch, 60, 11]
- نوع: طبقهبندی سهکلاسه با Softmax
- P(Up): احتمال صعود در 3 کندل آینده
- P(Down): احتمال نزول در 3 کندل آینده
- P(Neutral): بازار sideways یا بدون سیگنال
- آستانه Buy: P(Up) > 0.62 → سیگنال خرید
- ارسال: از طریق ZeroMQ به EA در MT5
معادلات دروازههای LSTM
# Forget gate — decides what fraction of the previous cell state to discard f_t = sigma( W_f . [h_(t-1), x_t] + b_f ) # Input gate — decides what new information gets stored i_t = sigma( W_i . [h_(t-1), x_t] + b_i ) # Candidate values for updating the cell state C~_t = tanh( W_C . [h_(t-1), x_t] + b_C ) # Cell state update: combine old memory (scaled by forget gate) with new candidate C_t = f_t * C_(t-1) + i_t * C~_t # Output gate — decides what fraction of memory is exposed as output o_t = sigma( W_o . [h_(t-1), x_t] + b_o ) # Final hidden state passed to the next layer or output h_t = o_t * tanh(C_t)
پیادهسازی LSTM با TensorFlow/Keras
import numpy as np import tensorflow as tf from tensorflow.keras import Sequential, Input from tensorflow.keras.layers import LSTM, Dense, Dropout, BatchNormalization from sklearn.preprocessing import MinMaxScaler # ── Stacked Bi-directional LSTM architecture for trend classification ── def build_lstm_model(seq_len=60, n_features=11, n_classes=3): model = Sequential([ Input(shape=(seq_len, n_features)), # First LSTM layer — returns full sequence for the second layer LSTM(128, return_sequences=True), BatchNormalization(), Dropout(0.25), # Second LSTM layer — collapses sequence to a single context vector LSTM(64, return_sequences=False), BatchNormalization(), Dropout(0.20), # Projection head before classifier Dense(32, activation='relu'), # Output: 3-class softmax — class 0=Down, 1=Neutral, 2=Up Dense(n_classes, activation='softmax') ]) model.compile( # learning_rate=1e-3 with cosine decay recommended for long runs optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss='sparse_categorical_crossentropy', metrics=['accuracy'] ) return model # ── Feature engineering: OHLCV + 6 technical indicators → [Batch, 60, 11] ── def make_sequences(df, seq_len=60): # Per-feature MinMax scaling applied on training split only (avoid leakage) scaler = MinMaxScaler() scaled = scaler.fit_transform(df[[ 'open', 'high', 'low', 'close', 'volume', # OHLCV 'rsi_14', 'atr_14', 'ema_20', 'ema_50', # momentum / volatility 'bb_upper', 'bb_lower' # Bollinger Band channels ]]) X, y = [], [] for i in range(seq_len, len(scaled)): X.append(scaled[i-seq_len:i]) # sliding window → shape [60, 11] y.append(get_label(df, i)) # forward-label: 0=Down, 1=Neutral, 2=Up return np.array(X), np.array(y), scaler # ── Real-time inference server: receives OHLCV from MT5 EA via ZeroMQ REP ── import zmq def signal_server(model, scaler, threshold=0.62): ctx = zmq.Context() sock = ctx.socket(zmq.REP) sock.bind("tcp://*:5555") while True: data = sock.recv_json() # receive last 60 candles from MT5 EA X = prepare_input(data, scaler) # scale + reshape → [1, 60, 11] probs = model.predict(X, verbose=0)[0] # [p_down, p_neutral, p_up] # Only emit a directional signal when confidence exceeds threshold signal = "BUY" if probs[2] > threshold else \ "SELL" if probs[0] > threshold else "HOLD" sock.send_json({"signal": signal, "confidence": float(probs.max()), "probs": probs.tolist()})
آموزش، پیشبینی و ارزیابی مدل LSTM
# ── Training run + Out-of-Sample evaluation ── from sklearn.metrics import classification_report, accuracy_score X, y, scaler = make_sequences(df, seq_len=60) # Time-ordered split — NEVER shuffle time series data (causes lookahead leakage) split = int(len(X) * 0.8) X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] model = build_lstm_model(seq_len=60, n_features=11, n_classes=3) history = model.fit( X_train, y_train, validation_split=0.15, epochs=50, batch_size=32, callbacks=[tf.keras.callbacks.EarlyStopping(patience=8, restore_best_weights=True)], verbose=1 ) # Out-of-sample prediction: probabilities per class → [Down, Neutral, Up] probs = model.predict(X_test) y_pred = probs.argmax(axis=1) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Down', 'Neutral', 'Up'])) # Single latest-window inference (what signal_server() does per tick) latest_probs = model.predict(X_test[-1:])[0] print(f"Latest signal -> Down={latest_probs[0]:.2f} Neutral={latest_probs[1]:.2f} Up={latest_probs[2]:.2f}")
اشتباهات رایج در پیادهسازی LSTM
-
●نشت داده از Scaler: اگر MinMaxScaler/StandardScaler را روی کل دیتاست (قبل از تقسیم Train/Test) فیت کنید، آمار داده آینده وارد داده آموزش میشود. Scaler فقط باید روی Train فیت و سپس روی Test فقط Transform شود.
-
●قیمت خام بهجای بازده: دادن قیمت مطلق (غیر ایستا) بهجای بازده لگاریتمی یا درصد تغییر باعث میشود مدل روی سطح قیمت Overfit کند و در بازه قیمتی جدید عملکردش بشکند.
-
●عدم توجه به عدمتوازن کلاس: کلاس Neutral معمولاً غالب است. بدون class_weight یا Resampling، مدل یاد میگیرد همیشه Neutral پیشبینی کند تا دقت را بالا نگه دارد — دقت بالا اما بیفایده.
-
●Shuffle در تقسیم Train/Test: استفاده از train_test_split با shuffle=True روی سریزمانی باعث Lookahead Bias میشود؛ مدل از الگوهای آینده در آموزش استفاده میکند.
LSTM برای کدام کاربردها مناسب است؟
-
●بازار Sideways: در بازارهای رنج و خنثی دقت به زیر ۵۵٪ کاهش مییابد. LSTM برای تشخیص روند است، نه بازارهای بدون جهت.
-
●نیاز به Retraining: مدل باید هفتگی یا ماهانه با داده جدید آموزش ببیند. بازار عوض میشود و مدل قدیمی میشود.
-
●Overfitting: بدون Walk-Forward Validation، مدل به داده Training Overfit میشود. دقت In-Sample بالا معیار کافی نیست.
-
●رویدادهای Black Swan: LSTM نمیتواند رویدادهای غیرمنتظره مانند بحرانهای ژئوپلیتیک یا تصمیمات ناگهانی فدرال رزرو را پیشبینی کند.
-
●تنها کافی نیست: هیچ مدلی بهتنهایی سیستم سودده نمیسازد. ترکیب LSTM با مدیریت ریسک کمّی ضروری است.
LSTM در مقابل سایر مدلهای Deep Learning
| ویژگی | LSTM | GRU | Transformer (TFT) | Attention Mechanism |
|---|---|---|---|---|
| سرعت آموزش | متوسط | سریع (+20٪) | کند (GPU ضروری) | متوسط |
| حافظه بلندمدت | ✓ قوی | ✓ خوب | ✓✓ بسیار قوی | ✓✓ بسیار قوی |
| قابلیت تفسیر | ضعیف | ضعیف | متوسط | عالی (Heatmap) |
| داده موردنیاز | +5000 کندل | +4000 کندل | +10000 کندل | +5000 کندل |
| دقت Out-of-Sample | 65–75٪ | 63–72٪ | 68–78٪ | 67–76٪ |
| مناسب برای | پیشبینی قیمت H1–D1 | Retrain روزانه | پیشبینی چندگامه | تشخیص کندلهای کلیدی |
مقالات پایه این مدل
-
Long Short-Term Memory Neural Computation, 9(8), 1735–1780مشاهده مقاله ↗
-
Learning to Forget: Continual Prediction with LSTM Neural Computation, 12(10), 2451–2471مشاهده مقاله ↗
آمادهاید ربات LSTM خود را بسازید؟
تیم ExpertNevees مدل LSTM سفارشی را با دادههای بازار هدف شما آموزش میدهد، Walk-Forward Validation انجام میدهد و از طریق ZeroMQ به MT5 متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
GRU — نسخه سریع و کارآمد LSTM
GRU (Gated Recurrent Unit) نسخه سادهشده LSTM است که با دو Gate بهجای سه Gate، سرعت آموزش را ۱۵-۲۵٪ افزایش میدهد بدون افت معنادار در دقت — انتخاب عملی برای سیستمهایی که نیاز به Retraining روزانه یا هفتگی دارند.
چگونه GRU یاد میگیرد؟ — دو Gate بهجای سه
مقایسه واقعی GRU با LSTM روی EUR/USD H1
(۵۰۰۰ کندل H1)
(در برابر ۴۵ دقیقه LSTM)
۳ Gate در LSTM
Retraining
مشخصات فنی پیادهسازی ExpertNevees
- OHLCV: همان پایپلاین Feature Engineering مدل LSTM
- تایمفریم: M15 تا H4 برای پیشبینی کوتاهمدت
- افق پیشبینی: ۱ تا ۵ کندل آینده
- Retraining: هر ۲۴ ساعت با داده جدید
- نوع: طبقهبندی سهکلاسه با Softmax
- دقت معمول: ۲٪ پایینتر از LSTM
- سرعت Inference: سریعتر بهدلیل پارامتر کمتر
- ارسال: از طریق ZeroMQ به EA در MT5
معادلات دروازههای GRU
# Update gate — how much of the previous state to keep (merges roles of f_t and i_t) z_t = sigma( W_z . [h_(t-1), x_t] ) # Reset gate — how much of the previous memory to ignore r_t = sigma( W_r . [h_(t-1), x_t] ) # Candidate state, with the reset gate applied to previous memory h~_t = tanh( W . [r_t * h_(t-1), x_t] ) # Final hidden state — linear interpolation between old memory and new candidate h_t = (1 - z_t) * h_(t-1) + z_t * h~_t
پیادهسازی GRU با TensorFlow/Keras
import pandas as pd import tensorflow as tf from tensorflow.keras.layers import GRU, Dense, Dropout, BatchNormalization from tensorflow.keras import Sequential, Input # ── GRU architecture — 2-gate design, 15-25% faster to train than LSTM ── def build_gru_model(seq_len=60, n_features=11, n_classes=3): model = Sequential([ Input(shape=(seq_len, n_features)), # Reset Gate + Update Gate fused — fewer params than LSTM's 3 gates GRU(128, return_sequences=True), BatchNormalization(), Dropout(0.25), # Final GRU layer outputs a single hidden state h_T GRU(64, return_sequences=False), BatchNormalization(), Dropout(0.20), Dense(32, activation='relu'), # 3-class softmax: 0=Down, 1=Neutral, 2=Up Dense(n_classes, activation='softmax') ]) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss='sparse_categorical_crossentropy', metrics=['accuracy'] ) return model # ── Adaptive daily retraining — fine-tunes existing weights on fresh data ── def daily_retrain_job(model_path, new_data_path): df = pd.read_csv(new_data_path) # make_sequences(): same feature pipeline as the LSTM model (11 features, window=60) X, y, scaler = make_sequences(df, seq_len=60) model = tf.keras.models.load_model(model_path) # Short fine-tune (5 epochs) avoids catastrophic forgetting model.fit(X, y, epochs=5, batch_size=32, verbose=0) model.save(model_path) # overwrite checkpoint with updated weights
آموزش، پیشبینی و ارزیابی مدل GRU
# ── Training run + Out-of-Sample evaluation ── from sklearn.metrics import classification_report, accuracy_score X, y, scaler = make_sequences(df, seq_len=60) split = int(len(X) * 0.8) # time-ordered split — no shuffling for time series X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] model = build_gru_model(seq_len=60, n_features=11, n_classes=3) model.fit( X_train, y_train, validation_split=0.15, epochs=50, batch_size=32, callbacks=[tf.keras.callbacks.EarlyStopping(patience=8, restore_best_weights=True)], verbose=1 ) model.save("gru_model.h5") # checkpoint used by daily_retrain_job() y_pred = model.predict(X_test).argmax(axis=1) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Down', 'Neutral', 'Up'])) # Latest-candle inference (single sample, what a live EA would call each tick) latest_probs = model.predict(X_test[-1:])[0] signal = ['SELL', 'HOLD', 'BUY'][latest_probs.argmax()] print(f"Latest signal: {signal} (confidence={latest_probs.max():.2%})")
اشتباهات رایج در پیادهسازی GRU
-
●مقایسه نکردن با LSTM: GRU را فقط بهخاطر سرعت بیشتر انتخاب نکنید. روی برخی دادهها LSTM دقت بالاتری دارد؛ همیشه هر دو را روی همان داده و همان Split مقایسه کنید.
-
●نشت داده از Scaler: دقیقاً مثل LSTM، Scaler باید فقط روی داده Train فیت شود، نه کل دیتاست.
-
●Early Stopping حذفشده: بدون patience مناسب در EarlyStopping، مدل روی Validation Loss نوسانی متوقف میشود در نقطه نامناسب یا اصلاً متوقف نمیشود و Overfit میکند.
-
●Retrain نامنظم: برخلاف تصور، سریعتر بودن GRU بهانهای برای Retrain نامنظم نیست؛ همان انضباط زمانبندی LSTM لازم است.
GRU برای کدام کاربردها مناسب است؟
- ●وابستگی بلندمدت ضعیفتر: در رویدادهای با تأثیر چندهفتهای، LSTM بهدلیل ساختار سهGate برتری نظری دارد.
- ●افت دقت ۲-۳٪: در بکتستهای مقایسهای، GRU معمولاً ۲ تا ۳ درصد دقت کمتر از LSTM نشان میدهد.
- ●بازار Sideways: مانند LSTM، در بازارهای رنج بدون روند مشخص دقت GRU نیز کاهش مییابد.
GRU در مقابل LSTM و سایر مدلهای Deep Learning
| ویژگی | GRU | LSTM | Transformer (TFT) |
|---|---|---|---|
| تعداد Gate | 2 | 3 | بدون Gate |
| سرعت آموزش | سریع (+20٪) | متوسط | کند (GPU ضروری) |
| دقت Out-of-Sample | 63–72٪ | 65–75٪ | 68–78٪ |
| مناسب برای | Retrain روزانه | پیشبینی قیمت H1–D1 | پیشبینی چندگامه |
مقالات پایه این مدل
-
Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation Proceedings of EMNLP 2014مشاهده مقاله ↗
-
Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling NeurIPS 2014 Deep Learning Workshopمشاهده مقاله ↗
آمادهاید ربات GRU خود را بسازید؟
تیم ExpertNevees مدل GRU سفارشی را با Adaptive Retraining روزانه میسازد و از طریق ZeroMQ به MT5 متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
MLP — شبکه عصبی پرسپترون چندلایه
MLP (Multi-Layer Perceptron) سادهترین و سریعترین مدل یادگیری عمیق برای طبقهبندی سیگنال معاملاتی است. عملکرد آن کاملاً به کیفیت Feature Engineering ورودی وابسته است، با استنتاج زیر نیم میلیثانیه.
ساختار لایههای MLP — از Feature تا سیگنال
۲۰-۴۰ Feature
۱۲۸ نورون + Dropout
۶۴ نورون + Dropout
Softmax: Buy/Sell/Hold
عملکرد واقعی MLP در طبقهبندی سیگنال
طبقهبندی Buy/Sell/Hold
ورودی
هر پیشبینی
پیشنهادی
مشخصات فنی پیادهسازی ExpertNevees
- RSI(14)، MACD Signal، ATR(14)/Price
- Bollinger %B: موقعیت قیمت در باند
- Candle Body/Shadow Ratio
- Volume Z-Score: نسبت به میانگین ۲۰ کندل
- Session Indicator: Asian/London/NY
- نوع: طبقهبندی Buy/Sell/Hold با Softmax
- سرعت: Inference زیر ۰.۵ میلیثانیه
- استقرار: ONNX یا ZMQ Socket در EA/cBot
انتشار پیشرو و تابع هزینه MLP
# First hidden layer: linear combination of inputs + ReLU non-linearity a1 = ReLU( W1 . x + b1 ) # Output layer: projection into class space z2 = W2 . a1 + b2 # Map output to a probability distribution over classes (Sell/Hold/Buy) y_hat = softmax(z2) = exp(z2_i) / sum_j exp(z2_j) # Cross-Entropy loss used to optimize weights via Backpropagation Loss = - sum_i y_i * log(y_hat_i)
پیادهسازی MLP با TensorFlow/Keras
import numpy as np import tensorflow as tf import onnxruntime as ort import tf2onnx from tensorflow.keras.layers import Dense, Dropout, BatchNormalization, Input from tensorflow.keras import Sequential, Model # ── MLP for tabular signal classification — no sequence dimension needed ── def build_mlp_model(n_features=30, n_classes=3): model = Sequential([ Input(shape=(n_features,)), # Wide first layer: captures non-linear interactions between indicators Dense(128, activation='relu'), BatchNormalization(), Dropout(0.3), # Narrower second layer: feature compression Dense(64, activation='relu'), BatchNormalization(), Dropout(0.3), # Output: Buy=2, Sell=0, Hold=1 (sparse integer labels) Dense(n_classes, activation='softmax') ]) model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'] ) return model # ── Export to ONNX for sub-0.5ms inference inside EA via onnxruntime ── def export_to_onnx(keras_model, output_path="mlp_signal.onnx"): spec = (tf.TensorSpec((None, keras_model.input_shape[-1]), tf.float32, name="features"),) tf2onnx.convert.from_keras(keras_model, input_signature=spec, output_path=output_path) # ── ONNX inference: load once, reuse session for every tick ── def predict_onnx(session, features: np.ndarray) -> str: # features shape: [1, n_features], dtype float32 inp = {session.get_inputs()[0].name: features.astype('float32')} probs = session.run(None, inp)[0][0] # [p_sell, p_hold, p_buy] return ["SELL", "HOLD", "BUY"][probs.argmax()]
آموزش، پیشبینی و ارزیابی مدل MLP
# ── Training run + Out-of-Sample evaluation ── from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report, accuracy_score # Tabular features (no time dimension) — indicators computed per row X = feature_df[feature_columns].values # shape: [n_samples, 30] y = feature_df['label'].values # 0=Sell, 1=Hold, 2=Buy # shuffle=False keeps the test set as the most recent time window X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, shuffle=False ) model = build_mlp_model(n_features=X.shape[1], n_classes=3) model.fit( X_train, y_train, validation_split=0.15, epochs=40, batch_size=64, callbacks=[tf.keras.callbacks.EarlyStopping(patience=6, restore_best_weights=True)], verbose=1 ) y_pred = model.predict(X_test).argmax(axis=1) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Sell', 'Hold', 'Buy'])) # Export + single-sample ONNX inference (production path used in the EA) export_to_onnx(model, "mlp_signal.onnx") session = ort.InferenceSession("mlp_signal.onnx") print("Live signal:", predict_onnx(session, X_test[-1:]))
اشتباهات رایج در پیادهسازی MLP
-
●حذف بعد زمانی: MLP ذاتاً ترتیب زمانی را نمیبیند؛ اگر ویژگیهای Lag (مثل بازده ۱ تا ۱۰ کندل قبل) بهصورت دستی اضافه نشوند، مدل اطلاعات روند اخیر را از دست میدهد.
-
●عدم Scale ویژگیها: شبکههای Fully-Connected به مقیاس متفاوت ویژگیها حساساند (مثلاً RSI بین ۰-۱۰۰ و بازده بین ۰.۰۰۱-). بدون StandardScaler، ویژگیهای بزرگمقیاس بر آموزش مسلط میشوند.
-
●لایههای زیاد نسبت به داده: استفاده از شبکه عمیق با نورون زیاد روی چند هزار نمونه معمولاً Overfitting شدید ایجاد میکند؛ Dropout و L2 Regularization ضروریاند.
-
●دقت طبقهبندی = سود نیست: دقت ۶۵٪ روی سیگنال خرید/فروش بدون احتساب اسپرد، کمیسیون و اسلیپیج نمیتواند نتیجه معاملاتی واقعی را نشان دهد.
MLP برای کدام کاربردها مناسب است؟
- ●بدون درک توالی زمانی: الگوهای متوالی را بدون Feature دستی نمیشناسد. برای داده Sequential از LSTM/GRU استفاده کنید.
- ●وابستگی شدید به Feature Engineering: بدون ورودی باکیفیت، دقت بهسرعت به سطح تصادفی نزدیک میشود.
- ●سقف دقت پایینتر: در مقایسه با مدلهای Sequential، سقف دقت MLP معمولاً ۵-۸٪ پایینتر است.
MLP در مقابل سایر مدلهای طبقهبندی
| ویژگی | MLP | Random Forest | LSTM |
|---|---|---|---|
| سرعت Inference | <0.5ms | ~1ms | ~3-5ms |
| درک توالی زمانی | ندارد | ندارد | قوی |
| تفسیرپذیری | ضعیف | Feature Importance | ضعیف |
| دقت Out-of-Sample | 60–70٪ | 62–70٪ | 65–75٪ |
مقالات پایه این مدل
-
Learning Representations by Back-Propagating Errors Nature, 323, 533–536مشاهده مقاله ↗
آمادهاید ربات MLP خود را بسازید؟
تیم ExpertNevees Feature Engineering قوی طراحی میکند، مدل MLP را آموزش میدهد و از طریق ONNX یا ZeroMQ به EA/cBot شما متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
Random Forest — طبقهبندی روند با رأیگیری جمعی
Random Forest ترکیبی از ۱۰۰ تا ۵۰۰ درخت تصمیم مستقل است که با رأیگیری اکثریت، پایدارترین مدل طبقهبندی روند را ارائه میدهد. مزیت کلیدی: Feature Importance قابل تفسیر.
چگونه Random Forest تصمیم میگیرد؟ — رأیگیری اکثریت
Feature Importance — مزیت منحصربهفرد روی XAUUSD
پس از آموزش روی دادههای XAUUSD، میتوان دید کدام اندیکاتور بیشترین تأثیر در پیشبینی دارد — اطلاعاتی که برای سادهسازی استراتژی بسیار ارزشمند است.
مشخصات فنی پیادهسازی ExpertNevees
- Feature تکنیکال: ATR، RSI، MACD، Volume Z-Score
- n_estimators: ۳۰۰-۵۰۰ درخت
- max_depth: ۸-۱۲ برای جلوگیری از Overfit
- Walk-Forward: پنجرههای ۶ ماهه (۴ Train / ۲ Test)
- نوع: طبقهبندی Up/Down/Neutral
- Feature Importance: رتبهبندی تأثیر هر اندیکاتور
- دقت معمول: ۶۲-۷۰٪ Out-of-Sample
معیار Gini و رأیگیری Ensemble
# Gini impurity — used to pick the best split at each tree node Gini(t) = 1 - sum_c ( p_c )^2 # p_c = fraction of class-c samples in node t # Impurity reduction from a split — the tree picks the split that maximizes this Delta_Gini = Gini(parent) - ( n_L/n * Gini(L) + n_R/n * Gini(R) ) # Each tree trains on a Bootstrap sample with a random feature subset (m ~ sqrt(p)) D_b = Bootstrap(D), features_b = RandomSubset(features, m) # Final prediction: majority vote across B independent trees y_hat = mode( T_1(x), T_2(x), ..., T_B(x) )
پیادهسازی Random Forest با Scikit-learn
import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import TimeSeriesSplit import matplotlib.pyplot as plt # ── Conservative hyperparameters tuned for noisy financial tabular data ── model = RandomForestClassifier( n_estimators=300, # 300 trees: accuracy plateaus beyond ~400 max_depth=10, # shallow depth prevents memorising tick noise min_samples_leaf=20, # at least 20 samples per leaf — key overfitting guard max_features='sqrt', # random feature subsetting ensures tree diversity class_weight='balanced', # compensates for imbalanced Up/Neutral/Down classes n_jobs=-1, # parallel training across all CPU cores random_state=42 ) # ── Purged Walk-Forward Validation — critical: no future leakage in splits ── tscv = TimeSeriesSplit(n_splits=5, gap=5) # gap=5 avoids look-ahead bias oos_scores = [] for fold, (train_idx, test_idx) in enumerate(tscv.split(X), 1): model.fit(X[train_idx], y[train_idx]) score = model.score(X[test_idx], y[test_idx]) oos_scores.append(score) print(f"Fold {fold} OOS Accuracy: {score:.2%}") print(f"Mean OOS Accuracy: {np.mean(oos_scores):.2%} ± {np.std(oos_scores):.2%}") # ── Feature Importance — reveals which indicators drive prediction ── importances = sorted( zip(feature_names, model.feature_importances_), key=lambda x: x[1], reverse=True ) for name, score in importances[:10]: print(f" {name:<20} {score:.4f}")
ارزیابی نهایی و پیشبینی با Random Forest
# ── Final model fit + holdout evaluation + single-sample prediction ── from sklearn.metrics import classification_report, accuracy_score # Fit on the full Walk-Forward training window, then evaluate on the final holdout train_idx, test_idx = list(tscv.split(X))[-1] # most recent fold = closest to live data model.fit(X[train_idx], y[train_idx]) y_pred = model.predict(X[test_idx]) print(f"Holdout Accuracy: {accuracy_score(y[test_idx], y_pred):.4f}") print(classification_report(y[test_idx], y_pred, target_names=['Down', 'Neutral', 'Up'])) # Prediction with class probabilities for the newest available candle latest_probs = model.predict_proba(X[-1:])[0] signal = ['Down', 'Neutral', 'Up'][latest_probs.argmax()] print(f"Latest signal: {signal} (confidence={latest_probs.max():.2%})")
اشتباهات رایج در پیادهسازی Random Forest
-
●Cross-Validation نادرست: استفاده از KFold معمولی بهجای TimeSeriesSplit باعث میشود داده آینده در فولدهای آموزش قرار گیرد — دقت گزارششده کاذب بالا خواهد بود.
-
●تفسیر نادرست Feature Importance: بین ویژگیهای همبسته (مثل چند اندیکاتور مشابه)، اهمیت بهصورت نامتوازن بین آنها تقسیم میشود و میتواند گمراهکننده باشد.
-
●عمق درخت کنترلنشده: بدون محدود کردن max_depth و min_samples_leaf، هر درخت میتواند نویز داده Training را بهخاطر بسپارد.
-
●نادیده گرفتن هزینه معامله در برچسبگذاری: اگر برچسب Buy/Sell صرفاً بر اساس علامت بازده باشد (بدون آستانه)، مدل روی نوسانات ریز و بیارزش هم سیگنال میدهد.
Random Forest برای کدام کاربردها مناسب است؟
- ●بدون درک توالی زمانی: هر نمونه را مستقل میبیند و وابستگی بین کندلهای متوالی را نمیفهمد.
- ●برونیابی ضعیف: در شرایط بازار کاملاً جدید که در داده Training دیده نشده، عملکرد ضعیف میشود.
- ●سقف دقت: در دادههای مالی پرنویز، بهندرت از ۷۰٪ Out-of-Sample عبور میکند.
Random Forest در مقابل سایر مدلهای Ensemble
| ویژگی | Random Forest | XGBoost | MLP |
|---|---|---|---|
| نحوه آموزش | موازی (سریعتر) | ترتیبی | Backpropagation |
| ریسک Overfitting | کم | متوسط | متوسط |
| تفسیرپذیری | Feature Importance | SHAP Values | ضعیف |
| دقت Out-of-Sample | 62–70٪ | 68–74٪ | 60–70٪ |
مقالات پایه این مدل
-
Random Forests Machine Learning, 45, 5–32مشاهده مقاله ↗
آمادهاید سیستم Random Forest خود را بسازید؟
تیم ExpertNevees مدل Random Forest را با Walk-Forward Validation کامل آموزش میدهد و گزارش Feature Importance ارائه میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
XGBoost — قهرمان طبقهبندی مالی
XGBoost یک الگوریتم Ensemble بر پایه درختهای تصمیم است که هر درخت جدید، خطاهای درخت قبلی را تصحیح میکند. در مسابقات پیشبینی مالی Kaggle، بیشترین جوایز را برده است.
چگونه XGBoost یاد میگیرد؟ — تصحیح ترتیبی خطا
هایپرپارامترهای کلیدی برای داده مالی
توصیهشده
توصیهشده
توصیهشده
توصیهشده
مشخصات فنی پیادهسازی ExpertNevees
- Feature ها: ۴۰ Feature تکنیکال و آماری
- Tuning: GridSearch یا Optuna
- حداقل نمونه: ۱۵۰۰ رکورد آموزشی
- ذخیره مدل: joblib pickle format
- سرویسدهی: FastAPI REST endpoint
- تاخیر: ۲-۸ میلیثانیه از طریق HTTP
تابع هدف منظمشده XGBoost
# Overall objective: prediction loss + model-complexity penalty Obj = sum_i l(y_i, y_hat_i) + sum_k Omega(f_k) # Regularization term — penalizes number of leaves (T) and leaf-weight magnitude (w) Omega(f) = gamma * T + (1/2) * lambda * ||w||^2 # Second-order Taylor approximation of the loss around the current prediction l(y, y_hat + f) ~= l(y, y_hat) + g*f + (1/2)*h*f^2 # g,h = first and second derivatives # Split gain — the criterion used to choose the best split at each boosting step Gain = (1/2) * [ G_L^2/(H_L+lambda) + G_R^2/(H_R+lambda) - (G_L+G_R)^2/(H_L+H_R+lambda) ] - gamma
پیادهسازی XGBoost با Optuna Tuning
import xgboost as xgb import optuna from sklearn.model_selection import TimeSeriesSplit import numpy as np # ── Optuna objective: Walk-Forward CV inside each trial prevents leakage ── def objective(trial): params = { 'max_depth': trial.suggest_int('max_depth', 4, 6), 'learning_rate': trial.suggest_float('learning_rate', 1e-2, 0.1, log=True), 'n_estimators': trial.suggest_int('n_estimators', 500, 2000), 'subsample': trial.suggest_float('subsample', 0.7, 0.9), 'colsample_bytree': trial.suggest_float('colsample_bytree', 0.6, 0.9), 'reg_lambda': trial.suggest_float('reg_lambda', 1, 10), # L2 regularisation 'objective': 'multi:softprob', 'num_class': 3, 'eval_metric': 'mlogloss', 'n_jobs': -1, } # TimeSeriesSplit ensures no look-ahead bias across folds tscv = TimeSeriesSplit(n_splits=4, gap=5) oos_scores = [] for tr, te in tscv.split(X): m = xgb.XGBClassifier(**params) m.fit(X[tr], y[tr], eval_set=[(X[te], y[te])], early_stopping_rounds=30, verbose=False) oos_scores.append(m.score(X[te], y[te])) return np.mean(oos_scores) study = optuna.create_study(direction='maximize') study.optimize(objective, n_trials=100, show_progress_bar=True) # ── Serve best model via FastAPI — EA calls POST /predict per tick ── from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() best_model = xgb.XGBClassifier(**study.best_params) best_model.fit(X, y) class Features(BaseModel): values: list[float] @app.post("/predict") def predict(req: Features): probs = best_model.predict_proba([req.values])[0] return {"signal": ["SELL", "HOLD", "BUY"][probs.argmax()], "confidence": float(probs.max())}
ارزیابی مدل بهینهشده و پیشبینی با XGBoost
# ── Holdout evaluation of the Optuna-tuned model + single-sample prediction ── from sklearn.metrics import classification_report, accuracy_score from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) final_model = xgb.XGBClassifier(**study.best_params) final_model.fit(X_train, y_train) y_pred = final_model.predict(X_test) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Sell', 'Hold', 'Buy'])) # Single-sample probability prediction — same call used inside the /predict endpoint probs = final_model.predict_proba(X_test[-1:])[0] print(f"Latest signal: {['SELL','HOLD','BUY'][probs.argmax()]} (confidence={probs.max():.2%})")
اشتباهات رایج در پیادهسازی XGBoost
-
●نشت داده در محاسبه اندیکاتور: محاسبه اندیکاتورهایی مثل SMA یا RSI با پنجرهای که کندل جاری/آینده را در بر میگیرد (بهجای Shift مناسب)، نشت داده ایجاد میکند.
-
●Overfitting به Validation از طریق Optuna: اجرای صدها Trial روی همان Validation Set باعث میشود پارامترها به آن Set خاص Overfit شوند؛ همیشه یک Test Set نهایی و دستنخورده نگه دارید.
-
●بدون early_stopping_rounds: تعداد ثابت n_estimators بدون Early Stopping باعث Overfitting یا زمان آموزش غیرضروری میشود.
-
●مقایسهنشده با مدل سادهتر: اگر Random Forest ساده به دقتی نزدیک XGBoost میرسد، پیچیدگی و زمان Tuning اضافه توجیه اقتصادی ندارد.
XGBoost برای کدام کاربردها مناسب است؟
- ●نیاز به Tuning دقیقتر: برخلاف Random Forest، XGBoost به تنظیم دقیق Hyperparameter حساستر است.
- ●ریسک Overfitting بالاتر: آموزش ترتیبی بدون Early Stopping میتواند بهسرعت Overfit شود.
- ●بدون درک توالی زمانی: مانند Random Forest، وابستگی بین کندلهای متوالی را بهصورت بومی نمیفهمد.
XGBoost در مقابل Random Forest و LSTM
| ویژگی | XGBoost | Random Forest | LSTM |
|---|---|---|---|
| دقت Out-of-Sample | 68–74٪ | 62–70٪ | 65–75٪ |
| حداقل داده | +1500 نمونه | +2000 نمونه | +5000 کندل |
| نیاز Tuning | بالا | کم | بالا |
| نیاز GPU | خیر | خیر | ترجیحاً بله |
مقالات پایه این مدل
-
XGBoost: A Scalable Tree Boosting System Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD '16)مشاهده مقاله ↗
-
Predicting Chinese Stock Market Using XGBoost Multi-Objective Optimization with Optimal Weighting PeerJ Computer Science, 10, e1931مشاهده مقاله ↗
آمادهاید سیستم XGBoost خود را بسازید؟
تیم ExpertNevees مدل XGBoost را با Optuna Tuning بهینه میکند و از طریق FastAPI یا ZeroMQ به EA/cBot شما متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
Linear Factor — استخراج سیگنال آلفا از بازار
Linear Factor Model روشی برای تبدیل دادههای خام بازار به سیگنالهای پیشبینیکننده بازده با Ridge/Lasso Regression است (Alpha Factor Engineering) — مهمترین گام در Pipeline هر استراتژی ML معاملاتی.
دستهبندی فاکتورهای آلفا در ترید الگوریتمی
Return-3M
RSI-Momentum
EV/EBITDA
Dividend Yield
Debt/Equity
Earnings Growth
Realized Vol
Beta
Analyst Revisions
ارزیابی فاکتور با Alphalens
مشخصات فنی پیادهسازی ExpertNevees
- داده بازار: OHLCV، حجم، Order Book
- داده جایگزین: Sentiment، تصاویر ماهوارهای، XBRL
- ترکیب: وزندهی خطی یا ML-based (XGBoost/RF)
- Factor Score: نمره ترکیبی نهایی هر دارایی
- رتبهبندی: داراییها بر اساس Alpha Score
- ادغام: ورودی برای مدلهای طبقهبندی یا HRP
مدل رگرسیون خطی چندعاملی
# Fama-French style factor model: excess return as a linear combination of risk factors r_i - r_f = alpha_i + beta_1*MKT + beta_2*SMB + beta_3*HML + epsilon_i # Ridge coefficient estimate with an L2 penalty to control multicollinearity between factors beta_hat = argmin_beta ||y - X*beta||^2 + lambda * ||beta||^2 # Information Coefficient — rank correlation between predicted and actual returns IC = corr( rank(y_hat), rank(y) )
پیادهسازی Alpha Factor با Alphalens
import pandas as pd import numpy as np from sklearn.linear_model import Ridge from sklearn.preprocessing import RobustScaler import alphalens as al # ── Build composite alpha factor from three orthogonal signal families ── def build_factor_score(df: pd.DataFrame) -> pd.DataFrame: # Momentum: 20-day price return — buy recent winners df['momentum'] = df['close'].pct_change(20) # Volatility: normalised ATR — penalise high-noise assets df['volatility'] = df['atr_14'] / df['close'] # Value: inverse P/E → lower P/E is more attractive df['value'] = -df['pe_ratio'] # Cross-sectionally scale each factor (RobustScaler handles outliers) scaler = RobustScaler() factors = scaler.fit_transform(df[['momentum', 'volatility', 'value']]) # Ridge regression learns optimal factor weights from realised forward returns model = Ridge(alpha=1.0) model.fit(factors, df['forward_return']) df['factor_score'] = model.predict(factors) return df # ── Evaluate with Alphalens — IC > 0.05 signals a statistically useful factor ── factor_data = al.utils.get_clean_factor_and_forward_returns( factor=df['factor_score'], prices=price_data, periods=(1, 5, 10) # 1-day, 5-day, 10-day forward return horizons ) ic = al.performance.factor_information_coefficient(factor_data) print(f"Mean IC: {ic.mean():.3f} IR: {(ic.mean()/ic.std()):.2f}")
ارزیابی و پیشبینی رتبهبندی دارایی با Factor Model
# ── Train/test split + regression evaluation + latest cross-sectional prediction ── from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, r2_score X = factors # scaled [momentum, volatility, value] matrix built above y = df['forward_return'].values X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) model = Ridge(alpha=1.0) model.fit(X_train, y_train) y_pred = model.predict(X_test) print(f"Test MSE: {mean_squared_error(y_test, y_pred):.6f}") print(f"Test R^2: {r2_score(y_test, y_pred):.4f}") # Latest cross-section: rank assets by predicted forward return (long top decile) latest_scores = model.predict(X[-len(symbols):]) ranked = sorted(zip(symbols, latest_scores), key=lambda x: x[1], reverse=True) print("Top ranked assets:", ranked[:5])
اشتباهات رایج در پیادهسازی Factor Model
-
●Look-Ahead Bias در داده بنیادی: استفاده از EPS یا صورت مالی با تاریخ گزارش (نه تاریخ واقعی انتشار عمومی) باعث میشود مدل از اطلاعاتی استفاده کند که در آن لحظه در دسترس نبوده.
-
●همخطی بین فاکتورها: فاکتورهای همبسته (مثلاً Momentum کوتاه و بلندمدت) ضرایب Ridge/Regression را ناپایدار میکنند؛ بررسی VIF قبل از مدلسازی ضروری است.
-
●ثابت فرضکردن روابط فاکتور: رابطه بین یک فاکتور و بازده آینده در طول زمان و بین رژیمهای بازار تغییر میکند؛ مدل باید بهصورت Rolling دوباره Fit شود.
-
●IC را با دقت اشتباه گرفتن: Information Coefficient (IC) پایین مثل ۰.۰۳-۰.۰۸ برای مدل فاکتور طبیعی است؛ انتظار دقت طبقهبندی مثل مدلهای یادگیری عمیق از آن نداشته باشید.
Alpha Factor Engineering برای کدام کاربردها مناسب است؟
- ●فاکتورها زوال مییابند: با عمومی شدن یک فاکتور، قدرت پیشبینی آن (Alpha Decay) معمولاً کاهش مییابد.
- ●وابستگی خطی محدود: Linear Factor روابط غیرخطی پیچیده را بهخوبی مدلهای Tree-based نمیگیرد.
- ●Data Snooping: آزمایش بیشازحد فاکتورهای مختلف روی همان داده تاریخی، ریسک الگوهای کاذب را افزایش میدهد.
Linear Factor در مقابل روشهای ترکیب پیشرفتهتر
| ویژگی | Linear Factor | XGBoost | Autoencoder |
|---|---|---|---|
| نوع رابطه | خطی | غیرخطی | غیرخطی پنهان |
| تفسیرپذیری | بسیار بالا | متوسط | پایین |
| سرعت محاسبه | بسیار سریع | سریع | متوسط |
مقالات پایه این مدل
-
Common Risk Factors in the Returns on Stocks and Bonds Journal of Financial Economics, 33(1), 3–56مشاهده مقاله ↗
آمادهاید استراتژی Factor-Based خود را بسازید؟
تیم ExpertNevees فاکتورهای آلفا را استخراج، با Alphalens ارزیابی، و بهعنوان ورودی استراتژیهای ML شما آماده میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
Transformer — پیشرفتهترین مدل پیشبینی مالی
Temporal Fusion Transformer (TFT) توسط Google DeepMind توسعه یافته و ترکیبی از Attention Mechanism، LSTM و Variable Selection Network است. تمام نقاط زمانی را موازی میبیند و با Self-Attention مهمترین لحظات را تشخیص میدهد.
چرا Transformer از LSTM پیشرفتهتر است؟
هر ستون یک کندل است؛ شدت رنگ وزن Self-Attention را نشان میدهد — Transformer همزمان به نشست FOMC سه هفته پیش و کندل امروز توجه میکند.
هزینه واقعی اجرای Transformer
GPU موردنیاز
برای آموزش مناسب
روی GPU
چندگامه (کندل)
مشخصات فنی پیادهسازی ExpertNevees
- قیمت + حجم: OHLCV چندتایمفریمی
- اخبار اقتصادی: تقویم اقتصادی + Sentiment Score
- متغیرهای استاتیک: نماد، Sector، نوع دارایی
- پیشبینی چندگامه: ۵، ۱۰ یا ۲۰ کندل آینده
- تشخیص رژیم بازار: Trending/Ranging/High Vol
- بازه اطمینان: Quantile Forecasts (P10/P50/P90)
فرمول Self-Attention و Multi-Head
# Scaled Dot-Product Attention Attention(Q, K, V) = softmax( Q * K^T / sqrt(d_k) ) * V # Combine multiple parallel attention heads to learn different relationships at once MultiHead(Q,K,V) = Concat(head_1, ..., head_h) * W_O , head_i = Attention(Q*W_i^Q, K*W_i^K, V*W_i^V) # Pinball (Quantile) loss for probabilistic P10/P50/P90 forecasting L_q(y, y_hat) = max( q*(y - y_hat), (q-1)*(y - y_hat) )
پیادهسازی TFT با PyTorch Forecasting
import pytorch_lightning as pl from pytorch_forecasting import TemporalFusionTransformer, TimeSeriesDataSet from pytorch_forecasting.metrics import QuantileLoss # ── Multi-source TimeSeriesDataSet ── # known_reals: features available at prediction time (e.g. calendar, macro) # unknown_reals: features only observed up to the encoder window training = TimeSeriesDataSet( df, time_idx="time_idx", target="close", group_ids=["symbol"], # one group per trading instrument max_encoder_length=60, # 60-candle lookback window max_prediction_length=10, # forecast 10 steps ahead simultaneously time_varying_known_reals=[ # available during the decoder phase "rsi", "atr", "sentiment_score", "hour_of_day", "day_of_week" # session / seasonality signals ], time_varying_unknown_reals=[ # observed only in the encoder "close", "volume", "spread" ], static_categoricals=["asset_class"], # FX, Crypto, Equity — handled by VSN target_normalizer="softplus", # ensures non-negative price targets ) # ── Build TFT with Quantile Loss for probabilistic forecasting ── # quantiles=[0.1, 0.5, 0.9] → P10/P50/P90 confidence bands per candle tft = TemporalFusionTransformer.from_dataset( training, hidden_size=64, attention_head_size=4, # Multi-Head Self-Attention heads dropout=0.2, hidden_continuous_size=16, loss=QuantileLoss(quantiles=[0.1, 0.5, 0.9]), log_interval=10, learning_rate=3e-3, ) # ── Train with early stopping to prevent overfitting ── trainer = pl.Trainer(max_epochs=30, gradient_clip_val=0.1, accelerator="gpu", devices=1) trainer.fit(tft, train_dataloaders=train_loader, val_dataloaders=val_loader) # ── Probabilistic prediction: returns P10/P50/P90 bands for 10 candles ── raw_predictions = tft.predict(val_loader, mode="raw", return_x=True) p10, p50, p90 = raw_predictions.output.prediction.unbind(dim=-1)
ارزیابی دقت پیشبینی و اجرای Transformer
# ── Evaluate probabilistic forecasts + single-series prediction ── from pytorch_forecasting.metrics import QuantileLoss # Quantile loss on the validation set — lower is better; compares P10/P50/P90 to actuals val_loss = trainer.validate(tft, dataloaders=val_loader)[0] print(f"Validation Quantile Loss: {val_loss['val_loss']:.4f}") # Point forecast accuracy using the P50 (median) quantile as the prediction actuals = torch.cat([y[0] for x, y in iter(val_loader)]) mae = (p50 - actuals).abs().mean() print(f"MAE (P50 vs actual close): {mae:.5f}") # Forecast the next 10 candles for a single symbol from the latest known window new_prediction = tft.predict(new_raw_data, mode="quantiles", trainer_kwargs=dict(accelerator="cpu")) p10, p50, p90 = new_prediction[0].unbind(dim=-1) print(f"Next-candle forecast: P10={p10[0]:.5f} P50={p50[0]:.5f} P90={p90[0]:.5f}")
اشتباهات رایج در پیادهسازی Transformer
-
●داده ناکافی: Transformer به دلیل تعداد پارامتر بالا، با کمتر از چند هزار دنباله زمانی بهشدت Overfit میشود؛ برای داده کم از LSTM یا GRU استفاده کنید.
-
●ادغام نادرست Covariateهای ثابت و متغیر: اگر ویژگی ثابت (مثل نماد) بهاشتباه بهعنوان Time-Varying تعریف شود، مدل الگوی غلط یاد میگیرد.
-
●وزن Attention را علّی تفسیر کردن: وزنهای Attention بالا لزوماً به معنای رابطه علّی نیست؛ فقط نشان میدهد مدل کجا تمرکز کرده، نه چرا.
-
●عدم بررسی Calibration کوانتایل: اگر بازه P10-P90 واقعاً حدود ۸۰٪ مقادیر واقعی را پوشش ندهد، مدل به بازههای عدم قطعیت خود Calibrate نیست.
Transformer برای کدام کاربردها مناسب است؟
- ●بدون GPU عملی نیست: استنتاج و آموزش روی CPU برای پروژههای واقعی غیرعملی است.
- ●بیشترین ریسک Overfitting: قویترین مدل، اما بدون Cross-Validation دقیق، نتایج In-Sample کاملاً فریبندهاند.
- ●نیاز داده بالا: با کمتر از ۱۰,۰۰۰ کندل، مدل بهسختی الگوهای معنادار یاد میگیرد.
Transformer در مقابل سایر مدلهای Deep Learning
| ویژگی | Transformer | LSTM | Attention |
|---|---|---|---|
| پردازش زمانی | موازی | ترتیبی | بسته به ترکیب |
| نیاز سختافزاری | GPU 8GB+ ضروری | GPU اختیاری | بسته به مدل پایه |
| پیشبینی چندگامه | بومی | نیاز پیکربندی | نیاز پیکربندی |
| داده موردنیاز | +10000 کندل | +5000 کندل | +5000 کندل |
مقالات پایه این مدل
-
Attention Is All You Need Advances in Neural Information Processing Systems 30 (NeurIPS 2017)مشاهده مقاله ↗
-
Temporal Fusion Transformers for Interpretable Multi-horizon Time Series Forecasting International Journal of Forecasting, 37(4), 1748–1764مشاهده مقاله ↗
آمادهاید ربات Transformer خود را بسازید؟
تیم ExpertNevees مدل TFT را با Cross-Validation دقیق و داده چندمنبعه پیادهسازی میکند و از طریق ZeroMQ به MT5 متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
Attention — مکانیزم توجه در معاملات الگوریتمی
Attention Mechanism به مدل اجازه میدهد بهجای وزندهی یکنواخت به همه گامهای زمانی، دقیقاً روی مهمترین کندلها متمرکز شود — درست مثل معاملهگری که به کندلهای کلیدی توجه ویژه دارد. در یک مطالعه منتشرشده (Zhang et al., 2019) روی سه شاخص Russell 2000، DJIA و Nasdaq، افزودن Attention به LSTM خطای پیشبینی (MAPE) را حدود ۲۲ تا ۳۴٪ نسبت به LSTM ساده کاهش داد. Attention Weight Heatmap هم به شما نشان میدهد مدل چرا و به کجا توجه کرده است.
انواع Attention در معاملات الگوریتمی
Attention Weight Visualization — مثال CPI
زمانی که نرخ CPI اعلام میشود، Cross-Attention وزن بالایی به آن گام زمانی میدهد — ابزار ارزشمند برای اطمینان از یادگیری معنادار.
مشخصات فنی پیادهسازی ExpertNevees
- خروجی LSTM/GRU: Hidden States هر گام زمانی
- منبع دوم (Cross): Sentiment یا تقویم اقتصادی
- تعداد Head: ۴-۸ Head موازی
- Context Vector: ترکیب وزندار Hidden States
- Attention Weights: قابل تصویرسازی Heat Map
- سیگنال نهایی: از Context Vector به Softmax
فرمول Attention روی خروجی LSTM
# Raw attention score for each time step relative to the context vector e_t = v^T * tanh( W_h * h_t + b ) # Normalize scores into a probability distribution over all time steps (60 candles) alpha_t = exp(e_t) / sum_j exp(e_j) # Final context vector: weighted average of all hidden states based on importance context = sum_t alpha_t * h_t
پیادهسازی Temporal Attention روی LSTM
import tensorflow as tf from tensorflow.keras.layers import LSTM, Dense, Dropout, Layer, Input from tensorflow.keras import Model # ── Custom Temporal Attention layer — additive (Bahdanau-style) ── # Computes a scalar alignment score for each time step, then softmax-normalises class TemporalAttention(Layer): def __init__(self, units=64, **kwargs): super().__init__(**kwargs) self.W = Dense(units) # projects LSTM hidden states self.V = Dense(1) # collapses to a single scalar score def call(self, lstm_outputs, return_weights=False): # lstm_outputs shape: [batch, T, units] scores = self.V(tf.nn.tanh(self.W(lstm_outputs))) # [batch, T, 1] weights = tf.nn.softmax(scores, axis=1) # attention distribution over time # Weighted sum: high-weight time steps contribute more to prediction context = tf.reduce_sum(weights * lstm_outputs, axis=1) # [batch, units] if return_weights: return context, weights # weights → Attention Heatmap visualisation return context # ── Build LSTM + Temporal Attention model using Functional API ── inp = Input(shape=(60, 11)) # [Batch, 60 candles, 11 features] x = LSTM(128, return_sequences=True)(inp) # full sequence → all hidden states h_1 … h_60 x = Dropout(0.25)(x) context = TemporalAttention(64)(x) # squeeze sequence → context vector x = Dropout(0.2)(context) x = Dense(32, activation='relu')(x) out = Dense(3, activation='softmax')(x) # Up / Neutral / Down model = Model(inp, out) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
آموزش، ارزیابی و تحلیل وزنهای Attention
# ── Training run + evaluation + attention-weight inspection ── from sklearn.metrics import classification_report, accuracy_score X, y, scaler = make_sequences(df, seq_len=60) split = int(len(X) * 0.8) X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] model.fit( X_train, y_train, validation_split=0.15, epochs=50, batch_size=32, callbacks=[tf.keras.callbacks.EarlyStopping(patience=8, restore_best_weights=True)], verbose=1 ) y_pred = model.predict(X_test).argmax(axis=1) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Down', 'Neutral', 'Up'])) # Extract per-candle attention weights for the latest window — powers the Heatmap UI attention_layer = TemporalAttention(64) context, weights = attention_layer(model.layers[1](X_test[-1:]), return_weights=True) top_candles = weights[0, :, 0].numpy().argsort()[-5:][::-1] print("Most influential candles (index from window start):", top_candles)
اشتباهات رایج در تفسیر Attention
-
●وزن Attention را مدرک علّی گرفتن: کندلهایی که وزن بالا میگیرند لزوماً علت حرکت قیمت نیستند؛ Heatmap ابزار تفسیر است نه اثبات.
-
●مقایسهنشده با LSTM ساده: افزودن Attention همیشه دقت را بهبود نمیدهد. بدون A/B Test مستقیم در برابر LSTM ساده، پیچیدگی اضافه ممکن است بیفایده باشد.
-
●نتیجهگیری از یک نمونه: الگوی توجه در یک پیشبینی میتواند نویز باشد؛ نتیجهگیری معتبر نیاز به میانگینگیری روی نمونههای زیاد دارد.
-
●تأخیر پیشبینی و ضعف در شرایط حدی: حتی نویسندگان AT-LSTM (Zhang et al., 2019) گزارش کردهاند مدلشان با وجود دقت بالا، Time Lag دارد و در نوسان شدید بازار حساسیت کافی نشان نمیدهد.
Attention برای کدام کاربردها مناسب است؟
- ●پیچیدگی حافظه O(n²): هر گام مستقیماً به هر گام دیگر دسترسی دارد و با توالی طولانی حافظه مصرفی رشد میکند.
- ●بهتنهایی کافی نیست: Attention معمولاً بهعنوان افزونه روی LSTM/GRU یا در دل Transformer استفاده میشود.
- ●تفسیر میتواند گمراهکننده باشد: وزن Attention بالا همیشه به معنای رابطه علّی واقعی نیست.
Attention در مقابل LSTM خام
| ویژگی | LSTM + Attention | LSTM خام | Transformer |
|---|---|---|---|
| وابستگی بلندمدت | بسیار قوی | متوسط | بسیار قوی |
| تفسیرپذیری | عالی (Heatmap) | ضعیف | متوسط |
| دقت Out-of-Sample | 67–76٪ | 65–75٪ | 68–78٪ |
مقالات پایه این مدل
-
Neural Machine Translation by Jointly Learning to Align and Translate International Conference on Learning Representations (ICLR 2015)مشاهده مقاله ↗
-
AT-LSTM: An Attention-based LSTM Model for Financial Time Series Prediction IOP Conference Series: Materials Science and Engineering, 569, 052037مشاهده مقاله ↗
-
Time Series Prediction Based on LSTM-Attention-LSTM Model IEEE Access, 11, 48322–48331مشاهده مقاله ↗
آمادهاید مدل Attention-Enhanced خود را بسازید؟
تیم ExpertNevees لایه Attention را روی LSTM/GRU شما پیادهسازی میکند و گزارش تصویری Heatmap ارائه میدهد.
سایر مدلهای هوش مصنوعی ExpertNevees
CNN — تشخیص الگوهای بصری در چارت
CNN (شبکه عصبی کانولوشنال) نوعی مدل یادگیری عمیق است که با تبدیل دادههای OHLCV به نمایش تصویری، الگوهای پیچیدهای را یاد میگیرد که بهصورت دستی قابل تعریف نیستند — از Head&Shoulders تا بیش از ۵۰ الگوی شمعی.
چگونه OHLCV به تصویر تبدیل میشود؟
هر ستون یک کندل است؛ Body و Shadow با رنگهای مختلف نمایش داده میشوند. بلوکهای ۲۰ کندل به تصویر ۲۰×۵ پیکسل تبدیل میشوند.
بیش از ۵۰ الگوی کندلاستیک و چارت
Double Top/Bottom
Pennant
Doji
قابل تشخیص
مشخصات فنی پیادهسازی ExpertNevees
- تصویر کندلاستیک: بلوک ۲۰ کندل با OHLC + Volume
- برچسبگذاری: توسط الگوریتم تشخیص الگوی کلاسیک یا دستی
- Augmentation: چرخش و نویز جزئی برای تعمیم بهتر
- نوع: طبقهبندی تصویر چندکلاسه
- خروجی: نام الگو + احتمال اطمینان
- کاربرد: تأیید سیگنال EA کلاسیک پرایساکشن
عملیات کانولوشن و ادغام
# 2D convolution operation over the candlestick image with filter K S(i,j) = sum_m sum_n I(i+m, j+n) * K(m,n) # Non-linearity applied after convolution A(i,j) = ReLU( S(i,j) + b ) # Max pooling to reduce dimensionality and add robustness to small shifts P(i,j) = max( A(2i:2i+1, 2j:2j+1) )
پیادهسازی CNN با TensorFlow
import numpy as np from tensorflow.keras.layers import (Conv2D, MaxPooling2D, GlobalAveragePooling2D, Dense, Dropout, BatchNormalization, Input) from tensorflow.keras import Sequential from tensorflow.keras.preprocessing.image import ImageDataGenerator # ── Convert a 20-candle OHLCV window into a 2D candlestick image ── # Output shape: [20, 64, 3] → time steps × price-channels × RGB def ohlcv_to_image(df_slice, img_h=64): n = len(df_slice) img = np.zeros((n, img_h, 3), dtype=np.float32) lo, hi = df_slice['low'].min(), df_slice['high'].max() def norm(v): return int((v - lo) / (hi - lo + 1e-9) * (img_h - 1)) for i, (_, row) in enumerate(df_slice.iterrows()): # Candle body: green for bullish, red for bearish color = [0, 1, 0] if row.close >= row.open else [1, 0, 0] y0, y1 = norm(min(row.open, row.close)), norm(max(row.open, row.close)) img[i, y0:y1+1, :] = color # Wicks: grey channel img[i, norm(row.low):norm(row.high)+1, :] = [0.5, 0.5, 0.5] return img # ── CNN architecture for chart pattern classification (50+ pattern classes) ── model = Sequential([ Input(shape=(20, 64, 3)), # Block 1: low-level edge and line detection Conv2D(32, (3, 3), activation='relu', padding='same'), BatchNormalization(), MaxPooling2D((2, 2)), # Block 2: composite pattern detection (Head&Shoulders, Double Top, etc.) Conv2D(64, (3, 3), activation='relu', padding='same'), BatchNormalization(), MaxPooling2D((2, 2)), Conv2D(128, (3, 3), activation='relu', padding='same'), BatchNormalization(), # Global pooling collapses spatial dims → fixed-length descriptor GlobalAveragePooling2D(), Dense(128, activation='relu'), Dropout(0.4), # 50+ pattern classes — use categorical_crossentropy with one-hot labels Dense(50, activation='softmax') ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
آموزش و ارزیابی طبقهبندی الگو با CNN
# ── Image dataset generation + training + evaluation ── from sklearn.metrics import classification_report, accuracy_score import numpy as np # Build image dataset from labelled 20-candle windows X_img = np.array([ohlcv_to_image(df.iloc[i:i+20]) for i in start_indices]) y_img = np.array(pattern_labels) # integer-encoded, one of 50 pattern classes split = int(len(X_img) * 0.8) X_train, X_test = X_img[:split], X_img[split:] y_train, y_test = y_img[:split], y_img[split:] datagen = ImageDataGenerator(horizontal_flip=False, brightness_range=[0.9, 1.1]) model.fit( datagen.flow(X_train, tf.keras.utils.to_categorical(y_train, 50), batch_size=32), validation_data=(X_test, tf.keras.utils.to_categorical(y_test, 50)), epochs=40, callbacks=[tf.keras.callbacks.EarlyStopping(patience=6, restore_best_weights=True)] ) y_pred = model.predict(X_test).argmax(axis=1) print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred)) # Classify the most recent 20-candle chart image latest_img = ohlcv_to_image(df.tail(20))[np.newaxis, ...] pred_class = model.predict(latest_img).argmax() print(f"Detected pattern class: {pattern_names[pred_class]}")
اشتباهات رایج در پیادهسازی CNN
-
●همپوشانی پنجرههای Train/Test: اگر پنجرههای ۲۰-کندلی مجاور بین Train و Test تقسیم شوند، همپوشانی زیاد باعث نشت داده و دقت کاذب بالا میشود.
-
●عدم توازن کلاسهای الگو: از ۵۰+ کلاس الگو، برخی بسیار نادرترند. بدون Class Weighting یا Oversampling، مدل الگوهای نادر را نادیده میگیرد.
-
●حساسیت به روش تبدیل به تصویر: تغییر تعداد کندل یا روش رنگآمیزی OHLCV-to-Image بهطور قابل توجهی توزیع برچسبها و دقت را تغییر میدهد؛ این انتخاب باید مستند و ثابت بماند.
-
●تشخیص الگو ≠ سیگنال سودده: طبقهبندی درست یک الگوی کلاسیک (مثل Head & Shoulders) تضمین نمیکند که حرکت قیمت بعدی هم مطابق تئوری کلاسیک آن الگو رخ دهد.
CNN برای کدام کاربردها مناسب است؟
- ●نیاز برچسبگذاری دقیق: کیفیت برچسبهای آموزشی تعیینکننده دقت نهایی است.
- ●الگو≠سودآوری: تشخیص صحیح الگوی بصری به معنای سیگنال سودده نیست؛ نیاز به مدیریت ریسک جداگانه دارد.
- ●حساس به مقیاسبندی: نحوه نرمالسازی قیمت به تصویر باید با دقت انجام شود.
CNN در مقابل تشخیص الگوی کلاسیک
| ویژگی | CNN | قواعد دستی کلاسیک |
|---|---|---|
| تعمیم به الگوهای جدید | بالا | ندارد |
| نیاز داده آموزشی | +3000 نمونه | ندارد |
| شفافیت قانون | غیرشفاف | کاملاً شفاف |
مقالات پایه این مدل
-
Gradient-Based Learning Applied to Document Recognition Proceedings of the IEEE, 86(11), 2278–2324مشاهده مقاله ↗
-
Enhancing Market Trend Prediction Using Convolutional Neural Networks on Japanese Candlestick Patterns PeerJ Computer Science, 11, e2719مشاهده مقاله ↗
آمادهاید مدل CNN خود را بسازید؟
تیم ExpertNevees پایپلاین تبدیل OHLCV به تصویر را میسازد، CNN را آموزش میدهد و بهعنوان فیلتر تأیید به EA شما متصل میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
DDQN — Agent معاملاتی یادگیری تقویتی
Double Deep Q-Network رویکردی است که Agent معاملاتی از طریق تعامل مستقیم با محیط بازار، استراتژی بهینه را میآموزد — بدون نیاز به برچسبگذاری دستی.
چرخه یادگیری Agent معاملاتی — State, Action, Reward
Reward بازخورد را به Agent برمیگرداند تا در چرخه بعدی State جدید را بهتر ارزیابی کند.
مشکل Overestimation در DQN استاندارد
Online + Target
Overestimation Bias
برای آموزش پایدار
برای آموزش سریعتر
معادله بلمن و بروزرسانی Double Q
# Standard DQN target — suffers from optimistic overestimation bias in value estimates y_DQN = r + gamma * max_a Q(s', a; theta_target) # Double DQN target — action selected by the online network, evaluated by the target network (reduces bias) y_DDQN = r + gamma * Q( s', argmax_a Q(s', a; theta_online); theta_target ) # Loss function — mean squared Temporal Difference (TD) error L(theta) = E[ ( y_DDQN - Q(s, a; theta_online) )^2 ]
پیادهسازی DDQN با OpenAI Gym
import gym import numpy as np import tensorflow as tf from collections import deque import random # ── Custom Gym environment — simulates order execution on historical OHLCV ── class TradingEnv(gym.Env): def __init__(self, df, window=60): super().__init__() self.df = df self.window = window self.action_space = gym.spaces.Discrete(3) # 0=Sell, 1=Hold, 2=Buy # State: last `window` candles × n_features self.observation_space = gym.spaces.Box( low=-np.inf, high=np.inf, shape=(window, df.shape[1]), dtype=np.float32) def step(self, action): prev_sharpe = self._calc_sharpe() self._execute_order(action) self.current_step += 1 # Reward: incremental Sharpe Ratio — penalises both loss and excess risk reward = self._calc_sharpe() - prev_sharpe done = self.current_step >= len(self.df) - 1 return self._get_obs(), reward, done, {} # ── Experience Replay Buffer (capacity: 50 k transitions) ── memory = deque(maxlen=50_000) # ── DDQN training step: decouples action selection from value estimation ── def train_step(online_net, target_net, gamma=0.99, batch_size=64): if len(memory) < batch_size: return batch = random.sample(memory, batch_size) states, actions, rewards, next_states, dones = map(np.array, zip(*batch)) # Double DQN: online net picks the best next action, target net evaluates it best_actions = online_net(next_states).numpy().argmax(axis=1) next_q = target_net(next_states).numpy() targets = rewards + gamma * next_q[np.arange(batch_size), best_actions] * (~dones) # Bellman update — only update Q-values for taken actions with tf.GradientTape() as tape: q_pred = online_net(states) q_taken = tf.reduce_sum(q_pred * tf.one_hot(actions, 3), axis=1) loss = tf.reduce_mean(tf.square(targets - q_taken)) # MSE (Huber also works) online_net.optimizer.minimize(loss, online_net.trainable_weights, tape=tape) # ── Sync target network every 500 steps to stabilise training ── if step % 500 == 0: target_net.set_weights(online_net.get_weights())
آموزش کامل Agent و ارزیابی سیاست یادگرفتهشده
# ── Full training loop over episodes + trained-policy inference ── online_net = build_q_network(input_shape=(60, n_features), n_actions=3) target_net = build_q_network(input_shape=(60, n_features), n_actions=3) target_net.set_weights(online_net.get_weights()) env = TradingEnv(train_df, window=60) epsilon, epsilon_min, epsilon_decay = 1.0, 0.05, 0.995 for episode in range(500): state, done, ep_reward = env.reset(), False, 0 while not done: # Epsilon-greedy exploration — decays toward pure exploitation over training if np.random.rand() < epsilon: action = env.action_space.sample() else: action = int(online_net(state[np.newaxis]).numpy().argmax()) next_state, reward, done, _ = env.step(action) memory.append((state, action, reward, next_state, done)) train_step(online_net, target_net) state, ep_reward = next_state, ep_reward + reward epsilon = max(epsilon_min, epsilon * epsilon_decay) if episode % 500 == 0: target_net.set_weights(online_net.get_weights()) if episode % 50 == 0: print(f"Episode {episode} reward={ep_reward:.3f} epsilon={epsilon:.3f}") # ── Evaluate the trained policy on unseen data (epsilon=0 → fully greedy) ── test_env = TradingEnv(test_df, window=60) state, done, total_reward = test_env.reset(), False, 0 while not done: action = int(online_net(state[np.newaxis]).numpy().argmax()) state, reward, done, _ = test_env.step(action) total_reward += reward print(f"Out-of-sample cumulative reward (Sharpe-based): {total_reward:.3f}")
اشتباهات رایج در پیادهسازی DDQN
-
●طراحی نادرست تابع پاداش: بزرگترین علت شکست DDQN در عمل، باگ در Reward Shaping است نه انتخاب الگوریتم. یک راهحل واقعی، یادگیری خودِ تابع پاداش از روی نمایشهای انسانی است — رویکرد Zhou et al. (2024) در مدل R-DDQN.
-
●عدم تطابق شبیهسازی با بروکر واقعی: اگر اسپرد، کمیسیون و اسلیپیج محیط شبیهسازی با شرایط واقعی بروکر یکی نباشد، سیاست آموزشدیده در حساب واقعی نتیجه متفاوتی میدهد.
-
●Overfitting به یک رژیم بازار: آموزش فقط روی یک بازه تاریخی (مثلاً فقط بازار صعودی ۲۰۲۰-۲۰۲۱) باعث میشود Agent در رژیمهای دیگر ضعیف عمل کند.
-
●عدم Retrain دورهای: بازار غیر ایستاست؛ سیاستی که سال گذشته خوب بود، بدون Retrain دورهای ممکن است دیگر بهینه نباشد.
DDQN برای کدام کاربردها مناسب است؟
- ●نیاز داده بسیار بالا: رویکرد RL نیاز به حداقل ۵۰,۰۰۰ گام محیطی دارد.
- ●حساس به تغییر رژیم بازار: ترکیب RL با Market Regime Detection برای بازارهای پرنوسان ضروری است.
- ●دشواری Reward Engineering: طراحی نادرست Reward Function میتواند Agent را به رفتارهای خطرناک سوق دهد.
DDQN در مقابل مدلهای Supervised
| ویژگی | DDQN (RL) | LSTM (Supervised) |
|---|---|---|
| نیاز برچسبگذاری | خیر | بله |
| هدف بهینهسازی | Sharpe Ratio مستقیم | دقت طبقهبندی |
| نیاز داده | +50,000 گام | +5,000 کندل |
| پیچیدگی آموزش | بسیار بالا | متوسط |
مقالات پایه این مدل
-
Human-Level Control through Deep Reinforcement Learning Nature, 518, 529–533مشاهده مقاله ↗
-
Deep Reinforcement Learning with Double Q-Learning Proceedings of the 30th AAAI Conference on Artificial Intelligenceمشاهده مقاله ↗
-
R-DDQN: Optimizing Algorithmic Trading Strategies Using a Reward Network in a Double DQN Mathematics, 12(11), 1621مشاهده مقاله ↗
آمادهاید Agent معاملاتی خود را بسازید؟
تیم ExpertNevees محیط Gym سفارشی، Reward Function مبتنی بر Sharpe Ratio و Agent DDQN را طراحی و آموزش میدهد.
سایر مدلهای هوش مصنوعی ExpertNevees
TimeGAN — دادههای سینتتیک سری زمانی مالی
TimeGAN یک شبکه مولد تخاصمی (GAN) است که دادههای مالی سری زمانی واقعگرایانه تولید میکند — برای مواردی که داده تاریخی کافی وجود ندارد، شبیهسازی سناریوهای بحرانی، و Data Augmentation برای رویدادهای نادر.
چهار جزء اصلی معماری TimeGAN
ارزیابی کیفیت داده سینتتیک
PCA / t-SNE
دقت طبقهبند
TSTR
Mode Collapse
مشخصات فنی پیادهسازی ExpertNevees
- سری زمانی واقعی: OHLCV تاریخی محدود
- طول توالی: پنجرههای ثابت (مثلاً ۶۰ کندل)
- سری زمانی سینتتیک: با ویژگیهای آماری مشابه واقعی
- کاربرد: افزایش دیتاست آموزشی برای LSTM/CNN/XGBoost
سه تابع هزینه TimeGAN
# Reconstruction loss — the autoencoder must be able to reconstruct the original data from latent space L_R = E[ || X - Decoder(Encoder(X)) ||^2 ] # Supervised loss — the next-step prediction in latent space must match the real data dynamics L_S = E[ || h_t - g(h_(t-1), z_t) ||^2 ] # Adversarial loss — the discriminator must tell real from synthetic, the generator must fool it L_U = E[ log D(H) ] + E[ log(1 - D(H_hat)) ]
پیادهسازی TimeGAN با TensorFlow
import numpy as np from ydata_synthetic.synthesizers.timeseries import TimeGAN # ── TimeGAN hyperparameters — tune noise_dim and hidden_dim for your dataset ── gan_args = { 'batch_size': 128, 'lr': 5e-4, # lower LR stabilises adversarial training 'noise_dim': 32, # latent space dimension for the generator 'seq_len': 60, # must match encoder window of downstream model 'n_features': 5, # OHLCV — extend to 11 to include indicators } # gamma: weight of supervised (reconstruction) loss vs adversarial loss synth = TimeGAN(model_parameters=gan_args, hidden_dim=24, seq_len=60, n_seq=5, gamma=1) # Increase train_steps to 20 k–50 k if mode collapse appears synth.train(real_data, train_steps=10_000) # ── Sample synthetic sequences for downstream data augmentation ── synthetic_data = synth.sample(n_samples=1_000) # shape: [1000, 60, 5] # ── TSTR evaluation: Train on Synthetic, Test on Real ── # A high TSTR accuracy proves the synthetic data captures real market dynamics model_synth = train_lstm(synthetic_data) tstr_acc, _ = model_synth.evaluate(real_test_X, real_test_y, verbose=0) print(f"TSTR Accuracy (synthetic→real): {tstr_acc:.2%}")
ارزیابی کیفیت داده مصنوعی TimeGAN
# ── Discriminative Score — the standard quality metric for synthetic time series ── # Train a classifier to distinguish real vs synthetic sequences. # Score near 0.5 = indistinguishable (ideal); near 1.0 = poor-quality synthetic data. from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score real_flat = real_data.reshape(len(real_data), -1) synth_flat = synthetic_data.reshape(len(synthetic_data), -1) X_disc = np.vstack([real_flat, synth_flat]) y_disc = np.concatenate([np.ones(len(real_flat)), np.zeros(len(synth_flat))]) X_train, X_test, y_train, y_test = train_test_split(X_disc, y_disc, test_size=0.3, random_state=42) clf = LogisticRegression(max_iter=1000) clf.fit(X_train, y_train) disc_score = accuracy_score(y_test, clf.predict(X_test)) print(f"Discriminative Score: {disc_score:.3f} (0.5 = ideal, indistinguishable from real)") # ── TSTR classification example — train an LSTM purely on synthetic sequences ── X_synth, y_synth = label_sequences(synthetic_data) # forward-return based labels model_synth = build_lstm_model(seq_len=60, n_features=5, n_classes=3) model_synth.fit(X_synth, y_synth, epochs=30, batch_size=32, verbose=0) tstr_acc = model_synth.evaluate(real_test_X, real_test_y, verbose=0)[1] print(f"TSTR Accuracy (trained on synthetic, tested on real): {tstr_acc:.2%}")
اشتباهات رایج در پیادهسازی TimeGAN
-
●Mode Collapse نادیدهگرفتهشده: اگر تولیدکننده فقط چند الگوی محدود تولید کند (تنوع کم)، Discriminative Score پایین بهتنهایی این مشکل را نشان نمیدهد؛ تنوع نمونهها هم باید بررسی شود.
-
●داده واقعی کم: آموزش GAN با کمتر از حدود ۲۰۰۰ دنباله واقعی معمولاً ناپایدار است و کیفیت داده مصنوعی افت میکند.
-
●جایگزین اصلاح مدل نیست: افزودن داده مصنوعی به یک استراتژی که ذاتاً Overfit است، مشکل زیربنایی را حل نمیکند؛ فقط داده بیشتر برای همان اشتباه فراهم میکند.
-
●فقط TSTR کافی نیست: علاوه بر TSTR (Train on Synthetic, Test on Real)، بررسی TRTS (Train on Real, Test on Synthetic) هم لازم است تا کیفیت دوطرفه داده مصنوعی سنجیده شود.
TimeGAN برای کدام کاربردها مناسب است؟
- ●حساسیت بالا به Hyperparameter: آموزش ناپایدار و Mode Collapse از چالشهای اصلی هستند.
- ●داده مصنوعی واقعی نیست: هرگز نباید جایگزین کامل داده واقعی برای ارزیابی نهایی شود.
- ●نیاز سختافزاری بالا: آموزش پایدار GAN معمولاً به GPU با حداقل ۸GB VRAM نیاز دارد.
TimeGAN در مقابل سایر مدلهای Generative/Unsupervised
| ویژگی | TimeGAN | Autoencoder (VAE) |
|---|---|---|
| هدف اصلی | تولید داده جدید | کاهش بعد / فاکتور پنهان |
| ثبات آموزش | پایینتر | بالاتر |
| کاربرد اصلی | Data Augmentation | Regime Detection |
مقالات پایه این مدل
-
Time-series Generative Adversarial Networks Advances in Neural Information Processing Systems 32 (NeurIPS 2019)مشاهده مقاله ↗
آمادهاید از داده سینتتیک استفاده کنید؟
تیم ExpertNevees مدل TimeGAN را روی داده تاریخی شما آموزش میدهد و کیفیت آن را ارزیابی میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
Autoencoder — استخراج فاکتور ریسک پنهان
Autoencoder یک شبکه عصبی Encoder-Decoder است که نمایش فشردهای از داده ورودی میسازد — در معاملات الگوریتمی برای کاهش بعد، شناسایی رژیم بازار و استخراج فاکتورهای ریسک پنهان به کار میرود.
چگونه Autoencoder داده را فشرده میکند؟
۴۰ Feature
فشردهسازی
فاکتور پنهان
بازسازی
۴۰ Feature
شناسایی رژیم بازار با Clustering
رژیم روند
رژیم رنج
رژیم پرنوسان
برای Clustering
هزینه بازسازی Autoencoder
# Compress the input into a lower-dimensional latent space (bottleneck) z = Encoder(x) , dim(z) << dim(x) # Reconstruct the input from the compressed representation x_hat = Decoder(z) # Reconstruction error — the main criterion used for anomaly scoring L = || x - x_hat ||^2 = || x - Decoder(Encoder(x)) ||^2
پیادهسازی Autoencoder برای تشخیص رژیم
import tensorflow as tf from tensorflow.keras.layers import Dense, Input, Dropout from tensorflow.keras.models import Model from sklearn.cluster import KMeans # ── Bottleneck Autoencoder for non-linear factor extraction ── # Encoder compresses 40 market features into a 2D latent embedding inp = Input(shape=(40,)) x = Dense(32, activation='relu')(inp) x = Dropout(0.1)(x) x = Dense(16, activation='relu')(x) # 2D latent space → directly visualisable as a scatter plot latent = Dense(2, activation='linear', name='latent')(x) # Decoder reconstructs the original feature vector from the latent code x = Dense(16, activation='relu')(latent) x = Dense(32, activation='relu')(x) output = Dense(40, activation='linear')(x) # MSE loss → minimise reconstruction error autoencoder = Model(inp, output) encoder = Model(inp, latent) # inference-time encoder only autoencoder.compile(optimizer='adam', loss='mse') autoencoder.fit(X_train, X_train, epochs=100, batch_size=64, verbose=0) # ── Cluster latent codes into market regimes via K-Means ── latent_features = encoder.predict(X_train, verbose=0) kmeans = KMeans(n_clusters=3, random_state=42, n_init=10) regimes = kmeans.fit_predict(latent_features) # cluster labels: 0=Trending, 1=Ranging, 2=High Volatility
ارزیابی خطای بازسازی و تشخیص رژیم/ناهنجاری
# ── Reconstruction-error evaluation + anomaly / new-regime prediction ── import numpy as np recon = autoencoder.predict(X_test, verbose=0) recon_error = np.mean(np.square(X_test - recon), axis=1) print(f"Mean reconstruction error (test set): {recon_error.mean():.5f}") # Anomaly threshold: 95th percentile of training reconstruction error train_recon = autoencoder.predict(X_train, verbose=0) train_error = np.mean(np.square(X_train - train_recon), axis=1) threshold = np.percentile(train_error, 95) # Predict on the newest market sample latest = X_test[-1:] latest_error = np.mean(np.square(latest - autoencoder.predict(latest, verbose=0))) is_anomaly = latest_error > threshold latest_regime = kmeans.predict(encoder.predict(latest, verbose=0))[0] print(f"Latest sample: regime={['Trending','Ranging','High Volatility'][latest_regime]}, " f"anomaly={is_anomaly} (error={latest_error:.5f}, threshold={threshold:.5f})")
اشتباهات رایج در پیادهسازی Autoencoder
-
●بعد Bottleneck خیلی بزرگ: اگر لایه فشردهسازی بهاندازه کافی کوچک نباشد، شبکه صرفاً ورودی را حفظ میکند بدون یادگیری نمایش معنادار.
-
●آستانه ناهنجاری ثابت: انتخاب یک درصدک ثابت (مثلاً ۹۵٪) برای آستانه Anomaly در طول زمان و بین رژیمهای نوسان مختلف پایدار نیست؛ باید بهصورت دورهای بازتنظیم شود.
-
●عدم Scale ورودی: بدون استانداردسازی ویژگیها، مقادیر بزرگمقیاس بر Loss بازسازی مسلط میشوند و فشردهسازی معنادار روی ویژگیهای کوچکمقیاس رخ نمیدهد.
-
●خطای بازسازی بهتنهایی جهت نمیدهد: خطای بازسازی بالا فقط «غیرعادی بودن» را نشان میدهد، نه جهت حرکت قیمت؛ باید با یک قانون معاملاتی مجزا ترکیب شود.
Autoencoder برای کدام کاربردها مناسب است؟
- ●تفسیرپذیری پایین: فاکتورهای استخراجشده در Latent Space معنای انسانی واضحی ندارند.
- ●انتخاب ابعاد Latent: تعداد ابعاد فضای پنهان باید با دقت انتخاب شود.
- ●بهتنهایی سیگنال معاملاتی نیست: خروجی آن Feature است، نیاز به مدل طبقهبندی بعدی دارد.
Autoencoder در مقابل PCA سنتی
| ویژگی | Deep Autoencoder | PCA سنتی |
|---|---|---|
| نوع کاهش بعد | غیرخطی | خطی |
| سرعت محاسبه | کندتر | بسیار سریع |
| کیفیت بازسازی | بالاتر برای داده پیچیده | محدود به روابط خطی |
مقالات پایه این مدل
-
Reducing the Dimensionality of Data with Neural Networks Science, 313(5786), 504–507مشاهده مقاله ↗
-
Auto-Encoding Variational Bayes International Conference on Learning Representations (ICLR 2014)مشاهده مقاله ↗
آمادهاید فاکتورهای پنهان بازار خود را استخراج کنید؟
تیم ExpertNevees Autoencoder مناسب را طراحی میکند و رژیم بازار یا فاکتور ریسک پنهان را استخراج میکند.
سایر مدلهای هوش مصنوعی ExpertNevees
HRP Portfolio — تخصیص ریسک سلسلهمراتبی
Hierarchical Risk Parity توسط Marcos López de Prado معرفی شده و با Clustering سلسلهمراتبی داراییها، پورتفولیویی میسازد که بدون نیاز به معکوس ماتریس کوواریانس، پایدارتر از Markowitz سنتی است.
سه مرحله الگوریتم HRP
دندروگرام نمونه: XAUUSD و XAGUSD زودتر از EURUSD و GBPUSD خوشه میخورند، چون همبستگی بالاتری دارند.
چرا HRP پایدارتر از Markowitz است؟
معکوس ماتریس
به خطای تخمین
Maximum Drawdown
برای N دارایی
مشخصات فنی پیادهسازی ExpertNevees
- بازده تاریخی: سری بازده روزانه/هفتگی هر دارایی
- ماتریس همبستگی: محاسبهشده از بازدههای تاریخی
- داراییها: فارکس، طلا، کریپتو، سهام (Multi-Asset)
- وزن تخصیص: درصد سرمایه برای هر دارایی
- Rebalancing: بازتخصیص دورهای (هفتگی/ماهانه)
- گزارش ریسک: Drawdown و Volatility پورتفولیو
فاصله همبستگی و تخصیص وزن HRP
# Convert the correlation matrix into a valid metric distance for hierarchical clustering d(i,j) = sqrt( 0.5 * (1 - rho(i,j)) ) # Cluster variance using inverse-variance weights within the cluster V_c = w_c^T * Sigma_c * w_c , w_c = diag(Sigma_c)^-1 / sum(diag(Sigma_c)^-1) # Recursive weight allocation between two sub-clusters at each binary split (Recursive Bisection) alpha = 1 - V_1 / (V_1 + V_2) , w_1 *= alpha , w_2 *= (1 - alpha)
پیادهسازی HRP با PyPortfolioOpt
import pandas as pd import numpy as np from pypfopt import HRPOpt, expected_returns, risk_models # ── Build daily return matrix for multi-asset portfolio ── # Supports any mix: Forex, Gold, Crypto, Equity indices returns = pd.DataFrame({ 'XAUUSD': gold_prices.pct_change(), 'XAGUSD': silver_prices.pct_change(), 'EURUSD': eurusd_prices.pct_change(), 'GBPUSD': gbpusd_prices.pct_change(), 'BTCUSD': btc_prices.pct_change(), }).dropna() # ── Run HRP: no covariance matrix inversion needed ── # Step 1: hierarchical clustering on correlation distance matrix # Step 2: recursive bisection to assign inverse-variance weights per cluster hrp = HRPOpt(returns) weights = hrp.optimize(linkage_method='ward') # ward linkage reduces within-cluster variance hrp.clean_weights() print("Portfolio Allocation:", weights) # e.g. {'XAUUSD': 0.31, 'XAGUSD': 0.19, 'EURUSD': 0.28, 'GBPUSD': 0.13, 'BTCUSD': 0.09} # ── Evaluate expected risk-adjusted performance ── perf = hrp.portfolio_performance(verbose=True) # returns: (expected_annual_return, annual_volatility, Sharpe_ratio) # ── Monthly rebalancing check — reallocate when weights drift > 5% ── current_weights = get_current_portfolio_weights() drift = {k: abs(current_weights[k] - weights[k]) for k in weights} if max(drift.values()) > 0.05: rebalance_to_target(weights) # sends orders to MT5/cTrader API
بکتست خارج از نمونه: HRP در برابر Equal-Weight
# ── Out-of-sample backtest: HRP allocation vs naive Equal-Weight benchmark ── from pypfopt import HRPOpt split = int(len(returns) * 0.7) train_ret, test_ret = returns.iloc[:split], returns.iloc[split:] hrp = HRPOpt(train_ret) hrp_weights = hrp.optimize(linkage_method='ward') equal_weights = {k: 1 / len(hrp_weights) for k in hrp_weights} def portfolio_return(weights, ret_df): w = np.array([weights[c] for c in ret_df.columns]) return (ret_df.values @ w) hrp_pnl = portfolio_return(hrp_weights, test_ret) eq_pnl = portfolio_return(equal_weights, test_ret) hrp_sharpe = hrp_pnl.mean() / hrp_pnl.std() * np.sqrt(252) eq_sharpe = eq_pnl.mean() / eq_pnl.std() * np.sqrt(252) print(f"HRP Out-of-Sample Sharpe: {hrp_sharpe:.2f}") print(f"Equal-Weight Out-of-Sample Sharpe: {eq_sharpe:.2f}") print(f"HRP Max Drawdown: {(1 - (1 + hrp_pnl).cumprod() / (1 + hrp_pnl).cumprod().cummax()).max():.2%}")
اشتباهات رایج در پیادهسازی HRP
-
●فرض ثبات همبستگی: خوشهبندی HRP بر پایه همبستگی تاریخی است؛ در بحرانهای مالی، همبستگی بین داراییها معمولاً ناگهان به سمت ۱ افزایش مییابد و ساختار خوشهبندی از هم میپاشد.
-
●حساسیت به معیار فاصله: فرمول فاصله (1-correlation)/2 به Outlierها حساس است؛ بازدههای حاوی جهشهای شدید باید قبل از محاسبه Winsorize یا فیلتر شوند.
-
●بدون در نظر گرفتن بازده مورد انتظار: HRP کاملاً بر پایه ریسک است و به بازده مورد انتظار توجه نمیکند؛ این یک مدل «بهینه ریسک» است، نه «بهینه بازده».
-
●عدم توازنبخشی دورهای: با گذشت زمان و تغییر نوسان داراییها، وزنهای ثابت HRP دیگر بهینه نیستند؛ Rebalance دورهای (مثلاً ماهانه) لازم است.
HRP برای کدام کاربردها مناسب است؟
- ●وابسته به ثبات همبستگی: اگر همبستگی بین داراییها بهسرعت تغییر کند، خوشهبندی قدیمی نامعتبر میشود.
- ●بدون پیشبینی بازده: HRP فقط ریسک را مدیریت میکند، پیشبینی بازده آینده را انجام نمیدهد.
- ●نیاز Rebalancing منظم: بدون بازتخصیص دورهای، وزنها از تخصیص بهینه منحرف میشوند.
HRP در مقابل Markowitz و Equal-Weight
| ویژگی | HRP | Markowitz (MVO) | Equal-Weight |
|---|---|---|---|
| معکوس ماتریس کوواریانس | خیر | بله | نامرتبط |
| حساسیت به خطای تخمین | کم | بسیار بالا | ندارد |
| در نظر گرفتن ریسک | بله (سلسلهمراتبی) | بله | خیر |
مقالات پایه این مدل
-
Building Diversified Portfolios that Outperform Out of Sample The Journal of Portfolio Management, 42(4), 59–69مشاهده مقاله ↗
-
Portfolio Selection The Journal of Finance, 7(1), 77–91مشاهده مقاله ↗
آمادهاید پورتفولیو چند-دارایی خود را بهینه کنید؟
تیم ExpertNevees الگوریتم HRP را روی داراییهای شما اجرا میکند و سیستم Rebalancing خودکار میسازد.
سایر مدلهای هوش مصنوعی ExpertNevees
Ensemble — ترکیب مدلهای هوش مصنوعی
Ensemble روشی است که خروجی چند مدل هوش مصنوعی مستقل (مثل LSTM، XGBoost و Random Forest) را ترکیب میکند تا نقطهضعف هر مدل با نقاط قوت مدلهای دیگر پوشش داده شود. طبق نظریه کلاسیک Bates & Granger (1969)، ترکیب چند پیشبینی معمولاً میانگین مربعات خطا (MSE) کمتری نسبت به بهترین مدل منفرد بهتنهایی دارد — مشروط به اینکه خطاهای مدلها با هم همبستگی بالا نداشته باشند.
پنج روش اصلی ترکیب مدلهای هوش مصنوعی
چرا ترکیب مدلها معمولاً بهتر از تکمدل عمل میکند؟
مشخصات فنی پیادهسازی ExpertNevees
- پیشبینی مدلهای پایه: خروجی/احتمال هر مدل مستقل (مثلاً LSTM، XGBoost، RF)
- خطای Out-of-Fold: برای تخمین وزنها یا آموزش Meta-Learner بدون نشت داده
- ویژگی رژیم (اختیاری): خروجی Autoencoder یا نوسان بازار برای سوییچینگ
- پیشبینی ترکیبی نهایی: سیگنال یا قیمت پیشبینیشده نهایی
- وزن هر مدل پایه: سهم هر مدل در تصمیم نهایی، برای تفسیرپذیری
- سطح توافق مدلها: میزان همجهتی مدلهای پایه، معیار اطمینان اضافی
فرمولهای ترکیب: میانگین، وزندهی و Stacking
# Simple average across N independent base models y_hat = (1/N) * sum_i( y_hat_i ) # Bates & Granger (1969) inverse-variance weighting — lower-error models get higher weight w_i = sigma_i^-2 / sum_j( sigma_j^-2 ) , y_hat = sum_i( w_i * y_hat_i ) # Stacking (Wolpert, 1992) — a meta-learner g() learns the optimal non-linear combination y_hat = g( y_hat_1, y_hat_2, ..., y_hat_N ; theta ) # Regime-gated mixture of experts — weight each model by the probability of its matching regime y_hat = sum_r( P(regime=r | x) * y_hat_r(x) )
Stacking صحیح با پیشبینی Out-of-Fold
import numpy as np from sklearn.model_selection import TimeSeriesSplit, cross_val_predict from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from xgboost import XGBClassifier from sklearn.metrics import accuracy_score, classification_report # ── Base models: intentionally diverse algorithms (low error correlation) ── base_models = { 'rf': RandomForestClassifier(n_estimators=300, max_depth=8, random_state=42), 'xgb': XGBClassifier(n_estimators=300, max_depth=4, learning_rate=0.05), 'lstm_probs': None, # pre-computed LSTM probabilities, see make_sequences() on the LSTM page } tscv = TimeSeriesSplit(n_splits=5) # time-ordered folds — never shuffle financial time series # ── Critical: generate OUT-OF-FOLD predictions for the meta-learner ── # Using in-sample predictions here would leak information and make the # meta-learner look far more accurate than it will be live (see Common Mistakes) oof_rf = cross_val_predict(base_models['rf'], X, y, cv=tscv, method='predict_proba')[:, 1] oof_xgb = cross_val_predict(base_models['xgb'], X, y, cv=tscv, method='predict_proba')[:, 1] oof_lstm = lstm_oof_probs # from a separate walk-forward LSTM training loop # ── Meta-learner: a simple Logistic Regression stacks the three OOF prediction columns ── meta_X = np.column_stack([oof_rf, oof_xgb, oof_lstm]) meta_model = LogisticRegression() meta_model.fit(meta_X, y) print("Learned ensemble weights:", dict(zip(['rf', 'xgb', 'lstm'], meta_model.coef_[0]))) # ── Fit final base models on ALL training data, then combine via the meta-learner ── base_models['rf'].fit(X_train, y_train) base_models['xgb'].fit(X_train, y_train) test_meta_X = np.column_stack([ base_models['rf'].predict_proba(X_test)[:, 1], base_models['xgb'].predict_proba(X_test)[:, 1], lstm_test_probs, ]) y_pred = meta_model.predict(test_meta_X) print(f"Ensemble Accuracy: {accuracy_score(y_test, y_pred):.4f}") print(classification_report(y_test, y_pred, target_names=['Down', 'Up']))
مقایسه Ensemble در برابر بهترین مدل منفرد
# ── Bates & Granger (1969) inverse-variance weighted average, computed from validation error ── from sklearn.metrics import mean_squared_error val_errors = { 'rf': mean_squared_error(y_val, rf_val_pred), 'xgb': mean_squared_error(y_val, xgb_val_pred), 'lstm': mean_squared_error(y_val, lstm_val_pred), } inv_var = {k: 1 / v for k, v in val_errors.items()} total = sum(inv_var.values()) weights = {k: v / total for k, v in inv_var.items()} print("Bates-Granger weights:", weights) ensemble_test_pred = ( weights['rf'] * rf_test_pred + weights['xgb'] * xgb_test_pred + weights['lstm'] * lstm_test_pred ) # ── Compare ensemble MSE against each individual model AND the naive equal-weight average ── naive_avg_pred = (rf_test_pred + xgb_test_pred + lstm_test_pred) / 3 results = { 'RF alone': mean_squared_error(y_test, rf_test_pred), 'XGBoost alone': mean_squared_error(y_test, xgb_test_pred), 'LSTM alone': mean_squared_error(y_test, lstm_test_pred), 'Equal-weight ensemble': mean_squared_error(y_test, naive_avg_pred), 'Bates-Granger ensemble': mean_squared_error(y_test, ensemble_test_pred), } for name, mse in sorted(results.items(), key=lambda x: x[1]): print(f"{name:24s} MSE = {mse:.6f}")
اشتباهات رایج در ترکیب مدلهای هوش مصنوعی
-
●ترکیب مدلهای همبسته: اگر خطای دو مدل با هم همبستگی بالا داشته باشد، ترکیبشان تقریباً هیچ بهبودی نمیدهد؛ تنوع واقعی الگوریتمی شرط لازم است.
-
●نشت داده در Stacking: آموزش Meta-Learner روی پیشبینی دروننمونهای مدلهای پایه، دقت را کاذباً بالا نشان میدهد.
-
●نادیده گرفتن هزینه تأخیر: اجرای N مدل یعنی N برابر زمان Inference؛ برای اسکالپینگ زیر ۱ میلیثانیه میتواند مضر باشد.
-
●ترکیب احتمالات کالیبرهنشده: قبل از میانگینگیری بین مدلهای مختلف، باید Calibration انجام شود.
-
●Overfitting در Meta-Learner: یک Meta-Learner پیچیده روی داده کم Overfit میکند؛ مدل خطی ساده معمولاً پایدارتر است.
ترکیب مدلها برای کدام کاربردها مناسب است؟
- ●پیچیدگی و دیباگ سختتر: فهمیدن دلیل یک معامله اشتباه در Ensemble دشوارتر از تکمدل است.
- ●بدون تضمین بهبود: اگر مدلهای پایه ضعیف یا همبسته باشند، Ensemble ممکن است بهبودی نداشته باشد.
- ●هزینه محاسباتی و زمان توسعه بیشتر: ساخت و نگهداری N مدل بهجای یک مدل، منابع بیشتری نیاز دارد.
رأیگیری در مقابل Stacking و سوییچینگ رژیم
| ویژگی | رأیگیری/میانگین | Stacking | سوییچینگ رژیم |
|---|---|---|---|
| پیچیدگی پیادهسازی | کم | متوسط | بالا |
| ریسک نشت داده | ندارد | بالا (بدون OOF) | متوسط |
| تفسیرپذیری | بالا | متوسط | بالا |
| سازگاری با تغییر رژیم بازار | کم | متوسط | بالا |
مقالات پایه این روش
-
The Combination of Forecasts Journal of the Operational Research Society, 20(4), 451–468مشاهده مقاله ↗
-
Stacked Generalization Neural Networks, 5(2), 241–259مشاهده مقاله ↗
-
Attention-based CNN-LSTM and XGBoost Hybrid Model for Stock Prediction arXiv:2204.02623 [q-fin.ST]مشاهده مقاله ↗
-
Time Series Prediction Based on LSTM-Attention-LSTM Model IEEE Access, 11, 48322–48331مشاهده مقاله ↗
آمادهاید چند مدل هوش مصنوعی را ترکیب کنید؟
تیم ExpertNevees میتواند چند مدل هوش مصنوعی را با Stacking یا سوییچینگ رژیم برای شما ترکیب کند.
مدلهای پایهای که معمولاً در Ensemble استفاده میشوند
MQL4 / MQL5 — برنامهنویسی ربات معاملاتی MetaTrader
MQL (MetaQuotes Language) زبان برنامهنویسی اختصاصی پلتفرم MetaTrader است که بر پایه C++ طراحی شده. MQL5 بهصورت کامل Object-Oriented است و امکان کلاس، وراثت و Polymorphism را فراهم میکند. تا سال ۲۰۲۶، MetaTrader 5 با ۶۲٪ سهم بازار CFD خرد، پلتفرم پیشرو در این حوزه است.
معماری Expert Advisor در MQL5
چه چیزی در MetaTrader 5 و MQL5 تغییر کرده است؟
ساختار کامل یک Expert Advisor در MQL5
// Volatility-adjusted position sizing based on ATR #includeCTrade trade; input double RiskPercent = 1.0; // risk per trade, % of balance input int AtrPeriod = 14; int atrHandle; int OnInit() { atrHandle = iATR(_Symbol, _Period, AtrPeriod); if(atrHandle == INVALID_HANDLE) return(INIT_FAILED); return(INIT_SUCCEEDED); } double CalculateLotSize(double stopLossPoints) { double atr[]; CopyBuffer(atrHandle, 0, 0, 1, atr); double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100.0; double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double lot = riskAmount / (stopLossPoints * tickValue); return NormalizeDouble(lot, 2); } void OnTick() { static datetime lastBar = 0; datetime currentBar = iTime(_Symbol, _Period, 0); if(currentBar == lastBar) return; // process once per new candle, not every tick lastBar = currentBar; double atr[]; CopyBuffer(atrHandle, 0, 0, 1, atr); double slPoints = atr[0] / _Point * 1.5; double lot = CalculateLotSize(slPoints); // CTrade handles requote retry, slippage and price normalization internally trade.Buy(lot, _Symbol, 0, SymbolInfoDouble(_Symbol, SYMBOL_BID) - slPoints * _Point); }
اشتباهات رایج در توسعه با MQL5
- ●اجرای منطق در هر Tick بهجای هر کندل: بدون بررسی زمان کندل جاری، ورود ممکنه چندبار در یک کندل اجرا بشه و معامله تکراری بسازه.
- ●عدم بررسی INVALID_HANDLE: بدون بررسی Handle در OnInit، CopyBuffer در OnTick بیصدا شکست میخوره و EA روی داده نامعتبر تصمیم میگیره.
- ●نادیده گرفتن Requote و Slippage: بدون مدیریت خطای سرور بروکر در بازار پرنوسان، معامله از دست میره یا با قیمت متفاوت اجرا میشه.
- ●بکتست با کیفیت داده نامناسب: حالت Every Tick معمولی (نه Real Ticks) برای اسکالپینگ نتایج غیرواقعی میده.
MQL5 برای کدام کاربردها مناسب است؟
- ●محدود به اکوسیستم MetaTrader: کد MQL5 مستقیماً روی cTrader، TradingView یا صرافیها اجرا نمیشه؛ باید بازنویسی بشه.
- ●کتابخانه یادگیری ماشین محدود: آموزش مدل باید در Python انجام و سپس با ONNX وارد MQL5 بشه.
- ●MQL4 در حال منسوخشدن است: پروژههای جدید بهتره مستقیماً با MQL5 شروع بشن.
مستندات و منابع رسمی MQL5
-
MQL5 Reference — Official Language Documentation MQL5.comمشاهده مستندات ↗
-
What's New in MetaTrader 5 — Release Notes MetaTrader5.comمشاهده مستندات ↗
آمادهاید ربات معاملاتی MQL5 خود را بسازید؟
تیم ExpertNevees با بیش از ۸۰ پروژه موفق MQL4/MQL5، از EA ساده تا سیستمهای ML با ONNX رو براتون پیادهسازی میکنه.
سایر زبانهای برنامهنویسی معاملاتی
cAlgo / cBot — برنامهنویسی ربات معاملاتی cTrader
cAlgo زبان برنامهنویسی بر پایه C# است که برای پلتفرم cTrader توسعه یافته. برخلاف MQL که سینتکس اختصاصی دارد، cAlgo از کامپایلر استاندارد .NET استفاده میکند و دسترسی کامل به اکوسیستم کتابخانههای C# را فراهم میکند. cTrader با Direct Market Access روی بروکرهای ECN/STP کار میکند.
معماری یک cBot در cAlgo
ساختار کامل یک cBot در C#
using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class AtrRiskBot : Robot { [Parameter("Risk %", DefaultValue = 1.0)] public double RiskPercent { get; set; } private AverageTrueRange atr; protected override void OnStart() { atr = Indicators.AverageTrueRange(14, MovingAverageType.Simple); } protected override void OnBar() { // Volatility-adjusted position size, mirrors the MQL5 ATR pattern double slPips = atr.Result.LastValue / Symbol.PipSize * 1.5; double riskAmount = Account.Balance * RiskPercent / 100; double volume = Symbol.NormalizeVolumeInUnits(riskAmount / (slPips * Symbol.PipValue)); if (Positions.Count == 0) { // ExecuteMarketOrder returns a TradeResult with slippage/fill details var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, "AtrRiskBot", slPips, null); if (!result.IsSuccessful) Print("Order failed: {0}", result.Error); } } }
اشتباهات رایج در توسعه با cAlgo
- ●عدم بررسی TradeResult.IsSuccessful: بدون بررسی نتیجه سفارش، شکست معامله بیصدا رد میشه و ربات فکر میکنه معامله باز شده.
- ●استفاده از حجم Raw بهجای NormalizeVolumeInUnits: حجم نرمالنشده باعث رد شدن سفارش توسط بروکر میشه.
- ●اتکا به OnTick برای منطق سنگین: محاسبات پیچیده در OnTick فشار پردازشی و تاخیر ایجاد میکنه؛ OnBar مناسبتره.
cAlgo برای کدام کاربردها مناسب است؟
- ●پایگاه کاربری کوچکتر از MetaTrader: بروکرهای پشتیبان cTrader کمتر از MetaTrader هستن؛ انتخاب محدودتره.
- ●نیاز به دانش C#/.NET: یادگیری cAlgo نیازمند آشنایی واقعی با مفاهیم OOP در C# هست.
مستندات و منابع رسمی cAlgo
-
cAlgo API Reference — Official Documentation help.ctrader.comمشاهده مستندات ↗
-
cTrader Open API — Developer Documentation openapi.ctrader.comمشاهده مستندات ↗
آمادهاید cBot خود را روی cTrader بسازید؟
تیم ExpertNevees با بیش از ۲۵ پروژه موفق cBot، از استراتژی ساده تا سیستم متصل به Open API رو براتون پیادهسازی میکنه.
سایر زبانهای برنامهنویسی معاملاتی
PineScript v6 — اندیکاتور و استراتژی برای TradingView
PineScript زبان اسکریپتنویسی اختصاصی TradingView است. در نوامبر ۲۰۲۴ نسخه ۶ منتشر شد که تحولی کامل در سیستم نوعبندی، درخواستهای داده پویا و انواع جدید ترسیم آورد؛ نسخه ۵ دیگر بهروزرسانی نمیشود و ویژگیهای جدید فقط در v6 منتشر میشوند.
چه چیزی در PineScript v6 تغییر کرده است؟
Indicator در برابر Strategy
استراتژی کامل با PineScript v6
//@version=6 strategy("ATR Risk Strategy", overlay = true, initial_capital = 10000) riskPercent = input.float(1.0, "Risk %", minval = 0.1) atrLen = input.int(14, "ATR Length") atrVal = ta.atr(atrLen) emaFast = ta.ema(close, 20) emaSlow = ta.ema(close, 50) // v6: boolean values are always strictly true/false, never na longCondition = ta.crossover(emaFast, emaSlow) if longCondition stopDistance = atrVal * 1.5 riskAmount = strategy.equity * riskPercent / 100 qty = riskAmount / stopDistance strategy.entry("Long", strategy.long, qty = qty) strategy.exit("Exit", "Long", stop = close - stopDistance) // v6: new log.* functions for real debugging instead of plotting hacks if barstate.islast log.info("ATR: {0}, Fast EMA: {1}, Slow EMA: {2}", atrVal, emaFast, emaSlow) plot(emaFast, color = color.orange) plot(emaSlow, color = color.blue) alertcondition(longCondition, title = "Long Signal", message = "Buy {{ticker}} at {{close}}")
اشتباهات رایج در PineScript
- ●Repainting در request.security(): بدون lookahead_off، بکتست از اطلاعات آینده استفاده میکنه و نتایج تکرارپذیر نیستن.
- ●نادیده گرفتن Commission و Slippage واقعی: بدون تنظیم اینها، نتایج بکتست خیلی خوشبینانهتر از واقعیته.
- ●عدم مهاجرت از Cast ضمنی Boolean: کد قدیمی v5 با if myInt در v6 دیگه کامپایل نمیشه؛ باید صریح بازنویسی بشه.
PineScript برای کدام کاربردها مناسب است؟
- ●بدون اجرای خودکار معامله بومی: برای اتوماسیون کامل باید هشدار از طریق Webhook به سرویس اجرایی خارجی وصل بشه.
- ●محدودیت منابع محاسباتی: اسکریپتهای سنگین ممکنه با خطای Timeout سرور TradingView متوقف بشن.
مستندات و منابع رسمی PineScript
-
Pine Script v6 Language Reference Manual tradingview.comمشاهده مستندات ↗
-
Migration Guide — To Pine Script Version 6 tradingview.comمشاهده مستندات ↗
آمادهاید اندیکاتور یا استراتژی PineScript v6 بسازید؟
تیم ExpertNevees اندیکاتور و استراتژی PineScript v6 طراحی میکنه و هشدارها رو در صورت نیاز به اجرای خودکار در MetaTrader وصل میکنه.
سایر زبانهای برنامهنویسی معاملاتی
Python — هوش مصنوعی، اتصال بروکر و صرافی
Python زبان غالب توسعه هوش مصنوعی در معاملات الگوریتمی است — از یادگیری ماشین با TensorFlow/PyTorch/Scikit-learn تا اتصال مستقیم به بروکر و صرافی. برخلاف MQL5 یا cAlgo که به یک پلتفرم محدودند، Python از طریق کتابخانه رسمی MetaTrader5، ZeroMQ یا API صرافیهای ارز دیجیتال به هر پلتفرمی متصل میشود.
معماری یک سیستم معاملاتی مبتنی بر Python
اتصال به MetaTrader و ارسال سفارش با Python
import MetaTrader5 as mt5 import pandas as pd # Official library talks directly to the terminal — no ZMQ bridge required if not mt5.initialize(): print("MT5 initialize failed:", mt5.last_error()) quit() symbol = "EURUSD" account_info = mt5.account_info() balance = account_info.balance # ATR-based position sizing, same risk model used in the MQL5/cAlgo pages rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_H1, 0, 15) df = pd.DataFrame(rates) atr = (df['high'] - df['low']).rolling(14).mean().iloc[-1] risk_percent = 1.0 point = mt5.symbol_info(symbol).point sl_points = atr / point * 1.5 tick_value = mt5.symbol_info(symbol).trade_tick_value lot = round((balance * risk_percent / 100) / (sl_points * tick_value), 2) price = mt5.symbol_info_tick(symbol).ask request = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": lot, "type": mt5.ORDER_TYPE_BUY, "price": price, "sl": price - sl_points * point, "deviation": 10, "magic": 123456, "type_filling": mt5.ORDER_FILLING_IOC, } result = mt5.order_send(request) if result.retcode != mt5.TRADE_RETCODE_DONE: print(f"Order failed, retcode={result.retcode}") mt5.shutdown()
اشتباهات رایج در توسعه معاملاتی با Python
- ●عدم بررسی retcode سفارش: بدون بررسی result.retcode، شکست سفارش بیصدا رد میشه.
- ●اجرای مدل سنگین در حلقه زنده: فراخوانی predict بدون بهینهسازی Batch/Cache، تاخیر قابلتوجهی ایجاد میکنه.
- ●Timezone نادرست در داده تاریخی: ترکیب داده MT5 با منابع دیگر بدون هماهنگ Timezone باعث خطای Off-by-one میشه.
- ●عدم مدیریت قطعی اتصال: بدون Reconnect خودکار، یک قطعی کوتاه اسکریپت رو کاملاً متوقف میکنه.
Python برای کدام کاربردها مناسب است؟
- ●سرعت اجرای پایینتر از C++/C#: برای HFT زیر میلیثانیه مناسب نیست؛ راهحل استاندارد Export به ONNX و اجرا در MQL5/cAlgo است.
- ●کتابخانه رسمی MetaTrader5 فقط روی ویندوز: روی Linux/Mac نیاز به Wine یا ZeroMQ Bridge داره.
مستندات و منابع رسمی
-
MetaTrader5 Python Package — Official Documentation PyPI / mql5.comمشاهده مستندات ↗
-
CCXT — CryptoCurrency eXchange Trading Library GitHub / docs.ccxt.comمشاهده مستندات ↗
آمادهاید سیستم معاملاتی مبتنی بر Python بسازید؟
تیم ExpertNevees مدلهای هوش مصنوعی، اتصال به بروکر/صرافی و Export مدل به ONNX رو براتون با Python پیادهسازی میکنه.
سایر زبانهای برنامهنویسی معاملاتی
مقایسه ۱۳ مدل هوش مصنوعی معاملاتی
هیچ مدلی برای همه شرایط بهترین نیست. این صفحه معیارهای کلیدی هر ۱۳ مدل — از Random Forest کلاسیک تا Transformer پیشرفته — را کنار هم میگذارد تا بر اساس داده در دسترس، منابع محاسباتی و نوع استراتژی، مدل درست را انتخاب کنید.
۱۳ مدل، ۷ معیار کلیدی
| مدل | دسته | وظیفه اصلی | حداقل داده | نیاز GPU | زمان آموزش | دقت/کیفیت |
|---|---|---|---|---|---|---|
| Random Forest | کلاسیک | طبقهبندی روند | ۱۰۰۰+ کندل | خیر | دقایق | 62–70% |
| XGBoost | کلاسیک | طبقهبندی روند | ۲۰۰۰+ کندل | خیر | دقایق تا ساعت | 68–74% |
| MLP | کلاسیک | طبقهبندی سیگنال | ۲۰۰۰+ نمونه | اختیاری | دقایق | 60–70% |
| Linear Factor | کلاسیک | رگرسیون / رتبهبندی | ۵۰۰+ نمونه | خیر | ثانیه تا دقیقه | IC ≈ ۰.۰۳–۰.۰۸ |
| LSTM | یادگیری عمیق | طبقهبندی سریزمانی | ۵۰۰۰+ کندل | پیشنهادی | ۱–۴ ساعت | 65–75% |
| GRU | یادگیری عمیق | طبقهبندی سریزمانی | ۵۰۰۰+ کندل | پیشنهادی | ۳۵–۹۰ دقیقه | 63–72% |
| Attention | یادگیری عمیق | طبقهبندی + تفسیر | ۵۰۰۰+ کندل | پیشنهادی | ۱–۴ ساعت | 67–76% |
| Transformer (TFT) | یادگیری عمیق | پیشبینی چندگامه | ۱۰۰۰۰+ کندل | الزامی | چند ساعت | بهترین در چندگامه |
| CNN | یادگیری عمیق | طبقهبندی الگوی بصری | ۵۰۰۰+ الگو | پیشنهادی | ۱–۳ ساعت | ۵۰+ کلاس الگو |
| DDQN | پیشرفته | یادگیری تقویتی | محیط شبیهسازی | پیشنهادی | چند ساعت تا روز | بر اساس Sharpe |
| TimeGAN | پیشرفته | تولید داده مصنوعی | ۲۰۰۰+ کندل واقعی | پیشنهادی | چند ساعت | امتیاز ≈ ۰.۵ ایدهآل |
| Autoencoder | پیشرفته | کاهش بعد / ناهنجاری | ۲۰۰۰+ نمونه | اختیاری | دقایق | بر اساس خطای بازسازی |
| HRP Portfolio | پیشرفته | تخصیص پورتفولیو | بازدهی چند دارایی | خیر | ثانیه | Sharpe نسبی |
بر اساس موقعیت خودتان، از کجا شروع کنید؟
-
●دقت بالا در تست کافی نیست: همیشه با Walk-Forward Validation یا TimeSeriesSplit ارزیابی کنید، نه تقسیم تصادفی ساده.
-
●مدل کلاسیک همیشه بیارزش نیست: Random Forest یا XGBoost اغلب با داده کمتر به دقتی نزدیک به LSTM میرسند.
-
●ترکیب مدلها (Ensemble) معمولاً بهتر از تکمدل است: ترکیب چند مدل با رأیگیری وزنی پایدارتر است.
-
●بازار تغییر میکند، مدل باید هم تغییر کند: بدون Retraining دورهای، مدل ظرف چند هفته منسوخ میشود.
-
●هیچ مدلی جایگزین مدیریت ریسک نیست: بدون حجمبندی درست و کنترل Drawdown، دقت بالا هم کافی نیست.
شروع کنید با یکی از این مدلها
چرا استراتژی معاملاتی را به ربات تبدیل کنیم؟
یک استراتژی معاملاتی، هرقدر هم دقیق طراحی شده باشد، وقتی توسط انسان و بهصورت دستی اجرا شود، تحت تاثیر تاخیر، خستگی و تصمیمگیری احساسی قرار میگیرد. خودکارسازی استراتژی در قالب یک ربات معاملاتی (Expert Advisor یا cBot)، اجرای آن را از «تصمیم لحظهای انسان» به «قوانین از پیش تعریفشده و قابل بکتست» منتقل میکند — بدون اینکه نتیجه معاملاتی به شرایط روانی معاملهگر در آن لحظه وابسته باشد.
چرا اجرای دستی حتی یک استراتژی خوب هم شکست میخورد؟
پژوهشهای رفتاری در حوزه مالی رفتاری (Behavioral Finance) نشان میدهند بیشترین شکاف بین نتیجه واقعی و نتیجه تئوریک یک استراتژی، نه از ضعف خود استراتژی، بلکه از انحراف معاملهگر در لحظه اجرا ناشی میشود. ترس از دستدادن سود باعث بستن زودهنگام معامله میشود، طمع باعث نگهداشتن بیش از حد یک پوزیشن زیانده میشود، و پس از یک ضرر، تمایل به جبران سریع (Revenge Trading) معاملهگر را از قوانین اولیهاش دور میکند. حتی معاملهگران باتجربه، در ساعات خستگی یا استرس بالا، بهطور ناخودآگاه قوانین مکتوب خودشان را زیر پا میگذارند.
شش دلیل فنی برای تبدیل استراتژی به ربات معاملاتی
چه زمانی خودکارسازی مناسب نیست؟
-
●استراتژی بدون قوانین دقیق: اگر ورود و خروج شما هنوز بر اساس «احساس بازار» است، ابتدا باید استراتژی مکتوب و دقیق شود.
-
●وابستگی شدید به تحلیل کیفی اخبار غیرقابل پیشبینی، خودکارسازی کامل را دشوار میکند.
-
●داده تاریخی ناکافی برای بکتست، اعتماد به عملکرد آینده ربات را بیپایه میکند.
-
●خودکارسازی، اجرا را بهبود میدهد نه ریسک ذاتی بازار را حذف میکند و تضمینی برای سود قطعی ایجاد نمیکند.