StonQL Reference

Securities Temporal ObservatioN Query Language

What is StonQL?

StonQL (pronounced "Stonk-QL") is a domain-specific language for filtering stocks based on price, volume, and technical indicators.

A basic scan:

close > 50;

This returns all stocks with a closing price above $50.

A more practical example:

close > sma(close, 50);

This returns stocks trading above their 50-day simple moving average.

Statements

A statement is a single condition that must be true for a stock to appear in your results. Every statement ends with a semicolon.

volume > 1M;

This statement filters for stocks with volume greater than 1 million shares.

Comments

Add notes to your scans using comments. Comments are ignored when the scan runs.

// Single-line comment
volume > 1M; // Comment at end of line

/* Multi-line comment
   spanning multiple lines */
close > open;

Combining Statements

When you write multiple statements, a stock must satisfy all of them to appear in results. Think of it as "AND" logic.

close > 10;           // Price above $10
close < 50;           // Price below $50
volume > 500K;        // Volume above 500,000

This scan returns only stocks where all three conditions are true: price between $10-$50 with decent volume.

Need "OR" logic? Use the or operator within a single statement:

rsi(close, 14) < 30 or rsi(close, 14) > 70;

This finds stocks that are either oversold (RSI below 30) or overbought (RSI above 70).

Fields

Fields are the data points you use in your scans. They represent price, volume, and other stock information.

close

Closing price for the period

close > 100;
open

Opening price for the period

close > open;
high

Highest price during the period

high > high[1];
low

Lowest price during the period

low > high[1];
volume

Number of shares traded during the period

volume > 1M;
typical_price (alias: hlc3)

(high + low + close) / 3

close > typical_price;
ohlc4

(open + high + low + close) / 4

sma(ohlc4, 20);
first_trade_date

The date the stock first started trading

months_since(first_trade_date) < 6;

Variables

Use variables to name your calculations. This makes complex scans easier to read and lets you reuse values.

avg_vol = sma(volume, 20);
volume > avg_vol * 2;  // Volume is 2x the 20-day average

Variables are especially helpful when you need the same calculation multiple times:

ma50 = sma(close, 50);
ma200 = sma(close, 200);
close > ma50;      // Price above 50-day MA
ma50 > ma200;      // 50-day MA above 200-day MA (bullish alignment)

Number Formats

StonQL supports several number formats for convenience:

Format Example Equals
K (thousands) 500K 500,000
M (millions) 1.5M 1,500,000
B (billions) 2B 2,000,000,000

Operators

Comparison Operators

Operator Description Example
> Greater than close > 50; // stocks above $50
>= Greater than or equal to rsi(close, 14) >= 70; // RSI at or above overbought level
< Less than close < sma(close, 200); // price below 200-day MA
<= Less than or equal to rsi(close, 14) <= 30; // RSI at or below oversold level
== Equal to (exact match) volume == 0; // no trading activity
!= Not equal to close != open; // price moved during the period
~= Approximately equal (0.1% tolerance) close ~= high; // closed near the high

Logical Operators

Operator Description Example
and Both conditions must be true close > 10 and volume > 1M; // above $10 with high volume
or Either condition can be true rsi(close, 14) < 30 or rsi(close, 14) > 70; // oversold or overbought
not Inverts a condition not close < 10; // equivalent to close >= 10

Arithmetic Operators

Operator Description Example
+ Addition typical = (high + low + close) / 3; // typical price
- Subtraction range = high - low; // trading range for the period
* Multiplication volume > sma(volume, 20) * 2; // 2x average volume
/ Division change = (close - open) / open; // price change ratio
\ Floor division (rounds down to integer) whole_dollars = close \ 1; // drops decimal portion
% Modulo (remainder) cents = (close * 100) % 100; // cents portion of price

Historical Reference

Access values from previous periods. The number in brackets indicates how many periods back.

Operator Description Example
[n] Value from n periods ago close > close[1]; // today's close above yesterday's

Multi-Timeframe Analysis

Use mtf() blocks to combine conditions across multiple timeframes in a single scan. Filter stocks that meet criteria on daily, weekly, and monthly charts simultaneously.

Filter Mode

When a mtf() block contains boolean conditions, stocks must pass all conditions in that timeframe to appear in results.

// Daily scan with weekly and monthly filters
close > sma(close, 20);        // Daily: above 20-day MA

