LTP API V2 is the upgraded version of LTP API V1 by allowing access of trading endpoints.
Attention: For users who created their LTP API before 2023-Oct-19th, you can upgrade to LTP API V2 or still utilise LTP API V1 for DMA features. If you wish to begin using RapidX trading, you must first inform your account manager to obtain permission. Afterward, you will need to use the example code of LTP API V2 for authentication.
With LTP API V2, users can access real-time market statistics and place orders on their preferred venues. LTP provides a WebSocket API for real-time market statistics and a REST API that caters to our users' trading requirements. To authenticate and begin your trading journey, please refer to the provided code example as follows.
If you don't have LTP API or your LTP API didn't have RapidX Trading permission yet, please contact your account manager for more information.
LTP REST API V2
API domain: https://api.liquiditytech.com
Please note that this API document only covers features related to the LTP API. For information on the Exchange API, please refer to the documentation provided by the relevant exchanges.
Third party class libraries involved
// JDK11 or later
<dependencies>
<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.fasterxml.jackson.databind.ObjectMapper;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
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.*;
@Slf4j
@UtilityClass
public class RapidXDemo {
private static final String HOST = "https://api.liquiditytech.com";
private static final HttpClient client = HttpClient.newHttpClient();
private static final String API_KEY = "your api key";
private static final String SECRET_KEY = "your secret key";
private static final ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) {
// Place order, POST example
placeOrder();
// Query order, GET example
queryOrder();
// Cancel order, DELETE example
cancelOrder();
}
private static void placeOrder() {
try {
String url = HOST + "/api/v1/trading/order";
SortedMap<String, Object> paramMap = new TreeMap<>();
// Trading pair unique identifier, example:BINANCE_SPOT_BTC_USDT, BINANCE_PERP_BTC_USDT
paramMap.put("sym", "BINANCE_SPOT_SOL_USDT");
// BUY or SELL
paramMap.put("side", "BUY");
// Order type(default LIMIT, support type enums:LIMIT,MARKET)
paramMap.put("orderType", "LIMIT");
// 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
paramMap.put("orderQty", "0.1");
// Limit order price(Mandatory for limit order)
paramMap.put("limitPrice", "110");
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String jsonBody = objectMapper.writeValueAsString(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());
log.info("response body{}", response.body());
// do something
} catch (Exception exception) {
log.error("placeOrder error:{}", exception.getMessage());
}
}
private static void queryOrder() {
try {
// replace with your orderId
String orderId = "your orderId";
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("orderId", orderId);
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String payload = getPayload(paramMap);
String url = HOST + "/api/v1/trading/order";
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());
log.info("response body {}", response.body());
// do something
} catch (Exception exception) {
log.error("queryOrder error:{}", exception.getMessage());
}
}
private static void cancelOrder() {
try {
String url = HOST + "/api/v1/trading/order";
// replace with your orderId
String orderId = "your orderId";
SortedMap<String, Object> paramMap = new TreeMap<>();
paramMap.put("orderId", orderId);
String nonce = gmtNow();
String sign = getSign(paramMap, SECRET_KEY, nonce);
String jsonBody = objectMapper.writeValueAsString(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());
log.info("response body {}", response.body());
// do something
} catch (Exception exception) {
log.error("cancelOrder error:{}", exception.getMessage());
}
}
private static String gmtNow() {
return String.valueOf(Instant.now().getEpochSecond());
}
private static String getSign(Map<String, Object> param, String secretKey, String nonce) {
String payload = getPayload(param);
payload += "&" + nonce;
try {
return hmacSHA1EncryptString(payload, secretKey);
} catch (Exception e) {
throw new RuntimeException("Error generating sign", e);
}
}
private static String getPayload(Map<String, Object> paramMap) {
if (Objects.isNull(paramMap) || paramMap.size() <= 0) {
return "";
}
StringBuilder buffer = new StringBuilder();
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
Object value = entry.getValue();
if (value != null) {
buffer.append(entry.getKey()).append("=").append(value.toString()).append("&");
}
}
return buffer.substring(0, buffer.length() - 1);
}
private static String hmacSHA1EncryptString(String encryptText, String
encryptKey) throws Exception {
return toHexString(hmacSHA1Encrypt(encryptText, encryptKey));
}
private static byte[] hmacSHA1Encrypt(String encryptText, String encryptKey)
throws Exception {
String MAC_NAME = "HmacSHA256";
String ENCODING = "UTF-8";
byte[] data = encryptKey.getBytes(ENCODING);
SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
Mac mac = Mac.getInstance(MAC_NAME);
mac.init(secretKey);
byte[] text = encryptText.getBytes(ENCODING);
return mac.doFinal(text);
}
private static String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
}
import requests
import json, hashlib, hmac, time
HOST = 'https://api.liquiditytech.com'
API_KEY = ""
SECRET_KEY = ""
sym = "OKX_PERP_BCH_USDT"
class Client:
def __init__(self, secret_key):
self.headers = {
'user-agent': 'pythonclient/0.0.1',
"Content-Type": "application/json"
}
self.secret_key = secret_key
def get_signForSha256(self, param, nonce):
payload = self.get_payload(param)
payload += "&" + str(nonce)
try:
sign = self.hmac_SHA256_encrypt_string(payload)
return sign
except Exception as e:
print("Exception:{}".format(e))
def hmac_SHA256_encrypt_string(self, encryptText):
sign = hmac.new(
SECRET_KEY.encode('utf-8'),
msg=encryptText.encode('utf-8'),
digestmod=hashlib.sha256).hexdigest()
return sign
def get_time_now(self):
t = time.time()
return int(round(t))
def get_payload(self, param):
buffer = ''
for key in sorted(param.keys()):
buffer += key + "=" + str(param[key]) + "&"
# delete the last &
return buffer[0:len(buffer) - 1]
def get_example(self):
url = HOST + "/api/v1/trading/order"
params = {
"orderId": "xxx",
}
nonce = self.get_time_now()
sign = self.get_signForSha256(params, nonce)
res = requests.get(url=url, params=self.get_payload(params),
headers={'nonce': str(nonce), 'signature': sign, 'X-MBX-APIKEY': API_KEY})
print(params)
print(url)
print(res.content)
def post_example(self):
url = HOST + "/api/v1/trading/position/leverage"
params = {
}
nonce = self.get_time_now()
sign = self.get_signForSha256(params, nonce)
res = requests.post(url=url, data=json.dumps(params),
headers={'Content-Type': "application/json", 'nonce': str(nonce), 'signature': sign,
'X-MBX-APIKEY': API_KEY})
print(res.status_code)
print(url)
print(params)
print(res.content)
def delete_example(self):
url = HOST + "/api/v1/trading/position"
params = {
}
nonce = self.get_time_now()
sign = self.get_signForSha256(params, nonce)
res = requests.delete(url=url, data=json.dumps(params),
headers={'Content-Type': "application/json", 'cache-control': "no-cache",
'nonce': str(nonce), 'signature': sign, 'X-MBX-APIKEY': API_KEY})
print(res.status_code)
print(url)
print(params)
print(res.content)
if __name__ == '__main__':
client = Client(SECRET_KEY)
client.post_example()
client.get_example()
client.delete_example()
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.liquiditytech.com/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.liquiditytech.com/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})