Skip to content

Limit Up Limit Down

Query Source: adopted from here

Introduction

March 2020 is definitely unprecedented in the history of financial markets. Both market volume and volatility heightened during this 2020 stock market crash. The market wide circuit breaker was triggered four times in 10 days (Mar 9, 12, 16 and 18) and thousands of individual stocks had circuit breaker activated. There is no respite in sight for this volatility.

The Limit Up Limit Down (LULD) was designed to replace the single stock circuit breaker. A stock enters a Limit State if its price deviation from previous close exceeds a certain percentage, which depends on the price of the stock. For Tier 1 securities, the threshold percentage from market open auction to 3:35pm is as follows:

Price Range Price Band Percentage
strictly greater than 3.0 5%
[0.75, 3.0] inclusive on both side 20%
strictly less than 0.75 The lesser of $0.15 and 75%

For more details about LULD, see Nasdaq LULD FAQ.

Question

Write a q function calculateLULD to calculate the LULD prices for a single price or list of prices. This function returns a list and each element of the list is a two-element list which has first element as the limit up price and the second element as the limit down price. For example,

calculateLULD 3            / enlist 3.6 2.4
calculateLULD 3 10         / (3.6 2.4;10.5 9.5)
calculateLULD 0.1 0.5 3 10 / (0.175 0.025;0.65 0.35;3.6 2.4;10.5 9.5)

Answer

Below is one suggested implementation to calculate the limit up limit down prices for Tier 1 securities in the opening auction period and the continuous session up to 15:35 in the U.S. equities market.

calculateLULD:{
    / Makes sure input is a list of float
    price:"f"$(),x;

    / Defines percentage bands
    bandPctCutoff:0.75 0.2 0.05;

    / Defines the lower bound price of each price band
    lowerBound:0.15 0w 0w;

    / Finds the percentage band bucket which each price falls into
    / Note that 0.74999 is used, instead of 0.75
    loc:0.749999 3f binr price;

    / Finds the price bands for the given list of prices
    priceBand:lowerBound[loc]&price*bandPctCutoff loc;

    / Applies the price bands to the given list of prices
    flip (price+priceBand;price-priceBand)
  };

My friend Alvi Kabir provides the following creative solution, which uses the fact that the sorted attribute (`s#) when applied to a dictionary makes the dictionary into a step function. See some official document here. I like a lot the way he handles the case when price is between $0.2 and $0.75.

calculateLULD:{
    d:`s#0 .2 .75 3.0001!(.75;0n;.2;.05);
    p:.15^x*d "f"$(),x;
    flip (x+p;x-p)
  };