*** با توجه به محدودیت های پیش آمده ، در حال حاضر دسترسی به اپلیکیشن برای آی پی های ایرانی امکان پذیر نمی باشد . ***

چگونه به کمک کد پایتون یک استراتژی معاملاتی را بهینه کنیم؟ ( بهینه سازی استراتژی معاملاتی با پایتون )

راهنمای جامع بهینه‌سازی علمی استراتژی‌های معاملاتی بوسیله ی پایتون : از جستجوی ساده پارامترها تا جلوگیری از اورفیتینگ با اعتبارسنجی پیشرفته و تحلیل Heatmap

بهینه‌سازی استراتژی معاملاتی با پایتون

در مقاله قبلی، “چگونه یک استراتژی ساده را به کمک پایتون بکتست‌گیری کنیم؟“، استراتژی SMA Crossover را پیاده‌سازی کردیم و حتی با افزودن RSI و حد سود/ضرر آن را ارتقا دادیم. اما یک سوال حیاتی باقی می‌ماند: آیا پارامترهای ۲۰ و ۵۰ برای SMA بهترین انتخاب بودند؟ چرا ۱۸ و ۴۵ نباشد؟ یا ۲۲ و ۶۰؟

پاسخ دادن به این سوالات با روش آزمون و خطای دستی کار زمان بری است. اینجاست که بهینه‌سازی خودکار (Automated Optimization) وارد می‌شود. در این مقاله، با استفاده از Python و کتابخانه backtesting.py، یاد می‌گیریم چگونه بهترین پارامترها را برای استراتژی خود به صورت علمی و سیستماتیک پیدا کنیم.

هدف این مقاله: فراتر از حدس و گمان ( استراتژی بهینه شده با پایتون )

ما در این مسیر، بهینه‌سازی را از ساده تا پیچیده پیش می‌بریم:

  • مبانی بهینه‌سازی: چرا و چگونه؟ آشنایی با تابع هدف و فضای پارامتر.
  • بهینه‌سازی تک پارامتر: پیدا کردن بهترین دوره برای SMA بلند وقتی SMA کوتاه ثابت است.
  • بهینه‌سازی چندپارامتر: جستجوی همزمان برای بهترین ترکیب SMA کوتاه و بلند.
  • بهینه‌سازی پیشرفته: اضافه کردن قیود (Constraints) و توابع هدف سفارشی.
  • تحلیل Heatmap: درک رابطه بین پارامترها و جلوگیری از اورفیتینگ.
  • اعتبارسنجی خارج از نمونه: آخرین و مهم‌ترین مرحله برای اطمینان از پایداری نتایج.

در پایان، شما قادر خواهید بود هر استراتژی را بهینه کرده و با اطمینان بیشتری در بازار واقعی به کار بگیرید.

⚠️ هشدار مهم قبل از شروع

اورفیتینگ (Overfitting) بزرگترین دام در بهینه‌سازی است. اورفیتینگ زمانی اتفاق می‌افتد که استراتژی آنقدر به داده‌های تاریخی خاص تنظیم می‌شود که فقط بر روی آن داده‌ها عالی کار می‌کند و در مواجهه با داده‌های جدید (آینده) شکست می‌خورد.

هدف ما بهینه‌سازی هوشمندانه است، نه اورفیت کردن! در طول این مقاله، تکنیک‌های متعددی برای کاهش این خطر یاد خواهیم گرفت.

مبانی بهینه‌سازی: تابع هدف و فضای جستجو

بهینه‌سازی در اصل یک مسئله جستجو است. ما باید در میان هزاران ترکیب ممکن پارامترها، ترکیبی را بیابیم که منجر به بهترین عملکرد شود.

اجزای کلیدی یک فرآیند بهینه‌سازی

عنصر
توضیح
مثال در استراتژی SMA
فضای پارامتر (Parameter Space)
مجموعه تمام مقادیر ممکنی که هر پارامتر می‌تواند بگیرد.
sma_short: [۱۰, ۲۰, ۳۰], sma_long: [۵۰, ۶۰, ۷۰]
تابع هدف (Objective Function)
معیاری که می‌خواهیم آن را بیشینه یا کمینه کنیم.
بازده کل (Return)، نسبت شارپ (Sharpe Ratio)، Profit Factor
قید (Constraint)
شرطی که ترکیبات پارامتر باید آن را ارضا کنند.
sma_long > sma_short (میانگین بلند باید از کوتاه بزرگتر باشد)
الگوریتم جستجو (Search Algorithm)
روشی برای پیمایش فضای پارامتر و یافتن بهینه.
جستجوی شبکه‌ای (Grid Search)، جستجوی تصادفی، الگوریتم‌های تکاملی

کد پایه: استراتژی و داده‌ها

ابتدا استراتژی پایه مقاله قبل (با SL/TP) را بارگذاری و داده‌های جدیدی دانلود می‌کنیم.

				
					
import pandas as pd
import numpy as np
import yfinance as yf
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
import warnings
warnings.filterwarnings('ignore')

# --- تعریف استراتژی پایه SMA با SL/TP (از مقاله قبل) ---
class SMACrossWithSLTP(Strategy):
    """استراتژی SMA Crossover همراه با حد سود و ضرر."""
    n1 = 20  # SMA کوتاه (پارامتر بهینه‌سازی)
    n2 = 50  # SMA بلند (پارامتر بهینه‌سازی)
    tp = 0.15  # حد سود 15% (پارامتر بهینه‌سازی)
    sl = 0.05   # حد ضرر 5% (پارامتر بهینه‌سازی)

    def init(self):
        close = self.data.Close
        self.sma1 = self.I(lambda x: pd.Series(x).rolling(self.n1).mean(), close)
        self.sma2 = self.I(lambda x: pd.Series(x).rolling(self.n2).mean(), close)

    def next(self):
        price = self.data.Close[-1]
        if not self.position and crossover(self.sma1, self.sma2):
            self.buy(sl=price * (1 - self.sl), tp=price * (1 + self.tp))
        elif self.position and crossover(self.sma2, self.sma1):
            self.position.close()

# --- دانلود و تقسیم داده ---
print("📥 آماده‌سازی داده‌ها برای بهینه‌سازی...")
filename = 'BTCUSDT-1d.csv'
full_data = pd.read_csv(filename, parse_dates=True, index_col='timestamp')

# مطمئن شوید داده ها همه ستونهای مورد نیاز برای محاسبات بکتست گیری و بهینه سازی را دارند
# در صورتیکه فایل داده ها ستونهای دیگری داشت، نام آنها را بروزرسانی کنید
full_data.rename(columns={
    'open': 'Open',
    'high': 'High',
    'low': 'Low',
    'close': 'Close',
    'volume': 'Volume'
}, inplace=True)

