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

JSON

JSON

JSON (JavaScript Object Notation) is a lightweight data format commonly used for exchanging data between systems. HaasScript provides the ParseJson() command to parse JSON strings or fetch JSON data from URLs.

Parsing JSON Strings

Parse a JSON string using ParseJson():

local jsonString = '{"symbol":"BTC-USDT","price":50000,"change":2.5}'
local data = ParseJson(jsonString)

-- Access parsed values
Log('Symbol: ' .. data.symbol)      -- BTC-USDT
Log('Price: ' .. data.price)        -- 50000
Log('Change: ' .. data.change)      -- 2.5

The parsed data is returned as an object (table) with properties matching the JSON keys.

Fetching JSON from URLs

ParseJson() can also fetch JSON data directly from URLs:

local apiUrl = 'https://api.example.com/price/BTC-USDT'
local data = ParseJson(apiUrl)

Log('Price: ' .. data.price)

This is useful for integrating with external APIs, such as:

  • Market data feeds
  • Sentiment analysis services
  • News aggregators
  • Custom trading signals

JSON Data Structures

Objects

JSON objects map to Lua tables:

local jsonString = '{"symbol":"BTC","price":50000}'
local data = ParseJson(jsonString)

-- Access properties
local symbol = data.symbol
local price = data.price

Arrays

JSON arrays map to Lua arrays:

local jsonString = '{"prices":[49500,50000,50500,51000,51500]}'
local data = ParseJson(jsonString)

