Backtesting בפייתון — מדריך שלב אחר שלב
מדריך מעשי ל-Backtesting בפייתון: איך למשוך נתונים, לכתוב לולאת בדיקה בסיסית, לחשב מדדים כמו Sharpe Ratio ו-Drawdown, ואיך להימנע מהשגיאות הנפוצות.
Backtesting בפייתון מתבצע בשלושה שלבים: משיכת נתוני מחיר היסטוריים, הרצת לוגיקת האסטרטגיה על הנתונים תוך שמירה על סדר הזמן הנכון, וחישוב מדדי ביצוע כמו Sharpe Ratio ו-Max Drawdown. הכלים הבסיסיים — yfinance, pandas, numpy — חינמיים לחלוטין ומספיקים לבדיקה ראשונית. השגיאה הכי יקרה בתהליך היא Look-ahead Bias — שימוש בטעות במידע שלא היה זמין בזמן אמת.
שלב 1: משיכת נתונים היסטוריים
import yfinance as yf
import pandas as pd
df = yf.download("AAPL", start="2019-01-01", end="2024-01-01", interval="1d")
df = df.dropna()
עבור בדיקה ראשונית, מספיקה מניה בודדת או כמה מניות. חשוב לבדוק תקופה שכוללת גם שנים "קשות" (כמו 2020 או 2022) ולא רק שנים של עלייה רציפה — אחרת הבדיקה לא תחשוף איך האסטרטגיה מתמודדת עם ירידות שוק.
שלב 2: חישוב אינדיקטורים
df["ma20"] = df["Close"].rolling(20).mean()
df["ma50"] = df["Close"].rolling(50).mean()
delta = df["Close"].diff()
gain = delta.where(delta > 0, 0).rolling(14).mean()
loss = -delta.where(delta < 0, 0).rolling(14).mean()
df["rsi"] = 100 - (100 / (1 + gain / loss))
rolling() מחשב את הערך רק על סמך הנתונים עד לאותה נקודה, בלי להסתכל קדימה — זה נכון מבחינת מניעת Look-ahead Bias. הסכנה מתחילה בשלב הבא, כשמחליטים איך להשתמש באינדיקטורים האלה להחלטת מסחר.
שלב 3: לוגיקת האיתותים — בלי להסתכל קדימה
# האיתות נבדק על נתוני היום הקודם (shift(1)), הביצוע קורה במחיר הפתיחה של היום
df["signal"] = (df["rsi"].shift(1) < 35) & (df["Close"].shift(1) > df["ma20"].shift(1))
df["entry_price"] = df["Open"].where(df["signal"], None)
ה-.shift(1) הוא ההבדל בין בקטסט תקין לבקטסט עם Look-ahead Bias: הוא מבטיח שההחלטה מתקבלת על סמך מידע שכבר היה ידוע במלואו (סוף היום הקודם), והביצוע קורה במחיר הפתיחה של היום הנוכחי — בדיוק כמו שבוט אמיתי היה פועל.
שלב 4: הרצת סימולציית העסקאות
trades = []
in_position = False
entry_price = 0
stop_loss_pct = 0.03
take_profit_pct = 0.06
for i in range(len(df)):
row = df.iloc[i]
if not in_position and row["signal"]:
entry_price = row["entry_price"]
stop_price = entry_price * (1 - stop_loss_pct)
target_price = entry_price * (1 + take_profit_pct)
in_position = True
elif in_position:
if row["Low"] <= stop_price:
trades.append({"entry": entry_price, "exit": stop_price, "result": "stop_loss"})
in_position = False
elif row["High"] >= target_price:
trades.append({"entry": entry_price, "exit": target_price, "result": "take_profit"})
in_position = False
trades_df = pd.DataFrame(trades)
trades_df["return_pct"] = (trades_df["exit"] - trades_df["entry"]) / trades_df["entry"]
זו לולאה בסיסית מתאימה להבנה ולבדיקה ראשונית. לאסטרטגיות מורכבות יותר (כמה פוזיציות בו-זמנית, עמלות, Slippage), ספריות ייעודיות כמו backtrader או vectorbt חוסכות הרבה עבודת תשתית וכוללות ניהול פוזיציות מובנה.
שלב 5: חישוב מדדי ביצוע
win_rate = (trades_df["return_pct"] > 0).mean()
avg_win = trades_df.loc[trades_df["return_pct"] > 0, "return_pct"].mean()
avg_loss = trades_df.loc[trades_df["return_pct"] < 0, "return_pct"].mean()
print(f"מספר עסקאות: {len(trades_df)}")
print(f"Win Rate: {win_rate:.1%}")
print(f"רווח ממוצע בעסקה מנצחת: {avg_win:.1%}")
print(f"הפסד ממוצע בעסקה מפסידה: {avg_loss:.1%}")
חישובי Sharpe Ratio ו-Max Drawdown המלאים מוסברים במדריכים הייעודיים שלהם — שני המדדים החשובים ביותר לצד Win Rate.
המדדים שחייבים לבדוק לפני שממשיכים הלאה
| מדד | ערך סביר | דגל אדום | |---|---|---| | מספר עסקאות | 50+ | פחות מ-30 — אין מובהקות סטטיסטית | | תקופת בדיקה | 3+ שנים, כולל שנה קשה | פחות משנה, או רק שנים "טובות" | | Sharpe Ratio | מעל 1.0 | מעל 3.0 — חשוד לOverfitting | | Max Drawdown | מתחת ל-20% | מעל 30% |
שאלות נפוצות
מה ההבדל בין הלולאה הידנית לספריות כמו backtrader?
הלולאה הידנית טובה להבנת המנגנון ולבדיקות ראשוניות פשוטות. backtrader ו-vectorbt מטפלים אוטומטית בעמלות, Slippage, ניהול כמה פוזיציות בו-זמנית, ומייצרים דוחות מפורטים — שווה לעבור אליהן ברגע שהאסטרטגיה מורכבת מ"קנה/מכור נכס בודד".
האם חובה לכלול עמלות ב-Backtesting?
מומלץ מאוד, במיוחד לאסטרטגיות עם מסחר תדיר. גם עמלה נמוכה של $0-1 לעסקה יכולה לשחוק משמעותית אסטרטגיה עם מרווחי רווח קטנים ומספר עסקאות גבוה.
כמה נתונים היסטוריים צריך לבדיקה אמינה?
מינימום 2-3 שנים, ועדיף יותר, כולל תקופה עם ירידת שוק משמעותית (כמו 2022). בדיקה רק על שוק עולה נותנת תמונה חלקית ומטעה על עמידות האסטרטגיה.
מה השלב הבא אחרי Backtesting מוצלח?
Paper Trading — הרצת האסטרטגיה בזמן אמת עם כסף וירטואלי, כדי לחשוף בעיות ש-Backtesting לא מדמה (Slippage, עיכובי API, תנאי שוק חיים). ראו את השלב המלא במדריך בניית בוט מסחר AI.