Trading Strategies
Overview
This chapter covers four classical trading strategies, the theory behind each, and their implementation in Puffin. All strategies share a common interface, making them interchangeable for backtesting and live trading.
The Strategy Interface
Every strategy in Puffin implements the same contract:
from puffin.strategies.base import Strategy, SignalFrame
class Strategy(ABC):
def generate_signals(self, data: pd.DataFrame) -> SignalFrame:
"""Returns DataFrame with 'signal' (-1 to 1) and 'confidence' (0 to 1)."""
def get_parameters(self) -> dict:
"""Returns current parameter values."""
This means you can swap any strategy into the backtester or live engine without code changes.
1. Momentum Strategy
Theory: Assets that have been rising tend to continue rising (and vice versa). This is one of the most well-documented anomalies in finance.
Implementation: Moving average crossover. When the short-term MA crosses above the long-term MA, the trend is up → buy. When it crosses below → sell.
from puffin.strategies.momentum import MomentumStrategy
strategy = MomentumStrategy(
short_window=20, # 20-day fast MA
long_window=50, # 50-day slow MA
ma_type="sma", # Simple moving average (or "ema")
)
signals = strategy.generate_signals(data)
EMA (exponential moving average) reacts faster to recent price changes than SMA. Try both and compare in your backtests.
2. Mean Reversion Strategy
Theory: Prices that deviate significantly from their historical mean tend to revert back. This works best in range-bound markets.
Implementation: Bollinger Bands with z-score. Buy when price is oversold (low z-score), sell when overbought (high z-score), exit at the mean.
from puffin.strategies.mean_reversion import MeanReversionStrategy
strategy = MeanReversionStrategy(
window=20, # Lookback period
num_std=2.0, # Bollinger Band width
zscore_entry=-2.0, # Buy below this z-score
zscore_exit=0.0, # Exit at the mean
)
Mean reversion strategies can suffer catastrophic losses in trending markets. Always pair with stop losses and regime detection.
3. Statistical Arbitrage (Pairs Trading)
Theory: Two historically correlated assets occasionally diverge. When they do, bet on convergence by going long the underperformer and short the outperformer.
Implementation: Cointegration testing to find pairs, then trade the spread.
from puffin.strategies.stat_arb import StatArbStrategy
# Step 1: Find cointegrated pairs
pairs = StatArbStrategy.find_cointegrated_pairs(
price_data, # DataFrame with tickers as columns
pvalue_threshold=0.05
)
# Step 2: Trade a pair
strategy = StatArbStrategy(
lookback=60,
entry_zscore=2.0,
exit_zscore=0.5,
)
Cointegration is not the same as correlation. Two assets can be highly correlated but not cointegrated. Cointegration means they share a long-run equilibrium relationship.
4. Market Making
Theory: Profit from the bid-ask spread by providing liquidity. Place buy orders below and sell orders above the current price. Earn the spread on each round trip.
Implementation: Quote placement around the mid-price with volatility-adjusted spreads.
from puffin.strategies.market_making import MarketMakingStrategy
strategy = MarketMakingStrategy(
spread_bps=10, # 10 basis points spread
max_inventory=100, # Maximum position size
volatility_window=20, # Lookback for vol calculation
)
quotes = strategy.get_quote_prices(mid_price=150.0)
# {'bid': 149.925, 'ask': 150.075, 'spread_bps': 10.0}
Using the Strategy Registry
All built-in strategies are registered and can be instantiated by name:
from puffin.strategies.registry import get_strategy, list_strategies
print(list_strategies())
# ['momentum', 'mean_reversion', 'stat_arb', 'market_making']
strategy = get_strategy("momentum", short_window=10, long_window=30)
Strategy Comparison
| Strategy | Market Regime | Holding Period | Complexity |
|---|---|---|---|
| Momentum | Trending | Days–Weeks | Low |
| Mean Reversion | Range-bound | Hours–Days | Low |
| Stat Arb | Any (pair-dependent) | Days–Weeks | Medium |
| Market Making | Any (prefers calm) | Seconds–Minutes | High |
Exercises
- Run the momentum strategy on SPY with different window sizes (10/30, 20/50, 50/200). Which performs best?
- Apply mean reversion to a range-bound stock. How does it perform on a trending stock?
- Use
find_cointegrated_pairson a set of bank stocks (JPM, BAC, WFC, C, GS). Which pairs are cointegrated?
Summary
- All strategies share the
Strategyinterface for interoperability - Momentum follows trends; mean reversion bets against them
- Stat arb exploits relative mispricings between correlated assets
- Market making profits from the spread but requires careful inventory management
- No strategy works in all market conditions — regime awareness is critical
Next Steps
In Part 4, we’ll build the backtesting engine to test these strategies against historical data.