curl --request POST \
--url https://perps-api.vooi.io/arbitrage-orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"hedge": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": true,
"timeInForce": "gtc"
},
"primary": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": true,
"timeInForce": "gtc"
},
"hedgeFailurePolicy": "alertAndHold",
"partialFillPolicy": "fullFill"
}
'import requests
url = "https://perps-api.vooi.io/arbitrage-orders"
payload = {
"hedge": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": True,
"timeInForce": "gtc"
},
"primary": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": True,
"timeInForce": "gtc"
},
"hedgeFailurePolicy": "alertAndHold",
"partialFillPolicy": "fullFill"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
hedge: {
asset: 'ETH',
size: '0.5',
price: '1850.50',
reduceOnly: true,
timeInForce: 'gtc'
},
primary: {
asset: 'ETH',
size: '0.5',
price: '1850.50',
reduceOnly: true,
timeInForce: 'gtc'
},
hedgeFailurePolicy: 'alertAndHold',
partialFillPolicy: 'fullFill'
})
};
fetch('https://perps-api.vooi.io/arbitrage-orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://perps-api.vooi.io/arbitrage-orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'hedge' => [
'asset' => 'ETH',
'size' => '0.5',
'price' => '1850.50',
'reduceOnly' => true,
'timeInForce' => 'gtc'
],
'primary' => [
'asset' => 'ETH',
'size' => '0.5',
'price' => '1850.50',
'reduceOnly' => true,
'timeInForce' => 'gtc'
],
'hedgeFailurePolicy' => 'alertAndHold',
'partialFillPolicy' => 'fullFill'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://perps-api.vooi.io/arbitrage-orders"
payload := strings.NewReader("{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://perps-api.vooi.io/arbitrage-orders")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://perps-api.vooi.io/arbitrage-orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}"
response = http.request(request)
puts response.read_body{
"createdAt": "2023-11-07T05:31:56Z",
"finishedAt": "2023-11-07T05:31:56Z",
"hedgeFailurePolicy": "alertAndHold",
"id": "019d5cbe-6980-7193-a80e-38a45eda36d8",
"partialFillPolicy": "fullFill",
"status": "primary_placed",
"strategy": "limitMarket",
"unifiedSymbol": "ETH",
"updatedAt": "2023-11-07T05:31:56Z",
"legs": {
"hedge": {
"baseSymbol": "ETH",
"clientOrderId": "<string>",
"error": "<string>",
"exchange": "aster",
"filledSize": "0.25",
"marketId": "ETHUSDT",
"orderId": "<string>",
"price": "1850.50",
"quoteSymbol": "USDT",
"reduceOnly": true,
"side": "buy",
"size": "0.5",
"status": "created",
"timeInForce": "gtc",
"type": "limit"
},
"primary": {
"baseSymbol": "ETH",
"clientOrderId": "<string>",
"error": "<string>",
"exchange": "aster",
"filledSize": "0.25",
"marketId": "ETHUSDT",
"orderId": "<string>",
"price": "1850.50",
"quoteSymbol": "USDT",
"reduceOnly": true,
"side": "buy",
"size": "0.5",
"status": "created",
"timeInForce": "gtc",
"type": "limit"
}
}
}{
"message": "Invalid order id: 123",
"statusCode": 503
}Create an arbitrage order
Opens a hedged position with one order on each exchange, each leg sized on its own. The primary leg is placed first, and the hedge leg is placed once the primary leg fills. Both legs are validated against their exchanges before the order is accepted.
curl --request POST \
--url https://perps-api.vooi.io/arbitrage-orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"hedge": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": true,
"timeInForce": "gtc"
},
"primary": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": true,
"timeInForce": "gtc"
},
"hedgeFailurePolicy": "alertAndHold",
"partialFillPolicy": "fullFill"
}
'import requests
url = "https://perps-api.vooi.io/arbitrage-orders"
payload = {
"hedge": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": True,
"timeInForce": "gtc"
},
"primary": {
"asset": "ETH",
"size": "0.5",
"price": "1850.50",
"reduceOnly": True,
"timeInForce": "gtc"
},
"hedgeFailurePolicy": "alertAndHold",
"partialFillPolicy": "fullFill"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
hedge: {
asset: 'ETH',
size: '0.5',
price: '1850.50',
reduceOnly: true,
timeInForce: 'gtc'
},
primary: {
asset: 'ETH',
size: '0.5',
price: '1850.50',
reduceOnly: true,
timeInForce: 'gtc'
},
hedgeFailurePolicy: 'alertAndHold',
partialFillPolicy: 'fullFill'
})
};
fetch('https://perps-api.vooi.io/arbitrage-orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://perps-api.vooi.io/arbitrage-orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'hedge' => [
'asset' => 'ETH',
'size' => '0.5',
'price' => '1850.50',
'reduceOnly' => true,
'timeInForce' => 'gtc'
],
'primary' => [
'asset' => 'ETH',
'size' => '0.5',
'price' => '1850.50',
'reduceOnly' => true,
'timeInForce' => 'gtc'
],
'hedgeFailurePolicy' => 'alertAndHold',
'partialFillPolicy' => 'fullFill'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://perps-api.vooi.io/arbitrage-orders"
payload := strings.NewReader("{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://perps-api.vooi.io/arbitrage-orders")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://perps-api.vooi.io/arbitrage-orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"hedge\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"primary\": {\n \"asset\": \"ETH\",\n \"size\": \"0.5\",\n \"price\": \"1850.50\",\n \"reduceOnly\": true,\n \"timeInForce\": \"gtc\"\n },\n \"hedgeFailurePolicy\": \"alertAndHold\",\n \"partialFillPolicy\": \"fullFill\"\n}"
response = http.request(request)
puts response.read_body{
"createdAt": "2023-11-07T05:31:56Z",
"finishedAt": "2023-11-07T05:31:56Z",
"hedgeFailurePolicy": "alertAndHold",
"id": "019d5cbe-6980-7193-a80e-38a45eda36d8",
"partialFillPolicy": "fullFill",
"status": "primary_placed",
"strategy": "limitMarket",
"unifiedSymbol": "ETH",
"updatedAt": "2023-11-07T05:31:56Z",
"legs": {
"hedge": {
"baseSymbol": "ETH",
"clientOrderId": "<string>",
"error": "<string>",
"exchange": "aster",
"filledSize": "0.25",
"marketId": "ETHUSDT",
"orderId": "<string>",
"price": "1850.50",
"quoteSymbol": "USDT",
"reduceOnly": true,
"side": "buy",
"size": "0.5",
"status": "created",
"timeInForce": "gtc",
"type": "limit"
},
"primary": {
"baseSymbol": "ETH",
"clientOrderId": "<string>",
"error": "<string>",
"exchange": "aster",
"filledSize": "0.25",
"marketId": "ETHUSDT",
"orderId": "<string>",
"price": "1850.50",
"quoteSymbol": "USDT",
"reduceOnly": true,
"side": "buy",
"size": "0.5",
"status": "created",
"timeInForce": "gtc",
"type": "limit"
}
}
}{
"message": "Invalid order id: 123",
"statusCode": 503
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
The hedging leg, placed once the primary leg fills. Fires immediately alongside the primary when both legs are market orders.
Show child attributes
Show child attributes
The leg placed first. Its fill triggers the hedge leg.
Show child attributes
Show child attributes
What happens when the hedge leg fails after the primary filled. Only alertAndHold — leave the naked leg and mark the order failed — is supported today.
alertAndHold When a partially filled primary leg gets hedged. Only fullFill — hedge after the primary leg fills completely — is supported today.
fullFill Response
When the order was accepted.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$When the order reached a terminal state. For fully hedged orders this is the moment both legs opened, so it doubles as the position start time.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$What happens when the hedge leg fails after the primary filled. alertAndHold — the naked leg is left in place and the order is marked failed. autoUnwind — the primary leg is closed with a market order.
alertAndHold, autoUnwind "alertAndHold"
Arbitrage order identifier.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"019d5cbe-6980-7193-a80e-38a45eda36d8"
When a partially filled primary leg gets hedged. fullFill — only after the primary leg fills completely. immediate — every fill is hedged as it arrives. threshold — hedged once unhedged size crosses a threshold.
fullFill, immediate, threshold "fullFill"
new — accepted, nothing on the exchange yet. primary_sent — the primary limit was sent to the exchange. primary_placed — the primary limit rests in the book. primary_partially_filled — the primary limit is partially filled. primary_full_filled — the primary is done, the hedge leg is being placed. hedge_sent — the hedge order was sent to the exchange. hedge_placed — the hedge order rests on the exchange. hedge_partially_filled — the hedge order is partially filled. hedge_full_filled — the hedge is fully filled, both legs are open and the order is finalized. canceled — canceled before any fill. failed — needs manual handling; the legs may be directionally exposed.
canceled, failed, hedge_full_filled, hedge_partially_filled, hedge_placed, hedge_sent, new, primary_full_filled, primary_partially_filled, primary_placed, primary_sent "primary_placed"
Leg types in execution order. marketMarket — both legs fire immediately. limitMarket — primary limit rests, hedge hedges with a market order once it fills. limitLimit — both legs are limit orders.
limitLimit, limitMarket, marketMarket "limitMarket"
Cross-exchange asset key — an alias (alias:1000bonk) when defined, otherwise the base symbol.
"ETH"
When the order last changed.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$Show child attributes
Show child attributes