📰 Latest: HaasOnline Academy Is Back — Structured Education for Smarter Trade Bots
Account
Operators

Deeper dive into Relational Operators

Deeper dive into Relational Operators

Relational operators compare two values and return a boolean result (true or false). They are fundamental to decision-making in HaasScript strategies.

Overview of Relational Operators

HaasScript provides six relational operators:

Operator Description Example
== Equal to a == b
~= Not equal to a ~= b
< Less than a < b
> Greater than a > b
<= Less than or equal to a <= b
>= Greater than or equal to a >= b

Equality Operators

Equal To (==)

Checks if two values are exactly the same:

local rsi = 30
local threshold = 30

if rsi == threshold then
    Log("RSI is exactly at threshold")
end

Not Equal To (~=)

Checks if two values are different:

local currentSignal = SignalLong
local expectedSignal = SignalShort

if currentSignal ~= expectedSignal then
    Log("Signals don't match")
end

Important: HaasScript uses ~= for "not equal", not != like many other languages:

-- Wrong
if a != b then  -- Error: invalid operator

-- Correct
if a ~= b then  -- Works correctly

Comparison Operators

Less Than (<)

local rsi = 25
local oversoldLevel = 30

if rsi < oversoldLevel then
    DoLong("RSI oversold")
end

Greater Than (>)

local rsi = 75
local overboughtLevel = 70

if rsi > overboughtLevel then
    DoShort("RSI overbought")
end

Less Than or Equal To (<=)

local price = 45000
local targetPrice = 45000

if price <= targetPrice then
    DoLong("Price at or below target")
end

Greater Than or Equal To (>=)

local price = 46000
local stopPrice = 45000

if price >= stopPrice then
    DoExitPosition("Stop loss hit")
end

Comparing Different Data Types

Numbers

Number comparisons work as expected:

local currentPrice = 45000
local entryPrice = 44000

if currentPrice > entryPrice then
    Log("Price increased since entry")
end

local percentage = 2.5
if percentage >= 2.0 then
    Log("Risk percentage acceptable")
end

Strings

Strings are compared alphabetically:

local market1 = "BTC_USDT"
local market2 = "ETH_USDT"

if market1 < market2 then
    Log("BTC comes before ETH alphabetically")
end

local market1 = "BTC_USDT"
local market2 = "BTC_USDT"

if market1 == market2 then
    Log("Markets are the same")
end

Important: String comparisons are case-sensitive:

local text1 = "BTC"
local text2 = "btc"

if text1 == text2 then
    -- This is FALSE (case mismatch)
end

if text1 ~= text2 then
    -- This is TRUE (different cases)
end

Booleans

Boolean comparisons are straightforward:

local inLong = HasLongPosition()
local inShort = HasShortPosition()

if inLong == true then
    -- Equivalent to: if inLong then
    Log("In long position")
end

if inShort ~= true then
    -- Equivalent to: if not inShort then
    Log("Not in short position")
end

Signals

Signal constants can be compared:

local currentSignal = SignalLong
local expectedSignal = SignalLong

if currentSignal == expectedSignal then
    DoSignal(currentSignal)
end

Collections

Collections use the latest value (index 1) when compared:

local closePrices = ClosePrices()
local threshold = 45000

-- Compares latest close price to threshold
if closePrices > threshold then
    DoLong("Price above threshold")
end

-- This is equivalent to:
if closePrices[1] > threshold then
    DoLong("Price above threshold")
end

Common Trading Patterns

RSI Thresholds

local rsi = RSI(ClosePrices(), 14)

if rsi <= 30 then
    DoLong("RSI oversold")
elseif rsi >= 70 then
    DoShort("RSI overbought")
end

Moving Average Crossover

local fastMA = EMA(ClosePrices(), 9)
local slowMA = EMA(ClosePrices(), 21)

if fastMA > slowMA then
    Log("Uptrend - fast MA above slow MA")
elseif fastMA < slowMA then
    Log("Downtrend - fast MA below slow MA")
end

Price Level Checks

local currentPrice = ClosePrices()
local supportLevel = 44000
local resistanceLevel = 46000

if currentPrice <= supportLevel then
    DoLong("Price at support")
elseif currentPrice >= resistanceLevel then
    DoShort("Price at resistance")
end

Percentage-Based Conditions

local entryPrice = 45000
local currentPrice = ClosePrices()
local profitTarget = 5.0  -- 5%

local profitPercentage = ((currentPrice - entryPrice) / entryPrice) * 100

if profitPercentage >= profitTarget then
    DoExitPosition("Take profit reached")
end

ATR-Based Comparisons

local atr = ATR(HighPrices(), LowPrices(), ClosePrices(), 14)
local currentPrice = ClosePrices()

local atrPercentage = (atr / currentPrice) * 100

if atrPercentage > 2.0 then
    Log("High volatility - tighten stops")
end

Combining with Logical Operators

Relational operators are often combined with logical operators:

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)

-- Both conditions must be true (AND)
if rsi < 30 and macd == SignalLong then
    DoLong("RSI oversold + MACD confirmation")
end

-- At least one condition must be true (OR)
if rsi > 70 or rsi < 30 then
    Log("RSI at extreme levels")
end

