پیش‌بینی قیمت سهام همواره یکی از چالش‌برانگیزترین مسائل در حوزه مالی محسوب می‌شود. در این مقاله، به بررسی جامع الگوریتم Gradient Boosting و نحوه پیاده‌سازی آن برای پیش‌بینی قیمت سهام می‌پردازیم. این الگوریتم با استفاده از ترکیب مدل‌های ضعیف و بهینه‌سازی تدریجی، توانایی بالایی در مدل‌سازی روابط پیچیده و غیرخطی بازار سهام دارد. نتایج تحقیقات نشان می‌دهد که مدل‌های مبتنی بر Gradient Boosting، به‌ویژه XGBoost، می‌توانند دقت پیش‌بینی بالاتری نسبت به روش‌های سنتی ارائه دهند.

1. مقدمه

بازار سهام یکی از پیچیده‌ترین سیستم‌های اقتصادی است که تحت تأثیر عوامل متعددی قرار دارد. پیش‌بینی دقیق قیمت سهام می‌تواند به سرمایه‌گذاران در اتخاذ تصمیمات بهتر کمک کند و ریسک سرمایه‌گذاری را کاهش دهد. در سال‌های اخیر، روش‌های یادگیری ماشین به‌ویژه الگوریتم‌های مبتنی بر Gradient Boosting، توجه زیادی را در این حوزه به خود جلب کرده‌اند.

الگوریتم XGBoost که نسخه پیشرفته Gradient Boosting است، در بسیاری از کاربردها ثابت کرده که عملکرد بهتر یا مشابهی نسبت به روش‌های سنتی یادگیری ماشین دارد. این الگوریتم با ترکیب درخت‌های تصمیم ضعیف و استفاده از تکنیک تقویت گرادیان، قادر به یادگیری الگوهای پیچیده در داده‌های مالی است.

1.1 اهمیت موضوع

پیش‌بینی قیمت سهام به دلایل زیر حائز اهمیت است:

  • مدیریت ریسک: کاهش ریسک سرمایه‌گذاری از طریق پیش‌بینی روند بازار
  • بهینه‌سازی پورتفولیو: انتخاب سهام مناسب بر اساس پیش‌بینی‌های دقیق
  • تصمیم‌گیری آگاهانه: ارائه بینش‌های مبتنی بر داده به سرمایه‌گذاران
  • خودکارسازی معاملات: امکان پیاده‌سازی سیستم‌های معاملاتی خودکار

1.2 چالش‌های پیش‌بینی قیمت سهام

بازار سهام دارای ویژگی‌های خاصی است که پیش‌بینی آن را دشوار می‌سازد:

  • غیرخطی بودن: روابط بین متغیرهای مختلف در بازار سهام غیرخطی است
  • نویز بالا: داده‌های قیمت سهام حاوی نویز و نوسانات کوتاه‌مدت زیادی هستند
  • عوامل خارجی: تأثیر اخبار، رویدادهای سیاسی و اقتصادی
  • رفتار احساسی: تأثیر احساسات و رفتار جمعی سرمایه‌گذاران

2. مبانی نظری الگوریتم Gradient Boosting

2.1 مفهوم Boosting

Boosting یک تکنیک یادگیری جمعی (Ensemble Learning) است که در آن چندین مدل ضعیف به صورت متوالی ترکیب می‌شوند تا یک مدل قوی ایجاد کنند. در این روش، هر مدل بعدی سعی می‌کند خطاهای مدل قبلی را اصلاح کند و به همین دلیل، مدل‌های بعدی وابسته به مدل‌های قبلی هستند.

2.2 الگوریتم Gradient Boosting

Gradient Boosting نوعی خاص از Boosting است که از گرادیان تابع خطا برای بهینه‌سازی استفاده می‌کند. مراحل اصلی این الگوریتم عبارتند از:

  1. شروع با یک مدل اولیه ساده (معمولاً میانگین مقادیر هدف)
  2. محاسبه باقیمانده‌ها (تفاوت بین مقدار واقعی و پیش‌بینی)
  3. آموزش یک مدل جدید برای پیش‌بینی باقیمانده‌ها
  4. به‌روزرسانی مدل با اضافه کردن مدل جدید با یک نرخ یادگیری
  5. تکرار مراحل 2-4 تا رسیدن به تعداد مشخصی از تکرار

2.3 مزایای Gradient Boosting در پیش‌بینی سهام

الگوریتم XGBoost با دقت 78.81% در پیش‌بینی جهت حرکت شاخص بورس تهران عملکرد موفقی داشته است. مزایای کلیدی این الگوریتم شامل:

  • قابلیت مدل‌سازی روابط غیرخطی: توانایی یادگیری الگوهای پیچیده
  • مقاومت در برابر نویز: عملکرد خوب حتی با داده‌های نویزی
  • انعطاف‌پذیری: قابلیت استفاده برای مسائل رگرسیون و دسته‌بندی
  • عملکرد بالا: سرعت و دقت بالا در مقایسه با روش‌های مشابه

