DEV Community

ICF Market LTD
ICF Market LTD

Posted on Edited on AI-assisted

Classifying Aggressor Side in Order Flow: Quote Rule vs. Tick Rule

A footprint chart may show buy volume, sell volume, and delta down to the price level. But a trade print alone does not necessarily tell you which side initiated the trade. Every classification method relies on some combination of exchange flags, quote context, or a price-change heuristic.

The engineering challenge is not simply to label every print. It is to keep the classification auditable when the data is incomplete.

In brief: Prefer a documented, time-aligned aggressor flag or quote context when available. Treat tick-rule results as estimates, and track trades you cannot classify instead of quietly forcing them into buy or sell volume.

What an aggressor-side label actually means

Every executed trade has a buyer and a seller. A buyer-initiated trade generally means an incoming order executed against resting sell liquidity; a seller-initiated trade executed against resting buy liquidity.

Neither label predicts what price will do next. It describes the likely mechanism of execution, not a trading signal.

Some feeds supply aggressor-side flags directly. Others expose prints and inside quotes from which a label must be inferred. Before combining data sources, check what each feed promises about quote timestamps, ordering, and venue coverage.

Two common classification methods

1. Quote rule: compare the trade with the spread

Given an appropriate bid/ask snapshot from the time of the trade:

  • Trade at or above the ask → buyer-initiated candidate.
  • Trade at or below the bid → seller-initiated candidate.
  • Trade inside the spread → uncertain under this rule.

The word appropriate matters. A quote received just before a trade is not necessarily the quote that applied when it executed. Trade and quote messages can arrive on different channels or out of order.

Reject invalid, locked, crossed, or stale quotes according to a documented feed policy. In particular, if both comparisons could be true, do not let the order of your if statements decide the trade's side.

2. Tick rule: infer from the previous trade price

If trustworthy quote context is missing, the tick rule provides a cheaper fallback:

  • Price above the previous print → buy candidate.
  • Price below the previous print → sell candidate.
  • Unchanged price → use an explicit zero-tick policy or mark unknown.

One common zero-tick policy carries forward the last nonzero price-change direction. That is still a heuristic. A wider spread, sparse trading, or incorrectly ordered prints can make it diverge from a quote-based label.

C# example: preserve an Unknown state

The following excerpt illustrates a conservative classification policy. It is application-level C#, not a complete NinjaScript indicator. It assumes trade and quote timestamps have already been normalized to a comparable clock.

enum AggressorSide { Buy, Sell, Unknown }

sealed class TradePrint
{
    public double Price;
    public DateTime TimeUtc;
}

sealed class QuoteSnapshot
{
    public double Bid;
    public double Ask;
    public DateTime TimeUtc;
}

static AggressorSide Classify(
    TradePrint trade,
    QuoteSnapshot quote,
    double? previousPrice,
    AggressorSide lastNonzeroTickSide,
    TimeSpan maxQuoteAge)
{
    bool usableQuote = quote != null
        && quote.Bid > 0
        && quote.Ask > quote.Bid
        && trade.TimeUtc >= quote.TimeUtc
        && trade.TimeUtc - quote.TimeUtc <= maxQuoteAge;

    if (usableQuote)
    {
        if (trade.Price >= quote.Ask) return AggressorSide.Buy;
        if (trade.Price <= quote.Bid) return AggressorSide.Sell;
        return AggressorSide.Unknown; // Inside the spread
    }

    // Fallback only when quote context is unavailable.
    if (!previousPrice.HasValue) return AggressorSide.Unknown;
    if (trade.Price > previousPrice.Value) return AggressorSide.Buy;
    if (trade.Price < previousPrice.Value) return AggressorSide.Sell;
    return lastNonzeroTickSide; // Explicit zero-tick policy
}
Enter fullscreen mode Exit fullscreen mode

The maxQuoteAge threshold is an application policy, not a universal constant. This example also does not prove that two timestamps from different feeds refer to the same clock or that the quote was valid at execution time.

For production code, normalize prices to integer tick indices where appropriate, record the method used for each label, and test how the zero-tick state survives repeated prices and session boundaries.

What should happen to unknown volume?

Maintain three buckets rather than quietly assigning every print to a side:

classified_delta  = buy_volume - sell_volume
classified_volume = buy_volume + sell_volume
total_volume      = classified_volume + unknown_volume
Enter fullscreen mode Exit fullscreen mode

A delta calculated from classified trades may still be useful. It should simply not be presented as though all traded volume was classified with equal certainty.

An unclassified-volume percentage is a useful quality metric: if it spikes on one instrument, session, or provider, that can reveal a quote-data problem before the histogram misleads someone.

Test the data pipeline, not just the chart

A compact regression fixture should include:

  1. Trades at bid and ask with valid, synchronized quotes.
  2. A print inside the spread and a locked or crossed quote.
  3. A stale quote, out-of-order timestamps, and the first print of a session.
  4. Multiple consecutive trades at the same price.
  5. A conservation check: buy + sell + unknown == total.

Keep ingestion, classification, aggregation, and rendering separate. That makes it possible to compare two classification policies against the same recorded data without changing the footprint renderer.

For background on tape reading and delta, I work with ICF Market, whose free volume and order-flow education series covers the underlying concepts. The C# policy above is an educational illustration, not a claim about ICF Market's internal implementation.

Key takeaways

  • An aggressor-side label is a statement about execution, not market direction.
  • Quote-rule and tick-rule labels are only as reliable as their inputs and documented assumptions.
  • Recording Unknown protects volume accounting and makes feed-quality problems visible.

Discussion: If your feed supplies an aggressor flag and synchronized bid/ask quotes, do you trust one as authoritative, or do you log disagreements for later analysis?


Disclosure: This article was prepared with AI assistance. The C# excerpt is illustrative and was not tested against a live market-data feed. Educational content only; not trading advice.

Top comments (0)