פיתוח דוחות בדיקת אסטרטגיה: מדדי שארפ, משיכה, ורווח והפסד

דוחות בדיקת אסטרטגיה מקצועיים: מדדים ולוחות מחוונים הרצת בדיקת אסטרטגיה וקיבלת תשואה סופית של 340% - ומה עכשיו? ללא דוח מפורט, זה רק מספר. ראינו אסטרטגיות עם אחוז ניצחון מעל 80% שעדיין הפסידו 60% מההון בחודש - כי המשיכה המקסימלית לא חושבה ו...

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • image_website-b2b-advance_0.webp
    פיתוח אתר חברה B2B ADVANCE
    1451
  • image_web-applications_feedme_466_0.webp
    פיתוח אפליקציית ווב עבור FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    פיתוח אתר עבור BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    פיתוח חנות מקוונת לחברת FURNORO
    1270
  • image_logo-advance_0.webp
    עיצוב לוגו לחברת B2B Advance
    719
  • image_crm_enviok_479_0.webp
    פיתוח אפליקציית ווב עבור Enviok
    1011

דוחות Backtest מקצועיים: מדדים ודשבורדים

הרצת backtest, קיבלת תשואה סופית של 340% — ועכשיו מה? בלי דוח מפורט, זה רק מספר. ראינו אסטרטגיות עם אחוז זכייה מעל 80% שעדיין הפסידו 60% מההון בחודש — כי משיכה מקסימלית (max drawdown) לא חושבה ופיזור העסקאות לא נותח. פיתוח דוחות backtest מוכנים לשימוש אינו רק פליטת מספרים; זו מערכת שחושפת סיכונים נסתרים, משווה השערות, ומצדיקה החלטות. הניסיון שלנו — מעל 5 שנים במסחר קריפטו ו-DeFi — מאפשר לנו לספק דוחות שבאמת נמצאים בשימוש בפועל. אוטמטנו חישובי מדדים כך שלא תבזבז זמן על גיליונות אלקטרוניים ידניים. סוחרים רבים מפסידים כסף כשהם מסתמכים רק על P&L — דוח מפורט עם מדדים מותאמי סיכון מונע זאת.

למה דוחות ברוקר סטנדרטיים לא מתאימים

דוחות ברוקר סטנדרטיים מספקים רק P&L ותשואה פשוטה. למסחר אלגוריתמי, אתה צריך מדדים מותאמי סיכון: Sharpe, Sortino, משך משיכה, פקטור רווח. בלעדיהם, אי אפשר לדעת אם אסטרטגיה תשרוד זעזוע שוק או רצף הפסדים. אנחנו משתמשים ב-pandas, plotly, ובמחלקות נתונים משלנו (ראה קוד למטה). כל הצינור אוטומטי — מייבוא עסקאות ועד דשבורד HTML אינטראקטיבי. יחס Sharpe נמצא בשימוש נרחב בפיננסים (Sharpe ratio). אנחנו מבטיחים שכל דוח עובר בדיקת עקביות.

אילו מלכודות נסתרות backtest טיפוסי מסתיר?

לקוח אחד הגיע עם אסטרטגיית Binance Futures שהראתה Sharpe של 2.3. הרצנו דוח עם חישוב משיכה נכון — ומצאנו ארבע משיכות מתחת ל-40%- . הסיבה: האסטרטגיה לא הייתה שורדת 2-3 עסקאות מפסידות רצופות. בדוח, הוספנו סעיף "משך משיכה מקסימלי" ו-"Rolling Sharpe". הלקוח עבד מחדש על לוגיקת ניהול הסיכונים שלו — ותוך חודש ה-Sharpe עלה ל-3.8. הגישה שלנו מהירה פי 3 מחישובי Excel ידניים. עם ניסיון של מעל 5 שנים ו-50+ פרויקטים שהושלמו, אנחנו מספקים דוחות אמינים. צוות האנליסטים המוסמכים שלנו מבטיח חישוב מדדים מדויק.

מה כלול

אנחנו מספקים חבילה מלאה:

  • דשבורד HTML אינטראקטיבי (Plotly) עם עקומת הון, משיכה, מפת חום של תשואות חודשיות, והתפלגות P&L.
  • קבצי מקור בפורמט JSON/CSV עבור מערכת ניהול הסיכונים שלך.
  • תיעוד: פירוש של כל גרף ומדד.
  • הדרכת צוות: כיצד לעדכן את הדוח כשהאסטרטגיה משתנה.
  • תמיכת התאמה: אנחנו עוזרים לשלב את הדוח עם ה-API שלך.

