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

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