# تقسیم به دو بخش: آموزش (In-Sample) و تست (Out-of-Sample)
# 70% اول برای آموزش و بهینه‌سازی
# 30% آخر برای اعتبارسنجی نهایی
split_ratio = 0.7
split_index = int(len(full_data) * split_ratio)

train_data = full_data.iloc[:split_index]  # داده آموزش
test_data = full_data.iloc[split_index:]   # داده تست (برای مرحله آخر)

print(f"📊 کل داده‌ها: {len(full_data)} روز")
print(f"📚 داده آموزش (برای بهینه‌سازی): {len(train_data)} روز ({split_ratio*100:.0f}%)")
print(f"🧪 داده تست (برای اعتبارسنجی): {len(test_data)} روز ({(1-split_ratio)*100:.0f}%)")
print(f"📅 آموزش: {train_data.index[0].date()} تا {train_data.index[-1].date()}")
print(f"📅 تست: {test_data.index[0].date()} تا {test_data.index[-1].date()}")
                    
				
			

با اجرای کد بالا، داده های تاریخی از یک فایل CSV خوانده میشوند و سپس به دو بخش آموزش و تست تقسیم میشوند. با اجرای این کُد، شما خروجی زیر را در ترمینال مشاهده خواهید کرد:

تقسیم داده ها به دو بخش آموزش و تست

گام ۱: بهینه‌سازی تک پارامتر (مقدماتی)

بیایید ساده شروع کنیم. فرض می‌کنیم SMA کوتاه را روی ۵۰ روز ثابت نگه داشته‌ایم و می‌خواهیم بهترین مقدار برای SMA بلند (n2) را پیدا کنیم که بیشترین بازده (Return) را ایجاد می‌کند.

📈 منطق این بهینه‌سازی ساده

ما یک حلقه می‌زنیم و استراتژی را با مقادیر مختلف n2 (مثلاً از ۵۵ تا ۲۰۰) اجرا می‌کنیم. سپس خروجی هر اجرا را ذخیره و در پایان، مقداری که بالاترین بازده را داشته، انتخاب می‌کنیم.

تابع هدف: ماکزیمم کردن بازدهی کل

فضای جستجو: n2 = [۵۵, ۶۰, ۶۵, …, ۱۹۵, ۲۰۰]

کد بهینه‌سازی تک پارامتر

				
					
print("\n🚀 شروع بهینه‌سازی تک پارامتر (SMA بلند)")
print("="*60)

# تعریف محدوده مقادیر برای SMA بلند
n2_values = range(55, 205, 5)  # از 55 تا 200 با گام 5
print(f"در حال آزمایش {len(n2_values)} مقدار مختلف برای SMA بلند...")

results = []
for n2 in n2_values:
    # ایجاد یک کلاس استراتژی موقت با پارامتر n2 جاری
    class TempStrategy(SMACrossWithSLTP):
        n1 = 50   # ثابت
        n2 = n2    # متغیر
        sl = 0.05 # ثابت
        tp = 0.15 # ثابت

    # اجرای بکتست با پارامترهای جاری
    bt = Backtest(train_data, TempStrategy,
                  cash=10000000,
                  commission=.002,
                  exclusive_orders=True)

    output = bt.run()
    
    # ذخیره نتایج
    results.append({
        'n2': n2,
        'Return': output['Return [%]'],
        'Sharpe': output.get('Sharpe Ratio', 0),
        'Trades': output['# Trades'],
        'WinRate': output['Win Rate [%]'],
        'MaxDD': output['Max. Drawdown [%]']
    })

# تبدیل نتایج به DataFrame برای تحلیل آسان‌تر
results_df = pd.DataFrame(results)

# یافتن بهترین نتیجه بر اساس Return
best_by_return = results_df.loc[results_df['Return'].idxmax()]

# یافتن بهترین نتیجه بر اساس Sharpe Ratio (معیار بهتر)
best_by_sharpe = results_df.loc[results_df['Sharpe'].idxmax()]

# نمایش نتایج
print("\n🏆 بهترین نتایج:")
print("-"*60)
print(f"🔹 بر اساس بازده بیشتر:")
print(f"   SMA بلند = {int(best_by_return['n2'])} -> Return: {best_by_return['Return']:.2f}%, Sharpe: {best_by_return['Sharpe']:.3f}, Trades: {int(best_by_return['Trades'])}")

print(f"\n🔹 بر اساس نسبت شارپ بهتر (ترجیح داده می‌شود):")
print(f"   SMA بلند = {int(best_by_sharpe['n2'])} -> Return: {best_by_sharpe['Return']:.2f}%, Sharpe: {best_by_sharpe['Sharpe']:.3f}, Trades: {int(best_by_sharpe['Trades'])}")

# نمایش ۱۰ ترکیب برتر
print("\n📋 ۱۰ ترکیب برتر بر اساس نسبت شارپ:")
print("-"*60)
top_10 = results_df.sort_values(by='Sharpe', ascending=False).head(10)
for i, (_, row) in enumerate(top_10.iterrows(), 1):
    print(f"{i:2d}. SMA بلند={int(row['n2']):3d} | Return: {row['Return']:6.2f}% | Sharpe: {row['Sharpe']:5.3f} | Trades: {int(row['Trades']):3d}")

# رسم نمودار رابطه SMA بلند با بازده و نسبت شارپ
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))

# نمودار بازده
ax1.plot(results_df['n2'], results_df['Return'], 'b-', linewidth=1.5, alpha=0.7, label='Return %')
ax1.axvline(x=best_by_return['n2'], color='r', linestyle='--', alpha=0.7, label=f'Optimized (Return) = {best_by_return["n2"]}')
ax1.set_xlabel('Long SMA period (n2)')
ax1.set_ylabel('Return %')
ax1.set_title('Long SMA period relation with strategy return')
ax1.grid(True, alpha=0.3)
ax1.legend()

# نمودار نسبت شارپ
ax2.plot(results_df['n2'], results_df['Sharpe'], 'g-', linewidth=1.5, alpha=0.7, label='Sharpe ratio')
ax2.axvline(x=best_by_sharpe['n2'], color='orange', linestyle='--', alpha=0.7, label=f'Optimized (Sharpe Ratio) = {best_by_sharpe["n2"]}')
ax2.set_xlabel('Long SMA period (n2)')
ax2.set_ylabel('Sharpe Ratio')
ax2.set_title('Long SMA period relation with Sharpe ratio')
ax2.grid(True, alpha=0.3)
ax2.legend()