3. پیاده‌سازی XGBoost: نسخه بهینه Gradient Boosting

3.1 معرفی XGBoost

XGBoost مخفف eXtreme Gradient Boosting است و یکی از محبوب‌ترین پیاده‌سازی‌های الگوریتم Gradient Boosting محسوب می‌شود. این الگوریتم بر پایه درخت‌های تصمیم بنا شده و از تکنیک تقویت گرادیان برای دستیابی به دقت و کارایی بی‌نظیر بهره می‌برد.

3.2 ویژگی‌های کلیدی XGBoost

XGBoost دارای ویژگی‌های منحصربه‌فردی است که آن را از سایر الگوریتم‌ها متمایز می‌کند:

3.2.1 منظم‌سازی (Regularization)

XGBoost از تکنیک‌های منظم‌سازی L1 و L2 برای جلوگیری از بیش‌برازش استفاده می‌کند. این ویژگی به مدل کمک می‌کند تا تعمیم‌پذیری بهتری داشته باشد.

3.2.2 مدیریت داده‌های گمشده

الگوریتم به صورت خودکار با داده‌های گمشده کار می‌کند و نیازی به پیش‌پردازش خاص ندارد.

3.2.3 موازی‌سازی

XGBoost از پردازش موازی برای افزایش سرعت آموزش استفاده می‌کند.

3.2.4 هرس درخت

الگوریتم از تکنیک‌های هرس درخت برای کنترل پیچیدگی مدل استفاده می‌کند.

4. مهندسی ویژگی برای پیش‌بینی قیمت سهام

4.1 اهمیت مهندسی ویژگی

مهندسی ویژگی نقش حیاتی در بهبود دقت مدل‌های پیش‌بینی دارد و اولین مطالعات نشان می‌دهد که استفاده از آن در دسته‌بندی چندکلاسه با روش‌های جمعی نتایج امیدوارکننده‌ای دارد.

4.2 اندیکاتورهای تکنیکال

اندیکاتورهای تکنیکال از مهم‌ترین ویژگی‌ها در پیش‌بینی قیمت سهام هستند:

4.2.1 اندیکاتورهای روند

  • میانگین متحرک ساده (SMA): میانگین قیمت در یک بازه زمانی مشخص
  • میانگین متحرک نمایی (EMA): میانگین وزنی با تأکید بیشتر بر داده‌های جدید
  • MACD: تفاوت بین دو میانگین متحرک نمایی

4.2.2 اندیکاتورهای مومنتوم

  • شاخص قدرت نسبی (RSI): اندازه‌گیری سرعت و تغییرات قیمت
  • استوکاستیک: مقایسه قیمت بسته شدن با محدوده قیمتی

4.2.3 اندیکاتورهای نوسان

  • باندهای بولینگر: نوارهای انحراف معیار اطراف میانگین متحرک
  • ATR (Average True Range): میانگین محدوده واقعی قیمت

4.3 ویژگی‌های مشتق‌شده

اندیکاتورهایی مانند RSI یا EMA به عنوان تقویت‌کننده سیگنال برای داده‌های مالی عمل می‌کنند. علاوه بر اندیکاتورهای استاندارد، می‌توان ویژگی‌های جدیدی ایجاد کرد:

  • نسبت‌های قیمتی: نسبت قیمت بسته شدن به باز شدن
  • ویژگی‌های زمانی: روز هفته، ماه سال، فصل
  • ویژگی‌های تأخیری (Lag Features): قیمت‌های روزهای گذشته
  • آمار خلاصه: میانگین، واریانس، چولگی در بازه‌های مختلف

4.4 انتخاب ویژگی

انتخاب ویژگی‌های مناسب برای جلوگیری از بیش‌برازش و بهبود عملکرد مدل ضروری است. روش‌های مختلفی برای انتخاب ویژگی وجود دارد، از جمله Relief که در ارزیابی‌های مبتنی بر دقت و هزینه بهترین عملکرد را داشته است.

5. پیاده‌سازی عملی در Python

5.1 آماده‌سازی محیط و کتابخانه‌ها

# وارد کردن کتابخانه‌های مورد نیاز
import pandas as pd
import numpy as np
import yfinance as yf
from sklearn.model_selection import train_test_split, GridSearchCV, TimeSeriesSplit
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import xgboost as xgb
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

# تنظیمات نمایش فارسی
plt.rcParams['font.family'] = 'B Nazanin'
plt.rcParams['axes.unicode_minus'] = False

5.2 جمع‌آوری و آماده‌سازی داده‌ها

def fetch_stock_data(symbol, start_date, end_date):
    """
    دریافت داده‌های تاریخی سهام
    """
    stock_data = yf.download(symbol, start=start_date, end=end_date)
    return stock_data

