Limit Up Limit Down¶
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)
};