ConneX REST API
API domain: https://api.connex.trade
Third party class libraries involved
// JDK11 or later
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.7</version>
</dependency>
</dependencies>
requests
json
hashlib
hmac
base64
websocket
time
ssl
Code example
Tip:Using java httpclient requires jdk11 or later jdk version.
import com.alibaba.fastjson.JSON;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.Instant;
import java.util.Formatter;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class ConneXDemo {
private static final String API_KEY = "your api key";
private static final String SECRET_KEY = "your secret key";
private static final String HOST = "https://api.connex.trade";
private static final HttpClient client = HttpClient.newHttpClient();
public static void main(String[] args) {
// Place order, POST example
String placeOrderResult = placeOrder("OKX_SPOT_ETH_USDT", "BUY", "LIMIT", "0.0001", "3001");
System.out.println(placeOrderResult);
// Query order, GET example
String queryOrderResult = queryOrder("");
System.out.println(queryOrderResult);
// Cancel order, DELETE example
String cancelOrderResult = cancelOrder("");
System.out.println(cancelOrderResult);
}
/**
* Place order, POST example
*
* @Param sym Trading pair unique identifier, example:BINANCE_SPOT_BTC_USDT, BINANCE_PERP_BTC_USDT
* @Param side BUY or SELL
* @Param orderType Order type(default LIMIT, support type enums:LIMIT,MARKET)
* @Param orderQty Order quantity(Mandatory, unless spot market buy ) note: trading unit of OKX is the number of contracts/ trading unit of Binance is the number of coin
* @Param limitPrice Limit order price(Mandatory for limit order)
* @see <a href="https://apiconnex.readme.io/reference/place-order-1">Place order</a>
*/
private static String placeOrder(String sym, String side, String orderType, String orderQty, String limitPrice) {
try {
String url = HOST + "/api/v1/trading/order";
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("sym", sym);
paramMap.put("side", side);
paramMap.put("orderType", orderType);
paramMap.put("orderQty", orderQty);
paramMap.put("limitPrice", limitPrice);
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String jsonBody = JSON.toJSONString(paramMap);
HttpRequest request = HttpRequest.newBuilder()
.timeout(Duration.ofSeconds(5))
.header("Content-Type", "application/json")
.header("nonce", nonce)
.header("signature", sign)
.header("X-MBX-APIKEY", API_KEY)
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.uri(URI.create(url))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
} catch (Exception exception) {
System.out.println("placeOrder error:" + exception.getMessage());
}
return null;
}
/**
* Query order, GET example
*
* @Param orderId
* @see <a href="https://apiconnex.readme.io/reference/query-order-detail">Query order</a>
*/
private static String queryOrder(String orderId) {
try {
String url = HOST + "/api/v1/trading/order";
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("orderId", orderId);
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String payload = getPayload(paramMap);
if (!payload.isEmpty()) {
url += "?" + payload;
}
HttpRequest request = HttpRequest.newBuilder()
.timeout(Duration.ofSeconds(5))
.header("Content-Type", "application/json")
.header("nonce", nonce)
.header("signature", sign)
.header("X-MBX-APIKEY", API_KEY)
.GET()
.uri(URI.create(url))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
} catch (Exception exception) {
System.out.println("queryOrder error:" + exception.getMessage());
}
return null;
}
/**
* Cancel order, DELETE example
*
* @see <a href="https://apiconnex.readme.io/reference/cancel-order-2">Cancel order</a>
*/
private static String cancelOrder(String orderId) {
try {
String url = HOST + "/api/v1/trading/order";
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("orderId", orderId);
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String jsonBody = JSON.toJSONString(paramMap);
HttpRequest request = HttpRequest.newBuilder()
.timeout(Duration.ofSeconds(5))
.header("Content-Type", "application/json")
.header("nonce", nonce)
.header("signature", sign)
.header("X-MBX-APIKEY", API_KEY)
.method("DELETE", HttpRequest.BodyPublishers.ofString(jsonBody))
.uri(URI.create(url))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
} catch (Exception exception) {
System.out.println("cancelOrder error:" + exception.getMessage());
}
return null;
}
/**
* Get the current time, in seconds
*/
private static String gmtNow() {
return String.valueOf(Instant.now().getEpochSecond());
}
/**
* Generate signature
*/
private static String getSign(Map<String, Object> param, String secretKey, String nonce) {
String payload = getPayloadForSign(param);
payload += "&" + nonce;
try {
String MAC_NAME = "HmacSHA256";
String ENCODING = "UTF-8";
byte[] data = secretKey.getBytes(ENCODING);
SecretKey secretKeySpec = new SecretKeySpec(data, MAC_NAME);
Mac mac = Mac.getInstance(MAC_NAME);
mac.init(secretKeySpec);
byte[] text = payload.getBytes(ENCODING);
byte[] textFinal = mac.doFinal(text);
Formatter formatter = new Formatter();
for (byte b : textFinal) {
formatter.format("%02x", b);
}
return formatter.toString();
} catch (Exception e) {
throw new RuntimeException("Error generating sign", e);
}
}
/**
* Generate payload
*/
private static String getPayload(Map<String, Object> paramMap) {
StringBuilder queryString = new StringBuilder();
try {
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
if (queryString.length() > 0) {
queryString.append("&");
}
queryString.append(URLEncoder.encode(entry.getKey(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return queryString.toString();
}
/**
* Generate payload for sign
*/
private static String getPayloadForSign(Map<String, Object> paramMap) {
StringBuilder queryString = new StringBuilder();
try {
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
if (queryString.length() > 0) {
queryString.append("&");
}
// force contact, without url decode
queryString.append(entry.getKey()).append("=").append(entry.getValue());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return queryString.toString();
}
}
#!/usr/bin/python
# -*encoding: utf-8 -*-
import json
import requests
import hmac
import time
import hashlib
# Method
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = 'DELETE'
def get_header(api_key: str, secret: str, params: dict = None):
if params is None:
params = dict()
nonce = get_timestamp()
message = "&".join([f"{arg}={params[arg]}" for arg in sorted(params.keys())]) + "&" + str(nonce)
sign = hmac.new(secret.encode("utf-8"), message.encode("utf-8"), digestmod=hashlib.sha256).hexdigest()
headers = {
'Content-Type': 'application/json',
'User-Agent': 'PythonClient/1.0.0',
'X-MBX-APIKEY': api_key,
'signature': sign,
'nonce': str(nonce)
}
return headers
def get_timestamp():
return int(time.time())
class Client(object):
def __init__(self, api_url, api_key, secret_key):
self.API_KEY = api_key
self.API_SECRET_KEY = secret_key
self.domain = api_url
def _request(self, method, request_path, params, timeout):
headers = get_header(self.API_KEY, self.API_SECRET_KEY, params)
params = json.dumps(params) if method != 'GET' else params
response = None
url = self.domain + request_path
if method == GET:
response = requests.get(url, params=params, headers=headers)
elif method == POST:
response = requests.post(url, data=params, headers=headers)
elif method == PUT:
response = requests.put(url, data=params, headers=headers)
elif method == DELETE:
response = requests.delete(url, data=params, headers=headers)
return response.json()
def _request_without_params(self, method, request_path):
return self._request(method, request_path, {})
def _request_with_params(self, method, request_path, params):
return self._request(method, request_path, params, timeout=100)
class ClientAPI(Client):
def transfer(self, from_trade_account_id=0, to_trade_account_id=0, from_account_type='', to_account_type='', currency='',
network='', amount=0, rapid_transfer="false", client_order_id=''):
params = {
"clientOrderId": client_order_id,
"fromAccountType": from_account_type,
"fromTradeAccountId": from_trade_account_id,
"toAccountType": to_account_type,
"toTradeAccountId": to_trade_account_id,
"currency": currency,
# "network": network,
"rapidTransfer": rapid_transfer,
"amount": amount,
}
return self._request_with_params(POST, '/api/v1/transfer/apply', params)
def get_transfer_record(self, transfer_id=0, client_order_id=''):
params = {
"clientOrderId": client_order_id,
"transferId": transfer_id,
}
return self._request_with_params(GET, '/api/v1/transfer/get', params)
def place_order(self, client_order_id: str, sym: str, side: str, position_side: str, ord_type: str,
time_in_force: str, order_qty: str, limit_price: str, quote_order_qty: str, reduce_only: str):
params = {
'clientOrderId': client_order_id,
'sym': sym,
'side': side,
'positionSide': position_side,
'ordType': ord_type,
'timeInForce': time_in_force,
'orderQty': order_qty,
'limitPrice': limit_price,
'quoteOrderQty': quote_order_qty,
'reduceOnly': reduce_only
}
return self._request_with_params(POST, '/api/v1/trading/order', params)
def get_order(self, order_id: str, client_order_id: str):
params = {
'orderId': order_id,
'clientOrderId': client_order_id
}
return self._request_with_params(GET, '/api/v1/trading/order', params)
def replace_order(self, order_id, replace_qty: str, replace_price: str):
params = {
'orderId': order_id,
'replaceQty': replace_qty,
'replacePrice': replace_price
}
return self._request_with_params(PUT, '/api/v1/trading/order', params)
def cancel_order(self, order_id: str, client_order_id: str):
params = {
'orderId': order_id,
'clientOrderId': client_order_id
}
return self._request_with_params(DELETE, '/api/v1/trading/order', params)
if __name__ == '__main__':
API_KEY = ""
SECRET_KEY = ""
client = ClientAPI('https://api.connex.trade', API_KEY, SECRET_KEY)
# transfer
transfer_resp = client.transfer(from_trade_account_id=123456, to_trade_account_id=123456,
from_account_type='BINANCE', to_account_type='OKX', currency='USDT', network='BSC',
amount=10, rapid_transfer="false", client_order_id='')
transfer_id: str = transfer_resp["data"]["transferId"]
# transfer detail
print(client.get_transfer_record(transfer_id, client_order_id=''))
# place order
order_resp = client.place_order(client_order_id='', sym='BINANCE_PERP_BTC_USDT', side='BUY', position_side='LONG',
ord_type='LIMIT',time_in_force='GTC', order_qty='0.003', limit_price='90000',
quote_order_qty='', reduce_only='')
order_id: str=order_resp['data']['orderId']
# get order
print(client.get_order(order_id, client_order_id=''))
# replace order
print(client.replace_order(order_id, '0.003', '90001'))
# cancel order
print(client.cancel_order(order_id, ''))
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.codec.binary.Hex;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebSocketClientDemo {
private static final String API_KEY = "your api key";
private static final String SECRET_KEY = "your secret key";
private static final String WS_URL = "wss://wss.connex.trade/v1/private";
public static void main(String[] args) throws Exception {
WebSocketClient client = new WebSocketClient(new URI(WS_URL)) {
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("open");
}
@Override
public void onMessage(String message) {
System.out.println("receive message " + message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("close");
}
@Override
public void onError(Exception ex) {
System.out.println("error");
}
};
client.connectBlocking();
// send ping every 10 seconds
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
client.send("ping");
}, 10, 10, TimeUnit.SECONDS);
// login
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String message = timestamp + "GET" + "/users/self/verify";
String signature = getSignature(message);
UserRequestArgs userRequestArgs = UserRequestArgs.builder()
.apiKey(API_KEY)
.timestamp(timestamp)
.sign(signature)
.build();
UserRequest userRequest = UserRequest.builder()
.action("login")
.args(userRequestArgs)
.build();
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(userRequest);
client.send(jsonString);
}
private static String getSignature(String message) throws Exception {
byte[] keyBytes = SECRET_KEY.getBytes(StandardCharsets.UTF_8);
byte[] messageBytes = message.getBytes();
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");
sha256_HMAC.init(secretKey);
return Hex.encodeHexString(sha256_HMAC.doFinal(messageBytes));
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UserRequestArgs {
private String apiKey;
private String timestamp;
private String sign;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UserRequest {
private String action;
private UserRequestArgs args;
}
}
import json, hashlib, hmac, time, ssl, requests
import websocket
import _thread as thread
ws_url = "wss://wss.connex.trade/v1/private"
apiKey = "xxx"
SECRET_KEY = "xxx"
timestamp = str(int(time.time()))
method = 'GET'
requestPath = '/users/self/verify'
message = timestamp + method + requestPath
# sign
key = bytes(SECRET_KEY, 'utf-8')
data = bytes(message, 'utf-8')
signature = hmac.new(key, data, hashlib.sha256).hexdigest()
def on_message(ws, message):
# print(time.time_ns())
print("message", message)
# Define a callback function to handle errors
def on_error(ws, error):
print(error)
# Define a callback function to handle the WebSocket connection closing
def on_close(ws):
print("Connection closed")
# Define a callback function to handle the WebSocket connection opening
def on_open(ws):
def process():
while True:
data = {
"action": "login",
"args":
{
"apiKey": apiKey,
"timestamp": timestamp,
"sign": signature
}
}
ws.send(json.dumps(data))
time.sleep(0.2)
while True:
time.sleep(28)
ws.send("ping")
ws.close()
print("Websocket closed")
thread.start_new_thread(process, ())
# Create a WebSocket connection with the defined callbacks
ws = websocket.WebSocketApp(ws_url,
on_message=on_message,
on_error=on_error,
on_close=on_close
)
ws.on_open = on_open
# Start the WebSocket connection
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})