כתבתם אסטרטגיית מסחר: על נתונים היסטוריים של Ethereum היא מציגה Sharpe של 2.8, משיכה מקסימלית של 12%, אחוז זכייה של 65%. אתם משיקים אותה בחשבון דמו — כעבור שבוע אתם במינוס 40%. הסיבה: התאמת יתר להיסטוריה. בדיקת Out-of-sample (OOS) היא הדרך היחידה לסנן אסטרטגיות כאלה לפני שאתם מסכנים כסף אמיתי. אנו בונים מערכות בדיקת OOS מותאמות אישית שמשתלבות בצנרת האלגוריתמית שלכם.
הניסיון שלנו בתחום זה: 5+ שנים בפיתוח מערכות מסחר לקריפטו, למעלה מ-60 פרויקטים שהושלמו, כולל מסגרות DeFi לארביטראז' ו-market making. אנו מבטיחים יישום נכון: כל הבדיקות נבחנות על נתונים סינתטיים עם תשובות ידועות. אנו מספקים קוד מלא, תיעוד וייעוץ.
מהי בדיקת out-of-sample ולמה היא נחוצה?
בדיקת Out-of-sample (OOS) היא הערכה של אסטרטגיית מסחר על נתונים שלא שימשו במהלך יצירתה. היא מסננת אלגוריתמים עם התאמת יתר לפני שהם מגיעים לחשבון אמיתי. ללא OOS, אתם מסכנים הון על סמך צירופי מקרים בנתונים היסטוריים.
אילו בעיות פותרת בדיקת OOS?
התאמת יתר. אם אסטרטגיה עובדת רק על הנתונים שעליהם כווננה, היא חסרת תועלת. בדיקת OOS חושפת את יכולת ההכללה האמיתית. אנו משתמשים במבחנים סטטיסטיים (t-test, גודל מדגם אפקטיבי המתוקן לאוטוקורלציה) כדי להעריך את המובהקות של תוצאות OOS. בניסיון שלנו, 70% מהאסטרטגיות שעוברות אופטימיזציית IS נכשלות באימות OOS.
הטיית מבט קדימה ודליפת נתונים. טעות נפוצה: כשמחלקים ל-IS/OOS, אינדיקטורים שמשתמשים בנתונים עתידיים לא מוזזים. אנו בודקים אוטומטית שתקופת ה-OOS מבודדת לחלוטין: 20% האחרונים של הכרונולוגיה. קוד החלוקה תמיד קפדני, עם בדיקות תאריכים.
חוסר מובהקות סטטיסטית. מדגם קטן או אוטוקורלציה גבוהה הופכים תוצאות לאקראיות. המסגרת שלנו מחשבת p-value לתשואות OOS ומתאימה את מספר התצפיות האפקטיביות. רק אם p < 0.05 ו-Sharpe > 0.5 האסטרטגיה מאושרת לפריסה.
איך אנחנו עושים את זה
ערימת טכנולוגיה: Python 3.10+, pandas, scipy, numpy. אנו משתמשים בבדיקות יחידה לרכיבי אימות. הלקוח מקבל לא רק דוח אלא גם לוח מחוונים אינטראקטיבי עם מדדים: ירידת Sharpe, משיכות, אחוז זכייה.
דוגמה ממקרה אחרון: עבור בוט ארביטראז' DeFi על Polygon, יישמנו אימות OOS עם אופטימיזציית walk-forward. על נתוני OOS, Sharpe ירד מ-3.2 ל-1.8, אך נשאר מובהק סטטיסטית (p=0.01). הלקוח ויתר על הפריסה, וחסך כ-$12k בעמלות ונזילות. בדיקה כזו שווה את ההשקעה.
מסגרת אימות
import pandas as pd def create_oos_split(data: pd.DataFrame, oos_pct: float = 0.20) -> tuple: """ Создаём строгое IS/OOS разбиение. OOS — последние 20% данных, хронологически. """ split_idx = int(len(data) * (1 - oos_pct)) in_sample = data.iloc[:split_idx] out_of_sample = data.iloc[split_idx:] print(f"In-sample: {in_sample.index[0].date()} → {in_sample.index[-1].date()} ({len(in_sample)} bars)") print(f"Out-of-sample: {out_of_sample.index[0].date()} → {out_of_sample.index[-1].date()} ({len(out_of_sample)} bars)") return in_sample, out_of_sample class OOSValidator: def __init__(self, backtester, significance_threshold: float = 0.05): self.backtester = backtester self.alpha = significance_threshold def validate( self, strategy_params: dict, is_result: BacktestResult, oos_data: pd.DataFrame, ) -> OOSValidationReport: # Запускаем финальный тест на OOS данных oos_result = self.backtester.run(strategy_params, oos_data) # Статистическая значимость OOS результатов oos_returns = oos_result.equity_curve.pct_change().dropna() significance = self._test_significance(oos_returns) # Сравнение IS vs OOS is_vs_oos = self._compare_is_oos(is_result, oos_result) # Вердикт passed = self._evaluate_verdict(oos_result, significance, is_vs_oos) return OOSValidationReport( is_result=is_result, oos_result=oos_result, significance=significance, is_vs_oos_comparison=is_vs_oos, passed=passed, recommendation=self._get_recommendation(passed, is_vs_oos), ) def _test_significance(self, returns: pd.Series) -> dict: """Тест статистической значимости положительной доходности""" from scipy import stats # t-тест: H0: mean return == 0 t_stat, p_value = stats.ttest_1samp(returns, 0) # Количество независимых наблюдений с учётом автокорреляции n_effective = self._effective_sample_size(returns) return { 't_statistic': t_stat, 'p_value': p_value, 'is_significant': p_value < self.alpha and t_stat > 0, 'n_effective': n_effective, } def _effective_sample_size(self, returns: pd.Series) -> float: """Корректируем выборку с учётом автокорреляции""" n = len(returns) autocorr = returns.autocorr(1) if abs(autocorr) >= 1: return n return n * (1 - autocorr) / (1 + autocorr) def _compare_is_oos(self, is_result: BacktestResult, oos_result: BacktestResult) -> dict: is_m = is_result.metrics oos_m = oos_result.metrics return { 'sharpe_ratio_degradation': (is_m.sharpe_ratio - oos_m.sharpe_ratio) / max(abs(is_m.sharpe_ratio), 0.01), 'return_ratio': oos_m.annual_return_pct / max(is_m.annual_return_pct, 0.01), 'drawdown_ratio': oos_m.max_drawdown_pct / max(abs(is_m.max_drawdown_pct), 0.01), 'win_rate_change': oos_m.win_rate - is_m.win_rate, } def _evaluate_verdict(self, oos_result, significance, comparison) -> bool: # Критерии прохождения OOS теста checks = [ oos_result.metrics.sharpe_ratio > 0.5, # положительный Sharpe significance['is_significant'], # статистически значимо comparison['sharpe_ratio_degradation'] < 0.7, # деградация < 70% oos_result.metrics.max_drawdown_pct > -40, # drawdown < 40% oos_result.metrics.total_trades >= 15, # достаточно сделок ] return all(checks) # Функция для печати отчёта def print_oos_report(report: OOSValidationReport): print("=" * 60) print("OOS VALIDATION REPORT") print("=" * 60) print(f"\n{'IS':25} {'OOS':>10}") print("-" * 40) print(f"{'Sharpe Ratio':25} {report.is_result.metrics.sharpe_ratio:>10.2f} {report.oos_result.metrics.sharpe_ratio:>10.2f}") print(f"{'Annual Return %':25} {report.is_result.metrics.annual_return_pct:>10.1f} {report.oos_result.metrics.annual_return_pct:>10.1f}") print(f"{'Max Drawdown %':25} {report.is_result.metrics.max_drawdown_pct:>10.1f} {report.oos_result.metrics.max_drawdown_pct:>10.1f}") print(f"{'Win Rate %':25} {report.is_result.metrics.win_rate*100:>10.1f} {report.oos_result.metrics.win_rate*100:>10.1f}") comp = report.is_vs_oos_comparison print(f"\nSharpe degradation: {comp['sharpe_ratio_degradation']:.1%}") print(f"OOS/IS return ratio: {comp['return_ratio']:.2f}x") sig = report.significance print(f"\nStatistical significance: p={sig['p_value']:.4f} (significant: {sig['is_significant']})") print(f"Effective sample size: {sig['n_effective']:.0f}") verdict = "PASSED" if report.passed else "FAILED" print(f"\n{'='*20} {verdict} {'='*20}") print(f"Recommendation: {report.recommendation}") איך לקבוע את חלוקת הנתונים הנכונה?
שאלה מרכזית אחת היא איזה אחוז נתונים להקצות ל-OOS. תקן: 70/20/10 (IS/OOS/ולידציה) או 80/20 למקרים פשוטים. לאופטימיזציית walk-forward אנו משתמשים בחלון נע: 12 חודשים IS, 3 חודשים OOS. קריפטו דורש כיול מחדש תכוף יותר — פעם בחודש.
| מדד | In-Sample | Out-of-Sample | סטייה מקובלת |
|---|---|---|---|
| יחס Sharpe | 2.0 – 3.0 | > 0.5 | ירידה < 70% |
| תשואה שנתית | 30% – 60% | > 0% | הפחתה פי 2–3 |
| משיכה מקסימלית | < 20% | < 40% | עלייה עד פי 2 |
| אחוז זכייה | 55% – 70% | > 50% | ירידה עד 10% |
איך להעריך מובהקות סטטיסטית של תוצאות OOS?
להערכת מובהקות אנו משתמשים ב-t-test והתאמת גודל מדגם לאוטוקורלציה. אם p-value < 0.05 ו-Sharpe > 0.5, האסטרטגיה נחשבת כעברה אימות OOS. מידע נוסף על ה-t-test ניתן לקרוא ב-ויקיפדיה.
תהליך העבודה
| שלב | מה אנחנו עושים | תוצאה |
|---|---|---|
| אנליטיקה | איסוף דרישות: סוגי נכסים, תדירות מסחר, מסגרות זמן | מפרט טכני |
| עיצוב | פיתוח ארכיטקטורה: חלוקת נתונים, מחלקות אימות, אינטגרציה עם backtester | תיעוד ארכיטקטורה |
| יישום | כתיבת אב טיפוס ב-Python בהתחשב בערימה שלכם | מאגר עם קוד |
| בדיקות | אימות על נתונים סינתטיים, בדיקת באגים ידועים (הטיית מבט קדימה, ריגול נתונים) | דוח אימות |
| פריסה | אינטגרציה לצנרת CI/CD, הדרכת הצוות | גישה למערכת + תיעוד |
למה תוצאות OOS תמיד גרועות מ-IS?
זה צפוי: האסטרטגיה מותאמת ל-IS, כך שירידה על נתונים חדשים היא בלתי נמנעת. מה שחשוב הוא לא ההפרש המוחלט אלא הסבירות שלו: ירידת Sharpe של לא יותר מ-70%, תשואות OOS חיוביות. אם OOS טוב יותר מ-IS, זה סימפטום של הטיית מבט קדימה וצריך לבדוק שוב.
טעויות אופייניות בבדיקת OOS
- הסתכלות על OOS לפני סיום האסטרטגיה. מבט אחד מספיק כדי שהנתונים כבר לא יהיו out-of-sample.
- שימוש בחלוקה אקראית במקום כרונולוגית. מסחר הוא סדרת זמן; ערבוב אקראי הורס את המבנה הזמני.
- אי בדיקת מובהקות סטטיסטית. עם מעט עסקאות (פחות מ-15), כל תוצאה היא אקראית.
- התעלמות מאוטוקורלציה. תשואות יומיות מתואמות; גודל המדגם האפקטיבי קטן יותר.
בגלל הטיית מבט קדימה, אחד הלקוחות שלנו הפסיד מעל $20k בחשבון אמיתי. מניעת הפסדים כאלה היא מטרת בדיקת OOS.
מה כלול בעבודה (תוצרים)
- מסגרת אימות OOS עם קוד מקור ובדיקות
- אינטגרציה עם ה-backtester שלכם (ספריות Python)
- דוח המסביר מדדים והמלצות
- תיעוד על שימוש והתאמה אישית
- גישה למאגר עם היסטוריית שינויים
- תמיכת ייעוץ ל-30 יום
הזמינו יישום של בדיקת OOS — צרו קשר לייעוץ. אנו נעריך את האסטרטגיה שלכם ונציע פתרון אופטימלי. קבלו ייעוץ ללא התחייבות. לחלופין, אם אתם רוצים לבדוק אסטרטגיה קיימת, הצוות שלנו יכול לבצע ביקורת תוך 1-2 ימים.