mtf("1W") {
    close > open;              // Weekly: green candle
    rsi(close, 14) > 50;       // Weekly: bullish momentum
}

mtf("1M") {
    close > sma(close, 3);     // Monthly: uptrend
}

Stocks must pass daily conditions AND weekly conditions AND monthly conditions.

Value Extraction Mode

Assign a mtf() block to a variable to extract values from another timeframe for use in comparisons.

// Extract previous week's high for breakout detection
prev_weekly_high = mtf("1W") { high[1]; };

// Daily breakout above last week's high
close > prev_weekly_high;
volume > sma(volume, 20) * 1.5;

The [1] gets the previous week's value, avoiding same-bar comparisons.

Scope Isolation

mtf() blocks are completely isolated. Variables defined outside cannot be used inside, and vice versa.

// CORRECT: Self-contained mtf() block
mtf("1W") {
    avg = sma(close, 20);      // 'avg' only exists inside this block
    close > avg;
}

// CORRECT: Value extraction creates outer variable
weekly_rsi = mtf("1W") { rsi(close, 14); };
rsi(close, 14) > weekly_rsi;   // Compare daily RSI to weekly RSI

// WRONG: Cannot reference outer variables in mtf() blocks
threshold = 50;
mtf("1W") { rsi(close, 14) > threshold; };  // ERROR!
// VALID: Check if today made the monthly high (equality)
monthly_high = mtf("1M") { high; };
high == monthly_high;          // Valid: detecting monthly high bar

// WRONG: Inequality comparison to containing period
monthly_high = mtf("1M") { high; };
high > monthly_high;           // NEVER true - daily high can't exceed monthly high it's part of!

// CORRECT: Use [1] for inequality comparisons
prev_monthly_high = mtf("1M") { high[1]; };
close > prev_monthly_high;     // Meaningful: breaking above last month's high

The rule: Equality checks (==, ~=) against current period values are valid for detecting extremes. Inequality checks (>, <) are faulty because the daily value is part of the aggregate. Use [1] for inequality comparisons.

Combining Indicators Across Timeframes

// Multi-timeframe momentum alignment
prev_weekly_rsi = mtf("1W") { rsi(close, 14)[1]; };
prev_monthly_rsi = mtf("1M") { rsi(close, 14)[1]; };

// Daily RSI stronger than both higher timeframes
rsi(close, 14) > prev_weekly_rsi;
rsi(close, 14) > prev_monthly_rsi;
rsi(close, 14) > 50;           // And above neutral

Functions

Click on any function to view detailed documentation with parameters, formulas, and examples.

Quick Index (A-Z)

abs() · all_time_high() · all_time_low() · and() · approx() · aroon_down() · aroon_osc() · aroon_up() · atr() · bb_lower() · bb_upper() · bb_width() · cci() · change() · count() · cross() · crossover() · crossunder() · days_since() · dev() · ema() · eq() · falling() · gt() · gte() · highest() · highest_bars_ago() · hma() · kc_lower() · kc_middle() · kc_upper() · kcw() · lowest() · lowest_bars_ago() · lt() · lte() · macd_histogram() · macd_line() · macd_signal() · max() · mean() · median() · mfi() · min() · mom() · months_since() · ne() · obv() · or() · pct_change() · percentrank() · pivothigh() · pivotlow() · pow() · range() · rising() · roc() · rsi() · sma() · sqrt() · stdev() · stoch_d() · stoch_k() · streak() · swma() · true_range() · variance() · vwma() · weeks_since() · wilderma() · williams_r() · wma() · years_since()

Functions by Category

Comparison

Function Description
and(left, right) Logical AND
approx(value, target, tolerance) Approximate equality with absolute tolerance
cross(source1, source2) Cross detection (either crossover or crossunder)
crossover(source1, source2) Crossover detection (source1 crosses above source2)
crossunder(source1, source2) Crossunder detection (source1 crosses below source2)
eq(left, right) Equality comparison (==)
gt(left, right) Greater than comparison (>)
gte(left, right) Greater than or equal comparison (>=)
lt(left, right) Less than comparison (<)
lte(left, right) Less than or equal comparison (<=)
ne(left, right) Not equal comparison (!=)
or(left, right) Logical OR

Date Functions

Function Description
days_since(date) Calendar days since given date
months_since(date) Months since given date (truncated)
weeks_since(date) Weeks since given date (truncated)
years_since(date) Years since given date (truncated)