def calculate_technical_indicators(df):
    """
    محاسبه اندیکاتورهای تکنیکال
    """
    # میانگین متحرک ساده
    df['SMA_10'] = df['Close'].rolling(window=10).mean()
    df['SMA_30'] = df['Close'].rolling(window=30).mean()
    df['SMA_50'] = df['Close'].rolling(window=50).mean()
    
    # میانگین متحرک نمایی
    df['EMA_12'] = df['Close'].ewm(span=12, adjust=False).mean()
    df['EMA_26'] = df['Close'].ewm(span=26, adjust=False).mean()
    
    # MACD
    df['MACD'] = df['EMA_12'] - df['EMA_26']
    df['Signal_Line'] = df['MACD'].ewm(span=9, adjust=False).mean()
    df['MACD_Histogram'] = df['MACD'] - df['Signal_Line']
    
    # RSI
    delta = df['Close'].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
    rs = gain / loss
    df['RSI'] = 100 - (100 / (1 + rs))
    
    # باندهای بولینگر
    df['BB_Middle'] = df['Close'].rolling(window=20).mean()
    bb_std = df['Close'].rolling(window=20).std()
    df['BB_Upper'] = df['BB_Middle'] + (bb_std * 2)
    df['BB_Lower'] = df['BB_Middle'] - (bb_std * 2)
    df['BB_Width'] = df['BB_Upper'] - df['BB_Lower']
    df['BB_Position'] = (df['Close'] - df['BB_Lower']) / df['BB_Width']
    
    # نوسان (Volatility)
    df['Volatility'] = df['Close'].pct_change().rolling(window=20).std()
    
    # حجم معاملات نرمال شده
    df['Volume_SMA'] = df['Volume'].rolling(window=20).mean()
    df['Volume_Ratio'] = df['Volume'] / df['Volume_SMA']
    
    # نسبت‌های قیمتی
    df['High_Low_Ratio'] = df['High'] / df['Low']
    df['Close_Open_Ratio'] = df['Close'] / df['Open']
    
    # بازده لگاریتمی
    df['Log_Return'] = np.log(df['Close'] / df['Close'].shift(1))
    
    # ویژگی‌های تأخیری
    for i in range(1, 6):
        df[f'Close_Lag_{i}'] = df['Close'].shift(i)
        df[f'Volume_Lag_{i}'] = df['Volume'].shift(i)
    
    # ویژگی‌های زمانی
    df['DayOfWeek'] = df.index.dayofweek
    df['Month'] = df.index.month
    df['Quarter'] = df.index.quarter
    
    # حذف ردیف‌های با مقادیر گمشده
    df.dropna(inplace=True)
    
    return df

# مثال: دریافت داده‌های یک سهم
symbol = 'AAPL'  # می‌توانید با نماد سهام مورد نظر خود جایگزین کنید
start_date = '2020-01-01'
end_date = '2024-01-01'

# دریافت داده‌ها
stock_data = fetch_stock_data(symbol, start_date, end_date)

# محاسبه اندیکاتورها
stock_data = calculate_technical_indicators(stock_data)

print(f"شکل داده‌ها: {stock_data.shape}")
print(f"ویژگی‌های ایجاد شده: {stock_data.columns.tolist()}")

5.3 آماده‌سازی داده‌ها برای مدل‌سازی

def prepare_data_for_modeling(df, target_col='Close', prediction_horizon=1):
    """
    آماده‌سازی داده‌ها برای آموزش مدل
    
    Parameters:
    -----------
    df : DataFrame
        دیتافریم حاوی ویژگی‌ها
    target_col : str
        نام ستون هدف
    prediction_horizon : int
        افق پیش‌بینی (چند روز آینده)
    """
    # ایجاد متغیر هدف (قیمت n روز آینده)
    df['Target'] = df[target_col].shift(-prediction_horizon)
    
    # حذف ردیف‌های آخر که مقدار هدف ندارند
    df = df[:-prediction_horizon]
    
    # انتخاب ویژگی‌ها
    feature_cols = [col for col in df.columns if col not in ['Target', 'Open', 'High', 'Low', 'Close', 'Adj Close']]
    
    X = df[feature_cols]
    y = df['Target']
    
    return X, y, feature_cols

# آماده‌سازی داده‌ها
X, y, feature_cols = prepare_data_for_modeling(stock_data)

print(f"تعداد نمونه‌ها: {len(X)}")
print(f"تعداد ویژگی‌ها: {len(feature_cols)}")

5.4 تقسیم داده‌ها و نرمال‌سازی