plt.tight_layout()
plt.savefig('single_param_optimization.png', dpi=150, bbox_inches='tight')
print(f"\n📈 نمودارهای تحلیل در فایل 'single_param_optimization.png' ذخیره شد.")
plt.show()
				
			

با اجرای کد بالا خروجی زیر در ترمینال نمایش داده میشود:

نتایج بهینه سازی ابتدایی

همچنین نمودارهای زیر در ترمینال یا در صفحه وب (بسته به محیط اجرای کد که محیط نوت بوک یا ادیتور کد باشد) به نمایش در می‌آیند:

🔍 تحلیل نتایج بهینه‌سازی تک پارامتر

پس از اجرای کد بالا، به چند نکته مهم پی می‌بریم:

  • معیارهای مختلف، نتایج مختلف می‌دهند: بهترین پارامتر بر اساس Return با بهترین پارامتر بر اساس Sharpe Ratio ممکن است متفاوت باشد. معمولاً Sharpe Ratio معیار بهتری است چون هم سود و هم ریسک (نوسانات) را در نظر می‌گیرد.
  • منحنی‌ها نویزی هستند: نمودار بازده بر حسب n2 یک خط صاف نیست. این نشان می‌دهد که عملکرد استراتژی به شدت به پارامترها حساس است و تغییرات کوچک ممکن است نتایج بزرگ ایجاد کند (علامت خطر برای اورفیتینگ!).
  • اهمیت تعداد معاملات: اگر بهترین پارامتر فقط ۱-۲ معامله انجام داده باشد، نتیجه قابل اعتماد نیست. یک استراتژی خوب باید در بازه تاریخی چندین بار فرصت معاملاتی ایجاد کند.

گام ۲: بهینه‌سازی چندپارامتر با تابع هدف سفارشی

در دنیای واقعی، ما فقط یک پارامتر را تغییر نمی‌دهیم. باید بهترین ترکیب پارامترها را پیدا کنیم. همچنین نیاز داریم تابع هدف پیچیده‌تری تعریف کنیم که چندین فاکتور را همزمان در نظر بگیرد.

تعریف یک تابع هدف هوشمندانه

تابع هدف زیر را در نظر بگیرید که می‌خواهیم آن را ماکزیمم کنیم:

  • Score = (Return %) × (تعداد معاملات) × (نشانگر پایداری)

    که در آن:

    • Return %: بازده کلی استراتژی
    • تعداد معاملات: برای اطمینان از آماری بودن نتایج (اگر کمتر از ۵ معامله باشد، جریمه می‌شود)
    • نشانگر پایداری: تابعی است که اگر Max Drawdown بیشتر از ۲۵٪ باشد، شدیداً جریمه می‌کند.

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

				
					
print("\n🚀 شروع بهینه‌سازی دوپارامتر با تابع هدف سفارشی")
print("="*70)

def custom_objective_function(output):
    """
    تابع هدف سفارشی برای بهینه‌سازی.
    ترکیبی از بازده، تعداد معاملات و کنترل ریسک.
    """
    return_pct = output['Return [%]']
    num_trades = output['# Trades']
    max_dd = output['Max. Drawdown [%]']
    sharpe = output.get('Sharpe Ratio', 0)
    
    # 1. جریمه برای تعداد معاملات کم (کمتر از 5 معامله غیرقابل اعتماد است)
    if num_trades < 5:
        trade_penalty = 0.1  # جریمه 90%
    elif num_trades < 10:
        trade_penalty = 0.5  # جریمه 50%
    else:
        trade_penalty = 1.0  # بدون جریمه
    
    # 2. جریمه برای افت سرمایه زیاد
    if max_dd > 30:
        dd_penalty = 0.1   # افت بیشتر از 30%: جریمه 90%
    elif max_dd > 20:
        dd_penalty = 0.5   # افت بین 20-30%: جریمه 50%
    else:
        dd_penalty = 1.0   # افت کمتر از 20%: بدون جریمه
    
    # 3. پاداش برای نسبت شارپ خوب
    if sharpe > 1.5:
        sharpe_bonus = 1.5
    elif sharpe > 1.0:
        sharpe_bonus = 1.2
    else:
        sharpe_bonus = 1.0
    
    # محاسبه نمره نهایی
    # می‌توانیم از ترکیب ضربی یا جمعی استفاده کنیم
    score = return_pct * trade_penalty * dd_penalty * sharpe_bonus
    
    return score

# محدوده پارامترها برای جستجو
n1_range = range(10, 41, 5)   # SMA کوتاه: 10, 15, 20, 25, 30, 35, 40
n2_range = range(50, 121, 10) # SMA بلند: 50, 60, 70, 80, 90, 100, 110, 120

print(f"در حال آزمایش {len(n1_range)} × {len(n2_range)} = {len(n1_range)*len(n2_range)} ترکیب پارامتر...")

multi_results = []
for n1 in n1_range:
    for n2 in n2_range:
        # اعمال قید: SMA بلند باید بزرگتر از SMA کوتاه باشد
        if n2 <= n1:
            continue
        
        class TempStrategy(SMACrossWithSLTP):
            n1 = n1
            n2 = n2
            sl = 0.05
            tp = 0.15
        
        bt = Backtest(train_data, TempStrategy,
                      cash=10000000,
                      commission=.002)
        
        output = bt.run()
        score = custom_objective_function(output)
        
        multi_results.append({
            'n1': n1,
            'n2': n2,
            'Score': score,
            'Return': output['Return [%]'],
            'Sharpe': output.get('Sharpe Ratio', 0),
            'Trades': output['# Trades'],
            'MaxDD': output['Max. Drawdown [%]']
        })

multi_df = pd.DataFrame(multi_results)

# یافتن بهترین ترکیب بر اساس نمره سفارشی
best_custom = multi_df.loc[multi_df['Score'].idxmax()]

print("\n🏆 بهترین ترکیب پارامترها (بر اساس تابع هدف سفارشی):")
print("="*70)
print(f"✅ SMA کوتاه (n1) = {int(best_custom['n1'])}")
print(f"✅ SMA بلند (n2)  = {int(best_custom['n2'])}")
print(f"📊 نمره سفارشی: {best_custom['Score']:.2f}")
print(f"📈 بازده: {best_custom['Return']:.2f}%")
print(f"⚖️  نسبت شارپ: {best_custom['Sharpe']:.3f}")
print(f"🔢 تعداد معاملات: {int(best_custom['Trades'])}")
print(f"😨 حداکثر افت سرمایه: {best_custom['MaxDD']:.2f}%")

