The exchange.Buy()
function is used to place buy orders. The Buy()
function is a member function of the exchange object {@var/EXCHANGE exchange}. The Buy()
function operates on the exchange account bound to the exchange object exchange
. The purpose of the member functions (methods) of the exchange
object is only related to exchange
, and it will not be repeated after the documentation.
A successful order returns the order Id, a failed order returns a null value.
The attribute Id
of the order {@struct/Order Order} structure of the FMZ platform consists of the exchange product code and the exchange original order ID, separated by English commas. For example, the attribute Id
format of the spot trading pair ETH_USDT
order of the OKX exchange is: ETH-USDT,1547130415509278720
.
When calling the exchange.Buy()
function to place an order, the return value order Id
is consistent with the Id
attribute of the order {@struct/Order Order} structure.
string, null value
exchange.Buy(price, amount) exchange.Buy(price, amount, …args)
The price
parameter is used to set the order price.
price
true
number
The amount
parameter is used to set the order amount.
amount
true
number
Extended parameters that can output accompanying information to this order log, arg
parameters can be passed more than one.
arg
false
string, number, bool, object, array, null and any other type supported by the system
function main() {
var id = exchange.Buy(100, 1);
Log("id:", id);
}
def main():
id = exchange.Buy(100, 1)
Log("id:", id)
void main() {
auto id = exchange.Buy(100, 1);
Log("id:", id);
}
The order number returned by exchange.Buy()
can be used to query the order information and cancel the order.
// The following is an error call
function main() {
exchange.SetContractType("quarter")
// Set the shorting direction
exchange.SetDirection("sell")
// If you place a buy order, an error will be reported, and shorting can only be sold
var id = exchange.Buy(50, 1)
// Set the long direction
exchange.SetDirection("buy")
// If you place a sell order, it will report an error, go long, only buy
var id2 = exchange.Sell(60, 1)
// Set direction to close long positions
exchange.SetDirection("closebuy")
// If you place a buy order, it will report an error, close long, only sell
var id3 = exchange.Buy(-1, 1)
// Set direction to close short positions
exchange.SetDirection("closesell")
// If you place a sell order, it will report an error, close short, only buy
var id4 = exchange.Sell(-1, 1)
}
# The following is an error call
def main():
exchange.SetContractType("quarter")
exchange.SetDirection("sell")
id = exchange.Buy(50, 1)
exchange.SetDirection("buy")
id2 = exchange.Sell(60, 1)
exchange.SetDirection("closebuy")
id3 = exchange.Buy(-1, 1)
exchange.SetDirection("closesell")
id4 = exchange.Sell(-1, 1)
// The following is an error call
void main() {
exchange.SetContractType("quarter");
exchange.SetDirection("sell");
auto id = exchange.Buy(50, 1);
exchange.SetDirection("buy");
auto id2 = exchange.Sell(60, 1);
exchange.SetDirection("closebuy");
auto id3 = exchange.Buy(-1, 1);
exchange.SetDirection("closesell");
auto id4 = exchange.Sell(-1, 1);
}
When placing an order for a cryptocurrency futures contract, care must be taken to ensure that the trade direction is set correctly, as a mismatch between the trade direction and the trade function will result in an error:
direction is sell, invalid order type Buy
direction is buy, invalid order type Sell
direction is closebuy, invalid order type Buy
direction is closesell, invalid order type Sell
// For example, the trading pair: ETH_BTC, place a buy order at the market price
function main() {
// Place a buy order at the market price and buy ETH coins with a value of 0.1 BTC (denominated currency)
exchange.Buy(-1, 0.1)
}
def main():
exchange.Buy(-1, 0.1)
void main() {
exchange.Buy(-1, 0.1);
}
Spot market order.
When placing an order for a futures contract, you must pay attention to whether the trade direction is set correctly, as an error will be reported if the trade direction and the trade function do not match. The order size for cryptocurrency futures contracts is the number of contracts if not specified.
The parameter price
is set to -1
for placing market orders, which requires the exchange’s order placement interface to support market orders. When placing market orders for cryptocurrency spot contracts, the parameter amount
is the amount of money in the currency of the order. When placing market orders for cryptocurrency futures contracts, the amount parameter amount
is the number of contracts. There are a few cryptocurrency exchanges that do not support market order interface during live trading. The order quantity for market buy orders on some spot exchanges is the number of trading coins. Please refer to the Special Instructions for Exchanges in the “User Guide” for details.
If you are using an older version of the docker, the return value of the order Id
of the exchange.Buy()
function may be different from the return value of the order Id
described in the current document.
{@fun/Trade/exchange.Sell exchange.Sell}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}, {@fun/Futures/exchange.SetDirection exchange.SetDirection}
The exchange.Sell()
function is used to place sell orders.
A successful order returns the order Id, a failed order returns a null value. The attribute Id
of the order {@struct/Order Order} structure of the FMZ platform consists of the exchange product code and the exchange original order ID, separated by English commas. For example, the attribute Id
format of the spot trading pair ETH_USDT
order of the OKX exchange is: ETH-USDT,1547130415509278720
. When calling the exchange.Sell()
function to place an order, the return value order Id
is consistent with the Id
attribute of the order {@struct/Order Order} structure.
string, null value
exchange.Sell(price, amount) exchange.Sell(price, amount, …args)
The price
parameter is used to set the order price.
price
true
number
The amount
parameter is used to set the order amount.
amount
true
number
Extended parameters that can output accompanying information to this order log, arg
parameters can be passed more than one.
arg
false
string, number, bool, object, array, null and any other type supported by the system
function main(){
var id = exchange.Sell(100, 1)
Log("id:", id)
}
def main():
id = exchange.Sell(100, 1)
Log("id:", id)
void main() {
auto id = exchange.Sell(100, 1);
Log("id:", id);
}
The order number returned by exchange.Sell()
can be used to query order information and cancel orders.
// The following is an error call
function main() {
exchange.SetContractType("quarter")
// Set the shorting direction
exchange.SetDirection("sell")
// If you place a buy order, an error will be reported, and shorting can only be sold
var id = exchange.Buy(50, 1)
// Set the long direction
exchange.SetDirection("buy")
// If you place a sell order, it will report an error, go long, only buy
var id2 = exchange.Sell(60, 1)
// Set direction to close long positions
exchange.SetDirection("closebuy")
// If you place a buy order, it will report an error, close long, only sell
var id3 = exchange.Buy(-1, 1)
// Set direction to close short positions
exchange.SetDirection("closesell")
// If you place a sell order, it will report an error, close short, only buy
var id4 = exchange.Sell(-1, 1)
}
# The following is an error call
def main():
exchange.SetContractType("quarter")
exchange.SetDirection("sell")
id = exchange.Buy(50, 1)
exchange.SetDirection("buy")
id2 = exchange.Sell(60, 1)
exchange.SetDirection("closebuy")
id3 = exchange.Buy(-1, 1)
exchange.SetDirection("closesell")
id4 = exchange.Sell(-1, 1)
// The following is an error call
void main() {
exchange.SetContractType("quarter");
exchange.SetDirection("sell");
auto id = exchange.Buy(50, 1);
exchange.SetDirection("buy");
auto id2 = exchange.Sell(60, 1);
exchange.SetDirection("closebuy");
auto id3 = exchange.Buy(-1, 1);
exchange.SetDirection("closesell");
auto id4 = exchange.Sell(-1, 1);
}
When placing an order for a cryptocurrency futures contract, care must be taken to ensure that the trade direction is set correctly, as a mismatch between the trade direction and the trade function will result in an error:
direction is sell, invalid order type Buy
direction is buy, invalid order type Sell
direction is closebuy, invalid order type Buy
direction is closesell, invalid order type Sell
// For example, the trading pair: ETH_BTC, place a sell order at the market price
function main() {
// Note: place a market order to sell, sell 0.2 ETH
exchange.Sell(-1, 0.2)
}
def main():
exchange.Sell(-1, 0.2)
void main() {
exchange.Sell(-1, 0.2);
}
Spot market order.
When placing an order for a futures contract, you must pay attention to whether the trade direction is set correctly, as an error will be reported if the trade direction and the trade function do not match. The order amount for cryptocurrency futures contracts is the number of contracts if not specified.
The parameter price
is set to -1
for placing market orders, which requires the exchange’s order placement interface to support market orders. When placing market orders for cryptocurrency spot contracts, the amount parameter amount
is the amount in trading currency. When placing market orders for cryptocurrency futures contracts, the amount parameter amount
is the number of contracts. There are a few cryptocurrency exchanges that do not support market order interface during live trading.
If you are using an older version of the docker, the return value of the order Id
of the exchange.Sell()
function may be different from the return value of the order Id
described in the current document.
{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}, {@fun/Futures/exchange.SetDirection exchange.SetDirection}
The exchange.CreateOrder()
function is used to place an order.
If the order is successfully placed, the order ID is returned; if the order fails, a null value is returned. The attribute Id
of the order {@struct/Order Order} structure of the FMZ platform consists of the exchange product code and the exchange original order ID, separated by English commas. For example, the attribute Id
format of the order of the spot trading pair ETH_USDT
of the OKX exchange is: ETH-USDT,1547130415509278720
. When calling the exchange.CreateOrder(symbol, side, price, amount)
function to place an order, the return value of the order Id
is consistent with the Id
property of the order {@struct/Order Order} structure.
string, null value
exchange.CreateOrder(symbol, side, price, amount) exchange.CreateOrder(symbol, side, price, amount, …args)
The parameter symbol
is used to specify the specific trading pair and contract code of the order. When calling the exchange.CreateOrder(symbol, side, price, amount)
function to place an order, exchange
is the spot exchange object. If the order denominated currency is USDT and the tranding currency is BTC, the parameter symbol
is: "BTC_USDT"
, in the format of the trading pair defined by the FMZ platform. When calling the exchange.CreateOrder(symbol, side, price, amount)
function to place an order, exchange
is the futures exchange object. If the order is a BTC’s U-standard perpetual contract order, the parameter symbol
is: "BTC_USDT.swap"
, and the format is a combination of the trading pair and contract code defined by the FMZ platform, separated by the character “.”. When calling the exchange.CreateOrder(symbol, side, price, amount)
function to place an order, exchange
is the futures exchange object. If the order is a BTC’s U-standard option contract order, the parameter symbol
is: "BTC_USDT.BTC-240108-40000-C"
(taking Binance Option BTC-240108-40000-C as an example), and the format is a combination of the trading pair defined by the FMZ platform and the specific option contract code defined by the exchange, separated by the character “.”.
symbol
true
string
The side
parameter is used to specify the trading direction of the order.
For spot exchange objects, the optional values of the side
parameter are: buy
, sell
. buy
means buying, and sell
means selling.
For futures exchange objects, the optional values of the side
parameter are: buy
, closebuy
, sell
, closesell
. buy
means opening a long position, closebuy
means closing a long position, sell
means opening a short position, and closesell
means closing a short position.
side
true
string
The parameter price
is used to set the price of the order. A price of -1 indicates that the order is a market order.
price
true
number
The parameter amount
is used to set the order quantity. Please note that when the order is a market buy order, the order quantity is the purchase amount; the order quantity of the market buy order of some spot exchanges is the number of trading coins. For details, please refer to the Special Instructions for Exchanges in the “User Guide”.
amount
true
number
Extended parameters can output additional information to this order log. Multiple arg
parameters can be passed.
arg
false
Any type supported by the system, such as string, number, bool, object, array, null value, etc.
function main() {
var id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01) // Spot exchange objects place orders for currency-to-currency transactions BTC_USDT trading pairs
// var id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01) // Futures exchange objects place orders for BTC's U-standard perpetual contracts
Log("Order Id:", id)
}
def main():
id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01) # Spot exchange objects place orders for currency-to-currency transactions BTC_USDT trading pairs
# id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01) # Futures exchange objects place orders for BTC's U-standard perpetual contracts
Log("Order Id:", id)
void main() {
auto id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01); // Spot exchange objects place orders for currency-to-currency transactions BTC_USDT trading pairs
// auto id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01); // Futures exchange objects place orders for BTC's U-standard perpetual contracts
Log("Order Id:", id);
}
Spot exchange objects and futures exchange objects call the exchange.CreateOrder()
function to place an order.
{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}
The exchange.CancelOrder()
function is used to cancel the order.
The attribute Id
of the order {@struct/Order Order} structure of the FMZ platform consists of the exchange product code and the exchange original order ID, separated by English commas. For example, the attribute Id
format of the order of the spot trading pair ETH_USDT
of the OKX exchange is: ETH-USDT,1547130415509278720
.
The parameter orderId
passed in when calling the exchange.CancelOrder()
function to cancel an order is consistent with the Id
property of the order {@struct/Order Order} structure.
The exchange.CancelOrder()
function returns a true value, for example true
means that the cancel order request was sent successfully. If it returns a false value, such as false
, means that the cancel order request failed to be sent. The return value only represents the success or failure of the request sent to determine whether the exchange cancels the order. You can call exchange.GetOrders()
to determine if the order is cancelled.
bool
exchange.CancelOrder(orderId) exchange.CancelOrder(orderId, …args)
The orderId
parameter is used to specify the order to be cancelled.
orderId
true
number, string
Extended parameters, you can output the attached information to this withdrawal log, arg
parameters can be passed more than one.
arg
false
string, number, bool, object, array, null and any other type supported by the system
function main(){
var id = exchange.Sell(99999, 1)
exchange.CancelOrder(id)
}
def main():
id = exchange.Sell(99999, 1)
exchange.CancelOrder(id)
void main() {
auto id = exchange.Sell(99999, 1);
exchange.CancelOrder(id);
}
Cancel the order.
function main() {
if (exchange.GetName().includes("Futures_")) {
Log("Set the contract as: perpetual contract, set the trade direction as: open long position.")
exchange.SetContractType("swap")
exchange.SetDirection("buy")
}
var ticker = exchange.GetTicker()
exchange.Buy(ticker.Last * 0.5, 0.1)
var orders = exchange.GetOrders()
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, "Cancelled orders:", orders[i])
Sleep(500)
}
}
def main():
if exchange.GetName().find("Futures_") != -1:
Log("Set the contract as: perpetual contract, set the trade direction as: open long position.")
exchange.SetContractType("swap")
exchange.SetDirection("buy")
ticker = exchange.GetTicker()
exchange.Buy(ticker["Last"] * 0.5, 0.1)
orders = exchange.GetOrders()
for i in range(len(orders)):
exchange.CancelOrder(orders[i]["Id"], "Cancelled orders:", orders[i])
Sleep(500)
void main() {
if (exchange.GetName().find("Futures_") != std::string::npos) {
Log("Set the contract as: perpetual contract, set the trade direction as: open long position.");
exchange.SetContractType("swap");
exchange.SetDirection("buy");
}
auto ticker = exchange.GetTicker();
exchange.Buy(ticker.Last * 0.5, 0.1);
auto orders = exchange.GetOrders();
for (int i = 0 ; i < orders.size() ; i++) {
exchange.CancelOrder(orders[i].Id, "Cancelled orders:", orders[i]);
Sleep(500);
}
}
FMZ API functions that can produce log output functions such as: Log()
, exchange.Buy()
, exchange.CancelOrder()
can be followed by some accompanying output parameters after the necessary parameters. For example: exchange.CancelOrder(orders[i].Id, orders[i])
, so that when canceling the order whose Id is orders[i].Id
, the order’s information is output with it. That is, the {@struct/Order Order} structure of orders[i]
.
If you are using an older version of the docker, the orderId parameter of the exchange.CancelOrder() function may be different from the orderId described in the current document.
{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}
The exchange.GetOrder()
function is used to get the order information.
Query the order details according to the order number, and return the {@struct/Order Order} structure if the query succeeds, or return null if the query fails. {@struct/Order Order}, null value
exchange.GetOrder(orderId)
The orderId
parameter is used to specify the order to be queried.
The attribute Id
of the order {@struct/Order Order} structure of the FMZ platform consists of the exchange product code and the exchange original order ID, separated by English commas. For example, the attribute Id
format of the order of the spot trading pair ETH_USDT
of the OKX exchange is: ETH-USDT,1547130415509278720
.
The parameter orderId
passed in when calling the exchange.GetOrder()
function to query an order is consistent with the Id
property of the order {@struct/Order Order} structure.
orderId true string
function main(){
var id = exchange.Sell(1000, 1)
// Parameter id is the order number, you need to fill in the number of the order you want to query
var order = exchange.GetOrder(id)
Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
order.DealAmount, "Status:", order.Status, "Type:", order.Type)
}
def main():
id = exchange.Sell(1000, 1)
order = exchange.GetOrder(id)
Log("Id:", order["Id"], "Price:", order["Price"], "Amount:", order["Amount"], "DealAmount:",
order["DealAmount"], "Status:", order["Status"], "Type:", order["Type"])
void main() {
auto id = exchange.Sell(1000, 1);
auto order = exchange.GetOrder(id);
Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
order.DealAmount, "Status:", order.Status, "Type:", order.Type);
}
The exchange.GetOrder()
function is not supported by some exchanges. The AvgPrice
attribute in the {@struct/Order Order} structure of the return value is the average price of the transaction. Some exchanges do not support this field, and if they do not, it is set to 0.
If you are using an older version of the docker, the orderId
parameter of the exchange.GetOrder()
function may differ from the orderId
described in the current documentation.
Exchanges that do not support the exchange.GetOrder()
function:
Function Name | Unsupported Spot Exchanges | Unsupported Futures Exchanges |
---|---|---|
GetOrder | Zaif / Coincheck / Bitstamp | – |
{@struct/Order Order}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}, {@fun/Trade/exchange.GetHistoryOrders exchange.GetHistoryOrders}
The exchange.GetOrders()
function is used to get outstanding orders.
The exchange.GetOrders()
function returns an array of {@struct/Order Order} structures if the request for data succeeds, and it returns null values if the request for data fails.
{@struct/Order Order} array, null value
exchange.GetOrders() exchange.GetOrders(symbol)
The parameter symbol
is used to set the transaction symbol or transaction symbol range to be queried.
For spot exchange objects, if the symbol
parameter is not passed, the uncompleted order data of all spot products will be requested.
For futures exchange objects, if the symbol
parameter is not passed, the default is to request the uncompleted order data of all varieties in the dimension range of the current trading pair and contract code.
symbol false string
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
function main() {
var arrSymbol = ["ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"]
for (var symbol of arrSymbol) {
var t = exchange.GetTicker(symbol)
exchange.CreateOrder(symbol, "buy", t.Last / 2, 0.01)
}
var spotOrders = exchange.GetOrders()
var tbls = []
for (var orders of [spotOrders]) {
var tbl = {type: "table", title: "test GetOrders", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
for (var order of orders) {
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
}
tbls.push(tbl)
}
LogStatus("`" + JSON.stringify(tbls) + "`")
// Print out the information once and then return to prevent the order from being executed during the subsequent backtest and affecting data observation
return
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
'''
import json
def main():
arrSymbol = ["ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"]
for symbol in arrSymbol:
t = exchange.GetTicker(symbol)
exchange.CreateOrder(symbol, "buy", t["Last"] / 2, 0.01)
spotOrders = exchange.GetOrders()
tbls = []
for orders in [spotOrders]:
tbl = {"type": "table", "title": "test GetOrders", "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], "rows": []}
for order in orders:
tbl["rows"].append([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
tbls.append(tbl)
LogStatus("`" + json.dumps(tbls) + "`")
return
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
void main() {
auto arrSymbol = {"ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"};
for (const auto& symbol : arrSymbol) {
auto t = exchange.GetTicker(symbol);
exchange.CreateOrder(symbol, "buy", t.Last / 2, 0.01);
}
auto spotOrders = exchange.GetOrders();
json tbls = R"([])"_json;
std::vector<std::vector<Order>> arr = {spotOrders};
for (const auto& orders : arr) {
json tbl = R"({
"type": "table",
"title": "test GetOrders",
"cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"],
"rows": []
})"_json;
for (const auto& order : orders) {
json arrJson = R"([])"_json;
arrJson.push_back("Symbol");
arrJson.push_back("Id");
arrJson.push_back(order.Price);
arrJson.push_back(order.Amount);
arrJson.push_back(order.DealAmount);
arrJson.push_back(order.AvgPrice);
arrJson.push_back(order.Status);
arrJson.push_back(order.Type);
arrJson.push_back(order.Offset);
arrJson.push_back(order.ContractType);
tbl["rows"].push_back(arrJson);
}
tbls.push_back(tbl);
}
LogStatus(_D(), "\n", "`" + tbls.dump() + "`");
return;
}
Use the spot exchange object to place buy orders for multiple different trading pairs at half the current price, and then query the outstanding order information.
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
function main() {
var arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]
for (var symbol of arrSymbol) {
var t = exchange.GetTicker(symbol)
exchange.CreateOrder(symbol, "buy", t.Last / 2, 1)
exchange.CreateOrder(symbol, "sell", t.Last * 2, 1)
}
var defaultOrders = exchange.GetOrders()
var swapOrders = exchange.GetOrders("USDT.swap")
var futuresOrders = exchange.GetOrders("USDT.futures")
var btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap")
var tbls = []
var arr = [defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders]
var tblDesc = ["defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"]
for (var index in arr) {
var orders = arr[index]
var tbl = {type: "table", title: tblDesc[index], cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
for (var order of orders) {
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
}
tbls.push(tbl)
}
LogStatus("`" + JSON.stringify(tbls) + "`")
// Print out the information once and then return to prevent the order from being executed during the subsequent backtest and affecting data observation
return
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
'''
import json
def main():
arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]
for symbol in arrSymbol:
t = exchange.GetTicker(symbol)
exchange.CreateOrder(symbol, "buy", t["Last"] / 2, 1)
exchange.CreateOrder(symbol, "sell", t["Last"] * 2, 1)
defaultOrders = exchange.GetOrders()
swapOrders = exchange.GetOrders("USDT.swap")
futuresOrders = exchange.GetOrders("USDT.futures")
btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap")
tbls = []
arr = [defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders]
tblDesc = ["defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"]
for index in range(len(arr)):
orders = arr[index]
tbl = {"type": "table", "title": tblDesc[index], "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], "rows": []}
for order in orders:
tbl["rows"].append([order["Symbol"], order["Id"], order["Price"], order["Amount"], order["DealAmount"], order["AvgPrice"], order["Status"], order["Type"], order["Offset"], order["ContractType"]])
tbls.append(tbl)
LogStatus("`" + json.dumps(tbls) + "`")
return
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
void main() {
auto arrSymbol = {"BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"};
for (const auto& symbol : arrSymbol) {
auto t = exchange.GetTicker(symbol);
exchange.CreateOrder(symbol, "buy", t.Last / 2, 1);
exchange.CreateOrder(symbol, "sell", t.Last * 2, 1);
}
auto defaultOrders = exchange.GetOrders();
auto swapOrders = exchange.GetOrders("USDT.swap");
auto futuresOrders = exchange.GetOrders("USDT.futures");
auto btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap");
json tbls = R"([])"_json;
std::vector<std::vector<Order>> arr = {defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders};
std::string tblDesc[] = {"defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"};
for (int index = 0; index < arr.size(); index++) {
auto orders = arr[index];
json tbl = R"({
"type": "table",
"cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"],
"rows": []
})"_json;
tbl["title"] = tblDesc[index];
for (const auto& order : orders) {
json arrJson = R"([])"_json;
arrJson.push_back(order.Symbol);
arrJson.push_back(to_string(order.Id)); // The Id attribute type in the Order structure is TId, which is encoded using a C++ function to_string built into the FMZ platform.
arrJson.push_back(order.Price);
arrJson.push_back(order.Amount);
arrJson.push_back(order.DealAmount);
arrJson.push_back(order.AvgPrice);
arrJson.push_back(order.Status);
arrJson.push_back(order.Type);
arrJson.push_back(order.Offset);
arrJson.push_back(order.ContractType);
tbl["rows"].push_back(arrJson);
}
tbls.push_back(tbl);
}
LogStatus(_D(), "\n", "`" + tbls.dump() + "`");
return;
}
Use futures exchange objects to place orders for multiple different trading pairs and contract codes. Place orders at prices far away from the counterparty price, keep orders in an unfulfilled state, and query orders in multiple ways.
function main() {
var orders = exchange.GetOrders("BTC_USDT") // Examples of spot products
// var orders = exchange.GetOrders("BTC_USDT.swap") // Examples of futures products
Log("orders:", orders)
}
def main():
orders = exchange.GetOrders("BTC_USDT") # Examples of spot products
# orders = exchange.GetOrders("BTC_USDT.swap") # Examples of futures products
Log("orders:", orders)
void main() {
auto orders = exchange.GetOrders("BTC_USDT"); // Examples of spot products
// auto orders = exchange.GetOrders("BTC_USDT.swap"); // Examples of futures products
Log("orders:", orders);
}
When calling the exchange.GetOrders()
function, pass in the Symbol
parameter to request order data for a specific trading pair and contract code.
In the GetOrders
function, the usage scenarios of the symbol parameter are summarized as follows:
Exchange Object Classification | symbol Parameters | Query Scope | Remark |
---|---|---|---|
Spot | Do not pass symbol parameter | Query all spot trading pairs | For all calling scenarios, if the exchange interface does not support it, an error will be reported and a null value will be returned. No further explanation will be given. |
Spot | Specify the trading type, the symbol parameter is: “BTC_USDT” | Query the specified BTC_USDT trading pair | For spot exchange objects, the symbol parameter format is: “BTC_USDT” |
Futures | Do not pass symbol parameter | Query all trading products within the current trading pair and contract code dimension range | If the current trading pair is BTC_USDT and the contract code is swap, all USDT-margined perpetual contracts will be queried. This is equivalent to calling GetOrders("USDT.swap") |
Futures | Specify the trading type, the symbol parameter is: “BTC_USDT.swap” | Query the USDT-based perpetual contract for a specified BTC | For futures exchange objects, the parameter symbol format is: a combination of trading pair and contract code defined by the FMZ platform, separated by the characters ". . |
Futures | Specify the range of trading products, the symbol parameter is: “USDT.swap” | Query all USDT-based perpetual contracts | - |
Futures exchanges that support options | Do not pass symbol parameter | Query all option contracts within the current trading pair dimension range | If the current trading pair is BTC_USDT, the contract is set to an option contract, for example, Binance option contract: BTC-240108-40000-C |
Futures exchanges that support options | Specify specific trading products | Query the specified option contract | For example, for Binance Futures Exchange, the symbol parameter is: BTC_USDT.BTC-240108-40000-C |
Futures exchanges that support options | Specify the range of trading products, the symbol parameter is: “USDT.option” | Query all USDT-based options contracts | - |
In the GetOrders
function, the futures exchange object query
dimension range is summarized as follows:
symbol Parameters | Request Range Definition | Remark |
---|---|---|
USDT.swap | USDT-based perpetual contract range. | For |
dimensions that are not supported by the exchange API interface, an error will be reported and a null value will be returned when calling. | | USDT.futures | USDT-based delivery contract range. | - | | USD.swap | Range of currency-based perpetual contracts. | - | | USD.futures | Range of currency-based delivery contracts. | - | | USDT.option | USDT-based options contract range. | - | | USD.option | Currency-based options contract range. | - | | USDT.futures_combo | Range of CFD combinations. | Futures_Deribit Exchange | | USD.futures_ff | Range of mixed margin delivery contracts. | Futures_Kraken Exchange | | USD.swap_pf | Range of mixed margin perpetual contracts. | Futures_Kraken Exchange |
When the account represented by the exchange object exchange
has no pending orders within the query range or specified trading instruments (active orders in an unfulfilled state), calling this function returns an empty array, that is: []
.
The following exchanges require the instrument to pass in the instrument parameter when querying the currently uncompleted orders. When calling the GetOrders function with these exchanges, if the instrument parameter is not passed in, only the uncompleted orders of the current instrument are requested, not the uncompleted orders of all instruments (because the exchange interface does not support this).
Zaif, MEXC, LBank, Korbit, Coinw, BitMart, Bithumb, BitFlyer, BigONE.
Exchanges that do not support the exchange.GetOrders()
function:
Function Name | Unsupported Spot Exchanges | Unsupported Futures Exchanges |
---|---|---|
GetOrders | – | Futures_Bibox |
{@struct/Order Order}, {@fun/Trade/exchange.GetOrder exchange.GetOrder}, {@fun/Trade/exchange.GetHistoryOrders exchange.GetHistoryOrders}
The exchange.GetHistoryOrders()
function is used to obtain the current trading pair, the historical orders for contracts; it supports the specification of specific trading varieties.
The exchange.GetHistoryOrders()
function returns an array of {@struct/Order Order} structures if the request for data succeeds, and null if the request fails.
{@struct/Order Order} arrays, null values
exchange.GetHistoryOrders() exchange.GetHistoryOrders(symbol) exchange.GetHistoryOrders(symbol, since) exchange.GetHistoryOrders(symbol, since, limit) exchange.GetHistoryOrders(since) exchange.GetHistoryOrders(since, limit)
The symbol
parameter is used to specify the trade symbol. In the case of the BTC_USDT
trading pair, for example, when the exchange
is a spot exchange object, the parameter format for symbol
is BTC_USDT
; if it’s a futures exchange object, taking perpetual contract as an example, the parameter format for symbol
is: BTC_USDT.swap
.
If you are querying the order data of option contracts, set the parameter symbol
to "BTC_USDT.BTC-240108-40000-C"
(taking Binance Option BTC-240108-40000-C as an example). The format is a combination of the trading pair defined by the FMZ platform and the specific option contract code defined by the exchange, separated by the character “.”.
If this parameter is not passed, the order data of the currently set trading pair and contract code will be requested by default.
symbol
false
string
The since
parameter is used to specify the starting timestamp of the query in milliseconds.
since
false
number
The limit
parameter is used to specify the number of orders to query.
limit
false
number
function main() {
var historyOrders = exchange.GetHistoryOrders()
Log(historyOrders)
}
def main():
historyOrders = exchange.GetHistoryOrders()
Log(historyOrders)
void main() {
auto historyOrders = exchange.GetHistoryOrders();
Log(historyOrders);
}
symbol
, since
, limit
parameters are not specified, the default query is the current trading pair, the historical orders of contract. Queries the historical orders within a certain range nearest to the current time, the query range depends on the single query range of the exchange interface.symbol
parameter is specified, query the history of orders for the set trade type.since
parameter is specified, query in the direction of the current time using the since
timestamp as the start time.limit
parameter is specified, the query is returned after a sufficient number of entries.Exchanges that do not support the exchange.GetHistoryOrders()
function:
Function Name | Unsupported Spot Exchanges | Unsupported Futures Exchanges |
---|---|---|
GetHistoryOrders | Zaif / Upbit / Coincheck / Bitstamp / Bithumb / BitFlyer / BigONE | Futures_dYdX / Futures_Bibox / Futures_ApolloX |
{@struct/Order Order}, {@fun/Trade/exchange.GetOrder exchange.GetOrder}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}
exchange.SetPrecision()
function is used to set the precision of the exchange
exchange object price and order amount, after setting, the system will ignore the excess data automatically.
exchange.SetPrecision(pricePrecision, amountPrecision)
The pricePrecision
parameter is used to control the precision of the price data.
pricePrecision
true
number
The amountPrecision
parameter is used to control the precision of the amount of data to be ordered.
amountPrecision
true
number
function main(){
// Set the decimal precision of price to 2 bits, and the decimal precision of variety order amount to 3 bits
exchange.SetPrecision(2, 3)
}
def main():
exchange.SetPrecision(2, 3)
void main() {
exchange.SetPrecision(2, 3);
}
The backtesting system does not support this function, and the numerical accuracy of the backtesting system is handled automatically.
{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}
Set the current exchange rate of the exchange object.
exchange.SetRate(rate)
The rate
parameter is used to specify the conversion exchange rate.
rate
true
number
function main(){
Log(exchange.GetTicker())
// Set exchange rate conversion
exchange.SetRate(7)
Log(exchange.GetTicker())
// Set to 1, no conversion
exchange.SetRate(1)
}
def main():
Log(exchange.GetTicker())
exchange.SetRate(7)
Log(exchange.GetTicker())
exchange.SetRate(1)
void main() {
Log(exchange.GetTicker());
exchange.SetRate(7);
Log(exchange.GetTicker());
exchange.SetRate(1);
}
If an exchange rate value has been set using the exchange.SetRate()
function, such as 7. Then all price information such as tickers, depths, order prices, etc. for the exchange represented by the current exchange
exchange object will be converted by multiplying it by the set exchange rate of 7. For example, exchange
is an exchange with the US dollar as the denomination currency. After executing exchange.SetRate(7)
, all prices on the live market will be converted to prices close to CNY denomination by multiplying by 7.
{@fun/Market/exchange.GetRate exchange.GetRate}
The exchange.IO()
function is used for other interface calls related to the exchange object.
The exchange.IO()
function calls other interfaces related to the exchange object, returning the requested response data on a successful call and it returns null on a failed call.
string, number, bool, object, array, null, and any other type supported by the system
exchange.IO(k, …args)
The k
parameter is used to set the call type, with optional values "api"
, "currency"
, "base"
, "trade_margin"
, "trade_normal"
, "public_base"
, "mbase"
, selfTradePreventionMode
, simulate
, cross
, dual
, unified
and so on.
k
true
string
Extended parameters, passed according to the specific call scenario, arg
parameters can be passed more than one. Due to the polymorphic mechanism of the exchange.IO()
function, different parameter settings correspond to different functions. The number and type of parameters to the exchange.IO()
function are indeterminate.
arg
true
string, number, bool, object, array, null and any other types supported by the system
function main() {
var arrOrders = [
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"},
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
]
// Call exchange.IO to access the exchange's bulk order interface directly
var ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", JSON.stringify(arrOrders))
Log(ret)
}
import json
def main():
arrOrders = [
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"},
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
]
ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", json.dumps(arrOrders))
Log(ret)
void main() {
json arrOrders = R"([
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"},
{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
])"_json;
auto ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", arrOrders.dump());
Log(ret);
}
Using the exchange.IO("api", httpMethod, resource, params, raw)
call form of the exchange.IO()
function, it is necessary to understand the API interface of the exchange and check the relevant documentation first. This will allow you to extend the functionality that is not added to the FMZ platform. Submitting a POST
request does not require you to worry about encrypting, signing, or verifying the parameters, which are already handled by FMZ at the bottom, as long as you fill in the corresponding parameters. You can refer to the batch order example of OKX Exchange futures contracts, and use the parameter raw
to pass the order parameters:
var amount = 1
var price = 10
var basecurrency = "ltc"
function main () {
// Note that both amount.toString() and price.toString() have a ' character on the left and right side
var message = "symbol=" + basecurrency + "&amount='" + amount.toString() + "'&price='" + price.toString() + "'&side=buy" + "&type=limit"
var id = exchange.IO("api", "POST", "/v1/order/new", message)
}
amount = 1
price = 10
basecurrency = "ltc"
def main():
message = "symbol=" + basecurrency + "&amount='" + str(amount) + "'&price='" + str(price) + "'&side=buy" + "&type=limit"
id = exchange.IO("api", "POST", "/v1/order/new", message)
void main() {
auto amount = 1.0;
auto price = 10.0;
auto basecurrency = "ltc";
string message = format("symbol=%s&amount=\"%.1f\"&price=\"%.1f\"&side=buy&type=limit", basecurrency, amount, price);
auto id = exchange.IO("api", "POST", "/v1/order/new", message);
}
If the key value in the params
parameter (i.e., Http request parameter) is a string, it needs to be written in single quotes (i.e., the symbol ') around the parameter value to wrap the parameter value.
function main() {
var ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC")
Log(ret)
}
def main():
ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC")
Log(ret)
void main() {
auto ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC");
Log(ret);
}
It supports passing in complete url parameters, which can omit the operation of switching the base address (calling the exchange.SetBase()
function).
function main(){
var ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT")
Log(ret)
}
def main():
ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT")
Log(ret)
void main() {
auto ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT");
Log(ret);
}
Example of a call without the parameter raw
:
function main() {
// For example, if you set the current trading pair of the exchange object to BTC_USDT at the beginning of the live trading, print the current trading pair tickers
Log(exchange.GetTicker())
// Switch the trading pair to LTC_BTC
exchange.IO("currency", "LTC_BTC")
Log(exchange.GetTicker())
}
def main():
Log(exchange.GetTicker())
exchange.IO("currency", "LTC_BTC")
Log(exchange.GetTicker())
void main() {
Log(exchange.GetTicker());
exchange.IO("currency", "LTC_BTC");
Log(exchange.GetTicker());
}
Switch the trading pair of current exchange, so that it will switch the trading pair configured by code at live trading creation or at backtest.
function main () {
// exchanges[0] is the first exchange object added when the live trading is created
exchanges[0].IO("base", "https://api.huobi.pro")
}
def main():
exchanges[0].IO("base", "https://api.huobi.pro")
void main() {
exchanges[0].IO("base", "https://api.huobi.pro");
}```
For example, the default base address when the exchange object is wrapped is ```https://api.huobipro.com```, and when you need to switch to ```https://api.huobi.pro```, use the following code to switch:
```javascript
function main() {
exchange.SetBase("https://api.bitfinex.com")
exchange.IO("mbase", "https://api-pub.bitfinex.com")
}
def main():
exchange.SetBase("https://api.bitfinex.com")
exchange.IO("mbase", "https://api-pub.bitfinex.com")
void main() {
exchange.SetBase("https://api.bitfinex.com");
exchange.IO("mbase", "https://api-pub.bitfinex.com");
}
For exchanges with different base addresses for the ticker interface and trading interface, for example, Bitfinex Futures have two addresses, one for the ticker interface and the other for the trading interface. Bitfinex futures switch private interface base address using exchange.SetBase("xxx")
. Bitfinex futures switch public interface base address using exchange.IO("mbase", "xxx")
.
I. For cryptocurrency-centric exchanges other API interface calls that are not uniformly encapsulated, with parameter k
set to "api"
:
exchange.IO("api", httpMethod, resource, params, raw)
POST
, GET
, etc.URL
.The exchange.IO("api", httpMethod, resource, params, raw)
function call will access the exchange interface and return null if the call fails and an error occurs.
Only the real trading supports calling the exchange.IO("api", httpMethod, resource, params, raw)
function.
II. For switching trading pairs, the parameter k
is set to "currency"
:
exchange.IO("currency", currency)
currency : The parameter is a string type with a uniform upper case format, using an underscore to separate baseCurrency
from quoteCurrency
, such as BTC_USDT
.
ETH_BTC
can only switch to LTC_BTC
, not to LTC_USDT
.exchange.IO("currency", currency)
to switch trading pairs.III. Used to switch the cryptocurrency spot exchange object leveraged account mode:
k
is set to "trade_margin"
to switch to the spot leverage account mode. Placing orders and obtaining account assets will access the exchange’s spot leveraged interface.
If the exchange distinguishes between full margin and isolated margin in spot leverage, use: exchange.IO("trade_super_margin")
to switch to full margin for leveraged account, and exchange.IO("trade_margin")
to switch to isolated margin for leveraged account.k
is set to "trade_normal"
to switch back to normal spot account mode.Spot exchanges that support switching between leveraged account models:
Exchanges | Special remarks |
---|---|
OKX | Trading pairs in leveraged account mode are different from normal ones, some trading pairs may not have them. Use exchange.IO("trade_super_margin") to switch to full position for leveraged accounts and use exchange.IO("trade_margin") to switch to position by position. Use trade_normal to switch to normal spot mode. Use exchange.IO("tdMode", "cross") to directly specify the leverage mode. |
Huobi | Leveraged account mode trading pairs are different from normal ones, some trading pairs may not have them. There are full positions and position-by-position in Huobi leveraged accounts. Use trade_margin to switch to leverage account position by position, use trade_super_margin to switch to leverage account full position. Use trade_normal to switch to normal currency-currency mode. |
Binance | Leveraged account mode is divided into position by position and full position, use trade_margin to switch to position by position, use trade_super_margin to switch to full position, use trade_normal to switch to normal currency-currency mode. |
GateIO | Leveraged account mode is divided into position by position and full position, use trade_margin to switch to position by position, use trade_super_margin to switch to full position, use trade_normal to switch to normal currency-currency mode. |
AscendEx | Use exchange.IO("trade_margin") to switch to leverage account mode and exchange.IO("trade_normal") to switch back to normal account mode. |
WOO | Use exchange.IO("trade_margin") to switch to leverage account mode and exchange.IO("trade_normal") to switch back to normal account mode. |
CoinEx | Use exchange.IO("trade_margin") to switch to leveraged account mode and exchange.IO("trade_normal") to switch back to normal account mode. |
IV. Other switching functions:
Check out the exchange.IO()
function for Other switching functions in the User Guide.
{@fun/NetSettings/exchange.SetBase exchange.SetBase}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}, {@var EXCHANGE_OP_IO_CONTROL}
The exchange.Log()
function is used to output the log of order placement and withdrawal in the log column area. When called, no orders are placed, only the transaction log is output and recorded.
exchange.Log(orderType, price, amount) exchange.Log(orderType, price, amount, …args)
The orderType
parameter is used to set the output log type, the optional values are {@var/LOG_TYPE/LOG_TYPE_BUY LOG_TYPE_BUY}, {@var/LOG_TYPE/LOG_TYPE_SELL LOG_TYPE_SELL}, {@var/LOG_TYPE/LOG_TYPE_CANCEL LOG_TYPE_CANCEL}.
orderType
true
number
The price
parameter is used to set the price displayed in the output log.
price
true
number
The amount
parameter is used to set the amount of orders placed displayed in the output log.
amount
true
number
Extended parameters that can output accompanying information to this log, arg
parameters can be passed more than one.
arg
false
string, number, bool, object, array, null and any other type supported by the system
var id = 123
function main() {
// Order type buy, price 999, amount 0.1
exchange.Log(LOG_TYPE_BUY, 999, 0.1)
// Cancel the order
exchange.Log(LOG_TYPE_CANCEL, id)
}
id = 123
def main():
exchange.Log(LOG_TYPE_BUY, 999, 0.1)
exchange.Log(LOG_TYPE_CANCEL, id)
void main() {
auto id = 123;
exchange.Log(LOG_TYPE_BUY, 999, 0.1);
exchange.Log(LOG_TYPE_CANCEL, id);
}
Using exchange.Log(orderType, price, amount)
can be used for live trading order following tests, simulated order placement, and it can assist in logging order placement. One of the most common scenarios is to use the {@fun/Trade/exchange.IO exchange.IO} function to access the exchange’s interface for creating conditional orders, but using the exchange.IO()
function does not output the transaction log information in the live trading log record. This is where the exchange.Log()
function can be used to supplement the output log in order to record order placement information, and the same is true for order withdrawal operations.
When the orderType
parameter is LOG_TYPE_CANCEL
, the price
parameter is the order Id of the withdrawn order, which is used to print the withdrawal log when the order is withdrawn directly using the exchange.IO()
function. The exchange.Log()
function is a member function of the {@var/EXCHANGE exchange} exchange object, as distinguished from the global function {@fun/Log Log}.
{@fun/Log Log}, {@var/EXCHANGE exchange}, {@var/LOG_TYPE/LOG_TYPE_BUY LOG_TYPE_BUY}, {@var/LOG_TYPE/LOG_TYPE_SELL LOG_TYPE_SELL}, {@var/LOG_TYPE/LOG_TYPE_CANCEL LOG_TYPE_CANCEL}
The exchange.Encode()
function is used for signature encryption calculations.
The exchange.Encode()
function returns the calculated hash value encoding.
string
exchange.Encode(algo, inputFormat, outputFormat, data) exchange.Encode(algo, inputFormat, outputFormat, data, keyFormat, key)
The parameter algo
is the algorithm used for encoding calculation. Supported settings are: “raw” (no algorithm used), “sign”, “signTx”, “md4”, “md5”, “sha256”, “sha512”, “sha1”, “keccak256”, “sha3.224”, “sha3.256”, “sha3.384”, “sha3.512”, “sha3.keccak256”, “sha3.keccak512”, “sha512.384”, “sha512.256”, “sha512.224”, “ripemd160”, “blake2b.256”, “blake2b.512”, “blake2s.128”, “blake2s.256”. The parameter algo
also supports: “text.encoder.utf8”, “text.decoder.utf8”, “text.encoder.gbk”, “text.decoder.gbk”, for encoding and decoding strings. The parameter algo
also supports: “ed25519” algorithm. It supports the use of different hash algorithms, for example, the parameter algo
can be written as “ed25519.md5”, “ed25519.sha512”, etc. Supports ed25519.seed
calculation.
algo
true
string
Used to specify the data format of the data
parameter. The inputFormat
parameter can be set to one of: “raw”, “hex”, “base64”, and “string”. “raw” means the data is raw data, “hex” means the data is hex
encoded, “base64” means the data is base64
encoded, and “string” means the data is a string.
inputFormat
true
string
Used to specify the output data format. The outputFormat
parameter supports the following settings: “raw”, “hex”, “base64”, “string”. “raw” means the data is raw data, “hex” means the data is hex
encoded, “base64” means the data is base64
encoded, and “string” means the data is a string.
outputFormat
true
string
The parameter data
is the data to be processed.
data
true
string
Used to specify the data format of the key
parameter. The key
parameter can be set to one of: “raw”, “hex”, “base64”, and “string”. “raw” means the data is raw data, “hex” means the data is hex
encoded, “base64” means the data is base64
encoded, and “string” means the data is a string.
keyFormat
false
string
The key
parameter is used to specify the key used in the signature calculation, and it can be used as a plaintext string. You can also use "{{accesskey}}"
, "{{secretkey}}"
to refer to the accessKey
and secretKey
configured in the {@var/EXCHANGE exchange} exchange object.
key
false
string
function main() {
var APIKEY = "your Access Key(Bitmex API ID)"
var expires = parseInt(Date.now() / 1000) + 10
var signature = exchange.Encode("sha256", "string", "hex", "GET/realtime" + expires, "hex", "{{secretkey}}")
var client = Dial("wss://www.bitmex.com/realtime", 60)
var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
var pos = 0
client.write(auth)
client.write('{"op": "subscribe", "args": "position"}')
while (true) {
bitmexData = client.read()
if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
pos = parseInt(bitmexData.data[0].currentQty)
}
}
}
import time
def main():
APIKEY = "your Access Key(Bitmex API ID)"
expires = int(time.time() + 10)
signature = exchange.Encode("sha256", "string", "hex", "GET/realtime" + expires, "hex", "{{secretkey}}")
client = Dial("wss://www.bitmex.com/realtime", 60)
auth = json.dumps({"args": [APIKEY, expires, signature], "op": "authKeyExpires"})
pos = 0
client.write(auth)
client.write('{"op": "subscribe", "args": "position"}')
while True:
bitmexData = json.loads(client.read())
if "table" in bitmexData and bitmexData["table"] == "position" and len(bitmexData["data"]) != 0 and pos != bitmexData["data"][0]["currentQty"]:
Log("position change", pos, bitmexData["data"][0]["currentQty"], "@")
pos = bitmexData["data"][0]["currentQty"]
void main() {
auto APIKEY = "your Access Key(Bitmex API ID)";
auto expires = Unix() + 10;
auto signature = exchange.Encode("sha256", "string", "hex", format("GET/realtime%d", expires), "hex", "{{secretkey}}");
auto client = Dial("wss://www.bitmex.com/realtime", 60);
json auth = R"({"args": [], "op": "authKeyExpires"})"_json;
auth["args"].push_back(APIKEY);
auth["args"].push_back(expires);
auth["args"].push_back(signature);
auto pos = 0;
client.write(auth.dump());
client.write("{\"op\": \"subscribe\", \"args\": \"position\"}");
while(true) {
auto bitmexData = json::parse(client.read());
if(bitmexData["table"] == "position" && bitmexData["data"][0].find("currentQty") != bitmexData["data"][0].end() && pos != bitmexData["data"][0]["currentQty"]) {
Log("test");
Log("position change", pos, bitmexData["data"][0]["currentQty"], "@");
pos = bitmexData["data"][0]["currentQty"];
}
}
}
Example of BitMEX position change push (wss protocol):
Only the real trading supports calling the exchange.Encode()
function. The "{{accesskey}}"
, "{{secretkey}}"
references are only valid when the exchange.Encode()
function is used.
{@var/EXCHANGE exchange}, {@fun/Global/Encode Encode}
Multi-threaded asynchronous support functions can turn the operations of all supported functions into asynchronous concurrent execution.
The exchange.Go()
function returns a concurrent object immediately, and you can use the wait()
method of that concurrent object to get the result of the concurrent request.
object
exchange.Go(method) exchange.Go(method, …args)
The method
parameter is used to specify the name of the concurrent function. Note that the parameter is a function name string, not a function reference.
method
true
string
Parameters to concurrently executing functions, there may be more than one parameter arg
. The type and number of parameter arg
depends on the parameters of the concurrent execution function.
arg
false
string, number, bool, object, array, function, null, and all other types supported by the system
function main(){
// The following four operations are concurrently executed asynchronously by multiple threads and do not take time and return immediately
var a = exchange.Go("GetTicker")
var b = exchange.Go("GetDepth")
var c = exchange.Go("Buy", 1000, 0.1)
var d = exchange.Go("GetRecords", PERIOD_H1)
// Call the wait method to wait for the return of the ticker results asynchronously
var ticker = a.wait()
// Returns the depth, or null if it fails
var depth = b.wait()
// return order number, limited to 1 second timeout, if timeout, returns undefined, the object can continue to call wait if the last wait timeout
var orderId = c.wait(1000)
if(typeof(orderId) == "undefined") {
// Timeout, reacquire
orderId = c.wait()
}
var records = d.wait()
}
def main():
a = exchange.Go("GetTicker")
b = exchange.Go("GetDepth")
c = exchange.Go("Buy", 1000, 0.1)
d = exchange.Go("GetRecords", PERIOD_H1)
ticker, ok = a.wait()
depth, ok = b.wait()
orderId, ok = c.wait(1000)
if ok == False:
orderId, ok = c.wait()
records, ok = d.wait()
void main() {
auto a = exchange.Go("GetTicker");
auto b = exchange.Go("GetDepth");
auto c = exchange.Go("Buy", 1000, 0.1);
auto d = exchange.Go("GetRecords", PERIOD_H1);
Ticker ticker;
Depth depth;
Records records;
TId orderId;
a.wait(ticker);
b.wait(depth);
if(!c.wait(orderId, 300)) {
c.wait(orderId);
}
d.wait(records);
}
Exchange.Go()
function usage example, to determine undefined
to use typeof(xx) === "undefined"
, because null == undefined
is valid in JavaScript.
function main() {
var d = exchange.Go("GetRecords", PERIOD_H1)
// Waiting for K-line results
var records = d.wait()
// Here waits an asynchronous operation that has been waited and finished, it will return null, and log the error message
var ret = d.wait()
}
def main():
d = exchange.Go("GetRecords", PERIOD_H1)
records, ok = d.wait()
ret, ok = d.wait()
void main() {
auto d = exchange.Go("GetRecords", PERIOD_H1);
Records records;
d.wait(records);
Records ret;
d.wait(ret);
}
Calling the wait()
method on a concurrent object that has been released will report an error:
function main() {
while(true) {
var beginTS = new Date().getTime()
var arrRoutine = []
var arrTicker = []
var arrName = []
for(var i = 0; i < exchanges.length; i++) {
arrRoutine.push(exchanges[i].Go("GetTicker"))
arrName.push(exchanges[i].GetName())
}
for(var i = 0; i < arrRoutine.length; i++) {
arrTicker.push(arrRoutine[i].wait())
}
var endTS = new Date().getTime()
var tbl = {
type: "table",
title: "ticker",
cols: ["index", "name", "latest-deal-price"],
rows: []
}
for(var i = 0; i < arrTicker.length; i++) {
tbl.rows.push([i, arrName[i], arrTicker[i].Last])
}
LogStatus(_D(), "Total time taken to obtain tickers from multiple exchanges concurrently:", endTS - beginTS, "millisecond", "\n", "`" + JSON.stringify(tbl) + "`")
Sleep(500)
}
}
import time
import json
def main():
while True:
beginTS = time.time()
arrRoutine = []
arrTicker = []
arrName = []
for i in range(len(exchanges)):
arrRoutine.append(exchanges[i].Go("GetTicker"))
arrName.append(exchanges[i].GetName())
for i in range(len(exchanges)):
ticker, ok = arrRoutine[i].wait()
arrTicker.append(ticker)
endTS = time.time()
tbl = {
"type": "table",
"title": "ticker",
"cols": ["index", "name", "latest-deal-price"],
"rows": []
}
for i in range(len(arrTicker)):
tbl["rows"].append([i, arrName[i], arrTicker[i]["Last"]])
LogStatus(_D(), "Total time taken to obtain tickers from multiple exchanges concurrently:", endTS - beginTS, "second", "\n", "`" + json.dumps(tbl) + "`")
Sleep(500)
void main() {
while(true) {
int length = exchanges.size();
auto beginTS = UnixNano() / 1000000;
Ticker arrTicker[length] = {};
string arrName[length] = {};
// Note that to add several exchange objects, several exchanges[n].Go functions have to be executed here, this example is to add four exchange objects, the details can be modified
auto r0 = exchanges[0].Go("GetTicker");
auto r1 = exchanges[1].Go("GetTicker");
auto r2 = exchanges[2].Go("GetTicker");
auto r3 = exchanges[3].Go("GetTicker");
GoObj *arrRoutine[length] = {&r0, &r1, &r2, &r3};
for(int i = 0; i < length; i++) {
arrName[i] = exchanges[i].GetName();
}
for(int i = 0; i < length; i++) {
Ticker ticker;
arrRoutine[i]->wait(ticker);
arrTicker[i] = ticker;
}
auto endTS = UnixNano() / 1000000;
json tbl = R"({
"type": "table",
"title": "ticker",
"cols": ["index", "name", "latest-deal-price"],
"rows": []
})"_json;
for(int i = 0; i < length; i++) {
json arr = R"(["", "", ""])"_json;
arr[0] = format("%d", i);
arr[1] = arrName[i];
arr[2] = format("%f", arrTicker[i].Last);
tbl["rows"].push_back(arr);
}
LogStatus(_D(), "Total time taken to obtain tickers from multiple exchanges concurrently:", format("%d", endTS - beginTS), "millisecond", "\n", "`" + tbl.dump() + "`");
Sleep(500);
}
}
Concurrent access to multiple exchange tickers:
function main() {
/*
Testing with OKX futures order interface
POST /api/v5/trade/order
*/
var beginTS = new Date().getTime()
var param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}
var ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
var ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
var ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
var id1 = ret1.wait()
var id2 = ret2.wait()
var id3 = ret3.wait()
var endTS = new Date().getTime()
Log("id1:", id1)
Log("id2:", id2)
Log("id3:", id3)
Log("Concurrent order placement time consumption:", endTS - beginTS, "millisecond")
}
import time
import json
def main():
beginTS = time.time()
param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}
ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))
ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))
ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))
id1, ok1 = ret1.wait()
id2, ok2 = ret2.wait()
id3, ok3 = ret3.wait()
endTS = time.time()
Log("id1:", id1)
Log("id2:", id2)
Log("id3:", id3)
Log("Concurrent order placement time consumption:", endTS - beginTS, "second")
void main() {
auto beginTS = UnixNano() / 1000000;
json param = R"({"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"})"_json;
auto ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());
auto ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());
auto ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());
json id1 = R"({})"_json;
json id2 = R"({})"_json;
json id3 = R"({})"_json;
ret1.wait(id1);
ret2.wait(id2);
ret3.wait(id3);
auto endTS = UnixNano() / 1000000;
Log("id1:", id1);
Log("id2:", id2);
Log("id3:", id3);
Log("Concurrent order placement time consumption:", endTS - beginTS, "millisecond");
}
Concurrent calls for exchange.IO("api", ...)
function:
This function only creates multi-threaded execution tasks when running in real trading, backtesting does not support multi-threaded concurrent task execution (backtesting is available, but still executed sequentially).
After the exchange.Go()
function returns an object, its wait()
function is called through that object to get the data returned by the thread. The wait()
function must be called to get the data before the thread will be released automatically. If the timeout parameter of the wait()
function is specified, the thread will not be released automatically even if a timeout occurs. The result of the thread must be obtained before it will be released automatically (regardless of the success or failure of the interface call for concurrent access). In simple terms, the requested thread must be obtained by the wait()
function regardless of whether the execution succeeds or fails, and the resource of the thread requested by the exchange.Go()
function must be released automatically by the docker.
The wait()
method supports a timeout parameter:
Without a timeout parameter, that is, wait()
, or with a timeout parameter of 0, that is, wait(0)
. The wait()
function blocks and waits until the concurrent thread has finished running, returning the result of the concurrent thread’s execution.
Set the timeout parameter -1, i.e. wait(-1)
. The wait()
function returns immediately, with different return values for different programming languages, see this subsection for an example call.
Set the specific timeout parameter, wait(300)
, and the wait()
function will wait a maximum of 300 milliseconds before returning.
If the return result of the final wait()
function is not obtained, the thread resources will not be released automatically, which will lead to the accumulation of threads requested, and more than 2000 will report an error: "too many routine wait, max is 2000"
.
Supported functions: GetTicker
, GetDepth
, GetTrades
, GetRecords
, GetAccount
, GetOrders
, GetOrder
, CancelOrder
, Buy
, Sell
, GetPositions
, IO
. All these functions are executed based on the current {@var/EXCHANGE exchange} exchange object when called concurrently.
The difference between Python language and JavaScript language is that the wait()
function of concurrent objects in Python language returns two parameters. The first parameter is the result returned by an asynchronous API call, and the second parameter indicates whether the asynchronous call is completed.
def main():
d = exchange.Go("GetRecords", PERIOD_D1)
# ok will return True definitely, unless the strategy is stopped
ret, ok = d.wait()
# If the wait times out, or if it waits for an instance that has already ended, ok returns False
ret, ok = d.wait(100)
{@fun/Global/Mail_Go Mail_Go}, {@fun/Global/HttpQuery_Go HttpQuery_Go}, {@fun/Global/EventLoop EventLoop}
Market Account