AlphaNova
1

Failed to Run

AmonRa's avatarAmonRa
3h ago

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:

  1. Diversify: Combine uncorrelated strategies.
  2. Normalize: Always normalize cross-sectionally
  3. De-mean: Verify de-meaning before submission
  4. Test: Run locally with test_runner.py
  5. Iterate: Submit multiple variations
  6. Document: Add comments explaining your approach

0 Replies

No replies yet. Be the first to reply!

Sign in to reply.

Failed to Run | AlphaNova Discussions