Skip to main content

Strategy Basics

Every quantitative strategy follows a lifecycle. Understanding this lifecycle is the foundation of successful strategy development.

The Strategy Lifecycle

Research → Develop → Backtest → Optimize → Deploy → Monitor
↑ │
└──────────────────── Iterate ←─────────────────────────┘

1. Research

Before writing any code, answer:

  • What market inefficiency am I trying to exploit?
  • Why does it exist? (behavioral bias, structural friction, information asymmetry)
  • Will it persist? (or will it be arbitraged away?)
tip

The best strategies are built on understanding why something works, not just finding patterns in data.

2. Develop

Convert your hypothesis into code:

from vecalpha import Strategy

class MomentumStrategy(Strategy):
"""Buy when price breaks above 20-day high."""

def on_bar(self, bar):
if self.position == 0:
if bar.close > self.high(20):
self.buy(size=self.calculate_position_size())
else:
if bar.close < self.low(10):
self.sell(size=self.position)

3. Backtest

Test on historical data. Key questions:

  • Would this have made money?
  • What were the worst losses?
  • How does it perform in different market conditions?

4. Optimize

Fine-tune parameters carefully:

  • Avoid overfitting
  • Use out-of-sample testing
  • Focus on robustness, not peak performance

5. Deploy

Move to live trading:

  • Start with paper trading
  • Scale up gradually
  • Set risk limits

6. Monitor

Track performance and iterate:

  • Compare live vs. backtest
  • Identify degradation early
  • Adapt to changing markets

Strategy Types

Trend Following

Capture sustained price movements.

Logic: Prices that have been rising tend to continue rising.

Indicators: Moving averages, breakout systems, ADX

Works best: Strong trending markets

Struggles: Sideways, choppy markets

Mean Reversion

Profit from prices returning to average.

Logic: Extreme moves tend to reverse.

Indicators: Bollinger Bands, RSI, z-scores

Works best: Range-bound, choppy markets

Struggles: Strong trends

Statistical Arbitrage

Exploit statistical relationships.

Logic: Related securities move together; divergences revert.

Indicators: Cointegration, correlation, pairs

Works best: Markets with related instruments

Struggles: Structural breaks, regime changes

Market Making

Provide liquidity for spread capture.

Logic: Buy at bid, sell at ask, capture spread.

Indicators: Order book analysis, volatility

Works best: High-volume, liquid markets

Struggles: Fast markets, adverse selection


Strategy Components

Every strategy needs these core components:

1. Data Input

What data does your strategy consume?

# Example data requirements
data_config = {
'symbols': ['AAPL', 'MSFT'],
'timeframe': '1h',
'fields': ['open', 'high', 'low', 'close', 'volume'],
'start_date': '2020-01-01',
}

2. Signal Generation

The logic that produces buy/sell signals.

def generate_signal(self, data):
"""Return: 1 (buy), -1 (sell), 0 (hold)"""
if condition_buy:
return 1
elif condition_sell:
return -1
return 0

3. Position Sizing

How much to trade.

def calculate_position_size(self):
"""Risk-based position sizing."""
risk_per_trade = 0.02 # 2% of portfolio
stop_loss_distance = self.entry_price * 0.05 # 5% stop
position_size = (self.portfolio_value * risk_per_trade) / stop_loss_distance
return position_size

4. Risk Management

Protect against losses.

risk_config = {
'max_position_size': 0.10, # Max 10% in one position
'max_drawdown': 0.15, # Stop if drawdown exceeds 15%
'max_correlation': 0.70, # Limit correlated positions
}

5. Execution

How orders are placed.

execution_config = {
'order_type': 'limit', # or 'market'
'time_in_force': 'GTC', # Good Till Cancel
'slippage_tolerance': 0.001, # Max slippage
}

Common Pitfalls

1. Overfitting

Problem: Strategy works perfectly on historical data but fails in live trading.

Solution:

  • Use out-of-sample testing
  • Limit parameters
  • Focus on economic rationale, not just data mining

2. Look-Ahead Bias

Problem: Using future information in signals.

Solution:

  • Always shift data properly
  • Test: "Could I have known this at trade time?"

3. Survivorship Bias

Problem: Testing only on currently traded securities.

Solution:

  • Use survivorship-free data
  • Include delisted/bankrupt securities

4. Ignoring Costs

Problem: Not accounting for commissions and slippage.

Solution:

  • Include realistic costs in backtests
  • Consider impact on high-frequency strategies

Your First Strategy

Ready to build? Here's a template:

from vecalpha import Strategy, Backtest

class SimpleMovingAverageStrategy(Strategy):
"""Simple MA crossover strategy."""

def __init__(self):
self.short_window = 20
self.long_window = 50

def on_bar(self, bar):
# Calculate indicators
short_ma = self.sma(self.short_window)
long_ma = self.sma(self.long_window)

# Generate signals
if self.position == 0: # No position
if short_ma > long_ma:
self.buy(size=self.calculate_position_size())
else: # Have position
if short_ma < long_ma:
self.sell(size=self.position)

# Run backtest
results = Backtest(
SimpleMovingAverageStrategy,
symbol='AAPL',
start='2020-01-01',
end='2024-01-01',
initial_capital=100000
).run()

print(results.summary())

Next Steps