From 9e3205bc652587c7171cac42c2e9fa54005b0d20 Mon Sep 17 00:00:00 2001 From: kolya-bybit Date: Fri, 10 Apr 2026 18:39:56 +0300 Subject: [PATCH] refactor(api_demo): clean up example code --- V5_demo/api_demo/Encryption_HMAC.cpp | 91 ++++---- V5_demo/api_demo/Encryption_HMAC.cs | 27 ++- V5_demo/api_demo/Encryption_HMAC.go | 106 +++++---- V5_demo/api_demo/Encryption_HMAC.java | 173 ++++++--------- V5_demo/api_demo/Encryption_HMAC.js | 64 +++--- V5_demo/api_demo/Encryption_HMAC.php | 66 +++--- V5_demo/api_demo/Encryption_HMAC.py | 117 ++++++---- V5_demo/api_demo/Encryption_HMAC.rb | 78 ++++--- V5_demo/api_demo/Encryption_HMAC.rs | 68 ++++-- V5_demo/api_demo/Encryption_HMAC.rs.bak | 103 --------- V5_demo/api_demo/Encryption_HMAC.scala | 170 ++++++-------- V5_demo/api_demo/Encryption_HMAC.sh | 20 +- V5_demo/api_demo/Encryption_HMAC.ts | 44 ++-- V5_demo/api_demo/Encryption_HMAC_async.py | 126 ++++++----- V5_demo/api_demo/Encryption_RSA.cs | 79 ++++--- V5_demo/api_demo/Encryption_RSA.java | 208 ++++++++---------- V5_demo/api_demo/Encryption_RSA.py | 104 +++++---- V5_demo/api_demo/comparePubPrvTrd.py | 256 ++++++++++++---------- 18 files changed, 911 insertions(+), 989 deletions(-) delete mode 100644 V5_demo/api_demo/Encryption_HMAC.rs.bak diff --git a/V5_demo/api_demo/Encryption_HMAC.cpp b/V5_demo/api_demo/Encryption_HMAC.cpp index 5767120..56a6781 100644 --- a/V5_demo/api_demo/Encryption_HMAC.cpp +++ b/V5_demo/api_demo/Encryption_HMAC.cpp @@ -1,15 +1,15 @@ #define WIN32_LEAN_AND_MEAN - #define CPPHTTPLIB_OPENSSL_SUPPORT + +#include +#include #include #include -#include #include -#include -#include // for setfill and setw -#include -#include + #include +#include +#include class Encryption { private: @@ -21,6 +21,7 @@ class Encryption { public: void PlaceOrder(); void GetOpenOrder(); + private: static std::string GeneratePostSignature(const nlohmann::json& parameters); static std::string GenerateGetSignature(const nlohmann::json& parameters); @@ -30,46 +31,56 @@ class Encryption { const std::string Encryption::ApiKey = "xxxxxxxxxxxxxxxx"; const std::string Encryption::ApiSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -const std::string Encryption::Timestamp = std::to_string(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); +const std::string Encryption::Timestamp = std::to_string( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count() +); const std::string Encryption::RecvWindow = "5000"; std::string Encryption::GeneratePostSignature(const nlohmann::json& parameters) { - std::string paramJson = parameters.dump(); - std::string rawData = Timestamp + ApiKey + RecvWindow + paramJson; + const std::string paramJson = parameters.dump(); + const std::string rawData = Timestamp + ApiKey + RecvWindow + paramJson; return ComputeSignature(rawData); } std::string Encryption::GenerateGetSignature(const nlohmann::json& parameters) { - std::string queryString = GenerateQueryString(parameters); - std::string rawData = Timestamp + ApiKey + RecvWindow + queryString; + const std::string queryString = GenerateQueryString(parameters); + const std::string rawData = Timestamp + ApiKey + RecvWindow + queryString; return ComputeSignature(rawData); } std::string Encryption::ComputeSignature(const std::string& data) { - unsigned char* digest = HMAC(EVP_sha256(), ApiSecret.c_str(), static_cast(ApiSecret.length()), - (unsigned char*)data.c_str(), static_cast(data.size()), NULL, NULL); + unsigned char* digest = HMAC( + EVP_sha256(), + ApiSecret.c_str(), + static_cast(ApiSecret.length()), + reinterpret_cast(data.c_str()), + static_cast(data.size()), + nullptr, + nullptr + ); std::ostringstream result; for (size_t i = 0; i < 32; i++) { - result << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i]; + result << std::hex << std::setw(2) << std::setfill('0') << static_cast(digest[i]); } return result.str(); } std::string Encryption::GenerateQueryString(const nlohmann::json& parameters) { - std::ostringstream oss; + std::ostringstream query; for (const auto& item : parameters.items()) { - std::string key = item.key(); - std::string value = item.value().get(); - oss << key << "=" << value << "&"; + query << item.key() << "=" << item.value().get() << "&"; } - std::string result = oss.str(); - return result.substr(0, result.length() - 1); // Remove trailing '&' + + const std::string result = query.str(); + return result.substr(0, result.length() - 1); } void Encryption::PlaceOrder() { - nlohmann::json parameters = { + const nlohmann::json parameters = { {"category", "linear"}, {"symbol", "BTCUSDT"}, {"side", "Buy"}, @@ -80,11 +91,11 @@ void Encryption::PlaceOrder() { {"timeInForce", "GTC"} }; - std::string signature = Encryption::GeneratePostSignature(parameters); - std::string jsonPayload = parameters.dump(); + const std::string signature = GeneratePostSignature(parameters); + const std::string jsonPayload = parameters.dump(); - httplib::SSLClient client("api-testnet.bybit.com", 443); // 443 is the default port for HTTPS - httplib::Headers headers = { + httplib::SSLClient client("api-testnet.bybit.com", 443); + const httplib::Headers headers = { {"X-BAPI-API-KEY", ApiKey}, {"X-BAPI-SIGN", signature}, {"X-BAPI-SIGN-TYPE", "2"}, @@ -92,23 +103,23 @@ void Encryption::PlaceOrder() { {"X-BAPI-RECV-WINDOW", RecvWindow} }; - auto res = client.Post("/v5/order/create", headers, jsonPayload, "application/json"); - if (res) { - std::cout << res->body << std::endl; + const auto response = client.Post("/v5/order/create", headers, jsonPayload, "application/json"); + if (response) { + std::cout << response->body << std::endl; } } void Encryption::GetOpenOrder() { - std::map parameters = { + const std::map parameters = { {"category", "linear"}, {"symbol", "BTCUSDT"} }; - std::string signature = Encryption::GenerateGetSignature(parameters); - std::string queryString = Encryption::GenerateQueryString(parameters); + const std::string signature = GenerateGetSignature(parameters); + const std::string queryString = GenerateQueryString(parameters); - httplib::SSLClient client("api-testnet.bybit.com", 443); // 443 is the default port for HTTPS - httplib::Headers headers = { + httplib::SSLClient client("api-testnet.bybit.com", 443); + const httplib::Headers headers = { {"X-BAPI-API-KEY", ApiKey}, {"X-BAPI-SIGN", signature}, {"X-BAPI-SIGN-TYPE", "2"}, @@ -116,15 +127,15 @@ void Encryption::GetOpenOrder() { {"X-BAPI-RECV-WINDOW", RecvWindow} }; - auto res = client.Get(("/v5/order/realtime?" + queryString).c_str(), headers); - if (res) { - std::cout << res->body << std::endl; + const auto response = client.Get(("/v5/order/realtime?" + queryString).c_str(), headers); + if (response) { + std::cout << response->body << std::endl; } } int main() { - Encryption encryptionTest; - encryptionTest.PlaceOrder(); - encryptionTest.GetOpenOrder(); + Encryption encryption; + encryption.PlaceOrder(); + encryption.GetOpenOrder(); return 0; -} \ No newline at end of file +} diff --git a/V5_demo/api_demo/Encryption_HMAC.cs b/V5_demo/api_demo/Encryption_HMAC.cs index b1318ca..9e817bc 100644 --- a/V5_demo/api_demo/Encryption_HMAC.cs +++ b/V5_demo/api_demo/Encryption_HMAC.cs @@ -1,4 +1,3 @@ - using System.Security.Cryptography; using System.Text; using Newtonsoft.Json; @@ -14,9 +13,9 @@ public class Encryption public static void Main() { - var encryptionTest = new Encryption(); - encryptionTest.PlaceOrder(); - encryptionTest.GetOpenOrder(); + var encryption = new Encryption(); + encryption.PlaceOrder(); + encryption.GetOpenOrder(); } public void PlaceOrder() @@ -33,11 +32,11 @@ public void PlaceOrder() {"timeInForce", "GTC"} }; - string signature = GeneratePostSignature(parameters); - string jsonPayload = JsonConvert.SerializeObject(parameters); + var signature = GeneratePostSignature(parameters); + var jsonPayload = JsonConvert.SerializeObject(parameters); using var client = new HttpClient(); - HttpRequestMessage request = new(HttpMethod.Post, "https://api-testnet.bybit.com/v5/order/create") + var request = new HttpRequestMessage(HttpMethod.Post, "https://api-testnet.bybit.com/v5/order/create") { Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json") }; @@ -60,8 +59,8 @@ public void GetOpenOrder() {"symbol", "BTCUSDT"} }; - string signature = GenerateGetSignature(parameters); - string queryString = GenerateQueryString(parameters); + var signature = GenerateGetSignature(parameters); + var queryString = GenerateQueryString(parameters); using var client = new HttpClient(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://api-testnet.bybit.com/v5/order/realtime?{queryString}"); @@ -77,8 +76,8 @@ public void GetOpenOrder() private static string GeneratePostSignature(IDictionary parameters) { - string paramJson = JsonConvert.SerializeObject(parameters); - string rawData = Timestamp + ApiKey + RecvWindow + paramJson; + var paramJson = JsonConvert.SerializeObject(parameters); + var rawData = Timestamp + ApiKey + RecvWindow + paramJson; using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(ApiSecret)); var signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawData)); @@ -87,8 +86,8 @@ private static string GeneratePostSignature(IDictionary paramete private static string GenerateGetSignature(Dictionary parameters) { - string queryString = GenerateQueryString(parameters); - string rawData = Timestamp + ApiKey + RecvWindow + queryString; + var queryString = GenerateQueryString(parameters); + var rawData = Timestamp + ApiKey + RecvWindow + queryString; return ComputeSignature(rawData); } @@ -96,7 +95,7 @@ private static string GenerateGetSignature(Dictionary parameters private static string ComputeSignature(string data) { using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(ApiSecret)); - byte[] signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); + var signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); return BitConverter.ToString(signature).Replace("-", "").ToLower(); } diff --git a/V5_demo/api_demo/Encryption_HMAC.go b/V5_demo/api_demo/Encryption_HMAC.go index e86b065..c199c3c 100644 --- a/V5_demo/api_demo/Encryption_HMAC.go +++ b/V5_demo/api_demo/Encryption_HMAC.go @@ -15,96 +15,118 @@ import ( "time" ) +const ( + url = "https://api-testnet.bybit.com" + apiKey = "XXXXXXXXXX" + apiSecret = "XXXXXXXXXX" + recvWindow = "5000" +) + func httpClient() *http.Client { - client := &http.Client{Timeout: 10 * time.Second} - return client + return &http.Client{Timeout: 10 * time.Second} } -var url string = "https://api-testnet.bybit.com" -var api_key = "XXXXXXXXXX" -var apiSecret = "XXXXXXXXXX" -var recv_window = "5000" -var signature = "" - func main() { - c := httpClient() + client := httpClient() - //POST Method - postParams := map[string]interface{}{"category": "linear", "symbol": "BTCUSDT", "side": "Buy", "positionIdx": 0, "orderType": "Limit", "qty": "0.001", "price": "10000", "timeInForce": "GTC"} - postEndPoint := "/v5/order/create" - postRequest(c, http.MethodPost, postParams, postEndPoint) + postParams := map[string]interface{}{ + "category": "linear", + "symbol": "BTCUSDT", + "side": "Buy", + "positionIdx": 0, + "orderType": "Limit", + "qty": "0.001", + "price": "10000", + "timeInForce": "GTC", + } + postRequest(client, http.MethodPost, postParams, "/v5/order/create") - //GET Method - getEndPoint := "/v5/order/realtime" getParams := "category=linear&settleCoin=USDT" - getRequest(c, http.MethodGet, getParams, getEndPoint) + getRequest(client, http.MethodGet, getParams, "/v5/order/realtime") } -func getRequest(client *http.Client, method string, params string, endPoint string) []byte { +func getRequest(client *http.Client, method string, params string, endpoint string) []byte { now := time.Now() - unixNano := now.UnixNano() - time_stamp := unixNano / 1000000 + timeStamp := now.UnixNano() / int64(time.Millisecond) hmac256 := hmac.New(sha256.New, []byte(apiSecret)) - hmac256.Write([]byte(strconv.FormatInt(time_stamp, 10) + api_key + recv_window + params)) - signature = hex.EncodeToString(hmac256.Sum(nil)) - request, error := http.NewRequest("GET", url+endPoint+"?"+params, nil) + hmac256.Write([]byte(strconv.FormatInt(timeStamp, 10) + apiKey + recvWindow + params)) + signature := hex.EncodeToString(hmac256.Sum(nil)) + + request, err := http.NewRequest(method, url+endpoint+"?"+params, nil) + if err != nil { + log.Fatal(err) + } + request.Header.Set("Content-Type", "application/json") - request.Header.Set("X-BAPI-API-KEY", api_key) + request.Header.Set("X-BAPI-API-KEY", apiKey) request.Header.Set("X-BAPI-SIGN", signature) - request.Header.Set("X-BAPI-TIMESTAMP", strconv.FormatInt(time_stamp, 10)) + request.Header.Set("X-BAPI-TIMESTAMP", strconv.FormatInt(timeStamp, 10)) request.Header.Set("X-BAPI-SIGN-TYPE", "2") - request.Header.Set("X-BAPI-RECV-WINDOW", recv_window) + request.Header.Set("X-BAPI-RECV-WINDOW", recvWindow) + reqDump, err := httputil.DumpRequestOut(request, true) if err != nil { log.Fatal(err) } fmt.Printf("Request Dump:\n%s", string(reqDump)) - response, error := client.Do(request) - if error != nil { - panic(error) + + response, err := client.Do(request) + if err != nil { + panic(err) } defer response.Body.Close() + elapsed := time.Since(now).Seconds() - fmt.Printf("\n%s took %v seconds \n", endPoint, elapsed) + fmt.Printf("\n%s took %v seconds \n", endpoint, elapsed) fmt.Println("response Status:", response.Status) fmt.Println("response Headers:", response.Header) + body, _ := ioutil.ReadAll(response.Body) fmt.Println("response Body:", string(body)) return body } -func postRequest(client *http.Client, method string, params interface{}, endPoint string) []byte { +func postRequest(client *http.Client, method string, params interface{}, endpoint string) []byte { now := time.Now() - unixNano := now.UnixNano() - time_stamp := unixNano / 1000000 + timeStamp := now.UnixNano() / int64(time.Millisecond) jsonData, err := json.Marshal(params) if err != nil { log.Fatal(err) } + hmac256 := hmac.New(sha256.New, []byte(apiSecret)) - hmac256.Write([]byte(strconv.FormatInt(time_stamp, 10) + api_key + recv_window + string(jsonData[:]))) - signature = hex.EncodeToString(hmac256.Sum(nil)) - request, error := http.NewRequest("POST", url+endPoint, bytes.NewBuffer(jsonData)) + hmac256.Write([]byte(strconv.FormatInt(timeStamp, 10) + apiKey + recvWindow + string(jsonData))) + signature := hex.EncodeToString(hmac256.Sum(nil)) + + request, err := http.NewRequest(method, url+endpoint, bytes.NewBuffer(jsonData)) + if err != nil { + log.Fatal(err) + } + request.Header.Set("Content-Type", "application/json") - request.Header.Set("X-BAPI-API-KEY", api_key) + request.Header.Set("X-BAPI-API-KEY", apiKey) request.Header.Set("X-BAPI-SIGN", signature) - request.Header.Set("X-BAPI-TIMESTAMP", strconv.FormatInt(time_stamp, 10)) + request.Header.Set("X-BAPI-TIMESTAMP", strconv.FormatInt(timeStamp, 10)) request.Header.Set("X-BAPI-SIGN-TYPE", "2") - request.Header.Set("X-BAPI-RECV-WINDOW", recv_window) + request.Header.Set("X-BAPI-RECV-WINDOW", recvWindow) + reqDump, err := httputil.DumpRequestOut(request, true) if err != nil { log.Fatal(err) } fmt.Printf("Request Dump:\n%s", string(reqDump)) - response, error := client.Do(request) - if error != nil { - panic(error) + + response, err := client.Do(request) + if err != nil { + panic(err) } defer response.Body.Close() + elapsed := time.Since(now).Seconds() - fmt.Printf("\n%s took %v seconds \n", endPoint, elapsed) + fmt.Printf("\n%s took %v seconds \n", endpoint, elapsed) fmt.Println("response Status:", response.Status) fmt.Println("response Headers:", response.Header) + body, _ := ioutil.ReadAll(response.Body) fmt.Println("response Body:", string(body)) return body diff --git a/V5_demo/api_demo/Encryption_HMAC.java b/V5_demo/api_demo/Encryption_HMAC.java index 3c9bc42..a95af96 100644 --- a/V5_demo/api_demo/Encryption_HMAC.java +++ b/V5_demo/api_demo/Encryption_HMAC.java @@ -5,6 +5,7 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; + import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; @@ -16,46 +17,37 @@ import java.util.Map; import java.util.Set; - -/** - * a sample for how to create & get an order for contract v5 - Linear perp - */ public class Encryption { - final static String API_KEY = "XXXXXXXXXX"; - final static String API_SECRET = "XXXXXXXXXX"; - final static String TIMESTAMP = Long.toString(ZonedDateTime.now().toInstant().toEpochMilli()); - final static String RECV_WINDOW = "5000"; + private static final String API_KEY = "XXXXXXXXXX"; + private static final String API_SECRET = "XXXXXXXXXX"; + private static final String TIMESTAMP = Long.toString(ZonedDateTime.now().toInstant().toEpochMilli()); + private static final String RECV_WINDOW = "5000"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException { - Encryption encryptionTest = new Encryption(); - - encryptionTest.placeOrder(); - -// encryptionTest.getOpenOrder(); + Encryption encryption = new Encryption(); + encryption.placeOrder(); +// encryption.getOpenOrder(); } - /** - * POST: place a Linear perp order - contract v5 - */ public void placeOrder() throws NoSuchAlgorithmException, InvalidKeyException { - Map map = new HashMap<>(); - map.put("category","linear"); - map.put("symbol", "BTCUSDT"); - map.put("side", "Buy"); - map.put("positionIdx", 0); - map.put("orderType", "Limit"); - map.put("qty", "0.001"); - map.put("price", "18900"); - map.put("timeInForce", "GTC"); - - String signature = genPostSign(map); - String jsonMap = JSON.toJSONString(map); - - OkHttpClient client = new OkHttpClient().newBuilder().build(); + Map parameters = new HashMap<>(); + parameters.put("category", "linear"); + parameters.put("symbol", "BTCUSDT"); + parameters.put("side", "Buy"); + parameters.put("positionIdx", 0); + parameters.put("orderType", "Limit"); + parameters.put("qty", "0.001"); + parameters.put("price", "18900"); + parameters.put("timeInForce", "GTC"); + + String signature = generatePostSignature(parameters); + String jsonPayload = JSON.toJSONString(parameters); + + OkHttpClient client = new OkHttpClient.Builder().build(); MediaType mediaType = MediaType.parse("application/json"); Request request = new Request.Builder() .url("https://api-testnet.bybit.com/v5/order/create") - .post(RequestBody.create(mediaType, jsonMap)) + .post(RequestBody.create(mediaType, jsonPayload)) .addHeader("X-BAPI-API-KEY", API_KEY) .addHeader("X-BAPI-SIGN", signature) .addHeader("X-BAPI-SIGN-TYPE", "2") @@ -63,33 +55,29 @@ public void placeOrder() throws NoSuchAlgorithmException, InvalidKeyException { .addHeader("X-BAPI-RECV-WINDOW", RECV_WINDOW) .addHeader("Content-Type", "application/json") .build(); + Call call = client.newCall(request); try { Response response = call.execute(); assert response.body() != null; System.out.println(response.body().string()); - }catch (IOException e){ - e.printStackTrace(); + } catch (IOException exception) { + exception.printStackTrace(); } } - /** - * GET: query unfilled order - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ public void getOpenOrder() throws NoSuchAlgorithmException, InvalidKeyException { - Map map = new HashMap<>(); - map.put("category","linear"); - map.put("symbol", "BTCUSDT"); - map.put("settleCoin", "USDT"); + Map parameters = new HashMap<>(); + parameters.put("category", "linear"); + parameters.put("symbol", "BTCUSDT"); + parameters.put("settleCoin", "USDT"); - String signature = genGetSign(map); - StringBuilder sb = genQueryStr(map); + String signature = generateGetSignature(parameters); + StringBuilder queryString = generateQueryString(parameters); - OkHttpClient client = new OkHttpClient().newBuilder().build(); + OkHttpClient client = new OkHttpClient.Builder().build(); Request request = new Request.Builder() - .url("https://api-testnet.bybit.com/v5/order/realtime?" + sb) + .url("https://api-testnet.bybit.com/v5/order/realtime?" + queryString) .get() .addHeader("X-BAPI-API-KEY", API_KEY) .addHeader("X-BAPI-SIGN", signature) @@ -97,85 +85,58 @@ public void getOpenOrder() throws NoSuchAlgorithmException, InvalidKeyException .addHeader("X-BAPI-TIMESTAMP", TIMESTAMP) .addHeader("X-BAPI-RECV-WINDOW", RECV_WINDOW) .build(); + Call call = client.newCall(request); try { Response response = call.execute(); assert response.body() != null; System.out.println(response.body().string()); - }catch (IOException e){ - e.printStackTrace(); + } catch (IOException exception) { + exception.printStackTrace(); } } - /** - * The way to generate the sign for POST requests - * @param params: Map input parameters - * @return signature used to be a parameter in the header - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - private static String genPostSign(Map params) throws NoSuchAlgorithmException, InvalidKeyException { - Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); - SecretKeySpec secret_key = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256"); - sha256_HMAC.init(secret_key); - - String paramJson = JSON.toJSONString(params); - String sb = TIMESTAMP + API_KEY + RECV_WINDOW + paramJson; - return bytesToHex(sha256_HMAC.doFinal(sb.getBytes())); + private static String generatePostSignature(Map parameters) throws NoSuchAlgorithmException, InvalidKeyException { + Mac sha256Hmac = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256"); + sha256Hmac.init(secretKey); + + String paramJson = JSON.toJSONString(parameters); + String payload = TIMESTAMP + API_KEY + RECV_WINDOW + paramJson; + return bytesToHex(sha256Hmac.doFinal(payload.getBytes())); } - /** - * The way to generate the sign for GET requests - * @param params: Map input parameters - * @return signature used to be a parameter in the header - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - private static String genGetSign(Map params) throws NoSuchAlgorithmException, InvalidKeyException { - StringBuilder sb = genQueryStr(params); - String queryStr = TIMESTAMP + API_KEY + RECV_WINDOW + sb; - - Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); - SecretKeySpec secret_key = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256"); - sha256_HMAC.init(secret_key); - return bytesToHex(sha256_HMAC.doFinal(queryStr.getBytes())); + private static String generateGetSignature(Map parameters) throws NoSuchAlgorithmException, InvalidKeyException { + StringBuilder queryString = generateQueryString(parameters); + String payload = TIMESTAMP + API_KEY + RECV_WINDOW + queryString; + + Mac sha256Hmac = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256"); + sha256Hmac.init(secretKey); + return bytesToHex(sha256Hmac.doFinal(payload.getBytes())); } - /** - * To convert bytes to hex - * @param hash - * @return hex string - */ private static String bytesToHex(byte[] hash) { StringBuilder hexString = new StringBuilder(); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) hexString.append('0'); + for (byte value : hash) { + String hex = Integer.toHexString(0xff & value); + if (hex.length() == 1) { + hexString.append('0'); + } hexString.append(hex); } return hexString.toString(); } - /** - * To generate query string for GET requests - * @param map - * @return - */ - private static StringBuilder genQueryStr(Map map) { - Set keySet = map.keySet(); - Iterator iter = keySet.iterator(); - StringBuilder sb = new StringBuilder(); - while (iter.hasNext()) { - String key = iter.next(); - sb.append(key) - .append("=") - .append(map.get(key)) - .append("&"); + private static StringBuilder generateQueryString(Map parameters) { + Set keySet = parameters.keySet(); + Iterator iterator = keySet.iterator(); + StringBuilder query = new StringBuilder(); + while (iterator.hasNext()) { + String key = iterator.next(); + query.append(key).append("=").append(parameters.get(key)).append("&"); } - sb.deleteCharAt(sb.length() - 1); - return sb; + query.deleteCharAt(query.length() - 1); + return query; } } - - - diff --git a/V5_demo/api_demo/Encryption_HMAC.js b/V5_demo/api_demo/Encryption_HMAC.js index 4f2615b..ecdf473 100644 --- a/V5_demo/api_demo/Encryption_HMAC.js +++ b/V5_demo/api_demo/Encryption_HMAC.js @@ -1,49 +1,47 @@ const crypto = require('crypto'); const axios = require('axios'); -url='https://api-testnet.bybit.com'; +const url = 'https://api-testnet.bybit.com'; +const apiKey = 'xxxxxxxxxx'; +const secret = 'xxxxxxxxxxxxxxxxxxx'; +const recvWindow = 5000; +const timestamp = Date.now().toString(); -var apiKey = "xxxxxxxxxx"; -var secret = "xxxxxxxxxxxxxxxxxxx"; -var recvWindow = 5000; -var timestamp = Date.now().toString(); - -function getSignature(parameters, secret) { - return crypto.createHmac('sha256', secret).update(timestamp + apiKey + recvWindow + parameters).digest('hex'); +function getSignature(parameters, secretKey) { + return crypto.createHmac('sha256', secretKey).update(timestamp + apiKey + recvWindow + parameters).digest('hex'); } -async function http_request(endpoint,method,data,Info) { - var sign=getSignature(data,secret); - var fullendpoint; +async function httpRequest(endpoint, method, data, info) { + const sign = getSignature(data, secret); + let fullEndpoint; - // Build the request URL based on the method if (method === "POST") { - fullendpoint = url + endpoint; + fullEndpoint = url + endpoint; } else { - fullendpoint = url + endpoint + "?" + data; + fullEndpoint = url + endpoint + "?" + data; data = ""; } - var headers = { + const headers = { 'X-BAPI-SIGN-TYPE': '2', 'X-BAPI-SIGN': sign, 'X-BAPI-API-KEY': apiKey, 'X-BAPI-TIMESTAMP': timestamp, - 'X-BAPI-RECV-WINDOW': recvWindow.toString() + 'X-BAPI-RECV-WINDOW': recvWindow.toString() }; if (method === "POST") { headers['Content-Type'] = 'application/json; charset=utf-8'; } - var config = { + const config = { method: method, - url: fullendpoint, + url: fullEndpoint, headers: headers, data: data }; - console.log(Info + " Calling...."); + console.log(info + " Calling...."); await axios(config) .then(function (response) { console.log(JSON.stringify(response.data)); @@ -54,23 +52,19 @@ async function http_request(endpoint,method,data,Info) { } //Create Order -async function TestCase() -{ -endpoint="/v5/order/create" -const orderLinkId = crypto.randomBytes(16).toString("hex"); -var data = '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}'; -await http_request(endpoint,"POST",data,"Create"); +async function testCase() { + let endpoint = "/v5/order/create"; + const orderLinkId = crypto.randomBytes(16).toString("hex"); + let data = '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}'; + await httpRequest(endpoint, "POST", data, "Create"); -//Get unfilled Order List -endpoint="/v5/order/realtime" -var data = 'category=linear&settleCoin=USDT'; -await http_request(endpoint,"GET",data,"Order List"); + endpoint = "/v5/order/realtime"; + data = 'category=linear&settleCoin=USDT'; + await httpRequest(endpoint, "GET", data, "Order List"); -//Cancel order -endpoint="/v5/order/cancel" -var data = '{"category":"linear","symbol": "BTCUSDT","orderLinkId": "'+orderLinkId+'"}'; -await http_request(endpoint,"POST",data,"Cancel"); + endpoint = "/v5/order/cancel"; + data = '{"category":"linear","symbol": "BTCUSDT","orderLinkId": "' + orderLinkId + '"}'; + await httpRequest(endpoint, "POST", data, "Cancel"); } -//Create, List and Cancel Orders -TestCase() \ No newline at end of file +testCase(); diff --git a/V5_demo/api_demo/Encryption_HMAC.php b/V5_demo/api_demo/Encryption_HMAC.php index b20f890..9630282 100644 --- a/V5_demo/api_demo/Encryption_HMAC.php +++ b/V5_demo/api_demo/Encryption_HMAC.php @@ -1,20 +1,22 @@ $url . $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', @@ -24,41 +26,39 @@ function http_req($endpoint,$method,$params,$Info){ CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_POSTFIELDS => $params, - CURLOPT_HTTPHEADER => array( + CURLOPT_HTTPHEADER => [ "X-BAPI-API-KEY: $api_key", "X-BAPI-SIGN: $signature", "X-BAPI-SIGN-TYPE: 2", "X-BAPI-TIMESTAMP: $timestamp", "X-BAPI-RECV-WINDOW: 5000", - "Content-Type: application/json" - ), - )); - if($method=="GET") - { - curl_setopt($curl, CURLOPT_HTTPGET, true); + 'Content-Type: application/json', + ], + ]); + + if ($method == 'GET') { + curl_setopt($curl, CURLOPT_HTTPGET, true); } - echo $Info . "\n"; + + echo $info . "\n"; $response = curl_exec($curl); echo $response . "\n"; } -#Create Order -$endpoint="/v5/order/create"; -$method="POST"; -$orderLinkId=uniqid(); -$params='{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' . $orderLinkId . '"}'; -http_req("$endpoint","$method","$params","Create Order"); +$endpoint = '/v5/order/create'; +$method = 'POST'; +$order_link_id = uniqid(); +$params = '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' . $order_link_id . '"}'; +http_req($endpoint, $method, $params, 'Create Order'); -#Get Order List -$endpoint="/v5/order/realtime"; -$method="GET"; -$params="category=linear&settleCoin=USDT"; -http_req($endpoint,$method,$params,"List Order"); +$endpoint = '/v5/order/realtime'; +$method = 'GET'; +$params = 'category=linear&settleCoin=USDT'; +http_req($endpoint, $method, $params, 'List Order'); -#Cancel Order -$endpoint="/v5/order/cancel"; -$method="POST"; -$params='{"category":"linear","symbol": "BTCUSDT","orderLinkId": "' . $orderLinkId . '"}'; -http_req($endpoint,$method,$params,"Cancel Order"); +$endpoint = '/v5/order/cancel'; +$method = 'POST'; +$params = '{"category":"linear","symbol": "BTCUSDT","orderLinkId": "' . $order_link_id . '"}'; +http_req($endpoint, $method, $params, 'Cancel Order'); curl_close($curl); diff --git a/V5_demo/api_demo/Encryption_HMAC.py b/V5_demo/api_demo/Encryption_HMAC.py index cc458f0..fce7e18 100644 --- a/V5_demo/api_demo/Encryption_HMAC.py +++ b/V5_demo/api_demo/Encryption_HMAC.py @@ -1,56 +1,83 @@ -import requests -import time import hashlib import hmac +import json +import time import uuid -api_key='XXXXXXXXXX' -secret_key='XXXXXXXXXX' -httpClient=requests.Session() -recv_window=str(5000) -url="https://api-testnet.bybit.com" # Testnet endpoint +import requests -def HTTP_Request(endPoint,method,payload,Info): +API_KEY = "XXXXXXXXXX" +SECRET_KEY = "XXXXXXXXXX" +HTTP_CLIENT = requests.Session() +RECV_WINDOW = str(5000) +URL = "https://api-testnet.bybit.com" + + +def http_request(endpoint, method, payload, info): global time_stamp - time_stamp=str(int(time.time() * 10 ** 3)) - signature=genSignature(payload) + time_stamp = str(int(time.time() * 10 ** 3)) + signature = gen_signature(payload) headers = { - 'X-BAPI-API-KEY': api_key, - 'X-BAPI-SIGN': signature, - 'X-BAPI-SIGN-TYPE': '2', - 'X-BAPI-TIMESTAMP': time_stamp, - 'X-BAPI-RECV-WINDOW': recv_window, - 'Content-Type': 'application/json' + "X-BAPI-API-KEY": API_KEY, + "X-BAPI-SIGN": signature, + "X-BAPI-SIGN-TYPE": "2", + "X-BAPI-TIMESTAMP": time_stamp, + "X-BAPI-RECV-WINDOW": RECV_WINDOW, + "Content-Type": "application/json", } - if(method=="POST"): - response = httpClient.request(method, url+endPoint, headers=headers, data=payload) + if method == "POST": + response = HTTP_CLIENT.request(method, URL + endpoint, headers=headers, data=payload) else: - response = httpClient.request(method, url+endPoint+"?"+payload, headers=headers) + response = HTTP_CLIENT.request(method, URL + endpoint + "?" + payload, headers=headers) print(response.text) print(response.headers) - print(Info + " Elapsed Time : " + str(response.elapsed)) - -def genSignature(payload): - param_str= str(time_stamp) + api_key + recv_window + payload - hash = hmac.new(bytes(secret_key, "utf-8"), param_str.encode("utf-8"),hashlib.sha256) - signature = hash.hexdigest() - return signature - -#Create Order -endpoint="/v5/order/create" -method="POST" -orderLinkId=uuid.uuid4().hex -params='{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}' -HTTP_Request(endpoint,method,params,"Create") - -#Get unfilled Orders -endpoint="/v5/order/realtime" -method="GET" -params='category=linear&settleCoin=USDT' -HTTP_Request(endpoint,method,params,"UnFilled") - -#Cancel Order -endpoint="/v5/order/cancel" -method="POST" -params='{"category":"linear","symbol": "BTCUSDT","orderLinkId": "'+orderLinkId+'"}' -HTTP_Request(endpoint,method,params,"Cancel") + print(info + " Elapsed Time : " + str(response.elapsed)) + + +def gen_signature(payload): + param_str = str(time_stamp) + API_KEY + RECV_WINDOW + payload + signature_hash = hmac.new( + bytes(SECRET_KEY, "utf-8"), + param_str.encode("utf-8"), + hashlib.sha256, + ) + return signature_hash.hexdigest() + + +endpoint = "/v5/order/create" +method = "POST" +order_link_id = uuid.uuid4().hex +params = json.dumps( + { + "category": "linear", + "symbol": "BTCUSDT", + "side": "Buy", + "positionIdx": 0, + "orderType": "Limit", + "qty": "0.001", + "price": "10000", + "timeInForce": "GTC", + "orderLinkId": order_link_id, + }, + separators=(",", ":"), +) +http_request(endpoint, method, params, "Create") + + +endpoint = "/v5/order/realtime" +method = "GET" +params = "category=linear&settleCoin=USDT" +http_request(endpoint, method, params, "UnFilled") + + +endpoint = "/v5/order/cancel" +method = "POST" +params = json.dumps( + { + "category": "linear", + "symbol": "BTCUSDT", + "orderLinkId": order_link_id, + }, + separators=(",", ":"), +) +http_request(endpoint, method, params, "Cancel") diff --git a/V5_demo/api_demo/Encryption_HMAC.rb b/V5_demo/api_demo/Encryption_HMAC.rb index 25165f5..6ef35f0 100644 --- a/V5_demo/api_demo/Encryption_HMAC.rb +++ b/V5_demo/api_demo/Encryption_HMAC.rb @@ -1,64 +1,60 @@ require 'digest' -require "uri" -require "net/http" -require "date" +require 'uri' +require 'net/http' +require 'date' require 'open-uri' require 'openssl' require 'securerandom' -$api_key='XXXXXXXXXX' -$secret_key='XXXXXXXXXX' +$api_key = 'XXXXXXXXXX' +$secret_key = 'XXXXXXXXXX' $recv_window = '5000' -$url = URI("https://api-testnet.bybit.com") # Testnet endpoint -$time_stamp = "" +$url = URI('https://api-testnet.bybit.com') +$time_stamp = '' -def HTTP_Request(endPoint,method,payload) +def http_request(end_point, method, payload) $time_stamp = DateTime.now.strftime('%Q') - signature = genSignature(payload) - fullUrl = $url + endPoint - if method == "POST" - request = Net::HTTP::Post.new(fullUrl,'Content-Type' => 'application/json') + signature = gen_signature(payload) + full_url = $url + end_point + if method == 'POST' + request = Net::HTTP::Post.new(full_url, 'Content-Type' => 'application/json') request.body = payload - elsif method == "GET" - payload="?"+payload - fullUrl = $url + endPoint + payload - request = Net::HTTP::Get.new(fullUrl) + elsif method == 'GET' + payload = '?' + payload + full_url = $url + end_point + payload + request = Net::HTTP::Get.new(full_url) else - puts "Check the method. It should be either GET or POST" + puts 'Check the method. It should be either GET or POST' exit end - https = Net::HTTP.new(fullUrl.host, fullUrl.port) - #https.set_debug_output($stdout) + https = Net::HTTP.new(full_url.host, full_url.port) https.use_ssl = true - request["X-BAPI-API-KEY"] = $api_key - request["X-BAPI-TIMESTAMP"] = $time_stamp - request["X-BAPI-RECV-WINDOW"] = $recv_window - request["X-BAPI-SIGN"] = signature + request['X-BAPI-API-KEY'] = $api_key + request['X-BAPI-TIMESTAMP'] = $time_stamp + request['X-BAPI-RECV-WINDOW'] = $recv_window + request['X-BAPI-SIGN'] = signature response = https.request(request) puts response.read_body end -def genSignature(payload) - param_str= $time_stamp + $api_key + $recv_window + payload +def gen_signature(payload) + param_str = $time_stamp + $api_key + $recv_window + payload OpenSSL::HMAC.hexdigest('sha256', $secret_key, param_str) end -#Create Order ( POST Method ) -endPoint = "/v5/order/create" -method = "POST" -orderLinkId = SecureRandom.uuid -payload='{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}' -HTTP_Request(endPoint,method,payload) +end_point = '/v5/order/create' +method = 'POST' +order_link_id = SecureRandom.uuid +payload = '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + order_link_id + '"}' +http_request(end_point, method, payload) -#Retrieve Unfilled Orders ( GET Method ) -endPoint = "/v5/order/realtime" -method = "GET" -payload='category=linear&settleCoin=USDT' -HTTP_Request(endPoint,method,payload) +end_point = '/v5/order/realtime' +method = 'GET' +payload = 'category=linear&settleCoin=USDT' +http_request(end_point, method, payload) -#Cancel Order -endPoint="/v5/order/cancel" -method="POST" -payload='{"category":"linear","symbol": "BTCUSDT","orderLinkId": "'+orderLinkId+'"}' -HTTP_Request(endPoint,method,payload) +end_point = '/v5/order/cancel' +method = 'POST' +payload = '{"category":"linear","symbol": "BTCUSDT","orderLinkId": "' + order_link_id + '"}' +http_request(end_point, method, payload) diff --git a/V5_demo/api_demo/Encryption_HMAC.rs b/V5_demo/api_demo/Encryption_HMAC.rs index 7497f7a..5842739 100644 --- a/V5_demo/api_demo/Encryption_HMAC.rs +++ b/V5_demo/api_demo/Encryption_HMAC.rs @@ -1,41 +1,46 @@ use std::collections::HashMap; use std::error::Error; -use hmac::{Hmac, Mac, NewMac}; -use sha2::Sha256; + +use chrono::Utc; +use hmac::{Hmac, Mac}; use serde_json::{json, Value}; -use reqwest; -use chrono::{Utc}; -use hex; +use sha2::Sha256; type HmacSha256 = Hmac; -fn main() -> Result<(), Box> { +fn main() -> Result<(), Box> { let api_key = "xxxxxxxx"; let api_secret = "xxxxxxxxxxx"; let timestamp = Utc::now().timestamp_millis().to_string(); let recv_window = "5000"; - place_order(api_key, api_secret, ×tamp, recv_window)?; + place_order(api_key, api_secret, timestamp.as_str(), recv_window)?; + get_open_order(api_key, api_secret, timestamp.as_str(), recv_window)?; - get_open_order(api_key, api_secret, ×tamp, recv_window)?; Ok(()) } -fn get_open_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: &str) -> Result<(), Box> { +fn get_open_order( + api_key: &str, + api_secret: &str, + timestamp: &str, + recv_window: &str, +) -> Result<(), Box> { let client = reqwest::blocking::Client::new(); let mut params = HashMap::new(); params.insert("category", "linear"); params.insert("symbol", "BTCUSDT"); params.insert("settleCoin", "USDT"); - let signature = generate_get_signature(×tamp, api_key, recv_window, ¶ms, api_secret)?; + let signature = generate_get_signature(timestamp, api_key, recv_window, ¶ms, api_secret)?; let query_str = generate_query_str(¶ms); - let response = client.get(&format!("https://api-testnet.bybit.com/v5/order/realtime?{}", query_str)) + let response = client + .get(&format!("https://api-testnet.bybit.com/v5/order/realtime?{}", query_str)) .header("X-BAPI-API-KEY", api_key) .header("X-BAPI-SIGN", signature) .header("X-BAPI-SIGN-TYPE", "2") - .header("X-BAPI-TIMESTAMP", timestamp.clone()) + .header("X-BAPI-TIMESTAMP", timestamp) .header("X-BAPI-RECV-WINDOW", recv_window) .send()?; @@ -43,7 +48,12 @@ fn get_open_order(api_key: &str, api_secret: &str, timestamp: &String, recv_wind Ok(()) } -fn place_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: &str) -> Result<(), Box> { +fn place_order( + api_key: &str, + api_secret: &str, + timestamp: &str, + recv_window: &str, +) -> Result<(), Box> { let client = reqwest::blocking::Client::new(); let mut params = serde_json::Map::new(); params.insert("category".to_string(), json!("linear")); @@ -55,14 +65,15 @@ fn place_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: params.insert("price".to_string(), json!("18900")); params.insert("timeInForce".to_string(), json!("GTC")); - let signature = generate_post_signature(×tamp, api_key, recv_window, ¶ms, api_secret)?; + let signature = generate_post_signature(timestamp, api_key, recv_window, ¶ms, api_secret)?; - let response = client.post("https://api-testnet.bybit.com/v5/order/create") + let response = client + .post("https://api-testnet.bybit.com/v5/order/create") .json(¶ms) .header("X-BAPI-API-KEY", api_key) - .header("X-BAPI-SIGN", &signature) + .header("X-BAPI-SIGN", signature) .header("X-BAPI-SIGN-TYPE", "2") - .header("X-BAPI-TIMESTAMP", timestamp.clone()) + .header("X-BAPI-TIMESTAMP", timestamp) .header("X-BAPI-RECV-WINDOW", recv_window) .header("Content-Type", "application/json") .send()?; @@ -71,19 +82,31 @@ fn place_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: Ok(()) } -fn generate_post_signature(timestamp: &str, api_key: &str, recv_window: &str, params: &serde_json::Map, api_secret: &str) -> Result> { +fn generate_post_signature( + timestamp: &str, + api_key: &str, + recv_window: &str, + params: &serde_json::Map, + api_secret: &str, +) -> Result> { let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes()).expect("HMAC can take key of any size"); mac.update(timestamp.as_bytes()); mac.update(api_key.as_bytes()); mac.update(recv_window.as_bytes()); - mac.update(serde_json::to_string(¶ms)?.as_bytes()); + mac.update(serde_json::to_string(params)?.as_bytes()); let result = mac.finalize(); let code_bytes = result.into_bytes(); Ok(hex::encode(code_bytes)) } -fn generate_get_signature(timestamp: &str, api_key: &str, recv_window: &str, params: &HashMap<&str, &str>, api_secret: &str) -> Result> { +fn generate_get_signature( + timestamp: &str, + api_key: &str, + recv_window: &str, + params: &HashMap<&str, &str>, + api_secret: &str, +) -> Result> { let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes()).expect("HMAC can take key of any size"); mac.update(timestamp.as_bytes()); mac.update(api_key.as_bytes()); @@ -96,8 +119,9 @@ fn generate_get_signature(timestamp: &str, api_key: &str, recv_window: &str, par } fn generate_query_str(params: &HashMap<&str, &str>) -> String { - params.iter() + params + .iter() .map(|(key, value)| format!("{}={}", key, value)) .collect::>() .join("&") -} \ No newline at end of file +} diff --git a/V5_demo/api_demo/Encryption_HMAC.rs.bak b/V5_demo/api_demo/Encryption_HMAC.rs.bak deleted file mode 100644 index 6c86de7..0000000 --- a/V5_demo/api_demo/Encryption_HMAC.rs.bak +++ /dev/null @@ -1,103 +0,0 @@ -use std::collections::HashMap; -use std::error::Error; -use hmac::{Hmac, Mac, NewMac}; -use sha2::Sha256; -use serde_json::{json, Value}; -use reqwest; -use chrono::{Utc}; -use hex; - -type HmacSha256 = Hmac; - -fn main() -> Result<(), Box> { - let api_key = "8wYkmpLsMg10eNQyPm"; - let api_secret = "Ouxc34myDnXvei54XsBZgoQzfGxO4bkr2Zsj"; - let timestamp = Utc::now().timestamp_millis().to_string(); - let recv_window = "5000"; - - place_order(api_key, api_secret, ×tamp, recv_window)?; - - get_open_order(api_key, api_secret, ×tamp, recv_window)?; - Ok(()) -} - -fn get_open_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: &str) -> Result<(), Box> { - let client = reqwest::blocking::Client::new(); - let mut params = HashMap::new(); - params.insert("category", "linear"); - params.insert("symbol", "BTCUSDT"); - params.insert("settleCoin", "USDT"); - - let signature = generate_get_signature(×tamp, api_key, recv_window, ¶ms, api_secret)?; - let query_str = generate_query_str(¶ms); - - let response = client.get(&format!("https://api-testnet.bybit.com/v5/order/realtime?{}", query_str)) - .header("X-BAPI-API-KEY", api_key) - .header("X-BAPI-SIGN", signature) - .header("X-BAPI-SIGN-TYPE", "2") - .header("X-BAPI-TIMESTAMP", timestamp.clone()) - .header("X-BAPI-RECV-WINDOW", recv_window) - .send()?; - - println!("Response: {:?}", response.text()?); - Ok(()) -} - -fn place_order(api_key: &str, api_secret: &str, timestamp: &String, recv_window: &str) -> Result<(), Box> { - let client = reqwest::blocking::Client::new(); - let mut params = serde_json::Map::new(); - params.insert("category".to_string(), json!("linear")); - params.insert("symbol".to_string(), json!("BTCUSDT")); - params.insert("side".to_string(), json!("Buy")); - params.insert("positionIdx".to_string(), json!(0)); - params.insert("orderType".to_string(), json!("Limit")); - params.insert("qty".to_string(), json!("0.001")); - params.insert("price".to_string(), json!("18900")); - params.insert("timeInForce".to_string(), json!("GTC")); - - let signature = generate_post_signature(×tamp, api_key, recv_window, ¶ms, api_secret)?; - - let response = client.post("https://api-testnet.bybit.com/v5/order/create") - .json(¶ms) - .header("X-BAPI-API-KEY", api_key) - .header("X-BAPI-SIGN", &signature) - .header("X-BAPI-SIGN-TYPE", "2") - .header("X-BAPI-TIMESTAMP", timestamp.clone()) - .header("X-BAPI-RECV-WINDOW", recv_window) - .header("Content-Type", "application/json") - .send()?; - - println!("Response: {:?}", response.text()?); - Ok(()) -} - -fn generate_post_signature(timestamp: &str, api_key: &str, recv_window: &str, params: &serde_json::Map, api_secret: &str) -> Result> { - let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes()).expect("HMAC can take key of any size"); - mac.update(timestamp.as_bytes()); - mac.update(api_key.as_bytes()); - mac.update(recv_window.as_bytes()); - mac.update(serde_json::to_string(¶ms)?.as_bytes()); - - let result = mac.finalize(); - let code_bytes = result.into_bytes(); - Ok(hex::encode(code_bytes)) -} - -fn generate_get_signature(timestamp: &str, api_key: &str, recv_window: &str, params: &HashMap<&str, &str>, api_secret: &str) -> Result> { - let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes()).expect("HMAC can take key of any size"); - mac.update(timestamp.as_bytes()); - mac.update(api_key.as_bytes()); - mac.update(recv_window.as_bytes()); - mac.update(generate_query_str(params).as_bytes()); - - let result = mac.finalize(); - let code_bytes = result.into_bytes(); - Ok(hex::encode(code_bytes)) -} - -fn generate_query_str(params: &HashMap<&str, &str>) -> String { - params.iter() - .map(|(key, value)| format!("{}={}", key, value)) - .collect::>() - .join("&") -} \ No newline at end of file diff --git a/V5_demo/api_demo/Encryption_HMAC.scala b/V5_demo/api_demo/Encryption_HMAC.scala index ffbe3b0..750ebca 100644 --- a/V5_demo/api_demo/Encryption_HMAC.scala +++ b/V5_demo/api_demo/Encryption_HMAC.scala @@ -5,6 +5,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response + import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec import java.io.IOException @@ -13,126 +14,93 @@ import java.security.NoSuchAlgorithmException import java.time.ZonedDateTime import java.{lang, util} - -/** - * a sample for how to create & get an order for contract v5 - Linear perpetual - */ object Encryption { - val API_KEY = "xxxxxxxxxx" - val API_SECRET = "xxxxxxxxxxxxxxxx" - val TIMESTAMP: String = ZonedDateTime.now.toInstant.toEpochMilli.toString - val RECV_WINDOW = "5000" + val ApiKey = "xxxxxxxxxx" + val ApiSecret = "xxxxxxxxxxxxxxxx" + val Timestamp: String = ZonedDateTime.now.toInstant.toEpochMilli.toString + val RecvWindow = "5000" @throws[NoSuchAlgorithmException] @throws[InvalidKeyException] def main(args: Array[String]): Unit = { - val encryptionTest = new Encryption - encryptionTest.placeOrder() - encryptionTest.getOpenOrder(); + val encryption = new Encryption + encryption.placeOrder() + encryption.getOpenOrder() } - /** - * The way to generate the sign for POST requests - * - * @param params : Map input parameters - * @return signature used to be a parameter in the header - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ @throws[NoSuchAlgorithmException] @throws[InvalidKeyException] - private def genPostSign(params: util.Map[String, AnyRef]) = { - val sha256_HMAC = Mac.getInstance("HmacSHA256") - val secret_key = new SecretKeySpec(API_SECRET.getBytes, "HmacSHA256") - sha256_HMAC.init(secret_key) + private def generatePostSignature(params: util.Map[String, AnyRef]): String = { + val sha256Hmac = Mac.getInstance("HmacSHA256") + val secretKey = new SecretKeySpec(ApiSecret.getBytes, "HmacSHA256") + sha256Hmac.init(secretKey) val paramJson = JSON.toJSONString(params) - val sb = TIMESTAMP + API_KEY + RECV_WINDOW + paramJson - bytesToHex(sha256_HMAC.doFinal(sb.getBytes)) + val payload = Timestamp + ApiKey + RecvWindow + paramJson + bytesToHex(sha256Hmac.doFinal(payload.getBytes)) } - /** - * The way to generate the sign for GET requests - * - * @param params : Map input parameters - * @return signature used to be a parameter in the header - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ @throws[NoSuchAlgorithmException] @throws[InvalidKeyException] - private def genGetSign(params: util.Map[String, AnyRef]) = { - val sb = genQueryStr(params) - val queryStr = TIMESTAMP + API_KEY + RECV_WINDOW + sb - val sha256_HMAC = Mac.getInstance("HmacSHA256") - val secret_key = new SecretKeySpec(API_SECRET.getBytes, "HmacSHA256") - sha256_HMAC.init(secret_key) - bytesToHex(sha256_HMAC.doFinal(queryStr.getBytes)) + private def generateGetSignature(params: util.Map[String, AnyRef]): String = { + val queryString = generateQueryString(params) + val payload = Timestamp + ApiKey + RecvWindow + queryString + val sha256Hmac = Mac.getInstance("HmacSHA256") + val secretKey = new SecretKeySpec(ApiSecret.getBytes, "HmacSHA256") + sha256Hmac.init(secretKey) + bytesToHex(sha256Hmac.doFinal(payload.getBytes)) } - /** - * To convert bytes to hex - * - * @param hash - * @return hex string - */ - private def bytesToHex(hash: Array[Byte]) = { + private def bytesToHex(hash: Array[Byte]): String = { val hexString = new lang.StringBuilder - for (b <- hash) { - val hex = Integer.toHexString(0xff & b) - if (hex.length == 1) hexString.append('0') + for (value <- hash) { + val hex = Integer.toHexString(0xff & value) + if (hex.length == 1) { + hexString.append('0') + } hexString.append(hex) } hexString.toString } - /** - * To generate query string for GET requests - * - * @param map - * @return - */ - private def genQueryStr(map: util.Map[String, AnyRef]) = { - val keySet = map.keySet - val iter = keySet.iterator - val sb = new lang.StringBuilder - while (iter.hasNext) { - val key = iter.next - sb.append(key).append("=").append(map.get(key)).append("&") + private def generateQueryString(map: util.Map[String, AnyRef]): lang.StringBuilder = { + val iterator = map.keySet.iterator + val query = new lang.StringBuilder + while (iterator.hasNext) { + val key = iterator.next + query.append(key).append("=").append(map.get(key)).append("&") } - sb.deleteCharAt(sb.length - 1) - sb + query.deleteCharAt(query.length - 1) + query } } class Encryption { - /** - * POST: place a Linear perp order - contract v5 - */ @throws[NoSuchAlgorithmException] @throws[InvalidKeyException] def placeOrder(): Unit = { - val map = new util.HashMap[String, AnyRef] - map.put("category", "linear") - map.put("symbol", "BTCUSDT") - map.put("side", "Buy") - map.put("positionIdx", 0: java.lang.Integer) - map.put("orderType", "Limit") - map.put("qty", "0.001") - map.put("price", "18900") - map.put("timeInForce", "GTC") - val signature = Encryption.genPostSign(map) - val jsonMap = JSON.toJSONString(map) + val params = new util.HashMap[String, AnyRef] + params.put("category", "linear") + params.put("symbol", "BTCUSDT") + params.put("side", "Buy") + params.put("positionIdx", 0: java.lang.Integer) + params.put("orderType", "Limit") + params.put("qty", "0.001") + params.put("price", "18900") + params.put("timeInForce", "GTC") + + val signature = Encryption.generatePostSignature(params) + val jsonPayload = JSON.toJSONString(params) val client = new OkHttpClient.Builder().build() val mediaType = MediaType.parse("application/json") - val body = RequestBody.create(jsonMap, mediaType) + val body = RequestBody.create(jsonPayload, mediaType) val request = new Request.Builder() .url("https://api-testnet.bybit.com/v5/order/create") .post(body) - .addHeader("X-BAPI-API-KEY", Encryption.API_KEY) + .addHeader("X-BAPI-API-KEY", Encryption.ApiKey) .addHeader("X-BAPI-SIGN", signature) .addHeader("X-BAPI-SIGN-TYPE", "2") - .addHeader("X-BAPI-TIMESTAMP", Encryption.TIMESTAMP) - .addHeader("X-BAPI-RECV-WINDOW", Encryption.RECV_WINDOW) + .addHeader("X-BAPI-TIMESTAMP", Encryption.Timestamp) + .addHeader("X-BAPI-RECV-WINDOW", Encryption.RecvWindow) .addHeader("Content-Type", "application/json") .build() @@ -142,36 +110,29 @@ class Encryption { assert(response.body() != null) println(response.body().string()) } catch { - case e: Exception => e.printStackTrace() + case exception: Exception => exception.printStackTrace() } - } - /** - * GET: query unfilled order - * - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ @throws[NoSuchAlgorithmException] @throws[InvalidKeyException] def getOpenOrder(): Unit = { - val map = new util.HashMap[String, AnyRef] - map.put("category", "linear") - map.put("symbol", "BTCUSDT") - map.put("settleCoin", "USDT") - val signature = Encryption.genGetSign(map) - val sb = Encryption.genQueryStr(map) - val client = new OkHttpClient.Builder().build() + val params = new util.HashMap[String, AnyRef] + params.put("category", "linear") + params.put("symbol", "BTCUSDT") + params.put("settleCoin", "USDT") + val signature = Encryption.generateGetSignature(params) + val queryString = Encryption.generateQueryString(params) + val client = new OkHttpClient.Builder().build() val request = new Request.Builder() - .url("https://api-testnet.bybit.com/v5/order/realtime?" + sb.toString) + .url("https://api-testnet.bybit.com/v5/order/realtime?" + queryString.toString) .get() - .addHeader("X-BAPI-API-KEY", Encryption.API_KEY) + .addHeader("X-BAPI-API-KEY", Encryption.ApiKey) .addHeader("X-BAPI-SIGN", signature) .addHeader("X-BAPI-SIGN-TYPE", "2") - .addHeader("X-BAPI-TIMESTAMP", Encryption.TIMESTAMP) - .addHeader("X-BAPI-RECV-WINDOW", Encryption.RECV_WINDOW) + .addHeader("X-BAPI-TIMESTAMP", Encryption.Timestamp) + .addHeader("X-BAPI-RECV-WINDOW", Encryption.RecvWindow) .build() val call = client.newCall(request) @@ -180,10 +141,7 @@ class Encryption { assert(response.body() != null) println(response.body().string()) } catch { - case e: IOException => - e.printStackTrace() + case exception: IOException => exception.printStackTrace() } } } - - diff --git a/V5_demo/api_demo/Encryption_HMAC.sh b/V5_demo/api_demo/Encryption_HMAC.sh index f4041a1..ed8a503 100644 --- a/V5_demo/api_demo/Encryption_HMAC.sh +++ b/V5_demo/api_demo/Encryption_HMAC.sh @@ -1,5 +1,4 @@ #!/bin/bash - api_key='XXXXXXXXXX' secret_key='XXXXXXXXXX' @@ -8,19 +7,18 @@ timestamp=$((time_in_seconds * 1000)) sign=$(echo -n "${timestamp}${api_key}"5000'{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "TEST1234"}' | openssl dgst -sha256 -hmac "${secret_key}") response=$(curl --location --request POST 'https://api-testnet.bybit.com/v5/order/create' \ ---header 'X-BAPI-SIGN-TYPE: 2' \ ---header 'X-BAPI-SIGN: '${sign} \ ---header 'X-BAPI-API-KEY: '${api_key} \ ---header 'X-BAPI-TIMESTAMP: '${timestamp} \ ---header 'X-BAPI-RECV-WINDOW: 5000' \ ---header 'Content-Type: application/json' \ ---data-raw '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "TEST1234"}') + --header 'X-BAPI-SIGN-TYPE: 2' \ + --header 'X-BAPI-SIGN: '${sign} \ + --header 'X-BAPI-API-KEY: '${api_key} \ + --header 'X-BAPI-TIMESTAMP: '${timestamp} \ + --header 'X-BAPI-RECV-WINDOW: 5000' \ + --header 'Content-Type: application/json' \ + --data-raw '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "TEST1234"}') echo "Curl Response : $?" echo "${response}" -order_id=$(jq '.result.orderId' <<< ${response}) -if [ "${order_id}" == "null" ] -then +order_id=$(jq '.result.orderId' <<< "${response}") +if [ "${order_id}" == "null" ]; then echo "${response}" else echo "Order ID # ${order_id}" diff --git a/V5_demo/api_demo/Encryption_HMAC.ts b/V5_demo/api_demo/Encryption_HMAC.ts index 405dc41..eb50e4c 100644 --- a/V5_demo/api_demo/Encryption_HMAC.ts +++ b/V5_demo/api_demo/Encryption_HMAC.ts @@ -1,29 +1,33 @@ import * as crypto from 'crypto'; -import axios, { AxiosRequestConfig } from 'axios'; +import axios from 'axios'; const url = 'https://api-testnet.bybit.com'; - const apiKey = "xxxxxxxxxxxx"; const secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; const recvWindow = 5000; const timestamp = Date.now().toString(); -function generateSignature(parameters: string, secret: string): string { - return crypto.createHmac('sha256', secret).update(timestamp + apiKey + recvWindow + parameters).digest('hex'); +function generateSignature(parameters: string, secretKey: string): string { + return crypto.createHmac('sha256', secretKey).update(timestamp + apiKey + recvWindow + parameters).digest('hex'); } -async function http_request(endpoint, method, data, Info) { - var sign = generateSignature(data, secret); - var fullendpoint: string; +async function httpRequest( + endpoint: string, + method: string, + data: string, + info: string, +): Promise { + const sign = generateSignature(data, secret); + let fullEndpoint: string; if (method === "POST") { - fullendpoint = url + endpoint; + fullEndpoint = url + endpoint; } else { - fullendpoint = url + endpoint + "?" + data; + fullEndpoint = url + endpoint + "?" + data; data = ""; } - var headers = { + const headers: Record = { 'X-BAPI-SIGN-TYPE': '2', 'X-BAPI-SIGN': sign, 'X-BAPI-API-KEY': apiKey, @@ -35,14 +39,14 @@ async function http_request(endpoint, method, data, Info) { headers['Content-Type'] = 'application/json; charset=utf-8'; } - var config = { + const config = { method: method, - url: fullendpoint, + url: fullEndpoint, headers: headers, data: data }; - console.log(Info + " Calling...."); + console.log(info + " Calling...."); await axios(config) .then(function (response) { console.log(JSON.stringify(response.data)); @@ -52,24 +56,20 @@ async function http_request(endpoint, method, data, Info) { }); } -async function TestCase(): Promise { +async function testCase(): Promise { const orderLinkId = crypto.randomBytes(16).toString("hex"); - // Create Order let endpoint = "/v5/order/create"; let data = `{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "${orderLinkId}"}`; - await http_request(endpoint, "POST", data, "Create"); + await httpRequest(endpoint, "POST", data, "Create"); - // Get unfilled Order List endpoint = "/v5/order/realtime"; data = 'category=linear&symbol=BTCUSDT'; - await http_request(endpoint, "GET", data, "Realtime"); + await httpRequest(endpoint, "GET", data, "Realtime"); - // Cancel order endpoint = "/v5/order/cancel"; data = `{"category":"linear","symbol": "BTCUSDT","orderLinkId": "${orderLinkId}"}`; - await http_request(endpoint, "POST", data, "Cancel"); + await httpRequest(endpoint, "POST", data, "Cancel"); } -// Create, List and Cancel Orders -TestCase(); \ No newline at end of file +testCase(); diff --git a/V5_demo/api_demo/Encryption_HMAC_async.py b/V5_demo/api_demo/Encryption_HMAC_async.py index 768d520..cf0a810 100644 --- a/V5_demo/api_demo/Encryption_HMAC_async.py +++ b/V5_demo/api_demo/Encryption_HMAC_async.py @@ -1,52 +1,74 @@ -import aiohttp -import asyncio -import time -import hmac -import hashlib -import uuid - -api_key = 'XXXXXXXXXX' -secret_key = 'XXXXXXXXXX' -recv_window = str(5000) -url = "https://api-testnet.bybit.com" # Testnet endpoint - -async def HTTP_Request(endPoint, method, payload, Info): - global time_stamp - time_stamp = str(int(time.time() * 10 ** 3)) - signature = genSignature(payload) - headers = { - 'X-BAPI-API-KEY': api_key, - 'X-BAPI-SIGN': signature, - 'X-BAPI-SIGN-TYPE': '2', - 'X-BAPI-TIMESTAMP': time_stamp, - 'X-BAPI-RECV-WINDOW': recv_window, - 'Content-Type': 'application/json' - } - - async with aiohttp.ClientSession() as session: - if method == "POST": - async with session.post(url + endPoint, headers=headers, data=payload) as response: - response_text = await response.text() - else: - async with session.get(url + endPoint + "?" + payload, headers=headers) as response: - response_text = await response.text() - - print(response_text) - print(Info + " Elapsed Time : " + str(response.elapsed)) - -def genSignature(payload): - param_str = time_stamp + api_key + recv_window + payload - hash = hmac.new(bytes(secret_key, "utf-8"), param_str.encode("utf-8"), hashlib.sha256) - signature = hash.hexdigest() - return signature - -async def main(): - # Create Order - endpoint = "/v5/order/create" - method = "POST" - orderLinkId = uuid.uuid4().hex - params = '{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}' - await HTTP_Request(endpoint, method, params, "Create") - -# Run the main function using asyncio -asyncio.run(main()) +import asyncio +import hashlib +import hmac +import json +import time +import uuid + +import aiohttp + +API_KEY = "XXXXXXXXXX" +SECRET_KEY = "XXXXXXXXXX" +RECV_WINDOW = str(5000) +URL = "https://api-testnet.bybit.com" + + +async def http_request(endpoint, method, payload, info): + global time_stamp + time_stamp = str(int(time.time() * 10 ** 3)) + signature = gen_signature(payload) + headers = { + "X-BAPI-API-KEY": API_KEY, + "X-BAPI-SIGN": signature, + "X-BAPI-SIGN-TYPE": "2", + "X-BAPI-TIMESTAMP": time_stamp, + "X-BAPI-RECV-WINDOW": RECV_WINDOW, + "Content-Type": "application/json", + } + + async with aiohttp.ClientSession() as session: + start_time = time.perf_counter() + if method == "POST": + async with session.post(URL + endpoint, headers=headers, data=payload) as response: + response_text = await response.text() + else: + async with session.get(URL + endpoint + "?" + payload, headers=headers) as response: + response_text = await response.text() + elapsed = time.perf_counter() - start_time + + print(response_text) + print(info + " Elapsed Time : " + str(elapsed)) + + +def gen_signature(payload): + param_str = time_stamp + API_KEY + RECV_WINDOW + payload + signature_hash = hmac.new( + bytes(SECRET_KEY, "utf-8"), + param_str.encode("utf-8"), + hashlib.sha256, + ) + return signature_hash.hexdigest() + + +async def main(): + endpoint = "/v5/order/create" + method = "POST" + order_link_id = uuid.uuid4().hex + params = json.dumps( + { + "category": "linear", + "symbol": "BTCUSDT", + "side": "Buy", + "positionIdx": 0, + "orderType": "Limit", + "qty": "0.001", + "price": "10000", + "timeInForce": "GTC", + "orderLinkId": order_link_id, + }, + separators=(",", ":"), + ) + await http_request(endpoint, method, params, "Create") + + +asyncio.run(main()) diff --git a/V5_demo/api_demo/Encryption_RSA.cs b/V5_demo/api_demo/Encryption_RSA.cs index 33cf42a..f6bbb8b 100644 --- a/V5_demo/api_demo/Encryption_RSA.cs +++ b/V5_demo/api_demo/Encryption_RSA.cs @@ -1,34 +1,33 @@ -using System.Text; +using System.Net.Http.Headers; using System.Security.Cryptography; +using System.Text; using Newtonsoft.Json; -using System.Net.Http.Headers; - public class Encryption { private const string API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxx"; private static readonly string TIMESTAMP = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); private const string RECV_WINDOW = "5000"; - private const string RsaPrivateKeyPath = @"C:\Path\To\private.pem"; // update path - private static readonly HttpClient httpClient = new HttpClient(); + private const string RsaPrivateKeyPath = @"C:\Path\To\private.pem"; + private static readonly HttpClient HttpClient = new(); public static void Main(string[] args) { - Encryption encryptionTest = new Encryption(); - encryptionTest.PlaceOrder(); - encryptionTest.GetOpenOrder(); + var encryption = new Encryption(); + encryption.PlaceOrder(); + encryption.GetOpenOrder(); } public void PlaceOrder() { - string keyPem = @"-----BEGIN PRIVATE KEY----- + const string keyPem = @"-----BEGIN PRIVATE KEY----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ... ... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END PRIVATE KEY-----"; - Dictionary map = new Dictionary + var map = new Dictionary { {"category", "linear"}, {"symbol", "BTCUSDT"}, @@ -39,20 +38,23 @@ public void PlaceOrder() {"price", "18900"}, {"timeInForce", "GTC"} }; - string jsonMap = JsonConvert.SerializeObject(map); - - string plainText = TIMESTAMP + API_KEY + RECV_WINDOW + jsonMap; - - string signature = GenSignature(keyPem, plainText); - - httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClient.DefaultRequestHeaders.Add("X-BAPI-API-KEY", API_KEY); - httpClient.DefaultRequestHeaders.Add("X-BAPI-SIGN", signature); - httpClient.DefaultRequestHeaders.Add("X-BAPI-TIMESTAMP", TIMESTAMP); - httpClient.DefaultRequestHeaders.Add("X-BAPI-RECV-WINDOW", RECV_WINDOW); - - StringContent content = new StringContent(jsonMap, Encoding.UTF8, "application/json"); - var response = httpClient.PostAsync("https://api-testnet.bybit.com/v5/order/create", content).Result; + var jsonMap = JsonConvert.SerializeObject(map); + var plainText = TIMESTAMP + API_KEY + RECV_WINDOW + jsonMap; + var signature = GenSignature(keyPem, plainText); + + HttpClient.DefaultRequestHeaders.Accept.Clear(); + HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + HttpClient.DefaultRequestHeaders.Remove("X-BAPI-API-KEY"); + HttpClient.DefaultRequestHeaders.Remove("X-BAPI-SIGN"); + HttpClient.DefaultRequestHeaders.Remove("X-BAPI-TIMESTAMP"); + HttpClient.DefaultRequestHeaders.Remove("X-BAPI-RECV-WINDOW"); + HttpClient.DefaultRequestHeaders.Add("X-BAPI-API-KEY", API_KEY); + HttpClient.DefaultRequestHeaders.Add("X-BAPI-SIGN", signature); + HttpClient.DefaultRequestHeaders.Add("X-BAPI-TIMESTAMP", TIMESTAMP); + HttpClient.DefaultRequestHeaders.Add("X-BAPI-RECV-WINDOW", RECV_WINDOW); + + var content = new StringContent(jsonMap, Encoding.UTF8, "application/json"); + var response = HttpClient.PostAsync("https://api-testnet.bybit.com/v5/order/create", content).Result; Console.WriteLine(response.Content.ReadAsStringAsync().Result); } @@ -61,43 +63,36 @@ public void GetOpenOrder() { var parameters = new Dictionary { - { "category", "linear" }, - { "symbol", "BTCUSDT" }, - { "settleCoin", "USDT" } + {"category", "linear"}, + {"symbol", "BTCUSDT"}, + {"settleCoin", "USDT"} }; var queryString = GenQueryString(parameters); var plainText = TIMESTAMP + API_KEY + RECV_WINDOW + queryString; - var signature = GenSignature(RsaPrivateKeyPath, plainText); var request = new HttpRequestMessage(HttpMethod.Get, "https://api-testnet.bybit.com/v5/order/realtime?" + queryString) { Headers = { - { "X-BAPI-API-KEY", API_KEY }, - { "X-BAPI-SIGN", signature }, - { "X-BAPI-TIMESTAMP", TIMESTAMP }, - { "X-BAPI-RECV-WINDOW", "5000" } + {"X-BAPI-API-KEY", API_KEY}, + {"X-BAPI-SIGN", signature}, + {"X-BAPI-TIMESTAMP", TIMESTAMP}, + {"X-BAPI-RECV-WINDOW", "5000"} } }; - var response = httpClient.SendAsync(request).Result; + var response = HttpClient.SendAsync(request).Result; Console.WriteLine(response.Content.ReadAsStringAsync().Result); } - /// - /// generate signature - /// - /// either absolute pem path or original private key pem string - /// plain text - /// private string GenSignature(string privateKey, string data) { - RSA rsaPrivateKey = RSA.Create(); + var rsaPrivateKey = RSA.Create(); rsaPrivateKey.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _); - byte[] dataBytes = Encoding.UTF8.GetBytes(data); - byte[] signatureBytes = rsaPrivateKey.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + var dataBytes = Encoding.UTF8.GetBytes(data); + var signatureBytes = rsaPrivateKey.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); return Convert.ToBase64String(signatureBytes); } diff --git a/V5_demo/api_demo/Encryption_RSA.java b/V5_demo/api_demo/Encryption_RSA.java index 33a3735..fbbec97 100644 --- a/V5_demo/api_demo/Encryption_RSA.java +++ b/V5_demo/api_demo/Encryption_RSA.java @@ -5,6 +5,7 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -20,76 +21,66 @@ import java.util.Map; import java.util.Set; -/** - * a sample for how to create & get an order for contract v5 - Linear perp - */ public class Encryption { - final static String API_KEY = "XXXXXXXXXX"; - final static String TIMESTAMP = Long.toString(ZonedDateTime.now().toInstant().toEpochMilli()); - final static String RECV_WINDOW = "5000"; - - public static void main(String[] args){ - Encryption encryptionTest = new Encryption(); - - encryptionTest.placeOrder(); - -// encryptionTest.getOpenOrder(); + private static final String API_KEY = "XXXXXXXXXX"; + private static final String TIMESTAMP = Long.toString(ZonedDateTime.now().toInstant().toEpochMilli()); + private static final String RECV_WINDOW = "5000"; + + public static void main(String[] args) { + Encryption encryption = new Encryption(); + encryption.placeOrder(); +// encryption.getOpenOrder(); } - /** - * POST: place a Linear perp order - contract v5 - */ - public void placeOrder(){ - String keyPem = "-----BEGIN PRIVATE KEY-----\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "R4gmvtpPbI3J2XKwzUXNDdGbXSZD/fONOfoyO5w05Ci3hDOyZtxFI33onEwGiZfp\n" + - "woeYLAB4Q8QhVRobi3NOC6BBmaRBYw6KWsx+qL6QoQQakJZAFtlZuVYUxXzMMU+M\n" + - "vDPvszOl3cFIO3UWxrUCqriM1b86DH6f7WrkP80nzTfWG5TMlzM6zYK0rgUiTrqH\n" + - "cDMsqT+ZAgMBAAECggEAAaUVGt8v4TB+8lTqvoprQJxtp85FQLpc78+v9Tw1sU9p\n" + - "Tz5gGR6Gra6Vs4FoQnmQdRt1bQrYxZQcNY23PlNLxYrtTz4cYvCYtEf0ivP+6igI\n" + - "ZExtwEZso998VzZNB+CcTp6vSXobtTq+Lzg5SbuxeHLnG30Lr6gHBaxxbfuCbIT9\n" + - "v/+Co+og0WqSmjLNuRu0gzfbK0X4Xl/fO3yuJxIr8ofSt2FW45Q/k+JWR9FHUJyN\n" + - "BQ0AxaNg9/DlLwwP0jlsQEcSv+i8VCOp9K2TYvv75uUSeq4AujdJjdIw/j9BQpDf\n" + - "1op59uGzjNgywsUptsePIObZXID+QdrxwGIuBHgcgQKBgQD6LrMI64706qf+4Eb9\n" + - "D6fXVxlbucyo7TZn0cZG8Cf/Dr7eg7hs6kK41+ZiMB5trfJ/1d6L65sDGmb/+KTF\n" + - "AGV1FiHpyx9hvGoIupEBEyeS7pH10eSk69THWrAgKW60Xeve1oCsRin+B9UwYtRz\n" + - "NL8o/+9W54yqLaRgeD7sRaETMQKBgQC81T25vssikzBSkrHCacYig5JCXmTce9NU\n" + - "L5BZzuCv5zWXRI95Q7FmsqlFY2BsByI1uiwxZJiEOj8IWjjxvd1CNj1ByQd7B8Sb\n" + - "ALQHetdel/D51mrbV1OyMdNsDuZJu7NiwDV92aVNiiKmTE6epP81qkFpwLQ19XQe\n" + - "YFx85flI6QKBgQDTSWVCf034YcUHZ/oL9pDVOGXeJYhGki+EdpFxj5j3u0hPPAch\n" + - "VKaM3Slgeyr3jhRjCggtOwlrEX0zaJYfGjqVK9/wRu91513ViVq1AaxGVt1GMcFb\n" + - "1x+YTWq5fsRT544wYA/Dbm5Ab/UILC8oLL/UrHFBf8Q4ZNuR7XuWpydlwQKBgBeZ\n" + - "FnOl8kDJ4BoRlwFSsp4Rjy+YGEatesVkhEeU4ONao4nZ2Ywv93V8EkdHmf8mDRJl\n" + - "x6wMhDrSBJqIm+Ep9wKVQKZ99t9bIyizt8vPgCakGks+jnAGw8DbFS7F1eWU/V/z\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + - "6DHWbgI1hfX8/y8pKHJkkyXn\n" + - "-----END PRIVATE KEY-----\n"; - - Map map = new HashMap<>(); - map.put("category","linear"); - map.put("symbol", "BTCUSDT"); - map.put("side", "Buy"); - map.put("positionIdx", 0); - map.put("orderType", "Limit"); - map.put("qty", "0.001"); - map.put("price", "18900"); - map.put("timeInForce", "GTC"); - - String jsonMap = JSON.toJSONString(map); - - String plainText = TIMESTAMP + API_KEY + RECV_WINDOW + jsonMap; - - String signature = genSignature(keyPem, plainText); - - OkHttpClient client = new OkHttpClient().newBuilder().build(); + public void placeOrder() { + String keyPem = "-----BEGIN PRIVATE KEY-----\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "R4gmvtpPbI3J2XKwzUXNDdGbXSZD/fONOfoyO5w05Ci3hDOyZtxFI33onEwGiZfp\n" + + "woeYLAB4Q8QhVRobi3NOC6BBmaRBYw6KWsx+qL6QoQQakJZAFtlZuVYUxXzMMU+M\n" + + "vDPvszOl3cFIO3UWxrUCqriM1b86DH6f7WrkP80nzTfWG5TMlzM6zYK0rgUiTrqH\n" + + "cDMsqT+ZAgMBAAECggEAAaUVGt8v4TB+8lTqvoprQJxtp85FQLpc78+v9Tw1sU9p\n" + + "Tz5gGR6Gra6Vs4FoQnmQdRt1bQrYxZQcNY23PlNLxYrtTz4cYvCYtEf0ivP+6igI\n" + + "ZExtwEZso998VzZNB+CcTp6vSXobtTq+Lzg5SbuxeHLnG30Lr6gHBaxxbfuCbIT9\n" + + "v/+Co+og0WqSmjLNuRu0gzfbK0X4Xl/fO3yuJxIr8ofSt2FW45Q/k+JWR9FHUJyN\n" + + "BQ0AxaNg9/DlLwwP0jlsQEcSv+i8VCOp9K2TYvv75uUSeq4AujdJjdIw/j9BQpDf\n" + + "1op59uGzjNgywsUptsePIObZXID+QdrxwGIuBHgcgQKBgQD6LrMI64706qf+4Eb9\n" + + "D6fXVxlbucyo7TZn0cZG8Cf/Dr7eg7hs6kK41+ZiMB5trfJ/1d6L65sDGmb/+KTF\n" + + "AGV1FiHpyx9hvGoIupEBEyeS7pH10eSk69THWrAgKW60Xeve1oCsRin+B9UwYtRz\n" + + "NL8o/+9W54yqLaRgeD7sRaETMQKBgQC81T25vssikzBSkrHCacYig5JCXmTce9NU\n" + + "L5BZzuCv5zWXRI95Q7FmsqlFY2BsByI1uiwxZJiEOj8IWjjxvd1CNj1ByQd7B8Sb\n" + + "ALQHetdel/D51mrbV1OyMdNsDuZJu7NiwDV92aVNiiKmTE6epP81qkFpwLQ19XQe\n" + + "YFx85flI6QKBgQDTSWVCf034YcUHZ/oL9pDVOGXeJYhGki+EdpFxj5j3u0hPPAch\n" + + "VKaM3Slgeyr3jhRjCggtOwlrEX0zaJYfGjqVK9/wRu91513ViVq1AaxGVt1GMcFb\n" + + "1x+YTWq5fsRT544wYA/Dbm5Ab/UILC8oLL/UrHFBf8Q4ZNuR7XuWpydlwQKBgBeZ\n" + + "FnOl8kDJ4BoRlwFSsp4Rjy+YGEatesVkhEeU4ONao4nZ2Ywv93V8EkdHmf8mDRJl\n" + + "x6wMhDrSBJqIm+Ep9wKVQKZ99t9bIyizt8vPgCakGks+jnAGw8DbFS7F1eWU/V/z\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" + + "6DHWbgI1hfX8/y8pKHJkkyXn\n" + + "-----END PRIVATE KEY-----\n"; + + Map parameters = new HashMap<>(); + parameters.put("category", "linear"); + parameters.put("symbol", "BTCUSDT"); + parameters.put("side", "Buy"); + parameters.put("positionIdx", 0); + parameters.put("orderType", "Limit"); + parameters.put("qty", "0.001"); + parameters.put("price", "18900"); + parameters.put("timeInForce", "GTC"); + + String jsonPayload = JSON.toJSONString(parameters); + String plainText = TIMESTAMP + API_KEY + RECV_WINDOW + jsonPayload; + String signature = generateSignature(keyPem, plainText); + + OkHttpClient client = new OkHttpClient.Builder().build(); MediaType mediaType = MediaType.parse("application/json"); Request request = new Request.Builder() .url("https://api-testnet.bybit.com/v5/order/create") - .post(RequestBody.create(mediaType, jsonMap)) + .post(RequestBody.create(mediaType, jsonPayload)) .addHeader("X-BAPI-API-KEY", API_KEY) .addHeader("X-BAPI-SIGN", signature) .addHeader("X-BAPI-TIMESTAMP", TIMESTAMP) @@ -98,78 +89,60 @@ public void placeOrder(){ .build(); System.out.println(request.headers()); System.out.println(request); + Call call = client.newCall(request); try { Response response = call.execute(); assert response.body() != null; System.out.println(response.body().string()); - }catch (IOException e){ - e.printStackTrace(); + } catch (IOException exception) { + exception.printStackTrace(); } } - /** - * GET: query unfilled order - */ public void getOpenOrder() { - Map map = new HashMap<>(); - - map.put("category","linear"); - map.put("symbol", "BTCUSDT"); - map.put("settleCoin", "USDT"); + Map parameters = new HashMap<>(); + parameters.put("category", "linear"); + parameters.put("symbol", "BTCUSDT"); + parameters.put("settleCoin", "USDT"); - StringBuilder sb = genQueryStr(map); + StringBuilder queryString = generateQueryString(parameters); + String plainText = TIMESTAMP + API_KEY + RECV_WINDOW + queryString; + String signature = generateSignature("/Users/xxxx/xxxxxx.pem", plainText); - String plainText = TIMESTAMP + API_KEY + RECV_WINDOW + sb; - - String signature = genSignature("/Users/xxxx/xxxxxx.pem", plainText); - - OkHttpClient client = new OkHttpClient().newBuilder().build(); + OkHttpClient client = new OkHttpClient.Builder().build(); Request request = new Request.Builder() - .url("https://api-testnet.bybit.com/v5/order/realtime?" + sb) + .url("https://api-testnet.bybit.com/v5/order/realtime?" + queryString) .get() .addHeader("X-BAPI-API-KEY", API_KEY) .addHeader("X-BAPI-SIGN", signature) .addHeader("X-BAPI-TIMESTAMP", TIMESTAMP) .addHeader("X-BAPI-RECV-WINDOW", RECV_WINDOW) .build(); + Call call = client.newCall(request); try { Response response = call.execute(); assert response.body() != null; System.out.println(response.body().string()); - }catch (IOException e){ - e.printStackTrace(); + } catch (IOException exception) { + exception.printStackTrace(); } } - /** - * To generate query string for GET requests - * @param map - * @return - */ - private static StringBuilder genQueryStr(Map map) { - Set keySet = map.keySet(); - Iterator iter = keySet.iterator(); - StringBuilder sb = new StringBuilder(); - while (iter.hasNext()) { - String key = iter.next(); - sb.append(key) - .append("=") - .append(map.get(key)) - .append("&"); + private static StringBuilder generateQueryString(Map parameters) { + Set keySet = parameters.keySet(); + Iterator iterator = keySet.iterator(); + StringBuilder query = new StringBuilder(); + while (iterator.hasNext()) { + String key = iterator.next(); + query.append(key).append("=").append(parameters.get(key)).append("&"); } - sb.deleteCharAt(sb.length() - 1); - return sb; + query.deleteCharAt(query.length() - 1); + return query; } - /** - * - * @param privateKey: either absolute pem path or original private key pem string - * @param data: plain text - * @return - */ - private String genSignature(String privateKey, String data) { + private String generateSignature(String privateKey, String data) { RSAPrivateKey rsaPrivateKey; try { String privateKeyPem = privateKey; @@ -177,35 +150,32 @@ private String genSignature(String privateKey, String data) { privateKeyPem = new String(Files.readAllBytes(Paths.get(privateKey))); } rsaPrivateKey = parsePrivateKey(privateKeyPem); - } catch (IOException e) { - throw new RuntimeException("Unable to find/read private key at given file path", e); - } catch (Exception e) { - throw new RuntimeException("Failed to parse RSA private key", e); + } catch (IOException exception) { + throw new RuntimeException("Unable to find/read private key at given file path", exception); + } catch (Exception exception) { + throw new RuntimeException("Failed to parse RSA private key", exception); } + try { Signature sha256Sign = Signature.getInstance("SHA256withRSA"); sha256Sign.initSign(rsaPrivateKey); sha256Sign.update(data.getBytes()); - byte[] signature = sha256Sign.sign(); - return Base64.getEncoder().encodeToString(signature); - } catch (Exception e) { + } catch (Exception exception) { throw new RuntimeException("Failed to calculate rsa-sha256"); } } private RSAPrivateKey parsePrivateKey(String privateKeyPem) throws Exception { - // Private key in PKCS#8 standard String parsedPem = privateKeyPem.replace("\n", "").trim(); parsedPem = parsedPem .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", ""); byte[] encoded = Base64.getDecoder().decode(parsedPem); - PKCS8EncodedKeySpec encodedKeySpec; - encodedKeySpec = new PKCS8EncodedKeySpec(encoded); - KeyFactory kf = KeyFactory.getInstance("RSA"); - return (RSAPrivateKey) kf.generatePrivate(encodedKeySpec); + PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(encoded); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return (RSAPrivateKey) keyFactory.generatePrivate(encodedKeySpec); } } diff --git a/V5_demo/api_demo/Encryption_RSA.py b/V5_demo/api_demo/Encryption_RSA.py index daa70a8..90b6998 100644 --- a/V5_demo/api_demo/Encryption_RSA.py +++ b/V5_demo/api_demo/Encryption_RSA.py @@ -1,45 +1,44 @@ -import requests +import base64 +import json import time -import hashlib import uuid -from Crypto.Hash import SHA256 # install pycryptodome libaray -from Crypto.Signature import PKCS1_v1_5 + +import requests +from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA -import base64 +from Crypto.Signature import PKCS1_v1_5 + +API_KEY = "XXXXXXXXXX" +RSA_PRIVATE_KEY_PATH = "/Users/XXXXXXXXXX/private.pem" -api_key='XXXXXXXXXX' -rsa_private_key_path = '/Users/XXXXXXXXXX/private.pem' # use absolute path +HTTP_CLIENT = requests.Session() +RECV_WINDOW = str(5000) +URL = "https://api-testnet.bybit.com" -httpClient=requests.Session() -recv_window=str(5000) -url="https://api-testnet.bybit.com" # Testnet endpoint -def HTTP_Request(endPoint,method,payload,Info): +def http_request(endpoint, method, payload, info): global time_stamp - time_stamp=str(int(time.time() * 10 ** 3)) - signature=genSignature(payload, rsa_private_key_path) + time_stamp = str(int(time.time() * 10 ** 3)) + signature = gen_signature(payload, RSA_PRIVATE_KEY_PATH) headers = { - 'X-BAPI-API-KEY': api_key, - 'X-BAPI-SIGN': signature, - 'X-BAPI-SIGN-TYPE': '2', - 'X-BAPI-TIMESTAMP': time_stamp, - 'X-BAPI-RECV-WINDOW': recv_window, - 'Content-Type': 'application/json' + "X-BAPI-API-KEY": API_KEY, + "X-BAPI-SIGN": signature, + "X-BAPI-SIGN-TYPE": "2", + "X-BAPI-TIMESTAMP": time_stamp, + "X-BAPI-RECV-WINDOW": RECV_WINDOW, + "Content-Type": "application/json", } - if(method=="POST"): - response = httpClient.request(method, url+endPoint, headers=headers, data=payload) + if method == "POST": + response = HTTP_CLIENT.request(method, URL + endpoint, headers=headers, data=payload) else: - response = httpClient.request(method, url+endPoint+"?"+payload, headers=headers) + response = HTTP_CLIENT.request(method, URL + endpoint + "?" + payload, headers=headers) print(response.text) print(response.status_code) - print(Info + " Elapsed Time : " + str(response.elapsed)) + print(info + " Elapsed Time : " + str(response.elapsed)) -""" -Load private_key.pem, then generate base64 signature -""" -def genSignature(payload, rsa_private_key_path): - param_str= str(time_stamp) + api_key + recv_window + payload +def gen_signature(payload, rsa_private_key_path): + param_str = str(time_stamp) + API_KEY + RECV_WINDOW + payload with open(rsa_private_key_path, "r") as private_key_obj: private_key_str = private_key_obj.read() @@ -49,21 +48,38 @@ def genSignature(payload, rsa_private_key_path): return base64.b64encode(signature).decode() -#Create Order -endpoint="/v5/order/create" -method="POST" -orderLinkId=uuid.uuid4().hex -params='{"category":"linear","symbol": "BTCUSDT","side": "Buy","positionIdx": 0,"orderType": "Limit","qty": "0.001","price": "10000","timeInForce": "GTC","orderLinkId": "' + orderLinkId + '"}' -HTTP_Request(endpoint,method,params,"Create") +endpoint = "/v5/order/create" +method = "POST" +order_link_id = uuid.uuid4().hex +params = json.dumps( + { + "category": "linear", + "symbol": "BTCUSDT", + "side": "Buy", + "positionIdx": 0, + "orderType": "Limit", + "qty": "0.001", + "price": "10000", + "timeInForce": "GTC", + "orderLinkId": order_link_id, + }, + separators=(",", ":"), +) +http_request(endpoint, method, params, "Create") -#Get unfilled Orders -endpoint="/v5/order/realtime" -method="GET" -params='category=linear&settleCoin=USDT' -HTTP_Request(endpoint,method,params,"UnFilled") +endpoint = "/v5/order/realtime" +method = "GET" +params = "category=linear&settleCoin=USDT" +http_request(endpoint, method, params, "UnFilled") -#Cancel Order -endpoint="/v5/order/cancel" -method="POST" -params='{"category":"linear","symbol": "BTCUSDT","orderLinkId": "'+orderLinkId+'"}' -HTTP_Request(endpoint,method,params,"Cancel") +endpoint = "/v5/order/cancel" +method = "POST" +params = json.dumps( + { + "category": "linear", + "symbol": "BTCUSDT", + "orderLinkId": order_link_id, + }, + separators=(",", ":"), +) +http_request(endpoint, method, params, "Cancel") diff --git a/V5_demo/api_demo/comparePubPrvTrd.py b/V5_demo/api_demo/comparePubPrvTrd.py index 1104849..e54ae8f 100644 --- a/V5_demo/api_demo/comparePubPrvTrd.py +++ b/V5_demo/api_demo/comparePubPrvTrd.py @@ -1,36 +1,30 @@ -import numpy as np -import os -import threading import hashlib import hmac import json -import logging -import logging.config -import logging.handlers +import threading import time -from pybit import HTTP from datetime import datetime from random import randrange -from functools import reduce -import re + import requests -import sys -apiKey='xxxx' -apiSecret='xxxx' -session=requests.Session() -URL="https://api-testnet.bybit.com" -WssURL="wss://stream-testnet.bybit.com" -topic="execution" -symbol="BTCUSDT" -topicPub="publicTrade."+symbol -wssResp={} -wssResp['responseHeaders']={} -tradeResults={} -tradePublicResults={} import websocket from urllib3.connection import HTTPConnection -HTTPConnection.debuglevel=0 + +API_KEY = "xxxx" +API_SECRET = "xxxx" +SESSION = requests.Session() +URL = "https://api-testnet.bybit.com" +WSS_URL = "wss://stream-testnet.bybit.com" +TOPIC = "execution" +SYMBOL = "BTCUSDT" +TOPIC_PUBLIC = "publicTrade." + SYMBOL +TRADE_RESULTS = {} +TRADE_PUBLIC_RESULTS = {} + +HTTPConnection.debuglevel = 0 + + def getresponse(self, *args, **kwargs): response = self._old_getresponse(*args, **kwargs) if self.sock: @@ -43,145 +37,183 @@ def getresponse(self, *args, **kwargs): HTTPConnection._old_getresponse = HTTPConnection.getresponse HTTPConnection.getresponse = getresponse -orderStatus={} -orderStatus['init']=False -orderStatus['results']={} -orderStatus['subtasks']=[] - -def placePubUSDTOrder(payload,timeStamp,orderLinkId): - url=URL+"/v5/order/create" - dataObj=json.loads(payload) - recv_window=str(5000) - param_str= str(timeStamp) + apiKey + recv_window + payload - hash = hmac.new(bytes(apiSecret, "utf-8"), param_str.encode("utf-8"),hashlib.sha256) - signature = hash.hexdigest() +ORDER_STATUS = {"init": False, "results": {}, "subtasks": []} + + +def place_public_usdt_order(payload, time_stamp, order_link_id): + url = URL + "/v5/order/create" + recv_window = str(5000) + param_str = str(time_stamp) + API_KEY + recv_window + payload + signature_hash = hmac.new( + bytes(API_SECRET, "utf-8"), + param_str.encode("utf-8"), + hashlib.sha256, + ) + signature = signature_hash.hexdigest() headers = { - 'X-BAPI-API-KEY': apiKey, - 'X-BAPI-SIGN': signature, - 'X-BAPI-SIGN-TYPE': '2', - 'X-BAPI-TIMESTAMP': str(timeStamp), - 'X-BAPI-RECV-WINDOW': recv_window, - 'cdn-request-id': orderLinkId, - 'Content-Type': 'application/json' + "X-BAPI-API-KEY": API_KEY, + "X-BAPI-SIGN": signature, + "X-BAPI-SIGN-TYPE": "2", + "X-BAPI-TIMESTAMP": str(time_stamp), + "X-BAPI-RECV-WINDOW": recv_window, + "cdn-request-id": order_link_id, + "Content-Type": "application/json", } - orderStatus['results'][orderLinkId]={} - orderStatus['results'][orderLinkId]['orderPlaceTime']=timeStamp - response = session.request("POST", url, headers=headers, data=payload) - orderStatus['results'][orderLinkId]['Traceid']=response.headers["Traceid"] - orderStatus['results'][orderLinkId]['elapsed']=int(response.elapsed.microseconds/1000) + ORDER_STATUS["results"][order_link_id] = {} + ORDER_STATUS["results"][order_link_id]["orderPlaceTime"] = time_stamp + response = SESSION.request("POST", url, headers=headers, data=payload) + ORDER_STATUS["results"][order_link_id]["Traceid"] = response.headers["Traceid"] + ORDER_STATUS["results"][order_link_id]["elapsed"] = int(response.elapsed.microseconds / 1000) + + +def place_order(side): + current_time = int(time.time() * 1000) + order_link_id = str(current_time) + "AK" + str(randrange(1000, 9999)) + payload = json.dumps( + { + "category": "linear", + "symbol": SYMBOL, + "side": side, + "positionIdx": 0, + "orderType": "Market", + "qty": "0.001", + "orderLinkId": order_link_id, + } + ) + place_public_usdt_order(payload, current_time, order_link_id) -def placeOrder(side): - currentTime=int(time.time()*1000) - orderLinkId=str(currentTime)+'AK'+str(randrange(1000,9999)) - placePubUSDTOrder(json.dumps({"category":"linear","symbol": symbol,"side": side,"positionIdx": 0,"orderType": "Market","qty": "0.001","orderLinkId": orderLinkId}),currentTime,orderLinkId) def on_message(ws, message): - ts=int(time.time()*1000) + ts = int(time.time() * 1000) data = json.loads(message) - if 'success' in data and data['success'] and data['ret_msg'] == "" and not orderStatus['init']: - orderStatus["conn_id"]=data["conn_id"] + if "success" in data and data["success"] and data["ret_msg"] == "" and not ORDER_STATUS["init"]: + ORDER_STATUS["conn_id"] = data["conn_id"] print("starting to place orders") - x=threading.Thread(target=loopPlaceOrder,args=()) - orderStatus['subtasks'].append(x) - x.start() - orderStatus['init']=True - elif 'topic' in data and data['topic'] == topic and 'data' in data and data['data'][0]['orderLinkId'] in orderStatus["results"]: - tradeResults[data['data'][0]['execId']]={} - tradeResults[data['data'][0]['execId']]["privateTS"]=ts - if data['data'][0]['execId'] in tradePublicResults: - tradeResults[data['data'][0]['execId']]["publicTS"]=tradePublicResults[data['data'][0]['execId']] - -def on_messagePub(ws, message): - ts=int(time.time()*1000) + thread = threading.Thread(target=loop_place_order, args=()) + ORDER_STATUS["subtasks"].append(thread) + thread.start() + ORDER_STATUS["init"] = True + elif ( + "topic" in data + and data["topic"] == TOPIC + and "data" in data + and data["data"][0]["orderLinkId"] in ORDER_STATUS["results"] + ): + TRADE_RESULTS[data["data"][0]["execId"]] = {} + TRADE_RESULTS[data["data"][0]["execId"]]["privateTS"] = ts + if data["data"][0]["execId"] in TRADE_PUBLIC_RESULTS: + TRADE_RESULTS[data["data"][0]["execId"]]["publicTS"] = TRADE_PUBLIC_RESULTS[ + data["data"][0]["execId"] + ] + + +def on_message_public(ws, message): + ts = int(time.time() * 1000) data = json.loads(message) - currentTime=int(time.time()*1000) - if "topic" in data and data["topic"]==topicPub: + if "topic" in data and data["topic"] == TOPIC_PUBLIC: for trade in data["data"]: - tradePublicResults[trade["i"]]=ts - if trade["i"] in tradeResults: - tradeResults[trade["i"]]["publicTS"]=ts + TRADE_PUBLIC_RESULTS[trade["i"]] = ts + if trade["i"] in TRADE_RESULTS: + TRADE_RESULTS[trade["i"]]["publicTS"] = ts + def on_error(ws, error): - print('we got error') - print("the type is "+type(error).__name__) + print("we got error") + print("the type is " + type(error).__name__) + def on_close(ws): print("### about to close please don't close ###") + def send_auth(ws): - expires=int((time.time() + 1) * 1000) - _val = f'GET/realtime{expires}' + expires = int((time.time() + 1) * 1000) + value = f"GET/realtime{expires}" signature = str(hmac.new( - bytes(apiSecret, 'utf-8'), - bytes(_val, 'utf-8'), digestmod='sha256' + bytes(API_SECRET, "utf-8"), + bytes(value, "utf-8"), + digestmod="sha256", ).hexdigest()) - ws.send(json.dumps({"op":"auth","args":[apiKey,expires,signature]})) + ws.send(json.dumps({"op": "auth", "args": [API_KEY, expires, signature]})) + def on_open(ws): - print('opened') + print("opened") send_auth(ws) - print('send topic') - ws.send(json.dumps({"op": "subscribe", "args": [topic]})) + print("send topic") + ws.send(json.dumps({"op": "subscribe", "args": [TOPIC]})) + + +def on_open_public(ws): + print("opened") + print("send subscription " + TOPIC_PUBLIC) + ws.send(json.dumps({"op": "subscribe", "args": [TOPIC_PUBLIC]})) -def on_openPub(ws): - print('opened') - print('send subscription ' + topicPub) - ws.send(json.dumps({"op": "subscribe", "args": [topicPub]})) def on_pong(ws, *data): - print('pong received') + print("pong received") + def on_ping(ws, *data): now = datetime.now() dt_string = now.strftime("%d/%m/%Y %H:%M:%S") print("date and time =", dt_string) - print('ping received') + print("ping received") -def loopPlaceOrder(): + +def loop_place_order(): while True: for i in range(10): - if i%2==0: - placeOrder("Buy") - elif i%2==1: - placeOrder("Sell") + if i % 2 == 0: + place_order("Buy") + elif i % 2 == 1: + place_order("Sell") time.sleep(1) - for tradeId in tradeResults: - print(tradeId+":private-public="+str(tradeResults[tradeId]["privateTS"]-tradeResults[tradeId]["publicTS"])) - -def connWs(): - ws = websocket.WebSocketApp(WssURL+"/v5/private", - on_message = on_message, - on_error = on_error, - on_close = on_close, + for trade_id in TRADE_RESULTS: + print( + trade_id + + ":private-public=" + + str(TRADE_RESULTS[trade_id]["privateTS"] - TRADE_RESULTS[trade_id]["publicTS"]) + ) + + +def connect_ws(): + ws = websocket.WebSocketApp( + WSS_URL + "/v5/private", + on_message=on_message, + on_error=on_error, + on_close=on_close, on_ping=on_ping, on_pong=on_pong, - on_open=on_open + on_open=on_open, ) ws.run_forever( ping_interval=15, - ping_timeout=10 + ping_timeout=10, ) -def connWsPub(): - ws = websocket.WebSocketApp(WssURL+"/v5/public/linear", - on_message=on_messagePub, + +def connect_ws_public(): + ws = websocket.WebSocketApp( + WSS_URL + "/v5/public/linear", + on_message=on_message_public, on_error=on_error, on_close=on_close, on_ping=on_ping, on_pong=on_pong, - on_open=on_openPub + on_open=on_open_public, ) ws.run_forever( ping_interval=15, - ping_timeout=10 + ping_timeout=10, ) + if __name__ == "__main__": websocket.enableTrace(True) - x=threading.Thread(target=connWsPub,args=()) - y=threading.Thread(target=connWs,args=()) - x.start() + public_thread = threading.Thread(target=connect_ws_public, args=()) + private_thread = threading.Thread(target=connect_ws, args=()) + public_thread.start() time.sleep(1) - y.start() + private_thread.start() time.sleep(3) - #print(tradeResults[tradeId]["privateTS"]-tradeResults[tradeId]["publicTS"])