@sylix/coworker 2.0.11 → 2.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/commands/slash/config.d.ts.map +1 -1
  2. package/dist/commands/slash/config.js +22 -4
  3. package/dist/commands/slash/config.js.map +1 -1
  4. package/dist/core/CoWorkerAgent.d.ts.map +1 -1
  5. package/dist/core/CoWorkerAgent.js +6 -3
  6. package/dist/core/CoWorkerAgent.js.map +1 -1
  7. package/dist/skills/defaults/accessibility/screen-reader-testing.md +545 -0
  8. package/dist/skills/defaults/accessibility/wcag-audit-patterns.md +555 -0
  9. package/dist/skills/defaults/ai-ml/rag.md +276 -0
  10. package/dist/skills/defaults/backend-development/api-design-principles.md +528 -0
  11. package/dist/skills/defaults/backend-development/api-design.md +285 -0
  12. package/dist/skills/defaults/backend-development/architecture-patterns.md +494 -0
  13. package/dist/skills/defaults/backend-development/async-python.md +237 -0
  14. package/dist/skills/defaults/backend-development/auth-implementation-patterns.md +638 -0
  15. package/dist/skills/defaults/backend-development/bazel-build-optimization.md +387 -0
  16. package/dist/skills/defaults/backend-development/billing-automation/SKILL.md +566 -0
  17. package/dist/skills/defaults/backend-development/code-review-excellence.md +538 -0
  18. package/dist/skills/defaults/backend-development/cqrs-implementation.md +554 -0
  19. package/dist/skills/defaults/backend-development/database-design.md +305 -0
  20. package/dist/skills/defaults/backend-development/debugging-strategies.md +536 -0
  21. package/dist/skills/defaults/backend-development/e2e-testing-patterns.md +544 -0
  22. package/dist/skills/defaults/backend-development/error-handling-patterns.md +641 -0
  23. package/dist/skills/defaults/backend-development/fastapi-templates.md +559 -0
  24. package/dist/skills/defaults/backend-development/fastapi.md +309 -0
  25. package/dist/skills/defaults/backend-development/git-advanced-workflows.md +405 -0
  26. package/dist/skills/defaults/backend-development/microservices-patterns.md +595 -0
  27. package/dist/skills/defaults/backend-development/microservices.md +284 -0
  28. package/dist/skills/defaults/backend-development/monorepo-management.md +623 -0
  29. package/dist/skills/defaults/backend-development/nodejs-backend-patterns.md +1048 -0
  30. package/dist/skills/defaults/backend-development/nx-workspace-patterns.md +457 -0
  31. package/dist/skills/defaults/backend-development/paypal-integration/SKILL.md +478 -0
  32. package/dist/skills/defaults/backend-development/pci-compliance/SKILL.md +480 -0
  33. package/dist/skills/defaults/backend-development/python-anti-patterns.md +349 -0
  34. package/dist/skills/defaults/backend-development/python-background-jobs.md +364 -0
  35. package/dist/skills/defaults/backend-development/python-code-style.md +360 -0
  36. package/dist/skills/defaults/backend-development/python-configuration.md +368 -0
  37. package/dist/skills/defaults/backend-development/python-design-patterns.md +296 -0
  38. package/dist/skills/defaults/backend-development/python-error-handling.md +323 -0
  39. package/dist/skills/defaults/backend-development/python-packaging.md +887 -0
  40. package/dist/skills/defaults/backend-development/python-performance-optimization.md +874 -0
  41. package/dist/skills/defaults/backend-development/python-project-structure.md +252 -0
  42. package/dist/skills/defaults/backend-development/python-resilience.md +376 -0
  43. package/dist/skills/defaults/backend-development/python-resource-management.md +421 -0
  44. package/dist/skills/defaults/backend-development/python-type-safety.md +428 -0
  45. package/dist/skills/defaults/backend-development/sql-optimization-patterns.md +509 -0
  46. package/dist/skills/defaults/backend-development/stripe-integration/SKILL.md +522 -0
  47. package/dist/skills/defaults/backend-development/turborepo-caching.md +376 -0
  48. package/dist/skills/defaults/blockchain/defi-protocol-templates.md +430 -0
  49. package/dist/skills/defaults/blockchain/nft-standards.md +364 -0
  50. package/dist/skills/defaults/blockchain/solidity-security.md +514 -0
  51. package/dist/skills/defaults/blockchain/web3-testing.md +360 -0
  52. package/dist/skills/defaults/business/competitive-landscape/SKILL.md +527 -0
  53. package/dist/skills/defaults/business/market-sizing-analysis/SKILL.md +451 -0
  54. package/dist/skills/defaults/business/startup-financial-modeling/SKILL.md +494 -0
  55. package/dist/skills/defaults/business/startup-metrics-framework/SKILL.md +564 -0
  56. package/dist/skills/defaults/business/team-composition-analysis.md +437 -0
  57. package/dist/skills/defaults/compliance/employment-contract-templates/SKILL.md +527 -0
  58. package/dist/skills/defaults/compliance/gdpr-data-handling/SKILL.md +630 -0
  59. package/dist/skills/defaults/data-engineering/airflow-dag-patterns.md +436 -0
  60. package/dist/skills/defaults/data-engineering/airflow.md +519 -0
  61. package/dist/skills/defaults/data-engineering/data-quality.md +583 -0
  62. package/dist/skills/defaults/data-engineering/dbt-transformation-patterns.md +482 -0
  63. package/dist/skills/defaults/data-engineering/dbt.md +556 -0
  64. package/dist/skills/defaults/data-engineering/ml-pipeline-workflow/SKILL.md +247 -0
  65. package/dist/skills/defaults/data-engineering/spark-optimization.md +348 -0
  66. package/dist/skills/defaults/data-engineering/spark.md +411 -0
  67. package/dist/skills/defaults/database/postgresql.md +202 -0
  68. package/dist/skills/defaults/debugging/systematic-debugging.md +249 -0
  69. package/dist/skills/defaults/devops/architecture-decision-records.md +448 -0
  70. package/dist/skills/defaults/devops/changelog-automation.md +580 -0
  71. package/dist/skills/defaults/devops/cicd.md +314 -0
  72. package/dist/skills/defaults/devops/cloud.md +263 -0
  73. package/dist/skills/defaults/devops/code-review-excellence.md +299 -0
  74. package/dist/skills/defaults/devops/cost-optimization.md +295 -0
  75. package/dist/skills/defaults/devops/deployment-pipeline-design.md +356 -0
  76. package/dist/skills/defaults/devops/docker.md +281 -0
  77. package/dist/skills/defaults/devops/git-workflows.md +205 -0
  78. package/dist/skills/defaults/devops/github-actions.md +311 -0
  79. package/dist/skills/defaults/devops/gitlab-ci-patterns.md +266 -0
  80. package/dist/skills/defaults/devops/hybrid-cloud-networking.md +241 -0
  81. package/dist/skills/defaults/devops/istio-traffic-management.md +327 -0
  82. package/dist/skills/defaults/devops/kubernetes.md +339 -0
  83. package/dist/skills/defaults/devops/linkerd-patterns.md +311 -0
  84. package/dist/skills/defaults/devops/multi-cloud-architecture.md +181 -0
  85. package/dist/skills/defaults/devops/observability.md +243 -0
  86. package/dist/skills/defaults/devops/openapi-spec-generation.md +1024 -0
  87. package/dist/skills/defaults/devops/postmortem-writing.md +396 -0
  88. package/dist/skills/defaults/devops/prometheus-configuration.md +265 -0
  89. package/dist/skills/defaults/devops/secrets-management.md +341 -0
  90. package/dist/skills/defaults/devops/service-mesh-observability.md +385 -0
  91. package/dist/skills/defaults/devops/terraform-module-library.md +244 -0
  92. package/dist/skills/defaults/finance/backtesting-frameworks/SKILL.md +663 -0
  93. package/dist/skills/defaults/finance/risk-metrics-calculation/SKILL.md +557 -0
  94. package/dist/skills/defaults/frontend/accessibility-compliance.md +420 -0
  95. package/dist/skills/defaults/frontend/design-system-patterns.md +337 -0
  96. package/dist/skills/defaults/frontend/interaction-design.md +327 -0
  97. package/dist/skills/defaults/frontend/javascript.md +311 -0
  98. package/dist/skills/defaults/frontend/modern-javascript-patterns.md +927 -0
  99. package/dist/skills/defaults/frontend/react-native-design.md +440 -0
  100. package/dist/skills/defaults/frontend/react.md +345 -0
  101. package/dist/skills/defaults/frontend/responsive-design.md +472 -0
  102. package/dist/skills/defaults/frontend/tailwind-design-system.md +337 -0
  103. package/dist/skills/defaults/frontend/typescript-advanced-types.md +724 -0
  104. package/dist/skills/defaults/frontend/typescript.md +334 -0
  105. package/dist/skills/defaults/frontend/visual-design-foundations.md +326 -0
  106. package/dist/skills/defaults/frontend/web-component-design.md +279 -0
  107. package/dist/skills/defaults/game-development/godot-gdscript-patterns.md +188 -0
  108. package/dist/skills/defaults/game-development/unity-ecs-patterns.md +594 -0
  109. package/dist/skills/defaults/kubernetes/gitops-workflow.md +285 -0
  110. package/dist/skills/defaults/kubernetes/gitops.md +280 -0
  111. package/dist/skills/defaults/kubernetes/helm-chart-scaffolding.md +553 -0
  112. package/dist/skills/defaults/kubernetes/helm.md +343 -0
  113. package/dist/skills/defaults/kubernetes/k8s-manifest-generator.md +501 -0
  114. package/dist/skills/defaults/kubernetes/k8s-security-policies.md +342 -0
  115. package/dist/skills/defaults/kubernetes/manifests.md +330 -0
  116. package/dist/skills/defaults/kubernetes/security.md +337 -0
  117. package/dist/skills/defaults/llm-application/embedding-strategies.md +608 -0
  118. package/dist/skills/defaults/llm-application/hybrid-search-implementation.md +570 -0
  119. package/dist/skills/defaults/llm-application/hybrid-search.md +570 -0
  120. package/dist/skills/defaults/llm-application/langchain-architecture.md +666 -0
  121. package/dist/skills/defaults/llm-application/langchain.md +259 -0
  122. package/dist/skills/defaults/llm-application/llm-evaluation.md +695 -0
  123. package/dist/skills/defaults/llm-application/prompt-engineering-patterns.md +449 -0
  124. package/dist/skills/defaults/llm-application/prompt-engineering.md +219 -0
  125. package/dist/skills/defaults/llm-application/rag-implementation.md +434 -0
  126. package/dist/skills/defaults/llm-application/similarity-search-patterns.md +560 -0
  127. package/dist/skills/defaults/llm-application/similarity-search.md +560 -0
  128. package/dist/skills/defaults/llm-application/vector-index-tuning.md +523 -0
  129. package/dist/skills/defaults/mobile/mobile-android-design.md +440 -0
  130. package/dist/skills/defaults/mobile/mobile-ios-design.md +266 -0
  131. package/dist/skills/defaults/monitoring/distributed-tracing.md +436 -0
  132. package/dist/skills/defaults/monitoring/grafana-dashboards.md +370 -0
  133. package/dist/skills/defaults/monitoring/prometheus-configuration.md +379 -0
  134. package/dist/skills/defaults/monitoring/slo-implementation.md +323 -0
  135. package/dist/skills/defaults/refactoring/code-refactoring.md +349 -0
  136. package/dist/skills/defaults/security/anti-reversing-techniques/SKILL.md +559 -0
  137. package/dist/skills/defaults/security/auditor.md +168 -0
  138. package/dist/skills/defaults/security/binary-analysis-patterns/SKILL.md +438 -0
  139. package/dist/skills/defaults/security/memory-forensics/SKILL.md +483 -0
  140. package/dist/skills/defaults/security/mtls-configuration.md +349 -0
  141. package/dist/skills/defaults/security/protocol-reverse-engineering/SKILL.md +520 -0
  142. package/dist/skills/defaults/security/sast-configuration.md +182 -0
  143. package/dist/skills/defaults/security/security.md +313 -0
  144. package/dist/skills/defaults/security/stride-analysis.md +273 -0
  145. package/dist/skills/defaults/security/threat-mitigation-mapping.md +290 -0
  146. package/dist/skills/defaults/systems/bash-defensive-patterns/SKILL.md +539 -0
  147. package/dist/skills/defaults/systems/bats-testing-patterns/SKILL.md +631 -0
  148. package/dist/skills/defaults/systems/go-concurrency-patterns.md +657 -0
  149. package/dist/skills/defaults/systems/memory-safety-patterns.md +605 -0
  150. package/dist/skills/defaults/systems/rust-async-patterns.md +519 -0
  151. package/dist/skills/defaults/systems/shellcheck-configuration/SKILL.md +456 -0
  152. package/dist/skills/defaults/team-collaboration/multi-reviewer-patterns.md +126 -0
  153. package/dist/skills/defaults/team-collaboration/parallel-feature-development.md +151 -0
  154. package/dist/skills/defaults/testing/javascript-testing-patterns.md +1021 -0
  155. package/dist/skills/defaults/testing/python-testing-patterns.md +351 -0
  156. package/dist/skills/defaults/testing/testing.md +332 -0
  157. package/dist/skills/defaults/workflows/context-driven-development.md +384 -0
  158. package/dist/skills/defaults/workflows/track-management.md +592 -0
  159. package/dist/skills/defaults/workflows/workflow-patterns.md +622 -0
  160. package/dist/skills/index.d.ts +11 -0
  161. package/dist/skills/index.d.ts.map +1 -0
  162. package/dist/skills/index.js +129 -0
  163. package/dist/skills/index.js.map +1 -0
  164. package/dist/utils/character.js +4 -4
  165. package/dist/utils/character.js.map +1 -1
  166. package/dist/utils/inputbar.d.ts.map +1 -1
  167. package/dist/utils/inputbar.js +7 -0
  168. package/dist/utils/inputbar.js.map +1 -1
  169. package/package.json +1 -1
