📰 Latest: HaasOnline Academy Is Back — Structured Education for Smarter Trade Bots
Account
Converting Other Languages

LUA

HaasScript for Lua Developers

HaasScript is built directly on Lua, so the core language — syntax, control flow, scoping, tables — works exactly as you expect. Most of your Lua knowledge transfers without changes. This page covers what is different, what is added, and what is removed.

What Works the Same

You can use standard Lua constructs directly:

-- Variables and scoping
local x = 10
local name = 'BTC'

-- Control flow
if x > 5 then
    Log('Above threshold')
elseif x < 3 then
    Log('Below minimum')
else
    Log('In range')
end

-- Loops
for i = 1, 10 do
    Log(i)
end

while x > 0 do
    x = x - 1
end

-- Tables (key-value)
local config = { period = 14, threshold = 30 }

-- Functions
local function calculateWeight(value, multiplier)
    return value * multiplier
end

The string library is also available:

local symbol = 'BTC_USDT'
local length = string.len(symbol)
local upper = string.upper(symbol)
local sub = string.sub(symbol, 1, 3)
local formatted = string.format('Trading %s at %d periods', 'RSI', 14)

See Lua's Text-Manipulation Methods for the full list of available string functions.

What Is Different

Use Log() Instead of print()

HaasScript does not expose Lua's print() function. All output goes through the bot's logging system:

-- Wrong
print('RSI value: ' .. rsi)

-- Correct
Log('RSI value: ' .. rsi)

Log() supports color, prefix, and suffix parameters. It writes to the bot's log panel, not stdout. See Logging for details.

HaasNumberCollection Is Not a Table

This is the most significant difference. Most HaasScript commands that return numeric data use HaasNumberCollection, a custom type that behaves differently from Lua tables:

  • It can be used as a single number (uses the latest value automatically)
  • It supports indexed access with [] syntax, but uses 1-based indexing where index 1 is the most recent value
  • It does not support # (length operator), table.insert(), table.remove(), or other table library functions
local rsi = RSI(ClosePrices(), 14)

-- Used directly as a number in comparisons and math
if rsi < 30 then
    DoLong()
end

-- Access specific values by index (1 = latest, 2 = one tick ago)
local currentRSI = rsi[1]
local previousRSI = rsi[2]

You can create your own HaasNumberCollection with HNC():

local empty = HNC()
local filled = HNC(5, 0)       -- Creates a collection with 5 elements, all set to 0

For more on working with collections, see Arrays and Collection Access Methods.

Prefer HaasScript Math Commands

Lua's math.* library is fully available, and HaasScript provides its own equivalents. Both work on plain numbers. The difference matters when working with HaasNumberCollection values — HaasScript's math commands handle them natively, while math.* functions only work on plain numbers:

Lua HaasScript Notes
math.abs(x) Abs(x) Handles collections
math.ceil(x) Ceil(x) Handles collections
math.floor(x) Floor(x) Handles collections
math.max(a, b) Max(a)
Max(a, b)
Max(a, b, c, ...)
Accepts one or more values
math.min(a, b) Min(a)
Min(a, b)
Min(a, b, c, ...)
Accepts one or more values
math.sqrt(x) Sqrt(x) Handles collections
math.pow(x, n) Pow(x, n) Handles collections
math.sin(x) Sin(x) Handles collections
math.cos(x) Cos(x) Handles collections
math.tan(x) Tan(x) Handles collections
math.log(x) Ln(x) Natural logarithm
math.log10(x) Log10(x) Base-10 logarithm
math.random() Random() Optional min/max params
math.pi PI Constant (not function call)
math.floor(x * 10^n + 0.5) / 10^n Round(x, decimals) Direct rounding

You do not need to convert every math.* call. If you are only working with plain numbers, math.abs() works fine. Use Abs() when the value might be a HaasNumberCollection.

Numeric Arrays: HNC() vs {}

In text-based HaasScript, you have two ways to create arrays:

-- Lua table syntax (works for general purpose)
local prices = {100, 105, 110, 108, 112}

-- HaasNumberCollection via HNC() (preferred when working with HaasScript commands)
local collection = HNC(5, 0)  -- 5 elements, all set to 0

Use HNC() when you need to pass data into HaasScript commands that expect HaasNumberCollection. Use {} for general-purpose key-value or mixed-type data.