-- Access array elements
local firstPrice = data.prices[1]
local lastPrice = data.prices[#data.prices]

-- Iterate through array
for i = 1, #data.prices do
    Log('Price ' .. i .. ': ' .. data.prices[i])
end

Nested Structures

JSON can contain nested objects and arrays:

local jsonString = [[{
    "market": {
        "symbol": "BTC-USDT",
        "exchange": "binance"
    },
    "data": {
        "price": 50000,
        "volume": 1000,
        "trades": [
            {"time": 123456, "price": 49990, "amount": 0.5},
            {"time": 123457, "price": 50010, "amount": 0.3}
        ]
    }
}]]

local data = ParseJson(jsonString)

-- Access nested data
Log('Symbol: ' .. data.market.symbol)
Log('Price: ' .. data.data.price)
Log('First trade price: ' .. data.data.trades[1].price)

Practical Examples

Fetching Market Price from API

-- Fetch current price from external API
local apiUrl = 'https://api.coincap.io/v2/assets/bitcoin'
local data = ParseJson(apiUrl)

-- Extract price
local priceUsd = tonumber(data.data.priceUsd)
Log('Bitcoin price: $' .. priceUsd)

-- Use in trading logic
local currentPrice = CurrentPrice().close
local priceDifference = math.abs(currentPrice - priceUsd) / currentPrice * 100

if priceDifference > 5 then
    Log('Warning: Price discrepancy detected: ' .. priceDifference .. '%')
end

Trading Signals from External Service

-- Fetch trading signals from external service
local signalUrl = 'https://signals.example.com/api/BTC-USDT'
local data = ParseJson(signalUrl)

-- Parse signal data
local signal = data.signal  -- "long", "short", or "hold"
local confidence = tonumber(data.confidence)  -- 0-100
local posDir = GetPositionDirection()

-- Only act if confidence is high enough
if confidence >= 70 then
    if signal == "long" and posDir != PositionLong then
        DoLong()
        Log('Long signal received (confidence: ' .. confidence .. '%)')
    elseif signal == "short" and posDir != PositionShort then
        DoShort()
        Log('Short signal received (confidence: ' .. confidence .. '%)')
    end
end

Multi-Asset Configuration

-- Load trading configuration from JSON
local configJson = [[{
    "assets": [
        {"symbol": "BTC-USDT", "enabled": true, "positionSize": 0.5},
        {"symbol": "ETH-USDT", "enabled": true, "positionSize": 1.0},
        {"symbol": "BNB-USDT", "enabled": false, "positionSize": 2.0}
    ],
    "settings": {
        "maxOpenPositions": 3,
        "riskPercent": 2.0
    }
}]]

local config = ParseJson(configJson)

-- Iterate through assets
for i = 1, #config.assets do
    local asset = config.assets[i]
    if asset.enabled then
        Log('Trading ' .. asset.symbol .. ' with size ' .. asset.positionSize)
        -- Add asset to watchlist or execute trades
    end
end

Log('Max open positions: ' .. config.settings.maxOpenPositions)

Historical Data Import

-- Import historical data from JSON
local historyUrl = 'https://data.example.com/historical/BTC-USDT.json'
local data = ParseJson(historyUrl)

-- Process historical prices
local prices = NewArray()
for i = 1, #data.prices do
    ArrayAdd(prices, tonumber(data.prices[i].close))
end

-- Calculate indicators on imported data
local rsi = RSI(prices, 14)
Log('Current RSI from imported data: ' .. rsi[1])

Sentiment Analysis Integration

-- Fetch market sentiment data
local sentimentUrl = 'https://sentiment.example.com/api/BTC'
local data = ParseJson(sentimentUrl)

-- Parse sentiment metrics
local score = tonumber(data.score)        -- -100 to 100
local trend = data.trend                   -- "bullish", "bearish", "neutral"
local articles = #data.articles           -- Number of recent articles

-- Use sentiment in strategy
if score > 50 and trend == "bullish" then
    local rsi = RSI(ClosePrices(), 14)
    if rsi < 30 then
        DoLong()
        Log('Long entry confirmed by bullish sentiment (score: ' .. score .. ')')
    end
elseif score < -50 and trend == "bearish" then
    local rsi = RSI(ClosePrices(), 14)
    if rsi > 70 then
        DoShort()
        Log('Short entry confirmed by bearish sentiment (score: ' .. score .. ')')
    end
end

Error Handling

When working with external data, always handle potential errors:

local apiUrl = 'https://api.example.com/data'

-- Wrap in protected call
local success, data = pcall(function()
    return ParseJson(apiUrl)
end)

if success then
    -- Process data
    if data ~= nil then
        Log('Data received successfully')
    else
        Log('Error: No data returned')
    end
else
    Log('Error fetching data: ' .. tostring(data))
end

Data Type Conversion

JSON values are typically returned as strings. Convert to appropriate types:

local data = ParseJson('{"price": "50000", "volume": 1000}')

-- Convert to numbers
local price = tonumber(data.price)
local volume = tonumber(data.volume)

-- Perform calculations
local totalValue = price * volume

Best Practices

Validate data before use:

local data = ParseJson(apiUrl)

if data == nil then
    Log('Error: No data received')
    return
end

if data.price == nil or tonumber(data.price) <= 0 then
    Log('Error: Invalid price data')
    return
end

Cache external data:

-- Don't fetch on every update
local lastFetchTime = Load('lastFetchTime')
local cachedData = Load('cachedData')

local currentTime = Time()
local fetchInterval = 60  -- seconds

if lastFetchTime == nil or currentTime >= lastFetchTime + fetchInterval then
    local newData = ParseJson(apiUrl)
    Save('cachedData', newData)
    Save('lastFetchTime', currentTime)
    cachedData = newData
end

-- Use cached data
if cachedData ~= nil then
    Log('Using cached price: ' .. cachedData.price)
end

Document your JSON structure:

-- === JSON DATA STRUCTURE ===
-- From: https://api.example.com/market
-- {
--   "symbol": string - Trading pair
--   "price": number - Current price
--   "change": number - 24h change percentage
--   "volume": number - 24h volume
--   "timestamp": number - Unix timestamp
-- }

Common Mistakes

Not converting string values:

-- Wrong: JSON numbers may be strings
local price = data.price  -- Could be "50000"
local total = price * 2  -- Error if price is string

-- Correct: Convert to number
local price = tonumber(data.price)
local total = price * 2

Assuming data exists:

-- Risky: Data might be missing
local price = data.price

-- Better: Check before use
local price = 0
if data.price ~= nil then
    price = tonumber(data.price)
end

Fetching large data too frequently:

-- Wrong: Fetches every update
local data = ParseJson(apiUrl)

-- Better: Cache and fetch at reasonable intervals
local data = OptimizedForInterval(
    60,
    function()
        return ParseJson(apiUrl)
    end
)

Ignoring API rate limits:

-- Respect API rate limits by implementing delays
local lastFetchTime = Load('lastFetchTime')
if lastFetchTime == nil or Time() - lastFetchTime >= 60 then
    -- Fetch data
end

Limitations

  • No JSON encoding: HaasScript doesn't have a built-in stringify() or encode() command for converting objects to JSON
  • URL-only: ParseJson() accepts strings or URLs, but not file paths
  • Dependent on network: URL fetching requires internet connectivity and may fail
  • No authentication: ParseJson() doesn't support authenticated APIs
  • Rate limiting: Respect API rate limits to avoid being blocked