Math

Function Description
abs(a) Absolute value operator
max(a, b) Maximum operator
min(a, b) Minimum operator
pow(a, b) Power operator
sqrt(a) Square root operator

Momentum

Function Description
cci(period) Commodity Channel Index
change(source, length) Change (Difference from historical value)
mfi(period) Money Flow Index (Volume-weighted momentum oscillator)
mom(source, length) Change (Difference from historical value)
pct_change(current, base) Percent Change between two values
roc(source, periods) Rate of Change
rsi(source, periods, matype="wilder") Relative Strength Index
stoch_d(k_period, d_period, matype="sma") Stochastic %D (Slow Stochastic - MA of %K)
stoch_k(period) Stochastic %K (Fast Stochastic)
williams_r(period) Williams %R momentum oscillator

Moving Averages

Function Description
ema(source, periods) Exponential Moving Average
hma(source, period) Hull Moving Average
sma(source, periods) Simple Moving Average
swma(source) Symmetrically Weighted Moving Average (fixed 4-period)
vwma(source, periods) Volume Weighted Moving Average
wilderma(source, periods) Wilder Moving Average (EMA with α = 1/N)
wma(source, periods) Weighted Moving Average

Price

Function Description
all_time_high(source) All-Time High (Maximum value from inception)
all_time_low(source) All-Time Low (Minimum value from inception)

Range

Function Description
highest(source, period) Highest value of field over period
highest_bars_ago(source, period) Bars ago when highest value occurred
lowest(source, period) Lowest value over period
lowest_bars_ago(source, period) Bars ago when lowest value occurred
pivothigh(source, leftbars, rightbars) Detects pivot high (local peak) points in a data series
pivotlow(source, leftbars, rightbars) Detects pivot low (local trough) points in a data series
range(max_source, min_source, period) Difference between max_field and min_field over period

Statistics

Function Description
count(condition, period) Count total occurrences of condition in lookback window
mean(source, period) Statistical Mean (same as SMA)
median(source, period) Statistical Median
percentrank(source, length) Percent Rank
streak(condition, period) Count consecutive bars where condition is true

Trend

Function Description
aroon_down(period) Aroon Down - measures time since lowest low
aroon_osc(period) Aroon Oscillator - difference between Aroon Up and Aroon Down
aroon_up(period) Aroon Up - measures time since highest high
falling(source, length) Falling trend detection (consecutively decreasing values)
macd_histogram(source, fast_period, slow_period, signal_period, fast_matype="ema", slow_matype="ema", matype="ema") MACD Histogram (MACD line - Signal line)
macd_line(source, fast_period, slow_period, signal_period, fast_matype="ema", slow_matype="ema") MACD Line (fast EMA - slow EMA)
macd_signal(source, fast_period, slow_period, signal_period, fast_matype="ema", slow_matype="ema", matype="ema") MACD Signal Line (EMA of MACD line)
rising(source, length) Rising trend detection (consecutively increasing values)

Volatility

Function Description
atr(periods, matype="wilder") Average True Range
bb_lower(source, period, num_stdev, matype="sma") Bollinger Bands Lower Band (MA - num_stdev * stdev)
bb_upper(source, period, num_stdev, matype="sma") Bollinger Bands Upper Band (MA + num_stdev * stdev)
bb_width(source, period, num_stdev, matype="sma") Bollinger Bands Width (upper_band - lower_band)
dev(source, length) Mean Absolute Deviation
kc_lower(source, length, mult, matype="ema", atr_length=..., atr_matype="wilder", bandstyle="atr") Keltner Channels Lower Band
kc_middle(source, length, matype="ema") Keltner Channels Middle Line (MA)
kc_upper(source, length, mult, matype="ema", atr_length=..., atr_matype="wilder", bandstyle="atr") Keltner Channels Upper Band
kcw(source, length, mult, matype="ema", atr_length=..., atr_matype="wilder", bandstyle="atr") Keltner Channels Width (percentage)
stdev(source, period) Standard Deviation
true_range() True Range (maximum range including gaps)
variance(source, period) Statistical Variance

Volume

Function Description
obv(source) On-Balance Volume (Cumulative volume indicator)

Ready to put this knowledge to use?

Try these functions in the scanner to build powerful stock scans

Open Scanner