← Back to Learn
II IntermediateWeek 4 • Lesson 12Duration: 50 min

ENT Entry Gate Systems

The filter that separates good signals from expensive noise

Learning Objectives

  • Understand the purpose and mechanics of entry filtering
  • Learn what features make effective entry filters
  • See how over-filtering destroys profitability
  • Design entry rules that improve signal quality without killing trade frequency

Explain Like I'm 5

Your signal model says "there might be an opportunity here." The entry gate says "sure, but is RIGHT NOW a good time to act on it?" It's like having a scout who says "the restaurant is great" vs. a friend who adds "yeah but there's a two-hour wait and the kitchen closes in 30 minutes — let's come back tomorrow."

Think of It This Way

Think of airport security. The ticket counter (L1) says "you're allowed to fly." Security (L2) says "but can you fly RIGHT NOW based on current conditions?" Most people pass both. But the ones who get stopped at security were going to cause problems. L2 catches the signals that look good on paper but would perform badly in current conditions.

1Why Entry Filtering Matters

Not every valid signal should be traded immediately. A signal might be statistically sound but the current market conditions make it a bad bet. Reasons to filter a valid L1 signal: Spread is too wide. During low liquidity (Asian session for EUR pairs, or around news events), spreads can blow out. A trade that's profitable at 1-pip spread might be a loser at 5-pip spread. Regime is unfavorable. If the market is in a choppy, random-walk regime and your signal is trend-following, the hit rate drops. Better to wait for a trending regime. Recent performance is poor. If the system has been losing, a drawdown-aware filter might reduce position sizes or skip marginal signals. This isn't superstition — a cluster of losses often signals a regime shift. Volatility is extreme. Very high volatility can mean your stop-loss gets hit by noise rather than genuine adverse price movement. Very low volatility can mean your take-profit is unreachable. The entry filter evaluates all of these and makes a binary decision: ENTER or SKIP.

Win Rate by Entry Condition

2The Over-Filtering Problem

Here's the trap: if you make your filter too aggressive, you kill trade frequency. And trade frequency matters. A system that takes 10 trades per month with 65% win rate might actually perform worse than a system taking 40 trades with 58% win rate, because the second system has more samples and lower variance in monthly outcomes. The math: • 10 trades × 65% WR × 1.5 avg R/trade = 9.75R expected, but with huge monthly variance • 40 trades × 58% WR × 1.2 avg R/trade = 27.84R expected, with tighter distribution More trades = more Law of Large Numbers = smoother equity curve = more predictable risk management. The goal isn't maximum win rate. It's maximum risk-adjusted return. Sometimes that means accepting slightly lower quality trades to maintain volume.

Trade Frequency vs Win Rate: The Filtering Tradeoff

3Effective Entry Filter Features

What actually works for entry filtering? Based on empirical results across different market clusters: Spread ratio (current spread / average spread). If it's above 2x normal, the edge gets eaten by transaction costs. Simple and effective. Regime classification. Is the market trending, mean-reverting, or random-walking? Each signal type performs differently in each regime. Trend signals in trending markets = good. Trend signals in choppy markets = bad. Time-of-day. Some sessions are better than others for specific pairs. London session for EUR crosses, New York for USD pairs. This is well-documented in market microstructure research. Model agreement. If you have an ensemble of models, how many agree? Unanimous agreement = higher confidence entry. Split vote = skip or reduce size. Drawdown context. If the system is in an elevated drawdown zone, filter more aggressively. Protect capital first, worry about missed opportunities later.

4ML-Based vs Rule-Based Filtering

There are two approaches to building L2: Rule-based. Simple conditionals: if spread > 2x normal, skip. If regime = choppy and signal = trend, skip. Easy to understand, easy to debug, transparent. ML-based. Train a classifier on historical data: given L1 output + market context, will this trade be profitable? More powerful in theory, but harder to interpret and more prone to overfitting. In practice, a hybrid approach works well. Use rules for the obvious stuff (spread filters, regime checks) and ML for the subtler patterns (timing, cross-factor interactions). One important caveat: ML-based filters have a nasty tendency to over-skip. They learn that "not trading" is often the safe choice, so they default to SKIP too frequently. You need to explicitly penalize over-filtering during training — either through class weighting or by including trade frequency as a loss function component. López de Prado, M. (2018). "Advances in Financial Machine Learning." Wiley.

Key Formulas

Entry Filter Expected Value

Expected return per trade that passes the filter. WR = win rate of filtered trades, W̄ = average win, L̄ = average loss. The filter should increase this relative to unfiltered trades.

Spread-Adjusted Edge

Edge after accounting for round-trip spread cost. When spread widens, your effective edge shrinks. If E_adj goes negative, don't trade.

Hands-On Code

Entry Filter Implementation

python
class EntryFilter:
    """L2 entry gate — filters L1 signals by market conditions."""
    
    def __init__(self, max_spread_ratio=2.0, min_confidence=0.55):
        self.max_spread_ratio = max_spread_ratio
        self.min_confidence = min_confidence
    
    def evaluate(self, l1_signal, market_context):
        """Decide whether to enter on an L1 signal."""
        reasons = []
        
        # Spread check
        spread_ratio = market_context['current_spread'] / market_context['avg_spread']
        if spread_ratio > self.max_spread_ratio:
            reasons.append(f"Spread too wide: {spread_ratio:.1f}x normal")
        
        # Confidence check
        if l1_signal['probability'] < self.min_confidence:
            reasons.append(f"Low confidence: {l1_signal['probability']:.2f}")
        
        # Regime check
        regime = market_context.get('regime', 'unknown')
        signal_type = l1_signal.get('type', 'trend')
        if regime == 'choppy' and signal_type == 'trend':
            reasons.append("Regime mismatch: trend signal in choppy market")
        
        # Drawdown check
        dd_zone = market_context.get('dd_zone', 'NORMAL')
        if dd_zone in ('DANGER', 'CRITICAL'):
            if l1_signal['probability'] < 0.60:
                reasons.append(f"DD zone {dd_zone}: need higher confidence")
        
        if reasons:
            return {'decision': 'SKIP', 'reasons': reasons}
        return {'decision': 'ENTER', 'reasons': ['All checks passed']}

Each check has a clear purpose: spread protects against transaction costs, confidence filters weak signals, regime prevents style mismatch, and drawdown protects capital during adverse periods. Any single failure = skip.

Knowledge Check

Q1.Your entry filter has a 68% win rate but only takes 8 trades per month. Is this good?

Assignment

Build a simple entry filter with three rules: spread check, regime check, and confidence threshold. Backtest your L1 signals with and without the filter. Compare: win rate, trade count, total R, and monthly Sharpe ratio. The filter should improve win rate but watch for over-filtering.