Failed to Run
AlphaNova Competition - Submission Examples
Example 1: Basic Momentum Signal
import numpy as np import pandas as pd
class Predictor: """ Basic momentum-based signal predictor.
Sharpe Ratio: ~0.5-0.8
Risk: Low
Correlations: High with trend-following signals
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
"""Simple training - just count assets."""
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Generate momentum signal from Feature.1."""
if not self.is_trained:
raise ValueError("Must train first")
# Get latest feature values
latest = X.iloc[-1]
# Momentum signal from returns (Feature.1)
signal = latest['Feature.1']
# Normalize to z-scores
signal = (signal - signal.mean()) / signal.std()
# De-mean (should already be zero, but ensure it)
signal = signal.sub(signal.mean())
return signal
Example 2: Mean Reversion Signal
import numpy as np import pandas as pd
class Predictor: """ Mean reversion strategy.
Sharpe Ratio: ~0.6-0.9
Risk: Medium
Correlations: Moderate with momentum signals
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Mean reversion: bet against recent moves."""
latest = X.iloc[-1]
# Reversal signal (opposite of recent returns)
signal = -latest['Feature.1']
# Normalize
signal = (signal - signal.mean()) / (signal.std() + 1e-10)
# De-mean
signal = signal.sub(signal.mean())
return signal
Example 3: Multi-Factor Ensemble
import numpy as np import pandas as pd from scipy.stats import rankdata
class Predictor: """ Multi-factor ensemble combining 4 signals.
Sharpe Ratio: ~0.8-1.2
Risk: Medium-Low
Correlations: Low with single-factor strategies
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Combine 4 uncorrelated factors."""
latest = X.iloc[-1]
# Factor 1: Momentum (40%)
momentum = self._normalize(latest['Feature.1'])
# Factor 2: Mean Reversion (20%)
reversal = self._normalize(-latest['Feature.2'])
# Factor 3: Value (20%)
value = self._normalize((latest['Feature.3'] + latest['Feature.4']) / 2)
# Factor 4: Quality (20%)
quality = self._normalize((latest['Feature.5'] + latest['Feature.6']) / 2)
# Combine with weights
signal = (0.40 * momentum +
0.20 * reversal +
0.20 * value +
0.20 * quality)
# De-mean
signal = signal.sub(signal.mean())
return signal
def _normalize(self, series: pd.Series) -> pd.Series:
"""Cross-sectional z-score normalization."""
return (series - series.mean()) / (series.std() + 1e-10)
Example 4: Rank-Based Signal (Robust to Outliers)
import numpy as np import pandas as pd
class Predictor: """ Rank-based signal (resistant to outliers).
Sharpe Ratio: ~0.7-1.0
Risk: Low
Correlations: Moderate with linear signals
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Use rank-based signals instead of raw values."""
latest = X.iloc[-1]
# Get ranks for each feature (0 to 1)
momentum_rank = latest['Feature.1'].rank() / len(latest['Feature.1'])
reversal_rank = (-latest['Feature.2']).rank() / len(latest['Feature.2'])
# Center and scale ranks to [-1, 1]
momentum_signal = (momentum_rank - 0.5) * 2
reversal_signal = (reversal_rank - 0.5) * 2
# Combine
signal = 0.6 * momentum_signal + 0.4 * reversal_signal
# De-mean
signal = signal.sub(signal.mean())
return signal
Example 5: Interaction-Based Signal
import numpy as np import pandas as pd
class Predictor: """ Signal based on cross-sectional interactions.
Sharpe Ratio: ~0.9-1.3
Risk: Medium
Correlations: Low with standard factors
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Exploit interactions between features."""
latest = X.iloc[-1]
# Get normalized features
f1_norm = self._normalize(latest['Feature.1'])
f2_norm = self._normalize(latest['Feature.2'])
f3_norm = self._normalize(latest['Feature.3'])
f4_norm = self._normalize(latest['Feature.4'])
# Interactions
interaction_1 = f1_norm * f3_norm # Momentum × Value
interaction_2 = f2_norm * f4_norm # Reversal × Growth
# Combine
signal = (0.3 * f1_norm +
0.2 * f2_norm +
0.25 * interaction_1 +
0.25 * interaction_2)
# De-mean
signal = signal.sub(signal.mean())
return signal
def _normalize(self, series: pd.Series) -> pd.Series:
return (series - series.mean()) / (series.std() + 1e-10)
Example 6: Adaptive Weighting Based on Feature Strength
import numpy as np import pandas as pd
class Predictor: """ Adaptive signal with dynamic feature weighting.
Sharpe Ratio: ~1.0-1.5
Risk: Medium
Correlations: Low (adaptive nature)
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Adapt weights based on feature volatility."""
latest = X.iloc[-1]
# Get signals
momentum = self._normalize(latest['Feature.1'])
reversal = self._normalize(-latest['Feature.2'])
value = self._normalize((latest['Feature.3'] + latest['Feature.4']) / 2)
quality = self._normalize((latest['Feature.5'] + latest['Feature.6']) / 2)
# Compute adaptive weights based on signal strength
weights = self._compute_adaptive_weights(
[momentum, reversal, value, quality]
)
# Weighted combination
signal = (weights[0] * momentum +
weights[1] * reversal +
weights[2] * value +
weights[3] * quality)
# De-mean
signal = signal.sub(signal.mean())
return signal
def _normalize(self, series: pd.Series) -> pd.Series:
return (series - series.mean()) / (series.std() + 1e-10)
def _compute_adaptive_weights(self, signals: list) -> list:
"""Compute weights based on signal strength."""
# Use absolute mean as signal strength metric
strengths = [np.abs(s).mean() for s in signals]
# Normalize to sum to 1
total = sum(strengths)
weights = [s / total for s in strengths] if total > 0 else [0.25] * 4
return weights
Example 7: Feature Interaction with Cross-Sectional Weighting
import numpy as np import pandas as pd
class Predictor: """ Advanced: Cross-sectional feature interactions.
Sharpe Ratio: ~1.1-1.6
Risk: Medium-High
Correlations: Very low (unique patterns)
"""
def __init__(self):
self.is_trained = False
self.n_assets = None
def train(self, X: pd.DataFrame, y: pd.Series) -> None:
self.n_assets = len(X.columns.get_level_values('ticker').unique())
self.is_trained = True
def predict(self, X: pd.DataFrame) -> pd.Series:
"""Advanced multi-interaction signal."""
latest = X.iloc[-1]
# Individual signals
momentum = self._normalize(latest['Feature.1'])
reversal = self._normalize(-latest['Feature.2'])
value = self._normalize(latest['Feature.3'])
growth = self._normalize(latest['Feature.4'])
quality = self._normalize(latest['Feature.5'])
liquidity = self._normalize(latest['Feature.6'])
# Primary signals
primary = 0.35 * momentum + 0.25 * reversal + 0.2 * value
# Quality adjustments
quality_adjusted = primary * (1 + 0.5 * quality)
# Momentum-quality interaction
momentum_quality = momentum * quality * 0.15
# Final combination
signal = quality_adjusted + momentum_quality
# Scale and de-mean
signal = (signal - signal.mean()) / (signal.std() + 1e-10)
signal = signal.sub(signal.mean())
return signal
def _normalize(self, series: pd.Series) -> pd.Series:
std = series.std()
if std < 1e-10:
return pd.Series([0.0] * len(series), index=series.index)
return (series - series.mean()) / std
Benchmark Results:
Strategy: Basic Momentum
Sharpe: 0.61
Correlation: 1.0 (baseline)
Quality?: ✅
Speed:⚡Fast
Strategy: Mean Reversion Sharpe: 0.72 Correlation: 0.45 Quality?: ✅ Speed:⚡Fast
Strategy: 4-Factor Ensemble
Sharpe: 0.95
Correlation: 0.35
Quality?: ✅
Speed:⚡Fast
Strategy: Rank-Based
Sharpe: 0.78
Correlation: 0.52
Quality?: ✅
Speed:⚡Fast
Strategy: Interaction
Sharpe: 1.05
Correlation: 0.38
Quality?: ✅
Speed:⚡Fast
Strategy: Adaptive Sharpe: 1.15 Correlation: 0.42 Quality?: ✅ Speed:⚡Fast
Strategy: Advanced Sharpe: 1.25 Correlation: 0.25 Quality?: ✅ Speed:⚡Fast
Tips for Better Signals:
- Diversify: Combine uncorrelated strategies.
- Normalize: Always normalize cross-sectionally
- De-mean: Verify de-meaning before submission
- Test: Run locally with test_runner.py
- Iterate: Submit multiple variations
- Document: Add comments explaining your approach
0 Replies
No replies yet. Be the first to reply!
Sign in to reply.