📍ConneX API common information

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})