def split_and_scale_data(X, y, test_size=0.2, validation_size=0.2):
    """
    تقسیم داده‌ها به مجموعه‌های آموزش، اعتبارسنجی و آزمون
    """
    # محاسبه اندازه‌ها
    n_samples = len(X)
    test_samples = int(n_samples * test_size)
    val_samples = int((n_samples - test_samples) * validation_size)
    train_samples = n_samples - test_samples - val_samples
    
    # تقسیم زمانی (برای داده‌های سری زمانی)
    X_train = X.iloc[:train_samples]
    y_train = y.iloc[:train_samples]
    
    X_val = X.iloc[train_samples:train_samples+val_samples]
    y_val = y.iloc[train_samples:train_samples+val_samples]
    
    X_test = X.iloc[train_samples+val_samples:]
    y_test = y.iloc[train_samples+val_samples:]
    
    # نرمال‌سازی ویژگی‌ها
    scaler = StandardScaler()
    X_train_scaled = pd.DataFrame(
        scaler.fit_transform(X_train),
        columns=X_train.columns,
        index=X_train.index
    )
    X_val_scaled = pd.DataFrame(
        scaler.transform(X_val),
        columns=X_val.columns,
        index=X_val.index
    )
    X_test_scaled = pd.DataFrame(
        scaler.transform(X_test),
        columns=X_test.columns,
        index=X_test.index
    )
    
    return X_train_scaled, X_val_scaled, X_test_scaled, y_train, y_val, y_test, scaler

# تقسیم و نرمال‌سازی داده‌ها
X_train, X_val, X_test, y_train, y_val, y_test, scaler = split_and_scale_data(X, y)

print(f"اندازه مجموعه آموزش: {X_train.shape}")
print(f"اندازه مجموعه اعتبارسنجی: {X_val.shape}")
print(f"اندازه مجموعه آزمون: {X_test.shape}")

5.5 پیاده‌سازی و آموزش مدل XGBoost

def train_xgboost_model(X_train, y_train, X_val, y_val):
    """
    آموزش مدل XGBoost با پارامترهای بهینه
    """
    # ایجاد مدل پایه
    xgb_model = xgb.XGBRegressor(
        objective='reg:squarederror',
        n_estimators=100,
        max_depth=6,
        learning_rate=0.1,
        subsample=0.8,
        colsample_bytree=0.8,
        random_state=42,
        tree_method='hist'  # برای سرعت بیشتر
    )
    
    # آموزش مدل با early stopping
    eval_set = [(X_train, y_train), (X_val, y_val)]
    xgb_model.fit(
        X_train, y_train,
        eval_set=eval_set,
        eval_metric=['rmse', 'mae'],
        early_stopping_rounds=20,
        verbose=False
    )
    
    return xgb_model

# آموزش مدل
model = train_xgboost_model(X_train, y_train, X_val, y_val)

# پیش‌بینی
train_pred = model.predict(X_train)
val_pred = model.predict(X_val)
test_pred = model.predict(X_test)

# محاسبه معیارهای ارزیابی
def evaluate_model(y_true, y_pred, dataset_name):
    """
    محاسبه و نمایش معیارهای ارزیابی
    """
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mae = mean_absolute_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
    
    print(f"\n=== نتایج ارزیابی {dataset_name} ===")
    print(f"RMSE: {rmse:.4f}")
    print(f"MAE: {mae:.4f}")
    print(f"R²: {r2:.4f}")
    print(f"MAPE: {mape:.2f}%")
    
    return {'rmse': rmse, 'mae': mae, 'r2': r2, 'mape': mape}

# ارزیابی مدل
train_metrics = evaluate_model(y_train, train_pred, "مجموعه آموزش")
val_metrics = evaluate_model(y_val, val_pred, "مجموعه اعتبارسنجی")
test_metrics = evaluate_model(y_test, test_pred, "مجموعه آزمون")

6. بهینه‌سازی هایپرپارامترها

6.1 اهمیت تنظیم هایپرپارامترها

عملکرد یک مدل یادگیری ماشین به شدت تحت تأثیر انتخاب هایپرپارامترها قرار دارد. در XGBoost، پارامترهای کلیدی شامل عمق درخت، نرخ یادگیری، و تعداد درخت‌ها هستند.

6.2 استفاده از Grid Search

def hyperparameter_tuning(X_train, y_train, X_val, y_val):
    """
    بهینه‌سازی هایپرپارامترها با استفاده از Grid Search
    """
    # تعریف فضای جستجو
    param_grid = {
        'n_estimators': [100, 200, 300],
        'max_depth': [3, 5, 7, 9],
        'learning_rate': [0.01, 0.05, 0.1, 0.2],
        'subsample': [0.6, 0.8, 1.0],
        'colsample_bytree': [0.6, 0.8, 1.0],
        'gamma': [0, 0.1, 0.2],
        'reg_alpha': [0, 0.1, 0.5],
        'reg_lambda': [0.5, 1, 1.5]
    }
    
    # ایجاد مدل پایه
    xgb_model = xgb.XGBRegressor(
        objective='reg:squarederror',
        random_state=42,
        tree_method='hist'
    )
    
    # استفاده از TimeSeriesSplit برای اعتبارسنجی متقاطع
    tscv = TimeSeriesSplit(n_splits=5)
    
    # Grid Search
    grid_search = GridSearchCV(
        estimator=xgb_model,
        param_grid=param_grid,
        cv=tscv,
        scoring='neg_mean_squared_error',
        n_jobs=-1,
        verbose=1
    )
    
    # برازش مدل
    print("شروع بهینه‌سازی هایپرپارامترها...")
    grid_search.fit(X_train, y_train)
    
    print(f"\nبهترین پارامترها: {grid_search.best_params_}")
    print(f"بهترین امتیاز: {-grid_search.best_score_:.4f}")
    
    return grid_search.best_estimator_