זו לא עבודה חד-פעמית: אנחנו נשארים בקשר כדי לחדד מדדים ככל שעולות דרישות חדשות. פיתוח דוח מתחיל ב-$1,500 וכולל הערכת פרויקט חינם.

הרכב הדוח

  • דשבורדים: עקומת הון, משיכה, מפת חום של תשואות חודשיות, התפלגות P&L (נבנה עם Binance Futures או plotly).
  • מדדים: Sharpe, Sortino, Calmar, פקטור רווח, אחוז זכייה, ממוצע רווח/הפסד, משך עסקה.
  • פורמטים: JSON, CSV, HTML עבור ניהול הסיכונים שלך.
  • תיעוד: כיצד לפרש כל גרף.
  • תמיכה לאחר מסירה: אנחנו עוזרים להתאים את הדוח לאסטרטגיות חדשות.

איך לפרש מדדים?

בואו נשווה טעויות נפוצות. אחוז זכייה גבוה לא יציל אותך אם ההפסד הממוצע גדול פי 3 מהרווח הממוצע. פקטור רווח (רווח גולמי / הפסד גולמי) צריך להיות > 2. יחס Sortino עדיף על Sharpe — הוא מעניש רק תנודתיות שלילית. טבלת הפירוש שלנו:

מדד טוב סביר חלש
יחס Sharpe > 2.0 1.0–2.0 < 1.0
יחס Sortino > 2.5 1.5–2.5 < 1.5
משיכה מקסימלית < 15% 15–30% > 30%
פקטור רווח > 2.0 1.5–2.0 < 1.5
אחוז זכייה > 55% (מעקב אחר מגמה) 45–55% < 45%

חשוב: אחוז זכייה ללא יחס סיכון/תגמול הוא מלכודת. פקטור רווח ותוחלת חשובים יותר. לניתוח אסטרטגיות מתקדם, אנחנו גם משלבים אופטימיזציית walk-forward וסימולציית מונטה קרלו.

השוואת פורמטי דוח

פורמט יתרונות חסרונות
HTML (Plotly) גרפים אינטראקטיביים, קל לשיתוף לא מתאים לעיבוד אוטומטי
JSON קריא למכונה, אינטגרציית API דורש ויזואליזציה נפרדת
CSV אוניברסלי, נפתח ב-Excel אין גרפים, קבצים גדולים

איך אנחנו בונים את הדוח: שלב אחר שלב

  1. ייבוא נתונים — ייצוא עסקאות מ-API או CSV.
  2. חישוב מדדים — חישוב Sharpe, Sortino, משיכה, ומדדים נוספים.
  3. יצירת גרפים — עקומת הון, משיכה, מפת חום חודשית, התפלגות P&L.
  4. ולידציה — בדיקה מול נתוני המקור, אימות עקביות.
  5. מסירה — דשבורד HTML + קבצי מקור (JSON/CSV).

צור קשר להערכת פרויקט חינם. הזמן את הדוח שלך היום וקבל ייעוץ על אופטימיזציית מדדים.

הצג קוד
from dataclasses import dataclass
from typing import Optional
import pandas as pd
import numpy as np

@dataclass
class BacktestReport:
    # Сводные метрики
    initial_capital: float
    final_capital: float
    total_return_pct: float
    annual_return_pct: float
    
    # Risk-adjusted
    sharpe_ratio: float
    sortino_ratio: float
    calmar_ratio: float
    
    # Drawdown
    max_drawdown_pct: float
    avg_drawdown_pct: float
    max_drawdown_duration_days: int
    
    # Торговля
    total_trades: int
    win_rate: float
    profit_factor: float
    avg_win_pct: float
    avg_loss_pct: float
    best_trade_pct: float
    worst_trade_pct: float
    avg_trade_duration_hours: float
    
    # Комиссии
    total_commission: float
    commission_as_pct_of_pnl: float
    
    # Временные серии
    equity_curve: pd.Series
    monthly_returns: pd.DataFrame
    trade_list: pd.DataFrame
