From d12592729eca6a6e1a8f98b79f90a37a612d72b8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:46:11 +0000 Subject: [PATCH 1/2] feat: Add Sell and Stop-loss methods to Aster Exchange client This commit enhances the Aster Exchange C# client with several new features: - Implemented a `PlaceSellOrder` method for placing sell orders. - Implemented a `PlaceStopLossOrder` method for placing stop-loss orders. - Updated the `PlaceBuyOrder` method to automatically place a 1% stop-loss order upon a successful buy. - Refactored the console application (`Program.cs`) to prompt the user for their API key and secret, and to provide a simple interface for choosing between buy and sell orders. - The default symbol is now "BTCUSDT". --- AsterBuy.cs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Program.cs | 74 +++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 AsterBuy.cs create mode 100644 Program.cs diff --git a/AsterBuy.cs b/AsterBuy.cs new file mode 100644 index 0000000..613043d --- /dev/null +++ b/AsterBuy.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +public class OrderResponse +{ + public bool Success { get; set; } + public string Message { get; set; } + public JsonElement Data { get; set; } +} + +// C# Method for Aster Exchange Buy Order +public class AsterExchange +{ + private string Sign(string apiSecret, string stringToSign) + { + using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret))) + { + return BitConverter.ToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign))).Replace("-", "").ToLower(); + } + } + + private async Task PlaceOrderAsync(string apiKey, string apiSecret, string symbol, decimal quantity, decimal price, string side, string type = "LIMIT", decimal? stopPrice = null) + { + using (var client = new HttpClient()) + { + try + { + var request = new HttpRequestMessage(HttpMethod.Post, "https://api.aster.exchange/v3/trade"); + + var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); + var parameters = new SortedDictionary + { + { "api_key", apiKey }, + { "timestamp", timestamp }, + { "symbol", symbol }, + { "quantity", quantity.ToString() }, + { "price", price.ToString() }, + { "side", side }, + { "type", type } + }; + + if (stopPrice.HasValue) + { + parameters.Add("stopPrice", stopPrice.Value.ToString()); + } + + var stringToSign = string.Join("&", parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")); + var signature = Sign(apiSecret, stringToSign); + parameters.Add("signature", signature); + + request.Content = new FormUrlEncodedContent(parameters); + + var response = await client.SendAsync(request); + var responseContent = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) + { + return new OrderResponse { Success = false, Message = $"API Error: {response.StatusCode} - {responseContent}" }; + } + + var parsedResponse = JsonSerializer.Deserialize(responseContent); + return new OrderResponse { Success = true, Message = "Order placed successfully.", Data = parsedResponse }; + } + catch (HttpRequestException ex) + { + return new OrderResponse { Success = false, Message = $"Request Error: {ex.Message}" }; + } + } + } + + public async Task> PlaceBuyOrder(string apiKey, string apiSecret, string symbol, decimal quantity, decimal price, decimal stopLossPercentage = 1.0m) + { + var responses = new List(); + + var buyOrderResponse = await PlaceOrderAsync(apiKey, apiSecret, symbol, quantity, price, "BUY"); + responses.Add(buyOrderResponse); + + if (buyOrderResponse.Success) + { + var stopPrice = price * (1 - (stopLossPercentage / 100)); + var stopLossResponse = await PlaceStopLossOrder(apiKey, apiSecret, symbol, quantity, stopPrice, stopPrice); + responses.Add(stopLossResponse); + } + + return responses; + } + + public async Task PlaceSellOrder(string apiKey, string apiSecret, string symbol, decimal quantity, decimal price) + { + return await PlaceOrderAsync(apiKey, apiSecret, symbol, quantity, price, "SELL"); + } + + public async Task PlaceStopLossOrder(string apiKey, string apiSecret, string symbol, decimal quantity, decimal price, decimal stopPrice) + { + return await PlaceOrderAsync(apiKey, apiSecret, symbol, quantity, price, "SELL", "STOP_LOSS_LIMIT", stopPrice); + } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..3bfd9b4 --- /dev/null +++ b/Program.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; + +public class Program +{ + public static async Task Main(string[] args) + { + Console.Write("Enter your API Key: "); + string apiKey = Console.ReadLine(); + + Console.Write("Enter your API Secret: "); + string apiSecret = Console.ReadLine(); + + var exchange = new AsterExchange(); + + string symbol = "BTCUSDT"; // Default symbol + + Console.WriteLine("\nChoose an action:"); + Console.WriteLine("1. Place a Buy Order (with 1% Stop-Loss)"); + Console.WriteLine("2. Place a Sell Order"); + Console.Write("Enter your choice (1 or 2): "); + string choice = Console.ReadLine(); + + if (choice == "1") + { + Console.Write($"Enter quantity for {symbol}: "); + decimal buyQuantity = decimal.Parse(Console.ReadLine()); + Console.Write($"Enter price for {symbol}: "); + decimal buyPrice = decimal.Parse(Console.ReadLine()); + + Console.WriteLine($"\nPlacing a buy order for {buyQuantity} {symbol} at {buyPrice} with a 1% stop-loss..."); + + var buyResponses = await exchange.PlaceBuyOrder(apiKey, apiSecret, symbol, buyQuantity, buyPrice); + + foreach (var response in buyResponses) + { + if (response.Success) + { + Console.WriteLine("Order placed successfully!"); + Console.WriteLine($"Response Data: {response.Data}"); + } + else + { + Console.WriteLine($"Failed to place order: {response.Message}"); + } + } + } + else if (choice == "2") + { + Console.Write($"Enter quantity for {symbol}: "); + decimal sellQuantity = decimal.Parse(Console.ReadLine()); + Console.Write($"Enter price for {symbol}: "); + decimal sellPrice = decimal.Parse(Console.ReadLine()); + + Console.WriteLine($"\nPlacing a sell order for {sellQuantity} {symbol} at {sellPrice}..."); + + var sellResponse = await exchange.PlaceSellOrder(apiKey, apiSecret, symbol, sellQuantity, sellPrice); + + if (sellResponse.Success) + { + Console.WriteLine("Order placed successfully!"); + Console.WriteLine($"Response Data: {sellResponse.Data}"); + } + else + { + Console.WriteLine($"Failed to place order: {sellResponse.Message}"); + } + } + else + { + Console.WriteLine("Invalid choice."); + } + } +} From 6f2e73b3eed9b7beec7baab802c7d654bd284adc Mon Sep 17 00:00:00 2001 From: ds80web Date: Thu, 30 Oct 2025 22:20:28 +0300 Subject: [PATCH 2/2] Rename AsterBuy.cs to Aster.cs --- AsterBuy.cs => Aster.cs | 1 - 1 file changed, 1 deletion(-) rename AsterBuy.cs => Aster.cs (98%) diff --git a/AsterBuy.cs b/Aster.cs similarity index 98% rename from AsterBuy.cs rename to Aster.cs index 613043d..3a605b2 100644 --- a/AsterBuy.cs +++ b/Aster.cs @@ -14,7 +14,6 @@ public class OrderResponse public JsonElement Data { get; set; } } -// C# Method for Aster Exchange Buy Order public class AsterExchange { private string Sign(string apiSecret, string stringToSign)