@@ -0,0 +1,663 @@
1
+ ---
2
+ name: backtesting-frameworks
3
+ description: Build robust backtesting systems for trading strategies with proper handling of look-ahead bias, survivorship bias, and transaction costs. Use when developing trading algorithms, validating strategies, or building backtesting infrastructure.
4
+ ---
5
+
6
+ # Backtesting Frameworks
7
+
8
+ Build robust, production-grade backtesting systems that avoid common pitfalls and produce reliable strategy performance estimates.
9
+
10
+ ## When to Use This Skill
11
+
12
+ - Developing trading strategy backtests
13
+ - Building backtesting infrastructure
14
+ - Validating strategy performance
15
+ - Avoiding common backtesting biases
16
+ - Implementing walk-forward analysis
17
+ - Comparing strategy alternatives
18
+
19
+ ## Core Concepts
20
+
21
+ ### 1. Backtesting Biases
22
+
23
+ | Bias | Description | Mitigation |
24
+ | ---------------- | ------------------------- | ----------------------- |
25
+ | **Look-ahead** | Using future information | Point-in-time data |
26
+ | **Survivorship** | Only testing on survivors | Use delisted securities |
27
+ | **Overfitting** | Curve-fitting to history | Out-of-sample testing |
28
+ | **Selection** | Cherry-picking strategies | Pre-registration |
29
+ | **Transaction** | Ignoring trading costs | Realistic cost models |
30
+
31
+ ### 2. Proper Backtest Structure
32
+
33
+ ```
34
+ Historical Data
35
+
36
+
37
+ ┌─────────────────────────────────────────┐
38
+ │ Training Set │
39
+ │ (Strategy Development & Optimization) │
40
+ └─────────────────────────────────────────┘
41
+
42
+
43
+ ┌─────────────────────────────────────────┐
44
+ │ Validation Set │
45
+ │ (Parameter Selection, No Peeking) │
46
+ └─────────────────────────────────────────┘
47
+
48
+
49
+ ┌─────────────────────────────────────────┐
50
+ │ Test Set │
51
+ │ (Final Performance Evaluation) │
52
+ └─────────────────────────────────────────┘
53
+ ```
54
+
55
+ ### 3. Walk-Forward Analysis
56
+
57
+ ```
58
+ Window 1: [Train──────][Test]
59
+ Window 2: [Train──────][Test]
60
+ Window 3: [Train──────][Test]
61
+ Window 4: [Train──────][Test]
62
+ ─────▶ Time
63
+ ```
64
+
65
+ ## Implementation Patterns
66
+
67
+ ### Pattern 1: Event-Driven Backtester
68
+
69
+ ```python
70
+ from abc import ABC, abstractmethod
71
+ from dataclasses import dataclass, field
72
+ from datetime import datetime
73
+ from decimal import Decimal
74
+ from enum import Enum
75
+ from typing import Dict, List, Optional
76
+ import pandas as pd
77
+ import numpy as np
78
+
79
+ class OrderSide(Enum):
80
+ BUY = "buy"
81
+ SELL = "sell"
82
+
83
+ class OrderType(Enum):
84
+ MARKET = "market"
85
+ LIMIT = "limit"
86
+ STOP = "stop"
87
+
88
+ @dataclass
89
+ class Order:
90
+ symbol: str
91
+ side: OrderSide
92
+ quantity: Decimal
93
+ order_type: OrderType
94
+ limit_price: Optional[Decimal] = None
95
+ stop_price: Optional[Decimal] = None
96
+ timestamp: Optional[datetime] = None
97
+
98
+ @dataclass
99
+ class Fill:
100
+ order: Order
101
+ fill_price: Decimal
102
+ fill_quantity: Decimal
103
+ commission: Decimal
104
+ slippage: Decimal
105
+ timestamp: datetime
106
+
107
+ @dataclass
108
+ class Position:
109
+ symbol: str
110
+ quantity: Decimal = Decimal("0")
111
+ avg_cost: Decimal = Decimal("0")
112
+ realized_pnl: Decimal = Decimal("0")
113
+
114
+ def update(self, fill: Fill) -> None:
115
+ if fill.order.side == OrderSide.BUY:
116
+ new_quantity = self.quantity + fill.fill_quantity
117
+ if new_quantity != 0:
118
+ self.avg_cost = (
119
+ (self.quantity * self.avg_cost + fill.fill_quantity * fill.fill_price)
120
+ / new_quantity
121
+ )
122
+ self.quantity = new_quantity
123
+ else:
124
+ self.realized_pnl += fill.fill_quantity * (fill.fill_price - self.avg_cost)
125
+ self.quantity -= fill.fill_quantity
126
+
127
+ @dataclass
128
+ class Portfolio:
129
+ cash: Decimal
130
+ positions: Dict[str, Position] = field(default_factory=dict)
131
+
132
+ def get_position(self, symbol: str) -> Position:
133
+ if symbol not in self.positions:
134
+ self.positions[symbol] = Position(symbol=symbol)
135
+ return self.positions[symbol]
136
+
137
+ def process_fill(self, fill: Fill) -> None:
138
+ position = self.get_position(fill.order.symbol)
139
+ position.update(fill)
140
+
141
+ if fill.order.side == OrderSide.BUY:
142
+ self.cash -= fill.fill_price * fill.fill_quantity + fill.commission
143
+ else:
144
+ self.cash += fill.fill_price * fill.fill_quantity - fill.commission
145
+
146
+ def get_equity(self, prices: Dict[str, Decimal]) -> Decimal:
147
+ equity = self.cash
148
+ for symbol, position in self.positions.items():
149
+ if position.quantity != 0 and symbol in prices:
150
+ equity += position.quantity * prices[symbol]
151
+ return equity
152
+
153
+ class Strategy(ABC):
154
+ @abstractmethod
155
+ def on_bar(self, timestamp: datetime, data: pd.DataFrame) -> List[Order]:
156
+ pass
157
+
158
+ @abstractmethod
159
+ def on_fill(self, fill: Fill) -> None:
160
+ pass
161
+
162
+ class ExecutionModel(ABC):
163
+ @abstractmethod
164
+ def execute(self, order: Order, bar: pd.Series) -> Optional[Fill]:
165
+ pass
166
+
167
+ class SimpleExecutionModel(ExecutionModel):
168
+ def __init__(self, slippage_bps: float = 10, commission_per_share: float = 0.01):
169
+ self.slippage_bps = slippage_bps
170
+ self.commission_per_share = commission_per_share
171
+
172
+ def execute(self, order: Order, bar: pd.Series) -> Optional[Fill]:
173
+ if order.order_type == OrderType.MARKET:
174
+ base_price = Decimal(str(bar["open"]))
175
+
176
+ # Apply slippage
177
+ slippage_mult = 1 + (self.slippage_bps / 10000)
178
+ if order.side == OrderSide.BUY:
179
+ fill_price = base_price * Decimal(str(slippage_mult))
180
+ else:
181
+ fill_price = base_price / Decimal(str(slippage_mult))
182
+
183
+ commission = order.quantity * Decimal(str(self.commission_per_share))
184
+ slippage = abs(fill_price - base_price) * order.quantity
185
+
186
+ return Fill(
187
+ order=order,
188
+ fill_price=fill_price,
189
+ fill_quantity=order.quantity,
190
+ commission=commission,
191
+ slippage=slippage,
192
+ timestamp=bar.name
193
+ )
194
+ return None
195
+
196
+ class Backtester:
197
+ def __init__(
198
+ self,
199
+ strategy: Strategy,
200
+ execution_model: ExecutionModel,
201
+ initial_capital: Decimal = Decimal("100000")
202
+ ):
203
+ self.strategy = strategy
204
+ self.execution_model = execution_model
205
+ self.portfolio = Portfolio(cash=initial_capital)
206
+ self.equity_curve: List[tuple] = []
207
+ self.trades: List[Fill] = []
208
+
209
+ def run(self, data: pd.DataFrame) -> pd.DataFrame:
210
+ """Run backtest on OHLCV data with DatetimeIndex."""
211
+ pending_orders: List[Order] = []
212
+
213
+ for timestamp, bar in data.iterrows():
214
+ # Execute pending orders at today's prices
215
+ for order in pending_orders:
216
+ fill = self.execution_model.execute(order, bar)
217
+ if fill:
218
+ self.portfolio.process_fill(fill)
219
+ self.strategy.on_fill(fill)
220
+ self.trades.append(fill)
221
+
222
+ pending_orders.clear()
223
+
224
+ # Get current prices for equity calculation
225
+ prices = {data.index.name or "default": Decimal(str(bar["close"]))}
226
+ equity = self.portfolio.get_equity(prices)
227
+ self.equity_curve.append((timestamp, float(equity)))
228
+
229
+ # Generate new orders for next bar
230
+ new_orders = self.strategy.on_bar(timestamp, data.loc[:timestamp])
231
+ pending_orders.extend(new_orders)
232
+
233
+ return self._create_results()
234
+
235
+ def _create_results(self) -> pd.DataFrame:
236
+ equity_df = pd.DataFrame(self.equity_curve, columns=["timestamp", "equity"])
237
+ equity_df.set_index("timestamp", inplace=True)
238
+ equity_df["returns"] = equity_df["equity"].pct_change()
239
+ return equity_df
240
+ ```
241
+
242
+ ### Pattern 2: Vectorized Backtester (Fast)
243
+
244
+ ```python
245
+ import pandas as pd
246
+ import numpy as np
247
+ from typing import Callable, Dict, Any
248
+
249
+ class VectorizedBacktester:
250
+ """Fast vectorized backtester for simple strategies."""
251
+
252
+ def __init__(
253
+ self,
254
+ initial_capital: float = 100000,
255
+ commission: float = 0.001, # 0.1%
256
+ slippage: float = 0.0005 # 0.05%
257
+ ):
258
+ self.initial_capital = initial_capital
259
+ self.commission = commission
260
+ self.slippage = slippage
261
+
262
+ def run(
263
+ self,
264
+ prices: pd.DataFrame,
265
+ signal_func: Callable[[pd.DataFrame], pd.Series]
266
+ ) -> Dict[str, Any]:
267
+ """
268
+ Run backtest with signal function.
269
+
270
+ Args:
271
+ prices: DataFrame with 'close' column
272
+ signal_func: Function that returns position signals (-1, 0, 1)
273
+
274
+ Returns:
275
+ Dictionary with results
276
+ """
277
+ # Generate signals (shifted to avoid look-ahead)
278
+ signals = signal_func(prices).shift(1).fillna(0)
279
+
280
+ # Calculate returns
281
+ returns = prices["close"].pct_change()
282
+
283
+ # Calculate strategy returns with costs
284
+ position_changes = signals.diff().abs()
285
+ trading_costs = position_changes * (self.commission + self.slippage)
286
+
287
+ strategy_returns = signals * returns - trading_costs
288
+
289
+ # Build equity curve
290
+ equity = (1 + strategy_returns).cumprod() * self.initial_capital
291
+
292
+ # Calculate metrics
293
+ results = {
294
+ "equity": equity,
295
+ "returns": strategy_returns,
296
+ "signals": signals,
297
+ "metrics": self._calculate_metrics(strategy_returns, equity)
298
+ }
299
+
300
+ return results
301
+
302
+ def _calculate_metrics(
303
+ self,
304
+ returns: pd.Series,
305
+ equity: pd.Series
306
+ ) -> Dict[str, float]:
307
+ """Calculate performance metrics."""
308
+ total_return = (equity.iloc[-1] / self.initial_capital) - 1
309
+ annual_return = (1 + total_return) ** (252 / len(returns)) - 1
310
+ annual_vol = returns.std() * np.sqrt(252)
311
+ sharpe = annual_return / annual_vol if annual_vol > 0 else 0
312
+
313
+ # Drawdown
314
+ rolling_max = equity.cummax()
315
+ drawdown = (equity - rolling_max) / rolling_max
316
+ max_drawdown = drawdown.min()
317
+
318
+ # Win rate
319
+ winning_days = (returns > 0).sum()
320
+ total_days = (returns != 0).sum()
321
+ win_rate = winning_days / total_days if total_days > 0 else 0
322
+
323
+ return {
324
+ "total_return": total_return,
325
+ "annual_return": annual_return,
326
+ "annual_volatility": annual_vol,
327
+ "sharpe_ratio": sharpe,
328
+ "max_drawdown": max_drawdown,
329
+ "win_rate": win_rate,
330
+ "num_trades": int((returns != 0).sum())
331
+ }
332
+
333
+ # Example usage
334
+ def momentum_signal(prices: pd.DataFrame, lookback: int = 20) -> pd.Series:
335
+ """Simple momentum strategy: long when price > SMA, else flat."""
336
+ sma = prices["close"].rolling(lookback).mean()
337
+ return (prices["close"] > sma).astype(int)
338
+
339
+ # Run backtest
340
+ # backtester = VectorizedBacktester()
341
+ # results = backtester.run(price_data, lambda p: momentum_signal(p, 50))
342
+ ```
343
+
344
+ ### Pattern 3: Walk-Forward Optimization
345
+
346
+ ```python
347
+ from typing import Callable, Dict, List, Tuple, Any
348
+ import pandas as pd
349
+ import numpy as np
350
+ from itertools import product
351
+
352
+ class WalkForwardOptimizer:
353
+ """Walk-forward analysis with anchored or rolling windows."""
354
+
355
+ def __init__(
356
+ self,
357
+ train_period: int,
358
+ test_period: int,
359
+ anchored: bool = False,
360
+ n_splits: int = None
361
+ ):
362
+ """
363
+ Args:
364
+ train_period: Number of bars in training window
365
+ test_period: Number of bars in test window
366
+ anchored: If True, training always starts from beginning
367
+ n_splits: Number of train/test splits (auto-calculated if None)
368
+ """
369
+ self.train_period = train_period
370
+ self.test_period = test_period
371
+ self.anchored = anchored
372
+ self.n_splits = n_splits
373
+
374
+ def generate_splits(
375
+ self,
376
+ data: pd.DataFrame
377
+ ) -> List[Tuple[pd.DataFrame, pd.DataFrame]]:
378
+ """Generate train/test splits."""
379
+ splits = []
380
+ n = len(data)
381
+
382
+ if self.n_splits:
383
+ step = (n - self.train_period) // self.n_splits
384
+ else:
385
+ step = self.test_period
386
+
387
+ start = 0
388
+ while start + self.train_period + self.test_period <= n:
389
+ if self.anchored:
390
+ train_start = 0
391
+ else:
392
+ train_start = start
393
+
394
+ train_end = start + self.train_period
395
+ test_end = min(train_end + self.test_period, n)
396
+
397
+ train_data = data.iloc[train_start:train_end]
398
+ test_data = data.iloc[train_end:test_end]
399
+
400
+ splits.append((train_data, test_data))
401
+ start += step
402
+
403
+ return splits
404
+
405
+ def optimize(
406
+ self,
407
+ data: pd.DataFrame,
408
+ strategy_func: Callable,
409
+ param_grid: Dict[str, List],
410
+ metric: str = "sharpe_ratio"
411
+ ) -> Dict[str, Any]:
412
+ """
413
+ Run walk-forward optimization.
414
+
415
+ Args:
416
+ data: Full dataset
417
+ strategy_func: Function(data, **params) -> results dict
418
+ param_grid: Parameter combinations to test
419
+ metric: Metric to optimize
420
+
421
+ Returns:
422
+ Combined results from all test periods
423
+ """
424
+ splits = self.generate_splits(data)
425
+ all_results = []
426
+ optimal_params_history = []
427
+
428
+ for i, (train_data, test_data) in enumerate(splits):
429
+ # Optimize on training data
430
+ best_params, best_metric = self._grid_search(
431
+ train_data, strategy_func, param_grid, metric
432
+ )
433
+ optimal_params_history.append(best_params)
434
+
435
+ # Test with optimal params
436
+ test_results = strategy_func(test_data, **best_params)
437
+ test_results["split"] = i
438
+ test_results["params"] = best_params
439
+ all_results.append(test_results)
440
+
441
+ print(f"Split {i+1}/{len(splits)}: "
442
+ f"Best {metric}={best_metric:.4f}, params={best_params}")
443
+
444
+ return {
445
+ "split_results": all_results,
446
+ "param_history": optimal_params_history,
447
+ "combined_equity": self._combine_equity_curves(all_results)
448
+ }
449
+
450
+ def _grid_search(
451
+ self,
452
+ data: pd.DataFrame,
453
+ strategy_func: Callable,
454
+ param_grid: Dict[str, List],
455
+ metric: str
456
+ ) -> Tuple[Dict, float]:
457
+ """Grid search for best parameters."""
458
+ best_params = None
459
+ best_metric = -np.inf
460
+
461
+ # Generate all parameter combinations
462
+ param_names = list(param_grid.keys())
463
+ param_values = list(param_grid.values())
464
+
465
+ for values in product(*param_values):
466
+ params = dict(zip(param_names, values))
467
+ results = strategy_func(data, **params)
468
+
469
+ if results["metrics"][metric] > best_metric:
470
+ best_metric = results["metrics"][metric]
471
+ best_params = params
472
+
473
+ return best_params, best_metric
474
+
475
+ def _combine_equity_curves(
476
+ self,
477
+ results: List[Dict]
478
+ ) -> pd.Series:
479
+ """Combine equity curves from all test periods."""
480
+ combined = pd.concat([r["equity"] for r in results])
481
+ return combined
482
+ ```
483
+
484
+ ### Pattern 4: Monte Carlo Analysis
485
+
486
+ ```python
487
+ import numpy as np
488
+ import pandas as pd
489
+ from typing import Dict, List
490
+
491
+ class MonteCarloAnalyzer:
492
+ """Monte Carlo simulation for strategy robustness."""
493
+
494
+ def __init__(self, n_simulations: int = 1000, confidence: float = 0.95):
495
+ self.n_simulations = n_simulations
496
+ self.confidence = confidence
497
+
498
+ def bootstrap_returns(
499
+ self,
500
+ returns: pd.Series,
501
+ n_periods: int = None
502
+ ) -> np.ndarray:
503
+ """
504
+ Bootstrap simulation by resampling returns.
505
+
506
+ Args:
507
+ returns: Historical returns series
508
+ n_periods: Length of each simulation (default: same as input)
509
+
510
+ Returns:
511
+ Array of shape (n_simulations, n_periods)
512
+ """
513
+ if n_periods is None:
514
+ n_periods = len(returns)
515
+
516
+ simulations = np.zeros((self.n_simulations, n_periods))
517
+
518
+ for i in range(self.n_simulations):
519
+ # Resample with replacement
520
+ simulated_returns = np.random.choice(
521
+ returns.values,
522
+ size=n_periods,
523
+ replace=True
524
+ )
525
+ simulations[i] = simulated_returns
526
+
527
+ return simulations
528
+
529
+ def analyze_drawdowns(
530
+ self,
531
+ returns: pd.Series
532
+ ) -> Dict[str, float]:
533
+ """Analyze drawdown distribution via simulation."""
534
+ simulations = self.bootstrap_returns(returns)
535
+
536
+ max_drawdowns = []
537
+ for sim_returns in simulations:
538
+ equity = (1 + sim_returns).cumprod()
539
+ rolling_max = np.maximum.accumulate(equity)
540
+ drawdowns = (equity - rolling_max) / rolling_max
541
+ max_drawdowns.append(drawdowns.min())
542
+
543
+ max_drawdowns = np.array(max_drawdowns)
544
+
545
+ return {
546
+ "expected_max_dd": np.mean(max_drawdowns),
547
+ "median_max_dd": np.median(max_drawdowns),
548
+ f"worst_{int(self.confidence*100)}pct": np.percentile(
549
+ max_drawdowns, (1 - self.confidence) * 100
550
+ ),
551
+ "worst_case": max_drawdowns.min()
552
+ }
553
+
554
+ def probability_of_loss(
555
+ self,
556
+ returns: pd.Series,
557
+ holding_periods: List[int] = [21, 63, 126, 252]
558
+ ) -> Dict[int, float]:
559
+ """Calculate probability of loss over various holding periods."""
560
+ results = {}
561
+
562
+ for period in holding_periods:
563
+ if period > len(returns):
564
+ continue
565
+
566
+ simulations = self.bootstrap_returns(returns, period)
567
+ total_returns = (1 + simulations).prod(axis=1) - 1
568
+ prob_loss = (total_returns < 0).mean()
569
+ results[period] = prob_loss
570
+
571
+ return results
572
+
573
+ def confidence_interval(
574
+ self,
575
+ returns: pd.Series,
576
+ periods: int = 252
577
+ ) -> Dict[str, float]:
578
+ """Calculate confidence interval for future returns."""
579
+ simulations = self.bootstrap_returns(returns, periods)
580
+ total_returns = (1 + simulations).prod(axis=1) - 1
581
+
582
+ lower = (1 - self.confidence) / 2
583
+ upper = 1 - lower
584
+
585
+ return {
586
+ "expected": total_returns.mean(),
587
+ "lower_bound": np.percentile(total_returns, lower * 100),
588
+ "upper_bound": np.percentile(total_returns, upper * 100),
589
+ "std": total_returns.std()
590
+ }
591
+ ```
592
+
593
+ ## Performance Metrics
594
+
595
+ ```python
596
+ def calculate_metrics(returns: pd.Series, rf_rate: float = 0.02) -> Dict[str, float]:
597
+ """Calculate comprehensive performance metrics."""
598
+ # Annualization factor (assuming daily returns)
599
+ ann_factor = 252
600
+
601
+ # Basic metrics
602
+ total_return = (1 + returns).prod() - 1
603
+ annual_return = (1 + total_return) ** (ann_factor / len(returns)) - 1
604
+ annual_vol = returns.std() * np.sqrt(ann_factor)
605
+
606
+ # Risk-adjusted returns
607
+ sharpe = (annual_return - rf_rate) / annual_vol if annual_vol > 0 else 0
608
+
609
+ # Sortino (downside deviation)
610
+ downside_returns = returns[returns < 0]
611
+ downside_vol = downside_returns.std() * np.sqrt(ann_factor)
612
+ sortino = (annual_return - rf_rate) / downside_vol if downside_vol > 0 else 0
613
+
614
+ # Calmar ratio
615
+ equity = (1 + returns).cumprod()
616
+ rolling_max = equity.cummax()
617
+ drawdowns = (equity - rolling_max) / rolling_max
618
+ max_drawdown = drawdowns.min()
619
+ calmar = annual_return / abs(max_drawdown) if max_drawdown != 0 else 0
620
+
621
+ # Win rate and profit factor
622
+ wins = returns[returns > 0]
623
+ losses = returns[returns < 0]
624
+ win_rate = len(wins) / len(returns[returns != 0]) if len(returns[returns != 0]) > 0 else 0
625
+ profit_factor = wins.sum() / abs(losses.sum()) if losses.sum() != 0 else np.inf
626
+
627
+ return {
628
+ "total_return": total_return,
629
+ "annual_return": annual_return,
630
+ "annual_volatility": annual_vol,
631
+ "sharpe_ratio": sharpe,
632
+ "sortino_ratio": sortino,
633
+ "calmar_ratio": calmar,
634
+ "max_drawdown": max_drawdown,
635
+ "win_rate": win_rate,
636
+ "profit_factor": profit_factor,
637
+ "num_trades": int((returns != 0).sum())
638
+ }
639
+ ```
640
+
641
+ ## Best Practices
642
+
643
+ ### Do's
644
+
645
+ - **Use point-in-time data** - Avoid look-ahead bias
646
+ - **Include transaction costs** - Realistic estimates
647
+ - **Test out-of-sample** - Always reserve data
648
+ - **Use walk-forward** - Not just train/test
649
+ - **Monte Carlo analysis** - Understand uncertainty
650
+
651
+ ### Don'ts
652
+
653
+ - **Don't overfit** - Limit parameters
654
+ - **Don't ignore survivorship** - Include delisted
655
+ - **Don't use adjusted data carelessly** - Understand adjustments
656
+ - **Don't optimize on full history** - Reserve test set
657
+ - **Don't ignore capacity** - Market impact matters
658
+
659
+ ## Resources
660
+
661
+ - [Advances in Financial Machine Learning (Marcos López de Prado)](https://www.amazon.com/Advances-Financial-Machine-Learning-Marcos/dp/1119482089)
662
+ - [Quantitative Trading (Ernest Chan)](https://www.amazon.com/Quantitative-Trading-Build-Algorithmic-Business/dp/1119800064)
663
+ - [Backtrader Documentation](https://www.backtrader.com/docu/)