# نمایش ۱۵ ترکیب برتر
print("\n📋 ۱۵ ترکیب برتر بر اساس نمره سفارشی:")
print("-"*70)
top_15_custom = multi_df.sort_values(by='Score', ascending=False).head(15)
for i, (_, row) in enumerate(top_15_custom.iterrows(), 1):
    print(f"{i:2d}. SMA({row['n1']:3f}/{row['n2']:3f}) | Score: {row['Score']:7.2f} | Return: {row['Return']:6.2f}% | Trades: {int(row['Trades']):3d}")
				
			

با اجرای کد بالا خروجی زیر در ترمینال نمایش داده میشود:

نتایج بهینه سازی استراتژی معاملاتی با تابع هدف دلخواه

مزایای تابع هدف سفارشی

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

گام ۳: بهینه‌سازی پیشرفته با backtesting.py و تحلیل Heatmap

کتابخانه backtesting.py دارای یک تابع بهینه‌سازی داخلی بسیار قدرتمند به نام bt.optimize() است. این تابع نه تنها جستجو را انجام می‌دهد، بلکه خروجی‌های مفیدی مانند Heatmap نیز تولید می‌کند.

کد بهینه‌سازی چهارپارامتر با قیود

این بار چهار پارامتر (n1, n2, sl, tp) را همزمان بهینه می‌کنیم و از قیود منطقی استفاده می‌کنیم.

				
					
print("\n🚀 شروع بهینه‌سازی پیشرفته چهارپارامتر با Heatmap")
print("="*80)

# 1. ایجاد موتور بکتست
bt = Backtest(train_data, SMACrossWithSLTP,
                cash=10000000,
                commission=.002,
                exclusive_orders=True)

# 2. تعریف فضای پارامترها برای بهینه‌سازی
# می‌توان از range، لیست یا tuple استفاده کرد
param_grid = {
    'n1': range(10, 35, 5),   # 10, 15, 20, 25, 30
    'n2': range(40, 110, 10), # 40, 50, 60, 70, 80, 90, 100
    'sl': [0.03, 0.05, 0.07, 0.10],  # حد ضرر: 3%, 5%, 7%, 10%
    'tp': [0.10, 0.15, 0.20, 0.25]   # حد سود: 10%, 15%, 20%, 25%
}

# 3. محاسبه تعداد کل ترکیبات
total_combinations = 1
for key in param_grid:
    total_combinations *= len(param_grid[key])

print(f"📊 فضای جستجو: {total_combinations} ترکیب پارامتر ممکن")
print("⏳ در حال اجرای بهینه‌سازی (این مرحله ممکن است چند دقیقه طول بکشد)...")

# 4. اجرای بهینه‌سازی
# maximize: معیاری که می‌خواهیم ماکزیمم شود
# constraint: قیدهایی که پارامترها باید رعایت کنند
# return_heatmap: برای تولید Heatmap
# max_tries: محدود کردن تعداد تست‌ها برای سرعت بیشتر (اختیاری)
optimization_stats, heatmap = bt.optimize(
    **param_grid,
    maximize='Sharpe Ratio',  # هدف: ماکزیمم کردن نسبت شارپ
    constraint=lambda p: p.n2 > p.n1,  # SMA بلند > SMA کوتاه
    return_heatmap=True,
    max_tries=500,  # فقط ۵۰۰ ترکیب را تست کن (برای سرعت)
    random_state=42   # برای تکرارپذیری نتایج
)

print("✅ بهینه‌سازی تکمیل شد!")

# 5. نمایش بهترین پارامترهای یافت شده
print("\n" + "="*80)
print("🎯 بهترین پارامترهای یافت شده:")
print("="*80)
print(f"📊 SMA کوتاه (n1): {optimization_stats['_strategy'].n1}")
print(f"📊 SMA بلند (n2): {optimization_stats['_strategy'].n2}")
print(f"🛑 حد ضرر (SL): {optimization_stats['_strategy'].sl*100:.1f}%")
print(f"🎯 حد سود (TP): {optimization_stats['_strategy'].tp*100:.1f}%")
print(f"\n📈 عملکرد با پارامترهای بهینه:")
print(f"   بازده: {optimization_stats['Return [%]']:.2f}%")
print(f"   نسبت شارپ: {optimization_stats['Sharpe Ratio']:.3f}")
print(f"   حداکثر افت سرمایه: {optimization_stats['Max. Drawdown [%]']:.2f}%")
print(f"   تعداد معاملات: {optimization_stats['# Trades']}")
print(f"   Win Rate: {optimization_stats['Win Rate [%]']:.1f}%")

# 6. تحلیل Heatmap
print("\n" + "="*80)
print("🔥 تحلیل Heatmap")
print("="*80)

