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()orencode()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