def compute_all_metrics(equity_curve: pd.Series, trades: list[dict]) -> BacktestReport:
    returns = equity_curve.pct_change().dropna()
    annual_factor = 252

    # Базовые
    total_return = (equity_curve.iloc[-1] / equity_curve.iloc[0]) - 1
    days = (equity_curve.index[-1] - equity_curve.index[0]).days
    annual_return = (1 + total_return) ** (365 / max(days, 1)) - 1

    # Sharpe (risk-free rate = 0 для крипто)
    sharpe = (returns.mean() * annual_factor) / (returns.std() * np.sqrt(annual_factor)) if returns.std() > 0 else 0

    # Sortino (только downside volatility)
    downside = returns[returns < 0].std()
    sortino = (returns.mean() * annual_factor) / (downside * np.sqrt(annual_factor)) if downside > 0 else 0

    # Drawdown
    rolling_max = equity_curve.cummax()
    drawdown_series = (equity_curve - rolling_max) / rolling_max
    max_dd = drawdown_series.min()

    # Max drawdown duration
    in_drawdown = drawdown_series < 0
    dd_start = None
    max_duration = 0
    for date, is_dd in in_drawdown.items():
        if is_dd and dd_start is None:
            dd_start = date
        elif not is_dd and dd_start is not None:
            duration = (date - dd_start).days
            max_duration = max(max_duration, duration)
            dd_start = None

    # Calmar
    calmar = annual_return / abs(max_dd) if max_dd != 0 else 0

    # Trade-level
    trades_df = pd.DataFrame(trades)
    if not trades_df.empty:
        winning = trades_df[trades_df['pnl'] > 0]
        losing = trades_df[trades_df['pnl'] < 0]

        win_rate = len(winning) / len(trades_df)
        gross_profit = winning['pnl'].sum()
        gross_loss = abs(losing['pnl'].sum())
        profit_factor = gross_profit / gross_loss if gross_loss > 0 else float('inf')

        avg_win_pct = (winning['pnl'] / winning['entry_value'] * 100).mean() if not winning.empty else 0
        avg_loss_pct = (losing['pnl'] / losing['entry_value'] * 100).mean() if not losing.empty else 0
    else:
        win_rate = profit_factor = avg_win_pct = avg_loss_pct = 0

    return BacktestReport(
        initial_capital=equity_curve.iloc[0],
        final_capital=equity_curve.iloc[-1],
        total_return_pct=total_return * 100,
        annual_return_pct=annual_return * 100,
        sharpe_ratio=round(sharpe, 3),
        sortino_ratio=round(sortino, 3),
        calmar_ratio=round(calmar, 3),
        max_drawdown_pct=max_dd * 100,
        avg_drawdown_pct=drawdown_series[drawdown_series < 0].mean() * 100,
        max_drawdown_duration_days=max_duration,
        total_trades=len(trades),
        win_rate=win_rate,
        profit_factor=profit_factor,
        avg_win_pct=avg_win_pct,
        avg_loss_pct=avg_loss_pct,
        equity_curve=equity_curve,
        trade_list=trades_df,
    )
def compute_monthly_returns(equity_curve: pd.Series) -> pd.DataFrame:
    """Создаём матрицу месячных доходностей для heatmap"""
    monthly = equity_curve.resample('ME').last()
    monthly_returns = monthly.pct_change().dropna()

    # Создаём матрицу год × месяц
    matrix = monthly_returns.groupby([
        monthly_returns.index.year,
        monthly_returns.index.month
    ]).first().unstack()

    matrix.columns = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                       'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    return matrix * 100  # в процентах
def generate_html_report(report: BacktestReport, strategy_name: str) -> str:
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots

    fig = make_subplots(
        rows=3, cols=2,
        subplot_titles=['Equity Curve', 'Drawdown', 'Monthly Returns', 'Trade P&L Distribution', 'Win/Loss', 'Rolling Sharpe'],
    )

    # Equity curve
    fig.add_trace(go.Scatter(x=report.equity_curve.index, y=report.equity_curve.values,
                              name='Portfolio', line=dict(color='#00C853')), row=1, col=1)

    # Drawdown
    rolling_max = report.equity_curve.cummax()
    drawdown = (report.equity_curve - rolling_max) / rolling_max * 100
    fig.add_trace(go.Scatter(x=drawdown.index, y=drawdown.values,
                              fill='tozeroy', name='Drawdown', line=dict(color='#FF5252')), row=1, col=2)

    # P&L distribution
    if not report.trade_list.empty:
        pnl_pct = report.trade_list['pnl'] / report.trade_list['entry_value'] * 100
        fig.add_trace(go.Histogram(x=pnl_pct, name='Trade P&L %', nbinsx=30), row=2, col=1)

    fig.update_layout(
        title=f'Backtest Report: {strategy_name}',
        height=1000,
        showlegend=False,
        template='plotly_dark',
    )

    return fig.to_html(include_plotlyjs='cdn')