JavaScript
Strategies can be written in JavaScript. The runtime is based on the QuickJS engine and supports modern syntax such as async/await, class and BigInt. In live trading the strategy runs on the docker; in backtesting it runs in the browser-side backtesting system. Adding // @ts-check to the code switches to TypeScript (see Programming Languages → TypeScript).
Structure and parameters
The entry point is function main(). The optional init(), onexit() and onerror(msg) are called automatically by the docker (see Writing Strategies → Strategy Structure). Interface parameters are global variables with the same names; they can be read directly and also modified in code (see Writing Strategies → Strategy Parameters).
Errors and return values
When an API call fails (the exchange returns an error, a network problem, etc.) it returns null and writes the error to the log. Check the return value before using it, or retry with _C:
javascript
function main() {
var ticker = exchange.GetTicker()
// null when the call fails
if (ticker) {
Log(ticker)
}
// retry until valid data is returned
var account = _C(exchange.GetAccount)
Log(account)
}
For program exceptions (for example reading a property of undefined) and API business errors, the log shows the line number in the strategy code where the error occurred, which makes debugging easier.
Strings and ArrayBuffer
JavaScript strings are UTF-16. If text returned by a platform API is not a valid UTF-8 byte sequence, an ArrayBuffer (the raw bytes) is returned instead so that no data is lost. Every API parameter that accepts a string also accepts an ArrayBuffer.
javascript
function stringToHex(str) {
let hex = ''
for (let i = 0; i < str.length; i++) {
const charCode = str.charCodeAt(i).toString(16)
hex += charCode.length === 1 ? '0' + charCode : charCode
}
return hex
}
function main() {
// the code point of "𠮷" exceeds 16 bits; it takes two UTF-16 code units in a JavaScript string
const inputString = "abc𠮷123"
// Encode outputs the UTF-8 bytes as hex
const encodedHex = Encode("raw", "string", "hex", inputString)
Log(encodedHex) // 616263f0a0aeb7313233
// charCodeAt returns UTF-16 code units, so "𠮷" becomes d842, dfb7 - not UTF-8
const manuallyEncodedHex = stringToHex(inputString)
Log(manuallyEncodedHex) // 616263d842dfb7313233
// valid UTF-8 bytes decode back to a string
const decodedString = Encode("raw", "hex", "string", encodedHex)
Log(decodedString) // abc𠮷123
// bytes that are not valid UTF-8 come back as an ArrayBuffer
// (with inputString = "abcG123" both encodings are identical and this is a string)
const outputD = Encode("raw", "hex", "string", manuallyEncodedHex)
Log(outputD instanceof ArrayBuffer) // true
// inspect the raw bytes in the ArrayBuffer
const bufferD = new Uint8Array(outputD)
let hexBufferD = ''
for (let i = 0; i < bufferD.length; i++) {
hexBufferD += bufferD[i].toString(16).padStart(2, '0')
}
Log(hexBufferD) // 616263d842dfb7313233
}
Asynchrony and threads
setTimeout/clearTimeout: callbacks run while the main thread is waiting inSleep(). Whenmain()returns, timers that have not fired yet run first, thenonexit()is called.fetch(url): returns aPromisethat resolves to a response object (ok,status,headers;text()andjson()return the content directly). On the docker,fetchcompletes the request synchronously when called and returns an already settledPromise, so combining severalfetchcalls withPromise.alldoes not make them concurrent.- Exchange APIs (such as
exchange.GetTicker()) are synchronous blocking calls; wrapping them in aPromiseor anasyncfunction does not make them concurrent either. - For concurrency use
exchange.Go,HttpQuery_Go, or create threads withThread(see Advanced Topics → JavaScript Multithreading).
javascript
async function main() {
let resp = await fetch("https://www.okx.com/api/v5/market/books?instId=BTC-USDT")
if (resp.ok) {
Log(resp.json())
} else {
Log("status:", resp.status)
}
}
Libraries and dependencies
JavaScript strategies can use the built-in TA and talib indicator libraries directly; see Writing Strategies → Built-in Libraries for what each language provides. Other third-party JavaScript libraries can be downloaded at run time and loaded with eval; the same page has an example.