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

Deeper dive into Logical Operators

Deeper dive into Logical Operators

Logical operators allow you to combine multiple conditions and control the flow of your trading logic. They are essential for creating sophisticated strategies that consider multiple factors before making trading decisions.

Overview of Logical Operators

HaasScript provides three logical operators:

Operator Description Example Result
and Logical AND true and true true
or Logical OR true or false true
not Logical NOT not true false

Logical AND (and)

The and operator returns true only if both conditions are true:

local condition1 = true
local condition2 = true

if condition1 and condition2 then
    Log("Both conditions are true")
end

AND Truth Table

Condition A Condition B A and B
true true true
true false false
false true false
false false false

AND in Trading Strategies

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

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

Multiple AND Conditions

local rsi = RSI(ClosePrices(), 14)
local price = ClosePrices()
local volume = Volume()
local avgVolume = SMA(volume, 20)

-- All three conditions must be true
if rsi < 30 and price > SMA(ClosePrices(), 20) and volume > avgVolume then
    DoLong("Multiple indicators confirm entry")
end

Logical OR (or)

The or operator returns true if at least one condition is true:

local condition1 = true
local condition2 = false

if condition1 or condition2 then
    Log("At least one condition is true")
end

OR Truth Table

Condition A Condition B A or B
true true true
true false true
false true true
false false false

OR in Trading Strategies

local rsi = RSI(ClosePrices(), 14)

-- Enter if either condition is true
if rsi < 20 or rsi < 30 then
    DoLong("RSI extremely oversold or moderately oversold")
end

Multiple OR Conditions

local rsi = RSI(ClosePrices(), 14)
local price = ClosePrices()
local lowerBB = BBANDS(ClosePrices(), 20, 2)

-- Enter if any condition is true
if rsi < 20 or price < lowerBB or price < SMA(ClosePrices(), 50) then
    DoLong("Multiple entry signals")
end

Logical NOT (not)

The not operator reverses a boolean value:

local condition = true

if not condition then
    Log("Condition is false")
end

NOT Truth Table

Condition not Condition
true false
false true

NOT in Trading Strategies

local hasLong = HasLongPosition()

-- Enter only if NOT already in long position
if not hasLong then
    DoLong("No existing long position")
end

Combining NOT with Other Operators

local rsi = RSI(ClosePrices(), 14)

-- Enter if RSI is NOT between 30 and 70
if not (rsi >= 30 and rsi <= 70) then
    Log("RSI is outside normal range")
end

Combining Logical Operators

You can combine multiple logical operators for complex conditions:

AND + OR Combination

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

-- RSI oversold AND (MACD bullish OR price above SMA)
if rsi < 30 and (macd == SignalLong or price > SMA(ClosePrices(), 20)) then
    DoLong("Strong entry signal")
end

NOT + AND Combination

local rsi = RSI(ClosePrices(), 14)
local hasPosition = HasLongPosition()

-- Not in position AND RSI oversold
if not hasPosition and rsi < 30 then
    DoLong("Entry condition met")
end

Complex Combinations

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)
local hasLong = HasLongPosition()
local hasShort = HasShortPosition()

-- No position AND ((RSI oversold AND MACD bullish) OR (RSI overbought AND MACD bearish))
if not (hasLong or hasShort) and ((rsi < 30 and macd == SignalLong) or (rsi > 70 and macd == SignalShort)) then
    if rsi < 30 then
        DoLong("Entry long")
    else
        DoShort("Entry short")
    end
end

Operator Precedence

Logical operators have specific precedence rules:

  1. not (highest precedence)
  2. and
  3. or (lowest precedence)

Precedence Examples

local a = true
local b = false
local c = true

-- Evaluated as: (a and b) or c
if a and b or c then
    Log("This is true")
end

-- Evaluated as: a and (not b)
if a and not b then
    Log("This is true")
end

-- Evaluated as: (a or b) and c
if (a or b) and c then
    Log("This is true")
end

Using Parentheses for Clarity

Always use parentheses when combining multiple operators:

-- Clear: Explicit grouping
if (rsi < 30 or rsi > 70) and not hasPosition then
    DoLong("Entry signal")
end

-- Ambiguous: Relies on precedence rules
if rsi < 30 or rsi > 70 and not hasPosition then
    -- Harder to read and understand
end

Short-Circuit Evaluation

HaasScript uses short-circuit evaluation for efficiency:

AND Short-Circuit

local condition1 = false
local expensiveCalculation = ComplexFunction()