if heatmap is not None and len(heatmap) > 0:
    # Convert heatmap to DataFrame if it's a Series
    if isinstance(heatmap, pd.Series):
        print("⚠️  Heatmap به صورت Series بازگشته است. در حال تبدیل به DataFrame...")
        # Convert Series to DataFrame
        heatmap_df = heatmap.to_frame('Sharpe Ratio').reset_index()
        # Rename columns appropriately
        heatmap_df.columns = ['n1', 'n2', 'sl', 'tp', 'Sharpe Ratio']
        # For backward compatibility, we'll use this as our main heatmap object
        heatmap = heatmap_df
        print(f"✅ تبدیل انجام شد. Heatmap شامل {len(heatmap)} ترکیب پارامتر است.")
    elif isinstance(heatmap, pd.DataFrame):
        print(f"📊 Heatmap شامل {len(heatmap)} ترکیب پارامتر تست شده است.")
    else:
        print(f"❌ نوع داده Heatmap نامشخص است: {type(heatmap)}")
        heatmap = pd.DataFrame()  # Create empty DataFrame to avoid further errors
    
    # Only proceed if we have data
    if len(heatmap) > 0:
        # مرتب کردن بر اساس نسبت شارپ
        # Check if 'Sharpe Ratio' column exists
        if 'Sharpe Ratio' in heatmap.columns:
            heatmap_sorted = heatmap.sort_values(by='Sharpe Ratio', ascending=False)
        else:
            # If Sharpe Ratio is in the index or Series values
            heatmap_sorted = heatmap.sort_values(ascending=False) if isinstance(heatmap, pd.Series) else heatmap
        
        # نمایش ۱۰ ترکیب برتر از Heatmap
        print("\n🏆 ۱۰ ترکیب برتر از Heatmap (بر اساس Sharpe Ratio):")
        print("-"*80)

        # Display top 10 results
        for i in range(min(10, len(heatmap_sorted))):
            if isinstance(heatmap_sorted, pd.DataFrame):
                row = heatmap_sorted.iloc[i]
                # Check if parameters are in columns or index
                if 'n1' in heatmap_sorted.columns:
                    n1 = row['n1']
                    n2 = row['n2']
                    sl = row['sl'] if 'sl' in row else row.get('sl', 0)
                    tp = row['tp'] if 'tp' in row else row.get('tp', 0)
                    sharpe = row['Sharpe Ratio'] if 'Sharpe Ratio' in row else row[0]
                    returns = row['Return [%]'] if 'Return [%]' in row else 'N/A'
                else:
                    # Parameters might be in the index
                    params = row.name
                    n1, n2, sl, tp = params
                    sharpe = row['Sharpe Ratio'] if 'Sharpe Ratio' in row else row[0]
                    returns = row['Return [%]'] if 'Return [%]' in row else 'N/A'
            else:
                # If it's a Series
                params = heatmap_sorted.index[i]
                if isinstance(params, tuple) and len(params) >= 4:
                    n1, n2, sl, tp = params[:4]
                else:
                    n1, n2, sl, tp = i, i, 0, 0
                sharpe = heatmap_sorted.iloc[i]
                returns = 'N/A'
            
            print(f"{i+1:2d}. SMA({int(n1):2d}/{int(n2):3d}) SL:{float(sl)*100:4.1f}% TP:{float(tp)*100:5.1f}% | Sharpe: {float(sharpe):.3f}")
        
        # محاسبه پراکندگی نتایج (برای تشخیص اورفیتینگ)
        try:
            if isinstance(heatmap, pd.DataFrame) and 'Sharpe Ratio' in heatmap.columns:
                sharpe_values = heatmap['Sharpe Ratio']
                sharpe_std = sharpe_values.std()
            else:
                sharpe_values = heatmap if isinstance(heatmap, pd.Series) else None
                sharpe_std = sharpe_values.std() if sharpe_values is not None else 0
            
            print(f"\n📐 پراکندگی نتایج در Heatmap:")
            print(f"   انحراف معیار Sharpe Ratio: {sharpe_std:.3f}")
            
            # اگر انحراف معیار بسیار بالا باشد، نشانه حساسیت زیاد به پارامترهاست (خطر اورفیتینگ)
            if sharpe_std > 0.5:
                print("   ⚠️  هشدار: پراکندگی Sharpe بالا است. استراتژی ممکن است به پارامترها بیش از حد حساس باشد.")
            else:
                print("   ✅ پراکندگی متوسط است. استراتژی از پایداری نسبی برخوردار است.")
        except Exception as e:
            print(f"   ⚠️  خطا در محاسبه پراکندگی: {e}")
        
        # 7. ایجاد Heatmap مصور برای دو پارامتر اصلی (n1, n2)
        print("\n🎨 در حال ایجاد Heatmap مصور برای SMA کوتاه و بلند...")
        
        try:
            # استخراج نتایج برای n1 و n2 (با میانگین‌گیری روی sl و tp)
            simple_heatmap_data = []
            
            # Extract data based on heatmap type
            if isinstance(heatmap, pd.DataFrame):
                for idx, row in heatmap.iterrows():
                    if isinstance(idx, tuple) and len(idx) >= 4:
                        # Parameters are in the index
                        n1, n2, sl, tp = idx[:4]
                        sharpe = row['Sharpe Ratio'] if 'Sharpe Ratio' in row else row[0]
                        returns = row['Return [%]'] if 'Return [%]' in row else 0
                    else:
                        # Parameters are in columns
                        n1 = row['n1'] if 'n1' in row else 0
                        n2 = row['n2'] if 'n2' in row else 0
                        sl = row['sl'] if 'sl' in row else 0
                        tp = row['tp'] if 'tp' in row else 0
                        sharpe = row['Sharpe Ratio'] if 'Sharpe Ratio' in row else row[0]
                        returns = row['Return [%]'] if 'Return [%]' in row else 0
                    
                    simple_heatmap_data.append({
                        'n1': n1,
                        'n2': n2,
                        'Sharpe': sharpe,
                        'Return': returns
                    })
            else:
                # If heatmap is a Series
                for (n1, n2, sl, tp), sharpe in heatmap.items():
                    simple_heatmap_data.append({
                        'n1': n1,
                        'n2': n2,
                        'Sharpe': sharpe,
                        'Return': 0  # Return data not available in Series
                    })
            
            if simple_heatmap_data:
                simple_df = pd.DataFrame(simple_heatmap_data)
                
                # محاسبه میانگین برای هر ترکیب n1, n2
                pivot_sharpe = simple_df.pivot_table(values='Sharpe', index='n1', columns='n2', aggfunc='mean')
                
                # رسم Heatmap
                fig, ax1 = plt.subplots(1, 1, figsize=(10, 8))
                
                # Heatmap برای Sharpe Ratio
                im1 = ax1.imshow(pivot_sharpe.values, cmap='RdYlGn', aspect='auto')
                ax1.set_xticks(range(len(pivot_sharpe.columns)))
                ax1.set_xticklabels([str(int(col)) for col in pivot_sharpe.columns])
                ax1.set_yticks(range(len(pivot_sharpe.index)))
                ax1.set_yticklabels([str(int(row)) for row in pivot_sharpe.index])
                ax1.set_xlabel('Long SMA (n2)')
                ax1.set_ylabel('Short SMA (n1)')
                ax1.set_title('Heatmap: Sharpe ratio average based on SMA parameters')
                plt.colorbar(im1, ax=ax1, label='Sharpe Ratio')
                
                # اضافه کردن اعداد در هر خانه
                for i in range(len(pivot_sharpe.index)):
                    for j in range(len(pivot_sharpe.columns)):
                        ax1.text(j, i, f"{pivot_sharpe.iloc[i, j]:.2f}",
                                ha="center", va="center", color="black", fontsize=8)
                
                plt.tight_layout()
                plt.savefig('heatmap_analysis.png', dpi=150, bbox_inches='tight')
                print(f"📈 Heatmap مصور در فایل 'heatmap_analysis.png' ذخیره شد.")
                plt.show()
            else:
                print("❌ داده‌ای برای ایجاد Heatmap وجود ندارد.")
                
        except Exception as e:
            print(f"❌ خطا در ایجاد Heatmap مصور: {e}")
            import traceback
            traceback.print_exc()
    