NewArray() and ArrayAdd() exist in HaasScript but are primarily for the visual editor (Visual HaasScript). In text-based scripts, stick with HNC() and Lua table syntax.

For more on working with arrays, see Arrays.

1-Based Indexing Enforced

Lua itself uses 1-based indexing, so this is familiar territory. But HaasScript is stricter — index 0 throws an error. There is no implicit nil fallback at index 0 like you might see in some Lua environments:

local prices = ClosePrices()

-- Correct: index 1 is the latest value
local current = prices[1]
local previous = prices[2]

-- Wrong: this throws an error
local nothing = prices[0]

No require() or Module System

HaasScript does not support Lua's require(), dofile(), or loadfile(). You cannot load external Lua modules or files.

Instead, HaasScript uses its own system for code reuse:

  • Custom Commands — define reusable logic with DefineCommand() that can be referenced from other scripts
  • Library() — wrap custom commands for use as shared libraries

This means any third-party Lua library (LuaSocket, LFS, etc.) cannot be imported. All functionality must come from HaasScript's built-in command set.

The Execution Model

In standard Lua, your script runs once and exits (or runs an event loop you build yourself). HaasScript scripts run repeatedly — once per tick or interval. The platform calls your script on each update cycle, so you do not need to build your own loop:

-- This runs on every tick automatically
local rsi = RSI(ClosePrices(), 14)

if rsi < 30 and GetPositionDirection() ~= PositionLong then
    DoLong()
end

State between updates is preserved through Save() and Load().

What Is Added

HaasScript adds over 600 commands on top of Lua. The main categories:

Price Data and Market Access

Direct access to price feeds, account balances, and market information:

local closePrices = ClosePrices()
local highPrices = HighPrices()
local lowPrices = LowPrices()
local volume = Volume()
local baseCurrency = BaseCurrency()
local quoteCurrency = QuoteCurrency()

Technical Indicators

Over 150 indicator commands — RSI, MACD, Bollinger Bands, ATR, Aroon, and many more:

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)
local bb = BBANDS(ClosePrices(), 20, 2.0, 2.0)
local atr = ATR(HighPrices(), LowPrices(), ClosePrices(), 14)

Trading Commands

Position management, order placement, and risk management:

DoLong()
DoShort()
DoSignal(signal)
StopLoss(2.5)
TakeProfit(5.0)
TrailingStopLoss(1.5)

Signal System

A structured approach to combining and evaluating trading conditions:

local rsiSignal = GetBuySellLevelSignal(rsi, 30, 70)
local macdValue = macd[1] - macd[3]
local macdSignal = GetThresholdSignal(macdValue, 0, 0.2)

local consensus = GetConsensusSignal(rsiSignal, macdSignal)
DoSignal(consensus)

Input Fields

Expose configurable parameters to the bot UI without building a custom interface:

local period = Input('RSI Period', 14)
local rsiThreshold = Input('RSI Threshold', 30)
local enableTrailing = Input('Use Trailing Stop', false)

Charting and Visualization

Commands for plotting indicators, zones, and shapes directly on the chart:

Plot(rsi, 'RSI', 'blue')
PlotHorizontalLine(30, 'Oversold', 'green')
PlotHorizontalLine(70, 'Overbought', 'red')

What Is Removed

Three standard Lua libraries remain fully available: math.*, string.*, and table.*. Everything beyond that is blocked:

Available Not Available
math.* io.*
string.* os.* (except os.time())
table.* require(), dofile(), loadfile()
tonumber(), tostring(), type() package.*
pairs(), ipairs() debug.*
coroutine.*
print() (use Log())

Quick Conversion Checklist

When porting Lua code to HaasScript:

  1. Replace print() with Log()
  2. Use HaasScript math commands (Abs(), Round(), etc.) when working with HaasNumberCollection values — math.* is fine for plain numbers
  3. Remove require() or dofile() calls — use custom commands instead
  4. Remove io.* and os.* calls (except os.time() can be replaced with Time())
  5. Remove any while true or manual loop constructs — the platform handles the update cycle
  6. Ensure no index 0 access on arrays or collections
  7. Use HNC() for numeric arrays that interact with HaasScript commands, {} for general-purpose tables