Разработка системы сравнения стратегий

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы сравнения стратегий
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1062
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы сравнения стратегий

Система сравнения стратегий позволяет объективно оценить несколько торговых стратегий по единому набору метрик, выявить их сильные и слабые стороны, выбрать лучшую или оптимальную комбинацию для портфеля.

Стандартизированный формат результатов

from dataclasses import dataclass
import pandas as pd
import numpy as np

@dataclass
class StrategyResult:
    name: str
    params: dict
    equity_curve: pd.Series
    trades: pd.DataFrame

    # Вычисленные метрики
    sharpe_ratio: float
    sortino_ratio: float
    calmar_ratio: float
    annual_return_pct: float
    max_drawdown_pct: float
    win_rate: float
    profit_factor: float
    total_trades: int
    avg_trade_duration_hours: float
    total_commission_pct: float

Comparison Engine

class StrategyComparator:
    def __init__(self, backtester, benchmark_data: pd.Series = None):
        self.backtester = backtester
        self.benchmark = benchmark_data  # Buy & Hold BTC для сравнения

    def compare(self, strategies: list[dict], data: pd.DataFrame) -> ComparisonReport:
        results = []

        for strategy_config in strategies:
            result = self.backtester.run(
                strategy_class=strategy_config['class'],
                params=strategy_config['params'],
                data=data,
                name=strategy_config['name'],
            )
            results.append(result)

        # Добавляем Buy & Hold как benchmark
        if self.benchmark is not None:
            bh_return = (self.benchmark.iloc[-1] / self.benchmark.iloc[0] - 1)
            results.append(self._create_buyhold_result(self.benchmark))

        return self.build_report(results)

    def build_report(self, results: list[StrategyResult]) -> ComparisonReport:
        comparison_df = pd.DataFrame([{
            'Strategy': r.name,
            'Annual Return %': round(r.annual_return_pct, 2),
            'Sharpe Ratio': round(r.sharpe_ratio, 3),
            'Sortino Ratio': round(r.sortino_ratio, 3),
            'Max Drawdown %': round(r.max_drawdown_pct, 2),
            'Calmar Ratio': round(r.calmar_ratio, 3),
            'Win Rate %': round(r.win_rate * 100, 1),
            'Profit Factor': round(r.profit_factor, 2),
            'Total Trades': r.total_trades,
            'Avg Trade Hours': round(r.avg_trade_duration_hours, 1),
            'Commission Drag %': round(r.total_commission_pct, 2),
        } for r in results])

        # Ранжирование по каждой метрике
        rankings = self._compute_rankings(comparison_df)

        # Корреляция между стратегиями
        correlations = self._compute_correlations(results)

        return ComparisonReport(
            summary=comparison_df,
            rankings=rankings,
            correlations=correlations,
            strategies=results,
        )

    def _compute_rankings(self, df: pd.DataFrame) -> pd.DataFrame:
        """Ранжируем стратегии по каждой метрике"""
        rankings = pd.DataFrame({'Strategy': df['Strategy']})

        for metric, ascending in [
            ('Annual Return %', False),
            ('Sharpe Ratio', False),
            ('Max Drawdown %', True),  # меньше = лучше
            ('Profit Factor', False),
            ('Win Rate %', False),
        ]:
            if metric in df.columns:
                rankings[f'Rank: {metric}'] = df[metric].rank(ascending=ascending).astype(int)

        # Общий rank (среднее по всем метрикам)
        rank_cols = [c for c in rankings.columns if c.startswith('Rank:')]
        rankings['Overall Rank'] = rankings[rank_cols].mean(axis=1).rank().astype(int)

        return rankings.sort_values('Overall Rank')

    def _compute_correlations(self, results: list[StrategyResult]) -> pd.DataFrame:
        """Корреляция доходностей между стратегиями"""
        returns_dict = {
            r.name: r.equity_curve.pct_change().dropna()
            for r in results
        }
        returns_df = pd.DataFrame(returns_dict).dropna()
        return returns_df.corr()

Визуализация сравнения

def plot_comparison(report: ComparisonReport):
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots

    fig = make_subplots(
        rows=2, cols=2,
        subplot_titles=[
            'Equity Curves',
            'Risk-Return Scatter',
            'Monthly Returns Distribution',
            'Drawdown Comparison',
        ]
    )

    colors = ['#00C853', '#2196F3', '#FF9800', '#E91E63', '#9C27B0']

    for i, strat in enumerate(report.strategies):
        color = colors[i % len(colors)]

        # Equity curves
        fig.add_trace(go.Scatter(
            x=strat.equity_curve.index,
            y=strat.equity_curve / strat.equity_curve.iloc[0] * 100,  # нормализованы к 100
            name=strat.name,
            line=dict(color=color),
        ), row=1, col=1)

        # Risk-Return scatter
        fig.add_trace(go.Scatter(
            x=[abs(strat.max_drawdown_pct)],
            y=[strat.annual_return_pct],
            mode='markers+text',
            marker=dict(size=12, color=color),
            text=[strat.name],
            textposition='top center',
            showlegend=False,
        ), row=1, col=2)

        # Drawdown
        rolling_max = strat.equity_curve.cummax()
        drawdown = (strat.equity_curve - rolling_max) / rolling_max * 100
        fig.add_trace(go.Scatter(
            x=drawdown.index,
            y=drawdown,
            fill='tozeroy',
            name=strat.name,
            line=dict(color=color),
            showlegend=False,
            opacity=0.6,
        ), row=2, col=2)

    fig.update_layout(
        title='Strategy Comparison Report',
        height=900,
        template='plotly_dark',
    )
    return fig

Portfolio Combination Analysis

Низкая корреляция между стратегиями — возможность диверсификации:

def analyze_portfolio_combination(
    strategy_returns: dict[str, pd.Series],
    target_sharpe: float = 2.0,
) -> dict:
    """Находим оптимальные веса для портфеля из нескольких стратегий"""
    from scipy.optimize import minimize

    returns_df = pd.DataFrame(strategy_returns).dropna()
    mean_returns = returns_df.mean()
    cov_matrix = returns_df.cov()

    def neg_sharpe(weights):
        portfolio_return = np.dot(weights, mean_returns) * 252
        portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix * 252, weights)))
        return -portfolio_return / portfolio_vol if portfolio_vol > 0 else 999

    n = len(strategy_returns)
    constraints = [{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
    bounds = [(0, 1)] * n
    x0 = [1/n] * n

    result = minimize(neg_sharpe, x0, method='SLSQP', bounds=bounds, constraints=constraints)

    optimal_weights = dict(zip(strategy_returns.keys(), result.x))
    combined_returns = sum(ret * w for ret, w in zip(returns_df.values.T, result.x))
    combined_sharpe = -result.fun

    return {
        'optimal_weights': optimal_weights,
        'combined_sharpe': combined_sharpe,
        'improvement_vs_best_single': combined_sharpe - max(
            ret.mean() / ret.std() * np.sqrt(252) for ret in strategy_returns.values()
        ),
    }

Комбинация некоррелированных стратегий часто даёт лучший risk-adjusted результат, чем любая отдельная стратегия. Это работает как диверсификация в классических финансах, только на уровне торговых алгоритмов.