else:
    print("❌ Heatmap تولید نشد یا خالی است.")
				
			

با اجرای کد بالا خروجی زیر در ترمینال نمایش داده میشود:

نتایج بهینه سازی استراتژی معاملاتی با افزودن قید در پایتون

و نقشه گرمایی زیر برای ترکیب پارامترها و مقدار sharpe ratio در خروجی نمایش داده میشود:

نتایج بهینه سازی استراتژی معاملاتی با افزودن قید در پایتون

🔍 چگونه Heatmap به ما در جلوگیری از اورفیتینگ کمک می‌کند؟

Heatmap یک ابزار تصویری قدرتمند است که می‌تواند خطرات اورفیتینگ را نشان دهد:

  • مناطق پایدار (سبز روشن بزرگ): اگر یک ناحیه گسترده از ترکیبات پارامتر نتایج خوبی نشان دهد، استراتژی پایدار است.
  • نقاط داغ ایزوله (قرمز کوچک): اگر فقط یک یا دو ترکیب خاص نتیجه عالی داشته باشند و اطرافشان نتایج ضعیفی باشد، احتمال اورفیتینگ زیاد است.
  • الگوهای منطقی: Heatmap باید الگوهای منطقی نشان دهد (مثلاً با افزایش دوره میانگین متحرک بلند، Sharpe کاهش یابد). الگوهای تصادفی و نویزی نشانه اورفیتینگ است.
  • پراکندگی بالا: اگر انحراف معیار Sharpe در Heatmap بالا باشد (> ۰.۵)، استراتژی به پارامترها بیش از حد حساس است.

یک استراتژی خوب باید در یک ناحیه از فضای پارامتر خوب عمل کند، نه فقط در یک نقطه خاص.

گام ۴: اعتبارسنجی نهایی روی داده خارج از نمونه

این مهم‌ترین مرحله است. پارامترهای بهینه‌شده روی داده آموزش (In-Sample) را روی داده‌ای که هرگز در فرآیند بهینه‌سازی استفاده نشده (Out-of-Sample) تست می‌کنیم.

کد اعتبارسنجی و مقایسه عملکرد

				
					
print("\n🔬 مرحله نهایی: اعتبارسنجی روی داده خارج از نمونه")
print("="*80)

# 1. ایجاد استراتژی با پارامترهای بهینه شده
OptimizedStrategy = type('OptimizedStrategy', (SMACrossWithSLTP,), {
    'n1': optimization_stats._strategy.n1,
    'n2': optimization_stats._strategy.n2,
    'sl': optimization_stats._strategy.sl,
    'tp': optimization_stats._strategy.tp
})

# 2. اجرای استراتژی بهینه شده روی داده TEST (خارج از نمونه)
print("🧪 در حال اجرای استراتژی بهینه شده روی داده تست (Out-of-Sample)...")
bt_test = Backtest(test_data, OptimizedStrategy,
                   cash=10000000,
                   commission=.002,
                   exclusive_orders=True)

test_results = bt_test.run()

# 3. اجرای استراتژی با پارامترهای اولیه (بدون بهینه‌سازی) روی داده TEST
print("🔄 در حال اجرای استراتژی اولیه (پارامترهای دستی) روی داده تست...")
OriginalStrategy = type('OriginalStrategy', (SMACrossWithSLTP,), {
    'n1': 20,
    'n2': 50,
    'sl': 0.05,
    'tp': 0.15
})

bt_original = Backtest(test_data, OriginalStrategy,
                       cash=10000000,
                       commission=.002,
                       exclusive_orders=True)

original_results = bt_original.run()

# 4. مقایسه جامع نتایج
print("\n" + "="*80)
print("📊 مقایسه نهایی: عملکرد در داده خارج از نمونه")
print("="*80)

comparison_data = []
metrics_to_compare = ['Return [%]', 'Sharpe Ratio', 'Max. Drawdown [%]',
                      '# Trades', 'Win Rate [%]', 'Profit Factor']

for metric in metrics_to_compare:
    original_val = original_results.get(metric, 0)
    optimized_val = test_results.get(metric, 0)
    
    # محاسبه درصد تغییر
    if isinstance(original_val, (int, float)) and original_val != 0:
        change_pct = ((optimized_val - original_val) / abs(original_val)) * 100
    else:
        change_pct = 0
    
    comparison_data.append({
        'Metric': metric,
        'Original': original_val,
        'Optimized': optimized_val,
        'Change %': change_pct
    })

comparison_df = pd.DataFrame(comparison_data)

# نمایش جدول مقایسه
print(f"\n{'Factor':<25} {'Initial':<12} {'Optimized':<12} {'Change %':<10}")
print("-"*60)
for _, row in comparison_df.iterrows():
    metric_name = row['Metric']
    
    # فرمت‌بندی مناسب برای هر معیار
    if '%' in metric_name:
        original_fmt = f"{row['Original']:.2f}%"
        optimized_fmt = f"{row['Optimized']:.2f}%"
    elif metric_name == 'Sharpe Ratio' or metric_name == 'Profit Factor':
        original_fmt = f"{row['Original']:.3f}"
        optimized_fmt = f"{row['Optimized']:.3f}"
    else:
        original_fmt = f"{row['Original']:.0f}"
        optimized_fmt = f"{row['Optimized']:.0f}"
    
    change_fmt = f"{row['Change %']:+.1f}%"
    
    # تعیین رنگ/نماد بر اساس تغییر
    if 'Drawdown' in metric_name:
        # برای Drawdown، کاهش بهتر است
        symbol = "✅" if row['Change %'] < 0 else "⚠️"
    else:
        # برای سایر معیارها، افزایش بهتر است
        symbol = "✅" if row['Change %'] > 0 else "⚠️"
    
    print(f"{symbol} {metric_name:<22} {original_fmt:<12} {optimized_fmt:<12} {change_fmt:<10}")

# 5. محاسبه افت عملکرد (Degradation) - شاخص اصلی اورفیتینگ
# افت عملکرد = (عملکرد در تست) / (عملکرد در آموزش) - 1
train_sharpe = optimization_stats.get('Sharpe Ratio', 0)
test_sharpe = test_results.get('Sharpe Ratio', 0)
train_return = optimization_stats.get('Return [%]', 0)
test_return = test_results.get('Return [%]', 0)

if train_sharpe != 0:
    sharpe_degradation = ((test_sharpe - train_sharpe) / abs(train_sharpe)) * 100
else:
    sharpe_degradation = 0

if train_return != 0:
    return_degradation = ((test_return - train_return) / abs(train_return)) * 100