# نکته: این فرایند ممکن است زمان‌بر باشد
# optimized_model = hyperparameter_tuning(X_train, y_train, X_val, y_val)

6.3 بهینه‌سازی با Bayesian Optimization

# برای بهینه‌سازی سریع‌تر می‌توان از روش‌های Bayesian استفاده کرد
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform, randint

def bayesian_optimization(X_train, y_train):
    """
    بهینه‌سازی با استفاده از Random Search (تقریبی از Bayesian Optimization)
    """
    param_distributions = {
        'n_estimators': randint(50, 500),
        'max_depth': randint(3, 12),
        'learning_rate': uniform(0.01, 0.3),
        'subsample': uniform(0.5, 0.5),
        'colsample_bytree': uniform(0.5, 0.5),
        'gamma': uniform(0, 0.5),
        'reg_alpha': uniform(0, 1),
        'reg_lambda': uniform(0.5, 2)
    }
    
    xgb_model = xgb.XGBRegressor(
        objective='reg:squarederror',
        random_state=42
    )
    
    random_search = RandomizedSearchCV(
        estimator=xgb_model,
        param_distributions=param_distributions,
        n_iter=100,
        cv=TimeSeriesSplit(n_splits=3),
        scoring='neg_mean_squared_error',
        n_jobs=-1,
        verbose=1,
        random_state=42
    )
    
    random_search.fit(X_train, y_train)
    
    return random_search.best_estimator_

7. تکنیک‌های جلوگیری از بیش‌برازش (Overfitting)

7.1 روش‌های منظم‌سازی در XGBoost

بیش‌برازش یکی از چالش‌های اصلی در مدل‌های Gradient Boosting است. XGBoost روش‌های مختلفی برای کنترل بیش‌برازش ارائه می‌دهد:

def create_regularized_model():
    """
    ایجاد مدل با تنظیمات منظم‌سازی قوی
    """
    regularized_model = xgb.XGBRegressor(
        objective='reg:squarederror',
        n_estimators=200,
        max_depth=4,  # محدود کردن عمق درخت
        learning_rate=0.05,  # نرخ یادگیری پایین‌تر
        subsample=0.7,  # استفاده از زیرمجموعه‌ای از داده‌ها
        colsample_bytree=0.7,  # استفاده از زیرمجموعه‌ای از ویژگی‌ها
        gamma=0.1,  # حداقل کاهش خطا برای ایجاد شاخه جدید
        reg_alpha=0.5,  # منظم‌سازی L1
        reg_lambda=1.0,  # منظم‌سازی L2
        min_child_weight=3,  # حداقل وزن در گره‌های فرزند
        random_state=42
    )
    
    return regularized_model

# آموزش مدل منظم‌سازی شده
reg_model = create_regularized_model()
reg_model.fit(
    X_train, y_train,
    eval_set=[(X_val, y_val)],
    early_stopping_rounds=30,
    verbose=False
)

7.2 Early Stopping

def train_with_early_stopping(X_train, y_train, X_val, y_val):
    """
    آموزش با استفاده از Early Stopping
    """
    model = xgb.XGBRegressor(
        n_estimators=1000,  # تعداد زیاد درخت
        learning_rate=0.05,
        max_depth=5,
        random_state=42
    )
    
    # آموزش با early stopping
    model.fit(
        X_train, y_train,
        eval_set=[(X_val, y_val)],
        early_stopping_rounds=50,
        eval_metric='rmse',
        verbose=True
    )
    
    print(f"بهترین تعداد درخت: {model.best_iteration}")
    
    return model

7.3 Cross-Validation برای ارزیابی مدل

def cross_validation_analysis(X, y):
    """
    اعتبارسنجی متقاطع برای ارزیابی واقعی‌تر مدل
    """
    # پارامترهای مدل
    params = {
        'objective': 'reg:squarederror',
        'max_depth': 6,
        'learning_rate': 0.1,
        'n_estimators': 100,
        'subsample': 0.8,
        'colsample_bytree': 0.8
    }
    
    # ایجاد ماتریس DMatrix برای XGBoost
    dtrain = xgb.DMatrix(X, label=y)
    
    # اجرای cross-validation
    cv_results = xgb.cv(
        params,
        dtrain,
        num_boost_round=100,
        nfold=5,
        metrics=['rmse', 'mae'],
        early_stopping_rounds=20,
        seed=42
    )
    
    print("نتایج Cross-Validation:")
    print(f"بهترین RMSE: {cv_results['test-rmse-mean'].min():.4f}")
    print(f"بهترین MAE: {cv_results['test-mae-mean'].min():.4f}")
    
    return cv_results

