Collection Access Methods
Collection Access Methods
HaasScript price data and indicator results are returned as HaasNumberCollection objects. These collections behave like arrays but have special properties that make them convenient for trading strategies.
HaasNumberCollection Basics
A HaasNumberCollection represents time series data—typically price data or indicator values. Commands like ClosePrices(), RSI(), and MACD() all return collections:
local closePrices = ClosePrices() -- Collection of close prices
local rsi = RSI(closePrices, 14) -- Collection of RSI values
local macd = MACD(closePrices, 12, 26, 9) -- Collection of MACD values
Automatic Value Extraction
When you use a HaasNumberCollection (without an index) in comparisons, HaasScript automatically uses the first (latest) value at index 1:
local rsi = RSI(ClosePrices(), 14)
-- Direct comparison - uses latest RSI value automatically
if rsi < 30 then
DoLong()
end
-- Arithmetic applies to all values in the collection
local atr = ATR(HighPrices(), LowPrices(), ClosePrices(), 14)
local atrPercentage = (atr / ClosePrices()) * 100 -- Applies to entire collections
Important: Do NOT use .Value to access the current value. Use the collection directly in comparisons:
-- WRONG: .Value is not needed
if rsi.Value < 30 then
DoLong()
end
-- CORRECT: Use collection directly
if rsi < 30 then
DoLong()
end
Indexing Collections
Collections are 1-indexed, meaning index 1 is the latest value and higher indexes go back in time.
Important: When you access a collection with an index like collection[3], it returns a subarray starting from that index, not just a single value:
local closePrices = ClosePrices()
-- Returns subarray from index 3 onwards
local priceFrom3 = closePrices[3] -- This is an array: [closePrices[3], closePrices[4], ...]
-- To get a single value, use it in a comparison or arithmetic context
if closePrices[3] > 10000 then
Log('Price at index 3 is greater than 10000')
end
When you assign collection[index] to a variable, you get the subarray from that index onwards:
local prices = ClosePrices()
local recentPrices = prices[3] -- Gets array from index 3 to end
Critical: Do NOT use index 0. This will throw an error:
-- WRONG: Index 0 doesn't exist
local price = closePrices[0] -- Error!
-- CORRECT: Use index 1 for latest value
local price = closePrices[1]
Collection Order
Price collections are sorted from new to old (most recent to oldest):
local closePrices = ClosePrices()
-- Index 1 = most recent candle
-- Index 2 = candle before that
-- Index N = oldest candle in the collection
This is intuitive for trading logic where you typically care about the most recent data first.
Subarray Access
Accessing collection[index] returns the subarray from that index onwards:
local prices = {100, 105, 110, 108, 112}
local subarray = prices[3] -- Returns: {110, 108, 112}
-- This is the array starting from index 3 to the end
Use this when you need to work with a portion of the collection from a specific point onwards.
Collection Size
Use the Count() command to get the number of elements in a collection:
local closePrices = ClosePrices()
local count = Count(closePrices)
Log('Number of price points: ' .. count)
Context-Based Behavior
HaasNumberCollections have special smart behavior. Regular arrays (tables) do NOT have this behavior and will throw errors.
HaasNumberCollection in comparisons: Uses single value at the specified index:
local rsi = RSI(ClosePrices(), 14) -- Returns HaasNumberCollection
if rsi[3] > 2 then
Log('Value at index 3 is greater than 2') -- Uses single value at index 3
end
HaasNumberCollection in arithmetic: Applies to all values:
local closePrices = ClosePrices() -- Returns HaasNumberCollection
local multiplier = 10
local result = closePrices * multiplier -- All values multiplied by 10
HaasNumberCollection when assigned: Returns subarray from that index onwards:
local closePrices = ClosePrices()
local subarray = closePrices[3] -- Returns: {prices[3], prices[4], ...}
HaasNumberCollection without index: Uses first value (index 1) in comparisons:
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 then -- Uses rsi[1] automatically
DoLong()
end
Regular arrays (tables) behave like standard Lua arrays:
local array = {1, 2, 3, 4, 5}
-- array * 3 -- ERROR: attempt to perform arithmetic on a table value
-- array > 3 -- ERROR: attempt to compare table with number
-- array[1] -- Returns: 1 (single value, not subarray)
Iterating Collections
Loop through collection elements using standard for loops:
local closePrices = ClosePrices()
-- Iterate through all price points
for i = 1, Count(closePrices) do
local price = closePrices[i]
Log('Price at index ' .. i .. ': ' .. price)
end
Indicator Collections
Indicators return collections calculated from the input price collection:
local closePrices = ClosePrices()
-- RSI collection
local rsi = RSI(closePrices, 14)
-- Each RSI value corresponds to a price point
-- In comparisons, collection[index] uses single value at that index
Log('Current RSI: ' .. rsi[1]) -- RSI for most recent candle
Log('Previous RSI: ' .. rsi[2]) -- RSI for previous candle
Collection Arithmetic
HaasNumberCollections support arithmetic operations:
local closePrices = ClosePrices()
-- Multiply all values by 10
local scaledPrices = closePrices * 10
-- Add 5 to all values
local shiftedPrices = closePrices + 5
When you use indexed collections in arithmetic, it operates on the subarrays:
local closePrices = ClosePrices()
-- Calculate percentage change from 5 candles ago
-- closePrices[1] and closePrices[5] return subarrays
-- In arithmetic, subarrays use their first values
local percentChange = ((closePrices[1] - closePrices[5]) / closePrices[5]) * 100
Log('5-candle change: ' .. percentChange .. '%')
Important: Regular arrays (tables) do not support arithmetic operations and will throw errors:
local array = {1, 2, 3, 4, 5}
-- array * 10 -- ERROR: attempt to perform arithmetic on a table value
Practical Examples
RSI Crossover Detection
local rsi = RSI(ClosePrices(), 14)
-- Compare values at specific indices directly
-- HaasNumberCollections use single value at index in comparisons
-- Detect RSI crossing below 70 (overbought to neutral)
if rsi[2] >= 70 and rsi[1] < 70 then
Log('RSI crossed below 70 - potential exit signal')
end
-- Detect RSI crossing above 30 (oversold to neutral)
if rsi[2] <= 30 and rsi[1] > 30 then
Log('RSI crossed above 30 - potential entry signal')
end
Price Change Calculation
local closePrices = ClosePrices()
-- Calculate 3-period price change
-- Log() displays values, HaasNumberCollections show first value
Log('Current price: ' .. closePrices[1])
Log('Price 3 candles ago: ' .. closePrices[3])
-- For arithmetic on specific values, use indexed collections directly
local priceChange = closePrices[1] - closePrices[3]
local percentChange = (priceChange / closePrices[3]) * 100
Log('Price change over 3 periods: ' .. percentChange .. '%')
Moving Average Comparison
local closePrices = ClosePrices()
local sma20 = SMA(closePrices, 20)
local sma50 = SMA(closePrices, 50)
-- Current price relative to moving averages
-- In comparisons, indexed collections use single values
local aboveSMA20 = closePrices[1] > sma20[1]
local aboveSMA50 = closePrices[1] > sma50[1]
-- Moving average crossover
local goldenCross = sma20[1] > sma50[1] and sma20[2] <= sma50[2]
local deathCross = sma20[1] < sma50[1] and sma20[2] >= sma50[2]
if goldenCross then
Log('Golden cross detected - potential bullish signal')
elseif deathCross then
Log('Death cross detected - potential bearish signal')
end
Multiple Timeframe Analysis
-- Get prices from different timeframes
local hourlyClose = ClosePrices(3600) -- 1 hour
local dailyClose = ClosePrices(86400) -- 1 day
-- Calculate RSI on both timeframes
local hourlyRsi = RSI(hourlyClose, 14)
local dailyRsi = RSI(dailyClose, 14)
-- Trade only when both timeframes align
-- Collections use first value in comparisons
if hourlyRsi < 30 and dailyRsi < 30 then
Log('Oversold on both 1h and 1d timeframes')
DoLong()
end
ATR-Based Stop Loss
local closePrices = ClosePrices()
local atr = ATR(HighPrices(), LowPrices(), closePrices, 14)
-- ATR is returned as a collection
-- Convert ATR to percentage for StopLoss - indexed collections use single values in arithmetic
local atrPercentage = (atr[1] / closePrices[1]) * 100
StopLoss(atrPercentage * 2)
MACD Signal Line Crossover
local macd = MACD(ClosePrices(), 12, 26, 9)
-- MACD returns collection with multiple series
-- In comparisons, indexed collections use single values
-- MACD bullish crossover (MACD crosses above signal)
if macd[2] <= macd[4] and macd[1] > macd[3] then
Log('MACD bullish crossover')
DoLong()
end
-- MACD bearish crossover (MACD crosses below signal)
if macd[2] >= macd[4] and macd[1] < macd[3] then
Log('MACD bearish crossover')
DoShort()
end
Collections vs Arrays
HaasNumberCollections and regular arrays (tables) have fundamentally different behavior:
| Feature | HaasNumberCollection | Array (Table) |
|---|---|---|
| Created by | Indicator commands | {} syntax |
| Indexing | 1-based | 1-based |
| array[index] returns | Subarray from index | Single value from index |
| Without index in comparison | Uses first value | Error |
| Arithmetic operations | Applies to all values | Error |
| Typical use | Price data, indicators | Custom data storage |
HaasNumberCollections have special smart behavior:
-
collection[3]assigned to variable → subarray from index 3 onwards -
collection[3]in comparison → single value at index 3 -
collection * number→ arithmetic on all values -
collection < 30→ uses first value in comparison
Regular arrays (tables) behave like standard Lua arrays:
-
array[3]→ single value at index 3 -
array * number→ ERROR: attempt to perform arithmetic on a table value -
array < 30→ ERROR: attempt to compare table with number -
array[3]assigned to variable → single value, not subarray
Important: Only HaasNumberCollections have the smart behavior. Regular arrays created with {} syntax will throw errors if you try arithmetic or comparisons on them directly. Always index regular arrays before using them in operations.
Common Mistakes
Using .Value property:
-- WRONG: .Value is not recommended
if rsi.Value < 30 then
DoLong()
end
-- CORRECT: Use collection directly
if rsi < 30 then
DoLong()
end
Assuming array[index] returns single value:
-- RISKY: array[index] returns subarray when assigned
local priceFromIndex3 = closePrices[3] -- This is an array, not a single value!
Save('pfi3', priceFromIndex3) -- Saves the whole subarray
-- CORRECT: Use ArrayGet with HNC's
local priceFromIndex3 = ArrayGet(closePrices, 3) -- Single price value from index 3
Save('pfi3', priceFromIndex3) -- Saves only the price
Using index 0:
-- WRONG: Index 0 doesn't exist
local price = prices[0]
-- CORRECT: Use index 1 for latest value
local price = prices[1]
Assuming index order:
-- WRONG: Thinking index 1 is oldest
local oldestPrice = prices[1]
-- CORRECT: Index 1 is most recent
local latestPrice = prices[1]
local oldestPrice = prices[#prices]
Not accounting for collection length:
-- RISKY: May access non-existent index
local price = closePrices[100]
-- BETTER: Check length first
local count = Count(closePrices)
if count >= 100 then
local price = closePrices[100]
end