else:
    return_degradation = 0

print("\n" + "="*80)
print("📉 تحلیل افت عملکرد (Degradation Analysis)")
print("="*80)
print(f"Sharpe Ratio در داده آموزش: {train_sharpe:.3f}")
print(f"Sharpe Ratio در داده تست: {test_sharpe:.3f}")
print(f"📊 افت عملکرد Sharpe: {sharpe_degradation:.1f}%")

# 6. نتیجه‌گیری نهایی درباره اورفیتینگ
print("\n" + "="*80)
print("🎯 نتیجه‌گیری: آیا استراتژی اورفیت شده است؟")
print("="*80)

if sharpe_degradation > -30 :
    print("✅ وضعیت: خوب - افت عملکرد قابل قبول است.")
    print("   استراتژی بهینه‌شده در داده جدید نیز عملکرد نسبتاً خوبی دارد.")
    print("   احتمال اورفیتینگ کم است. می‌توان با احتیاط در بازار واقعی استفاده کرد.")
elif sharpe_degradation > -50 :
    print("⚠️ وضعیت: متوسط - افت عملکرد قابل توجه است.")
    print("   استراتژی ممکن است تا حدی اورفیت شده باشد.")
    print("   نیاز به بررسی بیشتر و احتمالاً استفاده از پارامترهای محافظه‌کارانه‌تر.")
else:
    print("❌ وضعیت: ضعیف - افت عملکرد شدید است.")
    print("   استراتژی به شدت اورفیت شده است.")
    print("   پارامترهای بهینه فقط روی داده آموزش کار می‌کنند.")
    print("   نباید در بازار واقعی استفاده شود.")

# 7. ذخیره تمام نتایج در یک فایل گزارش
import json
report = {
    'optimization_parameters': {
        'n1': int(optimization_stats._strategy.n1),
        'n2': int(optimization_stats._strategy.n2),
        'sl': optimization_stats._strategy.sl,
        'tp': optimization_stats._strategy.tp
    },
    'in_sample_performance': {
        k: (float(v) if isinstance(v, (int, float)) else v)
        for k, v in optimization_stats.items()
        if not k.startswith('_')
    },
    'out_of_sample_performance': {
        k: (float(v) if isinstance(v, (int, float)) else v)
        for k, v in test_results.items()
        if not k.startswith('_')
    },
    'degradation_analysis': {
        'sharpe_degradation_pct': sharpe_degradation,
        'return_degradation_pct': return_degradation
    },
    'data_info': {
        'train_period': f"{train_data.index[0].date()} to {train_data.index[-1].date()}",
        'test_period': f"{test_data.index[0].date()} to {test_data.index[-1].date()}",
        'symbol': "GOOGL"
    }
}

from datetime import datetime
report_filename = f"optimization_final_report_{datetime.now().strftime('%Y%m%d_%H%M')}.json"
with open(report_filename, 'w') as f:
    json.dump(report, f, indent=4, default=str)

print(f"\n💾 گزارش کامل با تمام جزئیات در فایل JSON '{report_filename}' ذخیره شد.")
print("\n✨ فرآیند بهینه‌سازی و اعتبارسنجی با موفقیت به پایان رسید!")
                    
				
			

با اجرای کد بالا خروجی زیر در ترمینال نمایش داده میشود:

نتایج بهینه سازی استراتژی معاملاتی روی داده های تست

چطور در تریدبرد استراتژی خود را بهینه کنیم؟

ابزارهای بهینه‌سازی در تریدبرد

خبر خوب این که ما در تریدبرد همه این ابزارهای حرفه‌ای را در اختیار شما گذاشته‌ایم:

⚙️
ابزار بهینه‌سازی پیشرفته

می‌توانید چندین پارامتر را همزمان تست کنید و “منطقه طلایی” را پیدا کنید.

📊
تقسیم داده‌ها

شما با مشاهده تاریخهای در دسترس برای هر نماد، میتوانید بکتست را به دو یا چند قسمت از نظر بازه زمانی تقسیم کنید. یک بازه زمانی را همواره برای تست استراتژی بهینه شده کنار بگذارید.

📈
گزارش‌های آماری کامل

تمام معیارهای مهم از نسبت شارپ گرفته تا حداکثر افت سرمایه را به طور خودکار محاسبه می‌کنیم.

🌍
تست روی چندین بازار

می‌توانید استراتژی بهینه‌شده خود را همزمان روی بازارهای مختلف (کریپتو، فارکس، بورس ایران، طلا) تست کنید تا از پایداری آن مطمئن شوید.

گزارش جامع بکتست گیری در تریدبرد

گزارش جامع بکتست گیری در تریدبرد - نمایش معیارهای مختلف آماری

یک مثال عملی از بهینه‌سازی استراتژی معاملاتی بوسیله ی پایتون

1

استراتژی اولیه

“اگر RSI به زیر ۳۰ برود، بخر.”

2

بهینه‌سازی اولیه

تست می‌کنید و می‌بینید سطح ۲۵ بهتر از ۳۰ جواب می‌دهد.

3

بهینه‌سازی پیشرفته

تست می‌کنید و می‌بینید “اگر RSI به زیر ۲۵ برود و حجم معاملات ۲۰٪ بالاتر از میانگین ۱۰ روزه باشد” نتیجه بسیار بهتری دارد.

4

بهینه‌سازی حرفه‌ای

تست روی داده‌های خارج از نمونه نشان می‌دهد این استراتژی بهینه‌شده نه تنها در داده‌های جدید هم جواب می‌دهد، بلکه در بازارهای مختلف (هم کریپتو و هم طلا) عملکرد پایدار دارد.

کاربران حرفه ای تریدبرد میتوانند درخواست بهینه سازی استراتژی های ساخته شده خود را با مشخص کردن پارامترها و بازه مدنظرشان، بصورت تیکت پشتیبانی در پلتفرم ثبت کنند تا کارشناسان ما در اولین فرصت نتیجه بهینه سازی استراتژی روی پارارمترهای مشخص شده را برای آنها ارسال کنند. این نتیجه بصورت یک گزارش جامع و کامل همراه با نمودارهای گرافیکی خروجی استراتژی به ازای ترکیبات مختلف از پارامترها خواهد بود.

برای آشنایی بیشتر با پلتفرم معاملاتی تریدبرد میتوانید از اینجا فیلم آموزشی تهیه شده را مشاهده نمایید .

بخشی از گزارش جامع بهینه سازی در تریدبرد

بخشی از گزارش جامع بهسنه سازی در تریدبرد - نمایش سود نهایی استراتژی به ازا یترکیب های مختلف سه پارامتر مختلف

