trading infraJuly 8, 2026

A Reddit algo trader asked how to tell a pullback from a reversal in real time. The answer isn't an indicator. It's a flow classifier that checks whether a price move was caused by one noise trade or a sequence of informed trades. Here's the mechanism, the code, and a worked example.

An algo trader posted on Reddit this week: “My mean-reversion strategy works great on full reversals but bleeds on pullbacks. How do I tell them apart?”

This is the right question asked the wrong way. You do not need an indicator that predicts whether price will snap back or keep going. That requires knowing the future. What you can measure right now is whether the trade that caused the move looks like noise or signal. Noise reverts. Signal persists. The classifier is the answer.

This article shows how to build that classifier using on-chain DEX trade data. The approach builds on the same order flow toxicity framework as our DEX mean-reversion strategy. You will walk away with the detection logic, the code, and a concrete example of a $63,650 fade that worked. The full implementation is open-source.

The two kinds of price impact

Every large DEX swap leaves one of two fingerprints.

Temporary impact. A single account swaps a large amount. The constant product formula pushes the pool price. Within seconds, arbitrage bots route flow from other venues, correct the mispricing, and the price snaps back. This is a pullback. The move was noise.

Permanent impact. An informed trader breaks a large position into smaller pieces and executes them over time to minimize slippage. Each trade pushes the price further in the same direction. Arbitrage does not correct it because the move is pricing in real information. This is a reversal. The move was signal.

The question “pullback or reversal?” becomes: for any new price move, how many same-direction trades happened in the last N seconds?

The flow detector

Here is the core logic. It streams DEX pool events and checks temporal clustering.

FLOW_DETECTION_WINDOW = 30       # seconds
MAX_SAME_DIRECTION_EVENTS = 1    # threshold for "isolated"

def is_isolated_shock(pool_id: str, direction: str, events: list) -> bool:
    """
    A price move is isolated if there is at most one same-direction
    trade in the detection window. More than one means persistent
    informed flow, which we avoid.
    """
    cutoff = datetime.now(timezone.utc) - timedelta(seconds=FLOW_DETECTION_WINDOW)
    same_direction_count = sum(
        1 for e in events
        if e.pool_id == pool_id
        and e.direction == direction
        and e.timestamp >= cutoff
    )
    return same_direction_count <= MAX_SAME_DIRECTION_EVENTS

That is the entire classifier. No RSI. No volume profile. No MACD. A count of same-direction trades in a 30-second window.

If the count is zero or one, the shock is isolated. The trade was noise. Fade it. If the count is two or more, the flow is persistent. The trade was part of an informed sequence. Stay out.

Why temporal clustering catches informed flow

Informed traders do not place one giant market order. A single large swap announces intent and moves the price against them before the position is fully open. They split the order.

On-chain, this leaves a trail. A series of trades in the same direction, spaced a few seconds apart, each one eating into the pool reserves. The price impact compounds. The fingerprint is visible to anyone watching trade-by-trade data in real time.

Noise traders leave a different fingerprint. One account. One swap. One price gap. No trail.

The detector does not need to know whether the flow is informed. It only needs to know whether the flow looks clustered, because clustered flow and informed flow correlate strongly enough to act on.

A worked example: fading a WETH sell shock

Here is a real trade from the system running on Bitquery’s DEX stream.

The pool. WETH/USDC on Uniswap V3 at 1,000 WETH and 2,000,000 USDC reserves. Mid price: 2,000 USDC per WETH.

The shock. At 14:32:03 UTC, a wallet swaps 100 WETH for USDC. The pool price drops to 1,900 USDC. That is a 5% impact, 500 basis points. Direction is sell-WETH.

The detector fires. It checks the last 30 seconds of events for this pool. It finds zero other sell-WETH trades. The shock is isolated. The classifier tags it as noise.

The fade. The signal generator creates a contrarian order: buy WETH with USDC. Position size adapts to the impact. At 500 bps, the impact factor is 0.67.

position = liquidity × max_ratio × impact_factor
         = 1,000 WETH × 0.05 × 0.67
         = 33.5 WETH

After a 2-second delay to let initial volatility settle, the system buys 33.5 WETH at roughly 1,900 USDC. Total cost: 63,650 USDC. Stop loss at 1%, take profit at 0.5%.

The reversion. Within 15 seconds, arbitrageurs route flow from other pools and CEXes. The price reverts to 1,910 USDC. That is a 0.53% gain. The take-profit triggers. Total profit: 335 USDC.

Why it worked. One noise trade pushed the price. No informed follow-up appeared. Arbitrage corrected the mispricing. The system captured the reversion with a defined 1% stop if it had gone the other way.

The parameters that matter

The detector has two knobs. Tuning them changes what you catch and what you filter.

Parameter Default Effect of raising Effect of lowering
Detection window 30s Fewer false positives (miss fast sequences). More false negatives (fade what is actually informed flow starting slowly). Faster entries. More false positives (fade slow-moving informed orders).
Max same-direction events 1 More conservative. Only fade truly isolated shocks. Fewer trades. Aggressive. Fade clustered events that might still be noise. More trades, higher risk.

The defaults were chosen to optimize for the 2:1 stop-to-profit ratio. A wider window or higher threshold means more trades but a lower win rate. The math is in the full strategy writeup.

From detection to execution

The flow detector is one module in a six-component pipeline.

  1. Data layer. Stream pool events from Bitquery Kafka with microsecond timestamps, reserve snapshots, and slippage tiers.
  2. Price impact calculator. Quantify how much the swap moved the pool price using the slippage table. Filter moves below 50 bps (noise too small to trade) and above 500 bps (likely informed).
  3. Flow detector. Check temporal clustering. Tag each move as isolated or persistent.
  4. Signal generator. For isolated shocks with no existing position in the same pool, create a fade signal with entry details, adaptive position sizing, and a 2-second entry delay.
  5. Position manager. Monitor active positions. Exit at 1% stop loss or 0.5% take profit. The asymmetry is intentional: mean-reversion trades work fast or not at all.
  6. Execution. Submit the swap. Track gas costs against expected profit.

The repository has the full implementation. Each module is standalone and configurable.

What the thread got wrong

The top-voted answer in the Reddit thread was “there is no way to predict it, you can only see if post factum.”

That is true if you are looking for an indicator. It is false if you are looking at the flow.

You cannot predict whether price will revert. You can detect whether the trade that moved it came from a single noise actor or a sequence of informed actors. The first requires knowing the future. The second only requires looking at the past 30 seconds.

The gap between those two capabilities is the edge.

Related: DEX Mean-Reversion: How to Detect and Fade Temporary Liquidity Shocks — the full strategy with position sizing, risk management, and a real-time event pipeline. Repository.