8. تحلیل اهمیت ویژگی‌ها

8.1 محاسبه و نمایش اهمیت ویژگی‌ها

def analyze_feature_importance(model, feature_names, top_n=20):
    """
    تحلیل و نمایش اهمیت ویژگی‌ها
    """
    # استخراج اهمیت ویژگی‌ها
    importance = model.feature_importances_
    
    # ایجاد DataFrame
    feature_importance_df = pd.DataFrame({
        'feature': feature_names,
        'importance': importance
    }).sort_values('importance', ascending=False)
    
    # نمایش top_n ویژگی مهم
    plt.figure(figsize=(12, 8))
    top_features = feature_importance_df.head(top_n)
    
    plt.barh(range(len(top_features)), top_features['importance'])
    plt.yticks(range(len(top_features)), top_features['feature'])
    plt.xlabel('اهمیت')
    plt.title(f'{top_n} ویژگی برتر در پیش‌بینی قیمت سهام')
    plt.gca().invert_yaxis()
    plt.tight_layout()
    plt.show()
    
    return feature_importance_df

# تحلیل اهمیت ویژگی‌ها
feature_importance = analyze_feature_importance(model, feature_cols)
print("\n10 ویژگی برتر:")
print(feature_importance.head(10))

8.2 استفاده از SHAP برای تفسیرپذیری

# import shap

def shap_analysis(model, X_sample):
    """
    تحلیل SHAP برای تفسیر پیش‌بینی‌ها
    """
    # محاسبه مقادیر SHAP
    explainer = shap.TreeExplainer(model)
    shap_values = explainer.shap_values(X_sample)
    
    # نمایش نمودار خلاصه
    shap.summary_plot(shap_values, X_sample)
    
    # نمایش نمودار واترفال برای یک نمونه
    shap.waterfall_plot(shap.Explanation(
        values=shap_values[0],
        base_values=explainer.expected_value,
        data=X_sample.iloc[0],
        feature_names=X_sample.columns.tolist()
    ))
    
    return shap_values

9. ایجاد سیستم معاملاتی

9.1 استراتژی معاملاتی بر اساس پیش‌بینی

def create_trading_strategy(model, X_test, y_test, initial_capital=1000000):
    """
    ایجاد استراتژی معاملاتی بر اساس پیش‌بینی مدل
    """
    # پیش‌بینی قیمت
    predictions = model.predict(X_test)
    
    # محاسبه سیگنال‌های خرید/فروش
    signals = pd.DataFrame(index=X_test.index)
    signals['actual_price'] = y_test
    signals['predicted_price'] = predictions
    signals['returns'] = signals['actual_price'].pct_change()
    
    # سیگنال خرید: پیش‌بینی افزایش قیمت بیش از 1%
    signals['signal'] = 0
    signals.loc[signals['predicted_price'] > signals['actual_price'] * 1.01, 'signal'] = 1
    signals.loc[signals['predicted_price'] < signals['actual_price'] * 0.99, 'signal'] = -1
    
    # محاسبه بازده استراتژی
    signals['strategy_returns'] = signals['signal'].shift(1) * signals['returns']
    
    # محاسبه بازده تجمعی
    signals['cumulative_returns'] = (1 + signals['returns']).cumprod()
    signals['cumulative_strategy_returns'] = (1 + signals['strategy_returns']).cumprod()
    
    # محاسبه معیارهای عملکرد
    total_return = signals['cumulative_strategy_returns'].iloc[-1] - 1
    sharpe_ratio = signals['strategy_returns'].mean() / signals['strategy_returns'].std() * np.sqrt(252)
    max_drawdown = calculate_max_drawdown(signals['cumulative_strategy_returns'])
    win_rate = len(signals[signals['strategy_returns'] > 0]) / len(signals[signals['strategy_returns'] != 0])
    
    print("\n=== معیارهای عملکرد استراتژی ===")
    print(f"بازده کل: {total_return*100:.2f}%")
    print(f"نسبت شارپ: {sharpe_ratio:.2f}")
    print(f"حداکثر افت: {max_drawdown*100:.2f}%")
    print(f"نرخ برد: {win_rate*100:.2f}%")
    
    return signals

def calculate_max_drawdown(cumulative_returns):
    """
    محاسبه حداکثر افت (Maximum Drawdown)
    """
    running_max = cumulative_returns.expanding().max()
    drawdown = (cumulative_returns - running_max) / running_max
    return drawdown.min()

9.2 بک‌تست استراتژی

