Saving and loading
Saving and Loading
HaasScript scripts run from top to bottom on every update cycle. Variables you define in one update are not visible in the next—each update starts fresh. To persist data between updates, you use the Save() and Load() commands.
Basic Save and Load
The Save() command stores a value under a unique key, and Load() retrieves it:
-- Load a value
local lastTradeTime = Load('lastTradeTime')
-- Save the value
Save('lastTradeTime', lastTradeTime)
The key is always a string. The value can be any HaasScript data type (number, string, boolean, table, etc.).
Default Values
Load() returns nil if no value exists for the key. You can provide a default value as the second parameter:
-- Load with default value
local tradeCount = Load('tradeCount', 0) -- Returns 0 if key doesn't exist
-- Increment and save
tradeCount = tradeCount + 1
Save('tradeCount', tradeCount)
This pattern is essential for initialization on first run.
Deleting Saved Data
Use Delete() to remove a saved value:
-- Delete a saved value
Delete('temporaryData')
-- Attempting to load after delete returns nil (or default)
local data = Load('temporaryData', 'default') -- Returns 'default'
Storage Limits
HaasScript allows a maximum of 10,000 unique keys. Use descriptive, organized keys to avoid hitting this limit:
-- Good: Organized keys
Save('strategy1/tradeCount', 5)
Save('strategy1/lastSignal', 'long')
Save('strategy2/tradeCount', 3)
-- Avoid: Random or unclear keys
Save('data1', 10)
Save('data2', 20)
Common Patterns
Counter Pattern
Track cumulative values across updates:
-- Load current count, default to 0
local totalTrades = Load('totalTrades', 0)
-- Increment when trade executes
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 and GetPositionDirection() != PositionLong then
DoLong()
totalTrades = totalTrades + 1
Save('totalTrades', totalTrades)
end
Log('Total trades: ' .. totalTrades)
Cooldown Pattern
Prevent rapid successive actions:
local lastTradeTime = Load('lastTradeTime')
local currentTime = Time()
local cooldownSeconds = 300 -- 5 minutes
-- Check if enough time has passed
if lastTradeTime == nil or currentTime >= lastTradeTime + cooldownSeconds then
-- Execute trade
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 then
DoLong()
Save('lastTradeTime', currentTime)
end
else
local remaining = lastTradeTime + cooldownSeconds - currentTime
Log('Cooldown: ' .. remaining .. ' seconds remaining')
end
State Flag Pattern
Track simple on/off states:
local isEnabled = Load('isEnabled', true) -- Default to enabled
if isEnabled then
-- Trading logic
local rsi = RSI(ClosePrices(), 14)
if rsi < 30 then
DoLong()
end
end
-- Disable after certain condition
if Load('disableAfter', false) then
Save('isEnabled', false)
end
Last Value Comparison
Detect changes between updates:
local lastRsi = Load('lastRsi')
local currentRsi = RSI(ClosePrices(), 14)
-- Check for crossover
if lastRsi ~= nil then
if lastRsi >= 70 and currentRsi < 70 then
Log('RSI crossed below 70 - potential short signal')
elseif lastRsi <= 30 and currentRsi > 30 then
Log('RSI crossed above 30 - potential long signal')
end
end
-- Save for next update
Save('lastRsi', currentRsi)
Complex Data Pattern
Store tables for structured data:
-- Load or initialize trade history
local tradeHistory = Load('tradeHistory', {})
-- Add new trade entry
local currentTime = Time()
table.insert(tradeHistory, {
time = currentTime,
type = 'long',
price = 45000,
rsi = 27
})
-- Save updated history
Save('tradeHistory', tradeHistory)
-- Access trade history
if #tradeHistory > 0 then
local lastTrade = tradeHistory[#tradeHistory]
Log('Last trade: ' .. lastTrade.type .. ' at ' .. lastTrade.price)
end
Performance Considerations
Save/load operations have minimal overhead, but consider these guidelines:
Batch saves when possible:
-- Less efficient
Save('value1', 1)
Save('value2', 2)
Save('value3', 3)
-- More efficient: single table
local data = {value1 = 1, value2 = 2, value3 = 3}
Save('batchData', data)
Avoid saving every update unless necessary:
-- Check if value changed before saving
local newRsi = RSI(ClosePrices(), 14)
local oldRsi = Load('currentRsi')
if newRsi ~= oldRsi then
Save('currentRsi', newRsi)
end
Or place all Save calls to the bottom of the script. They will then execute only after everything else has been processed.
Key Management Best Practices
Use descriptive, hierarchical keys:
-- Good: Clear and organized
Save('rsiStrategy/tradeCount', 10)
Save('rsiStrategy/lastTradeTime', Time())
Save('bbStrategy/tradeCount', 5)
-- Bad: Unclear purpose
Save('data1', 10)
Save('data2', 1234567890)
Document your keys:
-- State management keys:
-- - 'enabled': boolean, overall strategy enable/disable
-- - 'lastTradeTime': number, Unix timestamp of last trade
-- - 'tradeCount': number, total trades executed
-- - 'winCount': number, winning trades
Clean up unused keys:
-- Delete temporary data when done
if someCondition then
Delete('temporaryFlag')
end
Testing and Debugging
Check if data exists before using:
if Load('myData') == nil then
Log('No data found, initializing...')
Save('myData', defaultValue)
end
Log save/load operations during development:
local tradeTime = Time()
Save('lastTradeTime', tradeTime)
Log('Saved trade time: ' .. tradeTime)
Use Delete() to reset state during testing:
-- Reset strategy state
Delete('tradeCount')
Delete('lastTradeTime')
Delete('isEnabled')
Log('State reset')
Common Mistakes
Forgetting default values:
-- Wrong: May cause nil errors
local count = Load('tradeCount')
count = count + 1 -- Error since count is nil
-- Correct: Always provide default
local count = Load('tradeCount', 0)
count = count + 1
Inconsistent key names:
-- Wrong: Different keys for same data
local tradeTime = Load('LastTrade') -- Never updates - keys are case-sensitive
Save('lastTrade', Time())
-- Correct: Use consistent keys
local tradeTime = Load('lastTrade')
Save('lastTrade', Time())
Saving unnecessary data:
-- Avoid: Saving values that can be recalculated
Save('currentPrice', CurrentPrice())
-- Better: Calculate when needed
local price = CurrentPrice()
Assuming data persists across script restarts:
- Saved data persists across updates within the same bot session
- Data may not persist if you stop/restart the bot or clear script data