Intervals vs timers
Intervals vs Timers
In HaasScript, "timers" can refer to two completely different concepts with different use cases. Understanding the distinction is critical for writing effective trading scripts:
-
Performance timers (
StartTimer,GetTimer,StopTimer) - For measuring execution time during development -
Interval-based timing (
Time(),AdjustTimestamp,CreateTimestamp,OptimizedForInterval) - For actual trading logic, scheduling actions, and working with time-based data
This page focuses on interval-based timing for trading logic.
Current Time: Time()
The Time() command returns the current Unix timestamp in UTC. This is your foundation for all time-based operations in HaasScript.
local currentTime = Time()
Log('Current Unix timestamp: ' .. currentTime)
Unix timestamps represent the number of seconds since January 1, 1970, 00:00:00 UTC. They're timezone-independent, which simplifies time calculations in trading scripts.
Creating Timestamps: CreateTimestamp
When you need a specific timestamp (not the current time), use CreateTimestamp:
-- Create a timestamp for a specific date/time
local tradeTime = CreateTimestamp(2026, 4, 13, 10, 30, 0) -- April 13, 2026, 10:30:00 UTC
-- Partial timestamps use current values for omitted parameters
local todayAtNoon = CreateTimestamp(2026, 4, 13, 12, 0) -- Seconds default to current
local thisYear = CreateTimestamp(2026) -- Uses current month, day, time
This is useful for:
- Scheduling trades at specific times
- Defining trading session boundaries
- Creating time-based filters
Adjusting Timestamps: AdjustTimestamp
AdjustTimestamp modifies a timestamp by adding or subtracting time units:
local currentTime = Time()
-- Add 1 hour
local oneHourLater = AdjustTimestamp(currentTime, 0, 0, 1)
-- Add 1 day
local tomorrow = AdjustTimestamp(currentTime, 0, 0, 0, 1)
-- Add 30 minutes and subtract 5 seconds
local adjustedTime = AdjustTimestamp(currentTime, -5, 30)
-- Add 1 week (7 days)
local nextWeek = AdjustTimestamp(currentTime, 0, 0, 0, 7)
Parameters are (in order): unix timestamp, addSeconds, addMinutes, addHours, addDays, addMonths, addYears. All time addition parameters are optional and default to zero.
Common Time-Based Patterns
Trading Session Filter
Only trade during specific hours:
local currentTime = Time()
-- Extract hour from timestamp (using current date context)
local currentHour = CurrentHour(currentTime)
-- Only trade between 9 AM and 5 PM UTC
if currentHour >= 9 and currentHour <= 17 then
-- Your trading logic here
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 then
Log('Executed buy trade')
end
end
Cooldown Period
Prevent rapid successive trades:
-- Store last trade time in script data
local lastTradeTime = Load('lastTradeTime')
local currentTime = Time()
local cooldownMinutes = 30
-- Check if enough time has passed since last trade
if lastTradeTime == nil or currentTime >= AdjustTimestamp(lastTradeTime, 0, cooldownMinutes) then
-- Execute trade
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 then
Log('Executed buy trade')
Save('lastTradeTime', currentTime)
end
end
Time-Based Exits
Close positions after a certain duration:
local position = PositionContainer()
if position.isLong or position.isShort then
local openTime = position.OpenTime
local currentTime = Time()
local maxHoldHours = 24
-- Check if position has been open too long
if currentTime >= AdjustTimestamp(openTime, 0, 0, maxHoldHours) then
-- Close position
if position.isLong then
DoExitPosition('Max Hold Long')
elseif position.isShort then
DoExitPosition('Max Hold Short')
end
end
end
Scheduled Action
Execute an action at a specific time:
local currentTime = Time()
local targetTime = CreateTimestamp(2026, 4, 13, 10, 0, 0) -- 10 AM UTC
-- Check if we've reached or passed target time
if currentTime >= targetTime then
-- One-time action
Log('Scheduled action executed at 10 AM UTC')
-- Prevent re-execution by storing a flag
local executed = Load('scheduledActionDone')
if executed == nil then
Save('scheduledActionDone', true)
-- Your action here
end
end
Interval Optimization: OptimizedForInterval
When working with interval-based data (like closed candles), OptimizedForInterval significantly speeds up backtesting by caching calculations:
-- Calculate RSI only when 1-hour candle closes, cache result
local rsiHourly = OptimizedForInterval(60, function()
return RSI(ClosePrices(), 14)
end)
-- Use the cached value
if rsiHourly < 30 then
DoLong()
end
The interval parameter is in minutes. Common intervals:
- 15 = 15 minutes
- 60 = 1 hour
- 1440 = 1 day
Set interval to 0 to use the main chart interval.
DefineIntervalOptimization for Custom Commands
When creating custom commands that should update only on interval ticks, use DefineIntervalOptimization:
-- Define a custom command that updates every 1 hour
DefineIntervalOptimization(60)
function CalculateHourlyRSI()
local rsi = RSI(ClosePrices(), 14)
return rsi
end
-- The command will only recalculate when the 1-hour interval ticks
local hourlyRSI = CalculateHourlyRSI()
Only use this when your command specifically needs updates once per interval tick. This optimization is designed for backtesting performance.
Practical Example: Time-Based Strategy
Here's a complete example combining multiple timing concepts:
-- Only trade during London session (8 AM - 4 PM UTC)
local currentTime = Time()
local currentHour = tonumber(CurrentDate(currentTime):sub(12, 13))
local inSession = currentHour >= 8 and currentHour <= 16
-- Get hourly RSI (cached, updates on 1-hour candle close)
local rsiHourly = OptimizedForInterval(60, function()
return RSI(ClosePrices(), 14)
end)
-- Check cooldown since last trade
local lastTradeTime = Load('lastTradeTime')
local cooldownMinutes = 60
local cooldownPassed = lastTradeTime == nil or currentTime >= AdjustTimestamp(lastTradeTime, 0, cooldownMinutes)
-- Execute trade if all conditions met
if inSession and cooldownPassed then
if rsiHourly < 30 then
DoLong()
Save('lastTradeTime', currentTime)
elseif rsiHourly > 70 then
DoShort()
Save('lastTradeTime', currentTime)
end
end
Time-Based vs Update-Based Logic
Understanding the difference is crucial:
Update-based (runs every update cycle):
local rsi = RSI(ClosePrices(), 14) -- Recalculated every update
if rsi < 30 then
DoLong() -- Can trigger multiple times per candle
end
Time/interval-based (runs only when conditions met):
local rsiHourly = OptimizedForInterval(60, function()
return RSI(ClosePrices(), 14) -- Only when 1-hour candle closes
end)
-- Trades 1-hour signals
if rsiHourly < 30 then
DoLong()
end
Common Mistakes
Using timers for time-based logic:
-- "Wrong": Performance timers don't persist
StartTimer()
if GetTimer() > 5 then
-- Only executes if it took more than 5ms to get here after timer started
DoSomething()
end
Forgetting UTC timezone:
-- Remember: Time() returns UTC, not local time
local currentTime = Time() -- Always UTC
Not accounting for interval in OptimizedForInterval:
-- Make sure interval matches your intended timeframe
local rsi15min = OptimizedForInterval(60, function() -- runs every hour
return RSI(ClosePrices(15), 14) -- uses 15-minute prices
end)