def backtest_strategy(signals, initial_capital=1000000, transaction_cost=0.001):
    """
    بک‌تست استراتژی با در نظر گرفتن هزینه‌های معاملاتی
    """
    portfolio = pd.DataFrame(index=signals.index)
    portfolio['signal'] = signals['signal']
    portfolio['price'] = signals['actual_price']
    
    # موقعیت‌های معاملاتی
    portfolio['positions'] = portfolio['signal'].diff()
    
    # محاسبه تعداد سهام
    portfolio['shares'] = 0
    cash = initial_capital
    shares = 0
    
    for i in range(len(portfolio)):
        if portfolio['positions'].iloc[i] == 1:  # خرید
            shares_to_buy = int(cash * 0.95 / portfolio['price'].iloc[i])
            cost = shares_to_buy * portfolio['price'].iloc[i] * (1 + transaction_cost)
            if cost <= cash:
                shares += shares_to_buy
                cash -= cost
                
        elif portfolio['positions'].iloc[i] == -1:  # فروش
            if shares > 0:
                cash += shares * portfolio['price'].iloc[i] * (1 - transaction_cost)
                shares = 0
        
        portfolio.loc[portfolio.index[i], 'shares'] = shares
        portfolio.loc[portfolio.index[i], 'cash'] = cash
    
    # محاسبه ارزش پورتفولیو
    portfolio['total_value'] = portfolio['cash'] + portfolio['shares'] * portfolio['price']
    portfolio['returns'] = portfolio['total_value'].pct_change()
    
    # نمایش نمودار
    plt.figure(figsize=(14, 7))
    plt.plot(portfolio.index, portfolio['total_value'], label='ارزش پورتفولیو')
    plt.axhline(y=initial_capital, color='r', linestyle='--', label='سرمایه اولیه')
    plt.title('عملکرد استراتژی معاملاتی')
    plt.xlabel('تاریخ')
    plt.ylabel('ارزش (تومان)')
    plt.legend()
    plt.grid(True)
    plt.show()
    
    return portfolio

10. مقایسه با سایر الگوریتم‌ها

10.1 مقایسه عملکرد

from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.svm import SVR
from sklearn.neural_network import MLPRegressor

def compare_models(X_train, y_train, X_test, y_test):
    """
    مقایسه XGBoost با سایر الگوریتم‌های یادگیری ماشین
    """
    models = {
        'XGBoost': xgb.XGBRegressor(n_estimators=100, random_state=42),
        'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42),
        'Gradient Boosting': GradientBoostingRegressor(n_estimators=100, random_state=42),
        'Linear Regression': LinearRegression(),
        'Ridge': Ridge(alpha=1.0),
        'Lasso': Lasso(alpha=0.1),
        'SVR': SVR(kernel='rbf'),
        'Neural Network': MLPRegressor(hidden_layer_sizes=(100, 50), random_state=42, max_iter=1000)
    }
    
    results = {}
    
    for name, model in models.items():
        print(f"آموزش مدل {name}...")
        
        # آموزش مدل
        model.fit(X_train, y_train)
        
        # پیش‌بینی
        y_pred = model.predict(X_test)
        
        # محاسبه معیارها
        mse = mean_squared_error(y_test, y_pred)
        rmse = np.sqrt(mse)
        mae = mean_absolute_error(y_test, y_pred)
        r2 = r2_score(y_test, y_pred)
        
        results[name] = {
            'RMSE': rmse,
            'MAE': mae,
            'R2': r2
        }
    
    # نمایش نتایج
    results_df = pd.DataFrame(results).T
    results_df = results_df.sort_values('R2', ascending=False)
    
    print("\n=== مقایسه عملکرد مدل‌ها ===")
    print(results_df)
    
    # نمودار مقایسه
    fig, axes = plt.subplots(1, 3, figsize=(15, 5))
    
    metrics = ['RMSE', 'MAE', 'R2']
    for i, metric in enumerate(metrics):
        ax = axes[i]
        values = results_df[metric].values
        models_names = results_df.index
        
        bars = ax.bar(range(len(models_names)), values)
        ax.set_xticks(range(len(models_names)))
        ax.set_xticklabels(models_names, rotation=45, ha='right')
        ax.set_ylabel(metric)
        ax.set_title(f'مقایسه {metric}')
        
        # رنگ‌آمیزی بهترین نتیجه
        if metric == 'R2':
            best_idx = np.argmax(values)
        else:
            best_idx = np.argmin(values)
        bars[best_idx].set_color('green')
    
    plt.tight_layout()
    plt.show()
    
    return results_df

11. نتایج و بحث

11.1 تحلیل نتایج

بر اساس پیاده‌سازی انجام شده و مقایسه با تحقیقات موجود:

  1. دقت پیش‌بینی: الگوریتم XGBoost توانسته است با دقت 70-80% جهت حرکت قیمت سهام را پیش‌بینی کند.
  2. عملکرد در مقایسه با سایر روش‌ها: XGBoost عملکرد بهتری نسبت به روش‌های خطی مانند رگرسیون خطی و مشابهی با Random Forest دارد.
  3. اهمیت ویژگی‌ها: اندیکاتورهای تکنیکال مانند RSI، MACD و میانگین‌های متحرک بیشترین تأثیر را در پیش‌بینی دارند.

