Skip to main content

backtesting-sim

Backtesting and simulation: vectorized backtesting, paper trading simulation, strategy A/B testing, automated strategy building, natural language to strategy, and trading plan generation. USE FOR: backtest, backtesting, paper trading, simulation, strategy builder, A/B test strategies, natural language strategy, trading plan, equity curve, drawdown analysis, walk-forward, Monte Carlo simulation, performance metrics, Sharpe, Sortino, Calmar, win rate, profit factor, expectancy, strategy validation, overfitting prevention, survivorship bias, look-ahead bias.

Zur Installation springen

Quellinformationen

Repository
mahmoud20138/Tradecraft
Letzte Quellaktivität
23. April 2026 um 08:40
Erkannte Sprache von SKILL.md
Englisch
Sterne
15
Forks
4

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
backtesting-sim
description
Backtesting and simulation: vectorized backtesting, paper trading simulation, strategy A/B testing, automated strategy building, natural language to strategy, and trading plan generation. USE FOR: backtest, backtesting, paper trading, simulation, strategy builder, A/B test strategies, natural language strategy, trading plan, equity curve, drawdown analysis, walk-forward, Monte Carlo simulation, performance metrics, Sharpe, Sortino, Calmar, win rate, profit factor, expectancy, strategy validation, overfitting prevention, survivorship bias, look-ahead bias.
related_skills
["statistics-timeseries","backtesting-sim","risk-and-portfolio","market-data-ingestion"]
tags
["trading","quant","backtesting","simulation","paper-trading","vectorized"]
skill_level
intermediate
kind
reference
category
trading/quant
status
active
> **Skill:** Backtesting Sim | **Domain:** trading | **Category:** quantitative | **Level:** intermediate > **Tags:** `trading`, `quant`, `backtesting`, `simulation`, `paper-trading`, `vectorized` ## Vectorized Backtester # Vectorized Backtester ```python import pandas as pd import numpy as np from typing import Callable, Optional # ── Shared helpers ────────────────────────────────────────────────────────── def _sharpe(r: np.ndarray, rfr: float = 0.04 / 252) -> float: std = r.std(ddof=1) return float((r.mean() - rfr) / std * np.sqrt(252)) if std > 0 else 0.0 def _sortino(r: np.ndarray, rfr: float = 0.04 / 252) -> float: down = r[r < rfr] std_dn = down.std(ddof=1) if len(down) > 1 else 0.0 return float((r.mean() - rfr) / std_dn * np.sqrt(252)) if std_dn > 0 else 0.0 def _calmar(r: np.ndarray) -> float: eq = np.cumprod(1 + r) peak = np.maximum.accumulate(eq) max_dd = abs(((eq - peak) / peak).min()) ann_ret = eq[-1] ** (252 / len(r)) - 1 return float(ann_ret / max_dd) if max_dd > 0 else 0.0 def _profit_factor(r: np.ndarray) -> float: gains = r[r > 0].sum() losses = abs(r[r < 0].sum()) return float(gains / losses) if losses > 0 else float("inf") class VectorizedBacktester: """ Production-quality vectorised backtester with full performance metrics. Signals must be pre-shifted (no look-ahead bias). Supports transaction costs, position sizing, and walk-forward validation. Example ------- >>> df["signal"] = np.sign(df["close"].pct_change(5)) # 5-bar momentum >>> result = VectorizedBacktester.backtest(df, spread_bps=2.0) >>> print(result["sharpe"], result["max_drawdown_pct"]) 1.34 -12.5 """ @staticmethod def backtest( df: pd.DataFrame, signal_col: str = "signal", spread_bps: float = 2.0, slippage_bps: float = 1.0, initial_capital: float = 10_000.0, position_size: float = 1.0, risk_free_annual: float = 0.04, ) -> dict: """ Vectorised backtest engine. Parameters ---------- df : OHLCV DataFrame with a signal column signal_col : column name for signal (1=long, -1=short, 0=flat) spread_bps : round-trip spread cost in basis points slippage_bps : round-trip slippage estimate in basis points initial_capital : starting capital position_size : fraction of capital at risk (1.0 = fully invested) risk_free_annual: used for Sharpe / Sortino calculations Returns ------- Comprehensive dict including Sharpe, Sortino, Calmar, max DD, win rate, profit factor, equity curve, and full annotated DataFrame. Notes ----- ALL signals are shifted by 1 bar to prevent look-ahead. Costs are charged on position changes (not every bar). """ if signal_col not in df.columns: raise KeyError(f"Column '{signal_col}' not found in DataFrame") if len(df) < 10: raise ValueError("Need at least 10 bars to backtest") out = df.copy() cost_rt = (spread_bps + slippage_bps) / 10_000.0 # Round-trip cost fraction out["returns"] = out["close"].pct_change() out["position"] = out[signal_col].shift(1).fillna(0) * position_size out["trade"] = out["position"].diff().abs().fillna(0) out["gross_return"] = out["position"] * out["returns"] out["cost"] = out["trade"] * cost_rt out["net_return"] = out["gross_return"] - out["cost"] # Equity curve (multiplicative) out["equity"] = initial_capital * (1 + out["net_return"]).cumprod() out["peak"] = out["equity"].cummax() out["drawdown"] = (out["equity"] - out["peak"]) / out["peak"] # Trade-level stats out["trade_entry"] = (out["position"] != 0) & (out["position"].shift(1) == 0) out["trade_exit"] = (out["position"] == 0) & (out["position"].shift(1) != 0) n_trades = int(out["trade_entry"].sum()) net = out["net_return"].dropna().values rfr_d = risk_free_annual / 252 # Compute comprehensive metrics from net returns total_return = float((out["equity"].iloc[-1] / initial_capital - 1) * 100) max_dd = float(out["drawdown"].min() * 100) sharpe = _sharpe(net, rfr_d) sortino = _sortino(net, rfr_d) calmar = _calmar(net) pf = _profit_factor(net) # Win rate on closed trades (more accurate than bar-level) exit_returns = out.loc[out["trade_exit"], "net_return"] win_rate = float((exit_returns > 0).mean() * 100) if len(exit_returns) > 0 else 0.0 # Consecutive loss streak signs = np.sign(net) streak = 0 max_streak = 0 for s in signs: if s < 0: streak += 1 max_streak = max(max_streak, streak) else: streak = 0 return { "total_return_pct": round(total_return, 2), "ann_return_pct": round(float((out["equity"].iloc[-1] / initial_capital) ** (252 / max(len(net), 1)) - 1) * 100, 2), "sharpe": round(sharpe, 3), "sortino": round(sortino, 3), "calmar": round(calmar, 3), "max_drawdown_pct": round(max_dd, 2), "profit_factor": round(pf, 3), "n_trades": n_trades, "win_rate": round(win_rate, 1), "max_consec_losses": int(max_streak), "total_costs_pct": round(float(out["cost"].sum() * 100), 2), "equity_curve": out["equity"], "drawdown_series": out["drawdown"], "df": out, } @staticmethod def walk_forward_backtest( df: pd.DataFrame, signal_fn: Callable, optimize_fn: Callable, train_bars: int = 500, test_bars: int = 100, min_folds: int = 3, **kwargs, ) -> dict: """ Anchored walk-forward validation. Parameters ---------- signal_fn : callable(df, params) → signal Series optimize_fn : callable(train_df) → params dict train_bars : in-sample training window test_bars : out-of-sample test window per fold min_folds : minimum folds required for a valid result Returns ------- dict with per-fold and aggregate OOS statistics. """ results: list[dict] = [] all_equity: list[pd.Series] = [] for start in range(0, len(df) - train_bars - test_bars, test_bars): train = df.iloc[start: start + train_bars] test = df.iloc[start + train_bars: start + train_bars + test_bars].copy() try: params = optimize_fn(train) test["signal"] = signal_fn(test, params) bt = VectorizedBacktester.backtest(test, **kwargs) results.append({ "fold": len(results), "sharpe": bt["sharpe"], "sortino": bt["sortino"], "return": bt["total_return_pct"], "max_dd": bt["max_drawdown_pct"], "params": params, }) all_equity.append(bt["equity_curve"]) except Exception as e: results.append({"fold": len(results), "error": str(e)}) valid = [r for r in results if "sharpe" in r] if len(valid) < min_folds: return { "method": "walk_forward", "error": f"Only {len(valid)} valid folds (need {min_folds})", "n_folds": len(results), } sharpes = [r["sharpe"] for r in valid] sortinos = [r["sortino"] for r in valid] returns = [r["return"] for r in valid] # Concatenate OOS equity curves for a continuous equity line oos_equity = pd.concat(all_equity).sort_index() if all_equity else pd.Series(dtype=float) return { "method": "walk_forward", "n_folds": len(results), "n_valid_folds": len(valid), "avg_sharpe": round(float(np.mean(sharpes)), 3), "median_sharpe": round(float(np.median(sharpes)), 3), "std_sharpe": round(float(np.std(sharpes, ddof=1)), 3), "pct_folds_positive": round(float(np.mean([r > 0 for r in returns])) * 100, 1), "avg_return": round(float(np.mean(returns)), 2), "avg_sortino": round(float(np.mean(sortinos)), 3), "fold_results": valid, "oos_equity": oos_equity, "WARNING": "Past performance ≠ future results. OOS validation required.", } @staticmethod def compare_strategies( df: pd.DataFrame, strategies: dict[str, pd.Series], spread_bps: float = 2.0, slippage_bps: float = 1.0, initial_capital: float = 10_000.0, ) -> pd.DataFrame: """ Run multiple strategies on the same data and compare side-by-side. Parameters ---------- strategies : {"name": signal_series, ...} Returns ------- DataFrame ranked by Sharpe ratio. """ results: list[dict] = [] for name, signal_series in strategies.items(): df_copy = df.copy() df_copy["signal"] = signal_series try: bt = VectorizedBacktester.backtest( df_copy, spread_bps=spread_bps, slippage_bps=slippage_bps, initial_capital=initial_capital, ) results.append({ "strategy": name, "return": bt["total_return_pct"], "sharpe": bt["sharpe"], "sortino": bt["sortino"], "calmar": bt["calmar"], "max_dd": bt["max_drawdown_pct"], "n_trades": bt["n_trades"], "win_rate": bt["win_rate"], "profit_factor": bt["profit_factor"], }) except Exception as e: results.append({"strategy": name, "error": str(e)}) return pd.DataFrame(results).sort_values("sharpe", ascending=False) ``` --- ## Trade Simulator Paper # Trade Simulator Paper ```python import pandas as pd import numpy as np from datetime import datetime from typing import Optional class PaperTradeSimulator: """ Realistic paper trading simulator with proper spread/slippage modelling, margin tracking, and full trade history for post-session analysis. Uses a reproducible RNG (np.random.default_rng) for slippage simulation. Example ------- >>> sim = PaperTradeSimulator(initial_balance=10_000, seed=42) >>> sim.open_trade("EURUSD", "buy", lots=0.1, price=1.0850, sl=1.0810, tp=1.0920) >>> closed = sim.check_positions({"EURUSD": 1.0920}) >>> print(closed[0]["reason"], closed[0]["pnl_usd"]) 'TP' 70.0 """
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen