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:
-
not(highest precedence) and-
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
- Use parentheses for complex conditions to improve clarity
- Break down complex logic into smaller, named variables
- Test edge cases like boundary values (exactly 30, exactly 70)
- Use short-circuit evaluation by ordering conditions efficiently
- Avoid double negatives - rephrase as positive statements
- Use descriptive variable names for intermediate conditions
- Consider operator precedence - use parentheses when in doubt
- Simplify when possible - combine redundant conditions
- Document complex logic with comments explaining the reasoning
- 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.