11.2 محدودیت‌ها

  • عدم در نظر گرفتن عوامل بنیادی: مدل فقط بر اساس داده‌های تکنیکال عمل می‌کند
  • حساسیت به تغییرات ساختاری بازار: مدل در شرایط بحرانی ممکن است عملکرد ضعیفی داشته باشد
  • نیاز به داده‌های با کیفیت بالا: عملکرد مدل به شدت به کیفیت داده‌ها وابسته است

11.3 پیشنهادات برای تحقیقات آینده

  1. ترکیب با تحلیل احساسات: استفاده از داده‌های شبکه‌های اجتماعی و اخبار
  2. استفاده از معماری‌های هیبرید: ترکیب XGBoost با شبکه‌های عصبی عمیق
  3. بهینه‌سازی پورتفولیو: استفاده از مدل برای بهینه‌سازی سبد سهام
  4. پیش‌بینی چندگامه: توسعه مدل برای پیش‌بینی افق‌های زمانی مختلف

12. کد کامل پروژه

class StockPricePredictor:
    """
    کلاس جامع برای پیش‌بینی قیمت سهام با XGBoost
    """
    
    def __init__(self, symbol, start_date, end_date):
        self.symbol = symbol
        self.start_date = start_date
        self.end_date = end_date
        self.model = None
        self.scaler = None
        self.feature_cols = None
        
    def fetch_and_prepare_data(self):
        """دریافت و آماده‌سازی داده‌ها"""
        self.data = fetch_stock_data(self.symbol, self.start_date, self.end_date)
        self.data = calculate_technical_indicators(self.data)
        
    def train_model(self, test_size=0.2, val_size=0.2):
        """آموزش مدل"""
        # آماده‌سازی داده‌ها
        X, y, self.feature_cols = prepare_data_for_modeling(self.data)
        
        # تقسیم داده‌ها
        X_train, X_val, X_test, y_train, y_val, y_test, self.scaler = \
            split_and_scale_data(X, y, test_size, val_size)
        
        # آموزش مدل
        self.model = train_xgboost_model(X_train, y_train, X_val, y_val)
        
        # ذخیره نتایج
        self.X_test = X_test
        self.y_test = y_test
        
        return self.model
    
    def predict(self, X):
        """پیش‌بینی قیمت"""
        if self.model is None:
            raise ValueError("مدل هنوز آموزش ندیده است!")
        
        X_scaled = self.scaler.transform(X)
        return self.model.predict(X_scaled)
    
    def evaluate(self):
        """ارزیابی مدل"""
        predictions = self.predict(self.X_test)
        return evaluate_model(self.y_test, predictions, "Test Set")
    
    def create_trading_signals(self):
        """ایجاد سیگنال‌های معاملاتی"""
        return create_trading_strategy(self.model, self.X_test, self.y_test)
    
    def save_model(self, filepath):
        """ذخیره مدل"""
        import joblib
        joblib.dump({
            'model': self.model,
            'scaler': self.scaler,
            'feature_cols': self.feature_cols
        }, filepath)
    
    def load_model(self, filepath):
        """بارگذاری مدل"""
        import joblib
        saved_data = joblib.load(filepath)
        self.model = saved_data['model']
        self.scaler = saved_data['scaler']
        self.feature_cols = saved_data['feature_cols']

# استفاده از کلاس
predictor = StockPricePredictor('AAPL', '2020-01-01', '2024-01-01')
predictor.fetch_and_prepare_data()
predictor.train_model()
results = predictor.evaluate()
signals = predictor.create_trading_signals()

13. نتیجه‌گیری

در این مقاله، به بررسی جامع پیاده‌سازی الگوریتم Gradient Boosting و به‌ویژه XGBoost برای پیش‌بینی قیمت سهام پرداختیم. نتایج نشان می‌دهد که این الگوریتم با ترکیب مناسب مهندسی ویژگی، تنظیم هایپرپارامترها و تکنیک‌های منظم‌سازی می‌تواند عملکرد قابل قبولی در پیش‌بینی قیمت سهام داشته باشد.

نکات کلیدی:

  • XGBoost با دقت بالا می‌تواند روند قیمت سهام را پیش‌بینی کند
  • مهندسی ویژگی نقش حیاتی در بهبود عملکرد مدل دارد
  • تنظیم صحیح هایپرپارامترها برای جلوگیری از بیش‌برازش ضروری است
  • ترکیب با سایر تکنیک‌ها می‌تواند عملکرد را بهبود بخشد

این الگوریتم می‌تواند به عنوان یک ابزار کمکی برای تصمیم‌گیری سرمایه‌گذاران استفاده شود، اما نباید تنها معیار تصمیم‌گیری باشد.