-- If condition1 is false, expensiveCalculation() is never called
if condition1 and expensiveCalculation() then
    DoLong()
end

OR Short-Circuit

local condition1 = true
local expensiveCalculation = ComplexFunction()

-- If condition1 is true, expensiveCalculation() is never called
if condition1 or expensiveCalculation() then
    DoLong()
end

Practical Benefits

local hasPosition = HasLongPosition()
local rsi = RSI(ClosePrices(), 14)

-- Check hasPosition first (fast)
-- Only calculate RSI if no position (expensive)
if not hasPosition and rsi < 30 then
    DoLong("Entry signal")
end

Common Trading Patterns

Multi-Indicator Entry

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

-- All indicators must agree
if rsi < 30 and macd == SignalLong and price < SMA(ClosePrices(), 20) then
    DoLong("All indicators bearish")
end

Entry with Exit Conditions

local rsi = RSI(ClosePrices(), 14)
local hasLong = HasLongPosition()

-- Entry: RSI oversold AND no long position
if rsi < 30 and not hasLong then
    DoLong("Entry signal")
end

-- Exit: RSI overbought OR has long position
if rsi > 70 or hasLong then
    DoExitPosition("Exit signal")
end

Risk Management Logic

local hasLong = HasLongPosition()
local hasShort = HasShortPosition()
local price = ClosePrices()
local stopLoss = 44000

-- Exit if stop loss hit
if hasLong and price <= stopLoss then
    DoExitPosition("Stop loss hit")
end

-- Don't enter if already in position
if (hasLong or hasShort) and price > stopLoss then
    Log("Already in position, no entry")
end

Time-Based Filtering

local rsi = RSI(ClosePrices(), 14)
local hour = GetHour()

-- Only trade during specific hours AND RSI condition
if (hour >= 9 and hour <= 16) and rsi < 30 then
    DoLong("Trading hours + RSI signal")
end

Volatility Filter

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

-- Low volatility AND RSI signal
if atrPercentage < 2.0 and rsi < 30 then
    DoLong("Low volatility + oversold")
end

-- High volatility OR extreme RSI
if atrPercentage > 3.0 or rsi < 20 or rsi > 80 then
    Log("High volatility or extreme RSI")
end

Trend Following

local fastMA = EMA(ClosePrices(), 9)
local slowMA = EMA(ClosePrices(), 21)
local rsi = RSI(ClosePrices(), 14)

-- Uptrend AND NOT overbought
if fastMA > slowMA and not (rsi > 70) then
    DoLong("Uptrend, not overbought")
end

-- Downtrend AND NOT oversold
if fastMA < slowMA and not (rsi < 30) then
    DoShort("Downtrend, not oversold")
end

Common Mistakes

Confusing AND with OR

local rsi = 25

-- Wrong: Using OR when you need AND
if rsi < 30 or rsi > 70 then
    -- This is TRUE (rsi < 30)
    -- But you probably wanted both conditions checked
end

-- Correct: Using AND for range check
if rsi >= 30 and rsi <= 70 then
    -- RSI is in normal range
end

Forgetting Parentheses

local rsi = 25
local hasPosition = false

-- Ambiguous: Relies on precedence
if rsi < 30 or rsi > 70 and not hasPosition then
    -- Evaluated as: rsi < 30 or (rsi > 70 and not hasPosition)
    -- This might not be what you intended
end

-- Clear: Explicit grouping
if (rsi < 30 or rsi > 70) and not hasPosition then
    -- Both conditions must be true
end

Double Negatives

local hasLong = HasLongPosition()

-- Confusing: Double negative
if not (not hasLong) then
    -- This is hard to read
end

-- Clear: Positive statement
if hasLong then
    -- Much clearer
end

Overly Complex Conditions

-- Bad: Hard to understand
if a and b or c and not d or e and f then
    DoLong()
end

-- Better: Break into smaller conditions
local condition1 = a and b
local condition2 = c and not d
local condition3 = e and f

if condition1 or condition2 or condition3 then
    DoLong()
end

-- Even better: Use descriptive variable names
local bullishIndicators = a and b
local bearishIndicators = c and not d
local neutralIndicators = e and f

if bullishIndicators or bearishIndicators or neutralIndicators then
    DoLong()
end

Negating Complex Conditions

local rsi = RSI(ClosePrices(), 14)
local price = ClosePrices()