-- Negate a condition (NOT)
if not (rsi >= 30 and rsi <= 70) then
    Log("RSI outside normal range")
end

Common Mistakes

Assignment vs Comparison

-- Wrong: Using = for comparison
if rsi = 30 then  -- Error: = is assignment, not comparison
    DoLong()
end

-- Correct: Using == for comparison
if rsi == 30 then
    DoLong()
end

Wrong Not-Equal Operator

-- Wrong: Using != for not equal
if rsi != 30 then  -- Error: invalid operator
    DoLong()
end

-- Correct: Using ~= for not equal
if rsi ~= 30 then
    DoLong()
end

Case-Sensitive String Comparisons

local market = "BTC_USDT"

-- Wrong: Case doesn't match
if market == "btc_usdt" then  -- This is FALSE
    DoLong()
end

-- Correct: Exact case match
if market == "BTC_USDT" then  -- This is TRUE
    DoLong()
end

Comparing Different Types

local number = 100
local text = "100"

-- These are NOT equal
if number == text then  -- This is FALSE
    Log("They are equal")
end

-- Correct: Convert to same type first
if tostring(number) == text then
    Log("They are equal")
end

Floating-Point Precision

local result = 0.1 + 0.2  -- May be 0.30000000000000004

-- Problematic: Exact comparison
if result == 0.3 then  -- Might be FALSE due to precision
    Log("Equal")
end

-- Better: Use tolerance or rounding
if math.abs(result - 0.3) < 0.0001 then
    Log("Equal within tolerance")
end

Collection Comparisons

local prices1 = ClosePrices()
local prices2 = ClosePrices()

-- This compares the collection objects, not their values
if prices1 == prices2 then
    -- This is TRUE (they reference the same collection)
end

-- To compare values, compare specific elements
if prices1[1] == prices2[1] then
    -- Compares latest prices
end

Operator Precedence

Relational operators have lower precedence than arithmetic operators:

local result = 5 + 3 > 7  -- Evaluated as: (5 + 3) > 7 = 8 > 7 = true

-- When in doubt, use parentheses
local result = (5 + 3) > 7  -- Clearer

Short-Circuit Evaluation

When combining conditions, HaasScript uses short-circuit evaluation:

local rsi = RSI(ClosePrices(), 14)
local expensiveCalculation = ComplexFunction()

-- If rsi < 30 is FALSE, expensiveCalculation() is never called
if rsi < 30 and expensiveCalculation() then
    DoLong()
end

-- If rsi > 70 is TRUE, expensiveCalculation() is never called
if rsi > 70 or expensiveCalculation() then
    DoLong()
end

This can improve performance when you have expensive calculations.

Practical Examples

Example 1: Multi-Condition Entry

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)
local volume = Volume()

local avgVolume = SMA(volume, 20)

-- Entry requires ALL conditions
if rsi < 30 and macd == SignalLong and volume > avgVolume then
    DoLong("Multiple indicators confirm entry")
end

Example 2: Trailing Stop

local entryPrice = 45000
local currentPrice = ClosePrices()
local trailPercent = 2.0

local highestPrice = entryPrice
local trailingStop = highestPrice * (1 - trailPercent / 100)

if currentPrice > highestPrice then
    highestPrice = currentPrice  -- Update highest
    trailingStop = highestPrice * (1 - trailPercent / 100)
end

if currentPrice <= trailingStop then
    DoExitPosition("Trailing stop hit")
end

Example 3: Range Breakout

local closePrices = ClosePrices()
local highPrices = HighPrices()
local lowPrices = LowPrices()

local lookback = 20
local highestHigh = Max(highPrices, lookback)
local lowestLow = Min(lowPrices, lookback)

if closePrices > highestHigh then
    DoLong("Breakout above range")
elseif closePrices < lowestLow then
    DoShort("Breakout below range")
end

Example 4: Volatility Filter

local atr = ATR(HighPrices(), LowPrices(), ClosePrices(), 14)
local atrPercentage = (atr / ClosePrices()) * 100

local lowVolThreshold = 1.0
local highVolThreshold = 3.0

if atrPercentage <= lowVolThreshold then
    Log("Low volatility - use wider stops")
elseif atrPercentage >= highVolThreshold then
    Log("High volatility - reduce position size")
else
    Log("Normal volatility")
end

Best Practices

  1. Use parentheses for complex conditions to improve clarity
  2. Combine related conditions with logical operators for filtering
  3. Be careful with floating-point comparisons - use tolerance when needed
  4. Remember case sensitivity when comparing strings
  5. Use ~= not != for not-equal comparisons
  6. Don't use = for comparison - use ==
  7. Test edge cases like exact threshold values
  8. Consider short-circuit evaluation when optimizing performance

Summary

  • Six relational operators: ==, ~=, <, >, <=, >=
  • Return boolean values (true or false)
  • Compare various types: numbers, strings, booleans, signals, collections
  • Common patterns: threshold checks, crossovers, price levels
  • Combine with logical operators: and, or, not
  • Avoid common mistakes: wrong operators, type mismatches, precision issues
  • Use parentheses for clarity in complex conditions

Relational operators are the foundation of decision-making in HaasScript. Master them to create sophisticated trading logic that responds to market conditions accurately.