Mã ví dụ cho API REST và WebSocket C#

Cập nhật lần cuối: 2 thg 4, 2025

Giới thiệu

Dưới đây là một tập lệnh ví dụ C# có thể được tham chiếu cho cả triển khai RESTWebSocket của API Kraken.

Nó trình bày các chức năng sau:

  • Điểm cuối API REST công khai

  • Điểm cuối API REST riêng tư

  • Đăng ký API WebSocket công khai

  • Đăng ký API WebSocket riêng tư

Cài đặt

Để chạy cục bộ, bạn có thể sao chép/dán mã bên dưới.

Lưu ý rằng việc đặt câu lệnh if từ 1 == 0 thành 1 == 1 sẽ thực thi khối mã cụ thể.

Trước khi chạy tập lệnh, bạn cần cập nhật tập lệnh bằng Khóa API Công khai và Riêng tư của bạn.

Bạn có thể tải xuống tệp này tại đây.

Mã C#

bash

Bash

using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace KrakenCSharpExampleConsole
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // TODO: UPDATE WITH YOUR KEYS :)
            string apiPublicKey = "YOUR_PUBLIC_KEY";
            string apiPrivateKey = "YOUR_PRIVATE_KEY";

            try
            {
                System.Console.WriteLine("|=========================================|");
                System.Console.WriteLine("|         KRAKEN.COM C# TEST APP          |");
                System.Console.WriteLine("|=========================================|");
                System.Console.WriteLine();

                #region Public REST API Examples

                if (1 == 0)
                {
                    string publicResponse = "";

                    string publicEndpoint = "SystemStatus";
                    string publicInputParameters = "";

                    // MORE PUBLIC REST EXAMPLES
                    // *

                    // string publicEndpoint = "AssetPairs";
                    // string publicInputParameters = "pair=ethusd,xbtusd";

                    // string publicEndpoint = "Ticker";
                    // string publicInputParameters = "pair=ethusd";

                    // string publicEndpoint = "Trades";
                    // string publicInputParameters = "pair=ethusd&since=0";

                    // *

                    publicResponse = await QueryPublicEndpoint(publicEndpoint, publicInputParameters);
                    System.Console.WriteLine(publicResponse);
                }

                #endregion

                #region Private REST API Examples

                if (1 == 0)
                {
                    string privateResponse = "";

                    string privateEndpoint = "Balance";
                    string privateInputParameters = "";

                    // MORE PRIVATE REST EXAMPLES
                    // *

                    // string privateEndpoint = "AddOrder";
                    // string privateInputParameters = "pair=xbteur&type=buy&ordertype=limit&price=1.00&volume=1";

                    // string privateEndpoint = "AddOrder";
                    // string privateInputParameters = "pair=xdgeur&type=sell&ordertype=limit&volume=3000&price=%2b10.0%"; // Positive Percentage Example

                    // string privateEndpoint = "AddOrder";
                    // string privateInputParameters = "pair=xdgeur&type=sell&ordertype=limit&volume=3000&price=-10.0%"; // Negative Percentage Example

                    // string privateEndpoint = "AddOrder";
                    // string privateInputParameters = "pair=xdgeur&type=buy&ordertype=market&volume=3000&userref=789"; // Userref Example

                    // string privateEndpoint = "Balance";
                    // string privateInputParameters = ""; //{"error":[]} IS SUCCESS, Means EMPTY BALANCE

                    // string privateEndpoint = "QueryOrders";
                    // string privateInputParameters = "txid=OFUSL6-GXIIT-KZ2JDJ";

                    // string privateEndpoint = "AddOrder";
                    // string privateInputParameters = "pair=xdgusd&type=buy&ordertype=market&volume=5000";

                    // string privateEndpoint = "DepositAddresses";
                    // string privateInputParameters = "asset=xbt&method=Bitcoin";

                    // string privateEndpoint = "DepositMethods";
                    // string privateInputParameters = "asset=eth";

                    // string privateEndpoint = "WalletTransfer";
                    // string privateInputParameters = "asset=xbt&to=Futures Wallet&from=Spot Wallet&amount=0.0045";

                    // string privateEndpoint = "TradesHistory";
                    // string privateInputParameters = "start=1577836800&end=1609459200";

                    // string privateEndpoint = "GetWebSocketsToken";
                    // string privateInputParameters = "";

                    // *

                    privateResponse = await QueryPrivateEndpoint(privateEndpoint, privateInputParameters, apiPublicKey, apiPrivateKey);
                    System.Console.WriteLine(privateResponse);
                }

                #endregion

                #region Public WebSocket API Examples

                if (1 == 0)
                {
                    string publicWebSocketURL = "wss://ws.kraken.com/";
                    string publicWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"ticker\"}, \"pair\": [ \"XBT/EUR\",\"ETH/USD\" ]}";

                    // MORE PUBLIC WEBSOCKET EXAMPLES
                    // *

                    // string publicWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"interval\": 1440, \"name\": \"ohlc\"}, \"pair\": [ \"XBT/EUR\"]}";

                    // string publicWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"spread\"}, \"pair\": [ \"XBT/EUR\",\"ETH/USD\" ]}";

                    // *

                    await OpenAndStreamWebSocketSubscription(publicWebSocketURL, publicWebSocketSubscriptionMsg);
                }

                #endregion

                #region Private WebSocket API Examples

                if (1 == 0)
                {
                    string privateWebSocketURL = "wss://ws-auth.kraken.com/";

                    // GET AND EXTRACT THE WEBSOCKET TOKEN FROM THE JSON RESPONSE
                    string webSocketRestResponseJSON = await QueryPrivateEndpoint("GetWebSocketsToken", "", apiPublicKey, apiPrivateKey);

                    var splits = webSocketRestResponseJSON.Split(new string[] { "\"token\":\"", "\"}}" }, StringSplitOptions.None);
                    string webSocketToken = splits[1];

                    string privateWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"ownTrades\", \"token\": \"#TOKEN#\"}}";

                    // MORE PRIVATE WEBSOCKET EXAMPLES
                    // *

                    // #TOKEN# IS A PLACEHOLDER

                    // string privateWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"openOrders\", \"token\": \"#TOKEN#\"}}";

                    // string privateWebSocketSubscriptionMsg = "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"balances\", \"token\": \"#TOKEN#\"}}";

                    // string addOrderExample = "{\"event\":\"addOrder\",\"reqid\":1234,\"ordertype\":\"limit\",\"pair\":\"XBT/EUR\",\"token\":\"#TOKEN#\",\"type\":\"buy\",\"volume\":\"1\", \"price\":\"1.00\"}";

                    // *

                    // REPLACE PLACEHOLDER WITH TOKEN
                    privateWebSocketSubscriptionMsg = privateWebSocketSubscriptionMsg.Replace("#TOKEN#", webSocketToken);
                    await OpenAndStreamWebSocketSubscription(privateWebSocketURL, privateWebSocketSubscriptionMsg);
                }

                #endregion

                System.Console.WriteLine();
                System.Console.WriteLine("|=========================================|");
                System.Console.WriteLine("|      END OF PROGRAM, HAVE A NICE DAY :) |");
                System.Console.WriteLine("|=========================================|");
                System.Console.WriteLine();
            }
            catch (Exception e)
            {
                System.Console.WriteLine();
                System.Console.WriteLine("AN EXCEPTION OCCURRED :(");
                System.Console.WriteLine(e.ToString());
            }
        }

        #region Public REST API Endpoints

        private static async Task<string> QueryPublicEndpoint(string endpointName, string inputParameters)
        {
            string jsonData;
            string baseDomain = "https://api.kraken.com";
            string publicPath = "/0/public/";
            string apiEndpointFullURL = baseDomain + publicPath + endpointName + "?" + inputParameters;

            using (HttpClient client = new HttpClient())
            {
                jsonData = await client.GetStringAsync(apiEndpointFullURL);
            }
            return jsonData;
        }

        #endregion

        #region Private REST API Endpoints

        private static async Task<string> QueryPrivateEndpoint(string endpointName, string inputParameters, string apiPublicKey, string apiPrivateKey)
        {
            string baseDomain = "https://api.kraken.com";
            string privatePath = "/0/private/";

            string apiEndpointFullURL = baseDomain + privatePath + endpointName;
            string nonce = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
            if (!string.IsNullOrWhiteSpace(inputParameters))
            {
                inputParameters = "&" + inputParameters;
            }
            string apiPostBodyData = "nonce=" + nonce + inputParameters;
            string signature = CreateAuthenticationSignature(apiPrivateKey, privatePath, endpointName, nonce, inputParameters);

            string jsonData;
            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add("API-Key", apiPublicKey);
                client.DefaultRequestHeaders.Add("API-Sign", signature);
                client.DefaultRequestHeaders.Add("User-Agent", "KrakenDotNet Client");

                StringContent data = new StringContent(apiPostBodyData, Encoding.UTF8, "application/x-www-form-urlencoded");
                HttpResponseMessage response = await client.PostAsync(apiEndpointFullURL, data);
                jsonData = response.Content.ReadAsStringAsync().Result;
            }
            return jsonData;
        }

        #endregion

        #region Authentication Algorithm

        public static string CreateAuthenticationSignature(string apiPrivateKey, string apiPath, string endpointName, string nonce, string inputParams)
        {
            byte[] sha256Hash = ComputeSha256Hash(nonce, inputParams);
            byte[] sha512Hash = ComputeSha512Hash(apiPrivateKey, sha256Hash, apiPath, endpointName, nonce, inputParams);
            string signatureString = Convert.ToBase64String(sha512Hash);
            return signatureString;
        }

        private static byte[] ComputeSha256Hash(string nonce, string inputParams)
        {
            byte[] sha256Hash;
            string sha256HashData = nonce.ToString() + "nonce=" + nonce.ToString() + inputParams;

            using (var sha = SHA256.Create())
            {
                sha256Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(sha256HashData));
            }
            return sha256Hash;
        }

        private static byte[] ComputeSha512Hash(string apiPrivateKey, byte[] sha256Hash, string apiPath, string endpointName, string nonce, string inputParams)
        {
            string apiEndpointPath = apiPath + endpointName;
            byte[] apiEndpointPathBytes = Encoding.UTF8.GetBytes(apiEndpointPath);
            byte[] sha512HashData = apiEndpointPathBytes.Concat(sha256Hash).ToArray();
            HMACSHA512 encryptor = new HMACSHA512(Convert.FromBase64String(apiPrivateKey));
            byte[] sha512Hash = encryptor.ComputeHash(sha512HashData);
            return sha512Hash;
        }

        #endregion

        #region WebSocket API

        private static async Task OpenAndStreamWebSocketSubscription(string connectionURL, string webSocketSubscription)
        {
            try
            {
                ClientWebSocket webSocketClient = new ClientWebSocket();
                CancellationTokenSource stoppingToken = new CancellationTokenSource();

                // OPEN CONNECTION
                await webSocketClient.ConnectAsync(new Uri(connectionURL), CancellationToken.None);
                System.Console.WriteLine("WEBSOCKET CONNECTION OPEN!");

                // SEND SUBSCRIPTION MESSAGE
                System.Console.WriteLine("WEBSOCKET SUBSCRIPTION MESSAGE:");
                System.Console.WriteLine(webSocketSubscription);
                if (webSocketClient.State == WebSocketState.Open)
                {
                    await webSocketClient.SendAsync(Encoding.UTF8.GetBytes(webSocketSubscription), WebSocketMessageType.Text, true, stoppingToken.Token);
                }

                // RECEIVE AND PRINT MESSAGE
                do
                {
                    await ReceiveMessage(webSocketClient, stoppingToken.Token);
                } while (webSocketClient.State == WebSocketState.Open);

                // CLOSE CONNECTION
                await webSocketClient.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", stoppingToken.Token);
            }
            catch (OperationCanceledException)
            {
                // DO NOTHING - ASSUME WAS REQUESTED
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static async Task ReceiveMessage(ClientWebSocket socket, CancellationToken stoppingToken)
        {
            var buffer = new ArraySegment<byte>(new byte[2048]);
            while (!stoppingToken.IsCancellationRequested)
            {
                WebSocketReceiveResult result;
                using (var ms = new MemoryStream())
                {
                    do
                    {
                        result = await socket.ReceiveAsync(buffer, stoppingToken);
                        ms.Write(buffer.Array, buffer.Offset, result.Count);
                    } while (!result.EndOfMessage);

                    if (result.MessageType == WebSocketMessageType.Close)
                    {
                        break;
                    }

                    string wsMsg = "";
                    ms.Seek(0, SeekOrigin.Begin);
                    using (var reader = new StreamReader(ms, Encoding.UTF8))
                    {
                        wsMsg = await reader.ReadToEndAsync();
                    }
                    string msgTime = DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss") + ": ";
                    System.Console.WriteLine(msgTime + wsMsg);
                }
            }
        }

        #endregion
    }
}

Bạn cần thêm trợ giúp?