Failures and null values
Failed calls return a null value
When a function of an exchange object, or most global functions, fails (network error, timeout, the exchange rejects the request, a parameter the exchange does not accept, etc.), the strategy is not stopped. Instead:
- an error log entry is written (it can be filtered with
SetErrorFilter); - the error message is kept as the last error and can be read with
GetLastError; - a null value is returned:
nullinJavaScript,NoneinPython,ErrinRust(carrying the error message).
A successful query with no data returns an empty array [] (for example exchange.GetOrders() with no open orders), which is different from the null value of a failure. Tell the two apart when checking results, and never treat a null value as "no data" and keep calculating. A few functions return something else on failure; the "Returns" section of each function page is authoritative (for example HttpQuery() returns an empty string on failure).
Unsupported functions
When an exchange or the runtime does not support a function or a query range, the call is treated as a failure: an "unsupported" error is recorded (error log + GetLastError()), a null value is returned and the strategy keeps running. It never returns values that look like data, such as [], {} or 0.
Programming errors throw
When the call itself is wrong (for example calling a function without symbol before any trading pair is set, or passing a parameter that cannot be parsed), JavaScript and Python throw an exception, which stops the strategy if it is not caught; Rust returns Err. Such errors need a code change; retrying does not help.
Pattern
Check for the null value before using a result; wrap calls that should be retried automatically with _C.
Examples
Distinguish a failed call (null value) from a successful query with no data (empty array).
javascript
function main() {
var ticker = exchange.GetTicker("BTC_USDT")
if (ticker === null) {
// the call failed: the error is already logged and GetLastError() returns the reason
Log("GetTicker failed:", GetLastError())
return
}
var orders = exchange.GetOrders("BTC_USDT")
if (orders === null) {
Log("GetOrders failed:", GetLastError())
} else if (orders.length === 0) {
Log("no open orders")
} else {
Log("open orders:", orders.length)
}
}
python
def main():
ticker = exchange.GetTicker("BTC_USDT")
if ticker is None:
# the call failed: the error is already logged and GetLastError() returns the reason
Log("GetTicker failed:", GetLastError())
return
orders = exchange.GetOrders("BTC_USDT")
if orders is None:
Log("GetOrders failed:", GetLastError())
elif len(orders) == 0:
Log("no open orders")
else:
Log("open orders:", len(orders))
rust
fn main() {
let ticker = match exchange.GetTicker("BTC_USDT") {
Ok(t) => t,
Err(e) => {
// the call failed: Err carries the error message
Log!("GetTicker failed:", e);
return;
}
};
Log!("last:", ticker.Last);
match exchange.GetOrders("BTC_USDT") {
Ok(orders) if orders.is_empty() => Log!("no open orders"),
Ok(orders) => Log!("open orders:", orders.len()),
Err(e) => Log!("GetOrders failed:", e),
}
}