جمع‌بندی: چک‌لیست یک بهینه‌سازی اصولی

✅ مراحل ضروری یک بهینه‌سازی معتبر

1

تقسیم داده

داده‌ها را به دو بخش آموزش (70-80%) و تست (20-30%) تقسیم کنید. فقط از داده آموزش برای بهینه‌سازی استفاده کنید.

2

تعریف تابع هدف هوشمند

تابع هدف باید چندبعدی باشد (مثلاً ترکیبی از بازده، ریسک و تعداد معاملات). از ماکزیمم کردن صرف بازده خودداری کنید.

3

اعمال قیود منطقی

قیودی مثل n2 > n1 یا تعداد معاملات ≥ ۵ اعمال کنید تا جستجو در مسیر منطقی باشد.

4

تحلیل Heatmap

Heatmap را بررسی کنید. به دنبال نواحی پایدار باشید، نه نقاط داغ ایزوله.

5

اعتبارسنجی خارج از نمونه

پارامترهای بهینه را روی داده تست اجرا کنید. افت عملکرد (Degradation) کمتر از ۳۰-۴۰٪ قابل قبول است.

6

تست روی چندین نماد/بازه

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

۱۰ اشتباه رایج در بهینه‌سازی و راه‌حل آن‌ها

اشتباه
توضیح
مثال در استراتژی SMA
عدم تقسیم داده
اورفیتینگ قطعی
همیشه داده را به آموزش و تست تقسیم کنید
فضای پارامتر بسیار بزرگ
اورفیتینگ و زمان اجرای طولانی
از محدوده‌های معقول و گام‌های بزرگتر شروع کنید
ماکزیمم کردن صرف بازده
انتخاب استراتژی‌های پرریسک
از معیارهای ترکیبی مثل Sharpe Ratio استفاده کنید
نادیده گرفتن تعداد معاملات
نتایج غیرآماری
ترکیبات با معاملات کم را جریمه یا حذف کنید
استفاده از یک بازه زمانی کوتاه
عدم پوشش انواع شرایط بازار
حداقل ۳-۵ سال داده برای بهینه‌سازی استفاده کنید

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

❓ آیا بهینه‌سازی همیشه منجر به استراتژی بهتر می‌شود؟

خیر. بهینه‌سازی فقط بهترین پارامترها را برای داده گذشته پیدا می‌کند. اگر استراتژی اساساً معیوب باشد یا بازار تغییر کرده باشد، بهینه‌سازی کمکی نمی‌کند. بهینه‌سازی یک ابزار است، نه جادو!

❓ هر چند وقت یکبار باید استراتژی را دوباره بهینه کرد؟

بستگی به استراتژی دارد. برای استراتژی‌های کوتاه‌مدت (اسکالپینگ)بهینه‌سازی ممکن است ماهانه مورد نیاز باشد، در حالی که استراتژی‌های میان‌مدت تا بلندمدت ممکن است به صورت فصلی یا سالانه اجرا شوند. قاعده کلی: وقتی عملکرد استراتژی به طور مداوم منحرف می‌شود یا شرایط بازار به شدت تغییر کرده است.

❓ آیا می‌توان همه پارامترها را همزمان بهینه کرد؟

از نظر فنی بله، اما عملاً خطر اورفیتینگ زیاد می‌شود. بهتر است ابتدا پارامترهای اصلی را بهینه کنید، سپس پارامترهای فرعی. همچنین می‌توانید از تکنیک‌هایی مانند بهینه‌سازی گام به گام استفاده کنید.

❓ تفاوت Grid Search با Random Search چیست؟

Grid Search: همه ترکیبات ممکن را تست می‌کند. کامل اما کند.
Random Search: ترکیبات را تصادفی انتخاب می‌کند. سریع‌تر و اغلب برای فضای پارامتر بزرگ بهتر است.
کتابخانه backtesting.py از ترکیبی از هر دو استفاده می‌کند.

نتیجه‌گیری: هنر و علم بهینه‌سازی

بهینه‌سازی استراتژی معاملاتی یک فرآیند علمی است که نیاز به هنر و قضاوت دارد. در این مقاله آموختیم که:

  • بهینه‌سازی تنها نقطه شروع است، نه پایان کار. پارامترهای بهینه شده باید همواره تحت نظارت باشند.
  • اورفیتینگ دشمن اصلی است و می‌توان با اعتبارسنجی خارج از نمونه و تحلیل Heatmap از آن جلوگیری کرد.
  • تابع هدف هوشمندانه باید ترکیبی از سودآوری، ریسک و قابلیت اطمینان باشد.
  • یک استراتژی خوب در یک ناحیه از فضای پارامتر خوب عمل می‌کند، نه فقط در یک نقطه خاص.
  • افت عملکرد (Degradation) کمتر از ۳۰-۴۰٪ در داده تست معمولاً قابل قبول است.

⚠️ هشدار پایانی: بهینه‌سازی مسئولیت‌پذیر

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

  • با سرمایه کم شروع کنید و به تدریج افزایش دهید.
  • همیشه از حد ضرر استفاده کنید.
  • به یک استراتژی متعهد نمانید؛ اگر کار نمی‌کند، آن را کنار بگذارید.
  • تنوع را فراموش نکنید: هم در استراتژی‌ها و هم در نمادها.

هدف نهایی ساخت سیستم‌هایی است که در بلندمدت پایدار باشند، نه کسب سودهای کلان در کوتاه‌مدت.

امیدواریم این راهنمای جامع به شما در ساخت استراتژی‌های معاملاتی قوی‌تر و مطمئن‌تر کمک کرده باشد. کدهای ارائه شده را اجرا کنید، پارامترها را تغییر دهید و با ایده‌های خود آزمایش کنید. اگر مایل هستید روش تعریف استراتژی معاملاتی را در پلتفرم تریدبرد بیاموزید پیشنهاد می کنیم فیلم آموزشی تهیه شده در این رابطه را با عنوان تعریف استراتژی معاملاتی در پلتفُرم تِریدبُرد مشاهده کنید . موفق و پرسود باشید! 🚀

کلمات کلیدی مرتبط

بهینه‌سازی استراتژی پایتون
اورفیتینگ Overfitting
اعتبارسنجی خارج از نمونه
تحلیل Heatmap
تابع هدف سفارشی
Grid Search
backtesting.py optimize
مدیریت ریسک پارامتریک
افت عملکرد Degradation
پایداری استراتژی
قیود بهینه‌سازی Constraints
Sharpe Ratio بهینه‌سازی