-- Confusing: Negating complex condition
if not (rsi >= 30 and price > SMA(ClosePrices(), 20)) then
    DoLong()
end

-- Clearer: Use De Morgan's laws
-- not (A and B) = (not A) or (not B)
if rsi < 30 or price <= SMA(ClosePrices(), 20) then
    DoLong()
end

Practical Examples

Example 1: Multi-Strategy Entry

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)
local bb = BBANDS(ClosePrices(), 20, 2)
local price = ClosePrices()
local hasPosition = HasLongPosition() or HasShortPosition()

-- No position AND at least 2 signals agree
local signalCount = 0

if rsi < 30 then
    signalCount = signalCount + 1
end

if macd == SignalLong then
    signalCount = signalCount + 1
end

if price < bb then
    signalCount = signalCount + 1
end

if not hasPosition and signalCount >= 2 then
    DoLong("Multiple signals confirm entry")
end

Example 2: Protective Exit Logic

local hasLong = HasLongPosition()
local hasShort = HasShortPosition()
local price = ClosePrices()
local rsi = RSI(ClosePrices(), 14)
local takeProfit = 46000
local stopLoss = 44000

-- Exit long position
if hasLong then
    if price >= takeProfit or price <= stopLoss or rsi > 70 then
        DoExitPosition("Exit long: TP or SL or RSI overbought")
    end
end

-- Exit short position
if hasShort then
    if price <= stopLoss or price >= takeProfit or rsi < 30 then
        DoExitPosition("Exit short: TP or SL or RSI oversold")
    end
end

Example 3: Confirmation Filter

local rsi = RSI(ClosePrices(), 14)
local macd = MACD(ClosePrices(), 12, 26, 9)
local volume = Volume()
local avgVolume = SMA(volume, 20)
local price = ClosePrices()
local sma20 = SMA(ClosePrices(), 20)

-- Primary signal
local primarySignal = rsi < 30

-- Confirmation filters
local trendFilter = price > sma20
local volumeFilter = volume > avgVolume
local macdFilter = macd == SignalLong

-- Entry requires primary signal AND at least one confirmation
if primarySignal and (trendFilter or volumeFilter or macdFilter) then
    DoLong("Primary signal + confirmation")
end

Example 4: State Machine Logic

local hasLong = HasLongPosition()
local hasShort = HasShortPosition()
local rsi = RSI(ClosePrices(), 14)

-- State 1: No position
if not hasLong and not hasShort then
    if rsi < 30 then
        DoLong("Entry long")
    elseif rsi > 70 then
        DoShort("Entry short")
    end
end

-- State 2: In long position
if hasLong and not hasShort then
    if rsi > 70 then
        DoExitPosition("Exit long")
    end
end

-- State 3: In short position
if hasShort and not hasLong then
    if rsi < 30 then
        DoExitPosition("Exit short")
    end
end

Debugging Logical Conditions

When debugging complex conditions, break them down:

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

-- Complex condition
if rsi < 30 and macd == SignalLong then
    DoLong()
end

-- Debug version
local rsiOversold = rsi < 30
local macdBullish = macd == SignalLong

Log("RSI oversold: " .. tostring(rsiOversold))
Log("MACD bullish: " .. tostring(macdBullish))

if rsiOversold and macdBullish then
    DoLong()
end

Best Practices

  1. Use parentheses for complex conditions to improve clarity
  2. Break down complex logic into smaller, named variables
  3. Test edge cases like boundary values (exactly 30, exactly 70)
  4. Use short-circuit evaluation by ordering conditions efficiently
  5. Avoid double negatives - rephrase as positive statements
  6. Use descriptive variable names for intermediate conditions
  7. Consider operator precedence - use parentheses when in doubt
  8. Simplify when possible - combine redundant conditions
  9. Document complex logic with comments explaining the reasoning
  10. Test each condition separately before combining them

Summary

  • AND (and): Both conditions must be true
  • OR (or): At least one condition must be true
  • NOT (not): Reverses the boolean value
  • Precedence: not > and > or
  • Short-circuit evaluation: Stops evaluating as soon as result is determined
  • Use parentheses: Essential for clarity in complex conditions
  • Common patterns: Multi-indicator entry, exit logic, filters, state machines
  • Avoid mistakes: Don't confuse AND/OR, use parentheses, avoid double negatives
  • Debug complex conditions: Break them down into smaller parts

Logical operators are the building blocks of sophisticated trading strategies. Master them to create strategies that make intelligent decisions based on multiple factors and conditions.