From 3cf5480cad23db99711486afbdb71e242f65de76 Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Wed, 19 Jan 2022 22:07:22 +0100 Subject: [PATCH] Example --- .../Exchanges/BinanceExchange.cs | 50 ++++++++ Examples/ConsoleClient/Exchanges/IExchange.cs | 9 +- Examples/ConsoleClient/Models/OpenOrder.cs | 20 +++ Examples/ConsoleClient/Program.cs | 115 ++++++++++++++++-- 4 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 Examples/ConsoleClient/Models/OpenOrder.cs diff --git a/Examples/ConsoleClient/Exchanges/BinanceExchange.cs b/Examples/ConsoleClient/Exchanges/BinanceExchange.cs index c518159..a4e1865 100644 --- a/Examples/ConsoleClient/Exchanges/BinanceExchange.cs +++ b/Examples/ConsoleClient/Exchanges/BinanceExchange.cs @@ -4,11 +4,42 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Binance.Net.Clients; +using Binance.Net.Interfaces.Clients; +using ConsoleClient.Models; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Sockets; namespace ConsoleClient.Exchanges { internal class BinanceExchange : IExchange { + private IBinanceSocketClient _socketClient = new BinanceSocketClient(); + + public async Task CancelOrder(string symbol, string id) + { + using var client = new BinanceClient(); + var result = await client.SpotApi.Trading.CancelOrderAsync(symbol, long.Parse(id)); + return result.AsDataless(); + } + + public async Task> GetOpenOrders() + { + using var client = new BinanceClient(); + var result = await client.SpotApi.Trading.GetOpenOrdersAsync(); + // Should check result success status here + return result.Data.Select(o => new OpenOrder + { + Symbol = o.Symbol, + OrderSide = o.Side.ToString(), + OrderStatus = o.Status.ToString(), + OrderTime = o.CreateTime, + OrderType = o.Type.ToString(), + Price = o.Price, + Quantity = o.Quantity, + QuantityFilled = o.QuantityFilled + }); + } + public async Task GetPrice(string symbol) { using var client = new BinanceClient(); @@ -16,5 +47,24 @@ namespace ConsoleClient.Exchanges // Should check result success status here return result.Data.Price; } + + public async Task> PlaceOrder(string symbol, string side, string type, decimal quantity, decimal? price) + { + using var client = new BinanceClient(); + var result = await client.SpotApi.Trading.PlaceOrderAsync( + symbol, + side.ToLower() == "buy" ? Binance.Net.Enums.OrderSide.Buy: Binance.Net.Enums.OrderSide.Sell, + type == "market" ? Binance.Net.Enums.OrderType.Market : Binance.Net.Enums.OrderType.Limit, + quantity, + price: price, + timeInForce: type == "market" ? null: Binance.Net.Enums.TimeInForce.GoodTillCanceled); + return result.As(result.Data?.Id.ToString()); + } + + public async Task SubscribePrice(string symbol, Action handler) + { + var sub = await _socketClient.SpotStreams.SubscribeToMiniTickerUpdatesAsync(symbol, data => handler(data.Data.LastPrice)); + return sub.Data; + } } } diff --git a/Examples/ConsoleClient/Exchanges/IExchange.cs b/Examples/ConsoleClient/Exchanges/IExchange.cs index a4a3277..be0f0a8 100644 --- a/Examples/ConsoleClient/Exchanges/IExchange.cs +++ b/Examples/ConsoleClient/Exchanges/IExchange.cs @@ -1,4 +1,7 @@ -using System; +using ConsoleClient.Models; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Sockets; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,5 +12,9 @@ namespace ConsoleClient.Exchanges public interface IExchange { Task GetPrice(string symbol); + Task> GetOpenOrders(); + Task CancelOrder(string symbol, string id); + Task> PlaceOrder(string symbol, string side, string type, decimal quantity, decimal? price ); + Task SubscribePrice(string symbol, Action handler); } } diff --git a/Examples/ConsoleClient/Models/OpenOrder.cs b/Examples/ConsoleClient/Models/OpenOrder.cs new file mode 100644 index 0000000..f264e99 --- /dev/null +++ b/Examples/ConsoleClient/Models/OpenOrder.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleClient.Models +{ + public class OpenOrder + { + public string Symbol { get; set; } + public decimal Price { get; set; } + public decimal Quantity { get; set; } + public decimal QuantityFilled { get; set; } + public string OrderType { get; set; } + public string OrderStatus { get; set; } + public string OrderSide { get; set; } + public DateTime OrderTime { get; set; } + } +} diff --git a/Examples/ConsoleClient/Program.cs b/Examples/ConsoleClient/Program.cs index 96fe79a..a5cc86d 100644 --- a/Examples/ConsoleClient/Program.cs +++ b/Examples/ConsoleClient/Program.cs @@ -1,7 +1,14 @@ using System; using System.Collections.Generic; +using System.Globalization; +using System.Linq; using System.Threading.Tasks; +using Binance.Net.Clients; +using Binance.Net.Objects; using ConsoleClient.Exchanges; +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Sockets; +using Microsoft.Extensions.Logging; namespace ConsoleClient { @@ -14,22 +21,36 @@ namespace ConsoleClient static async Task Main(string[] args) { - Console.WriteLine("> Available commands: PlaceOrder, GetOrders, GetPrice"); + BinanceClient.SetDefaultOptions(new BinanceClientOptions + { + LogLevel = LogLevel.Trace, + ApiCredentials = new ApiCredentials("APIKEY", "APISECRET") + }); + while (true) { + Console.WriteLine("> Available commands: PlaceOrder, GetOpenOrders, CancelOrder, GetPrice, SubscribePrice"); var input = Console.ReadLine(); switch (input) { case "PlaceOrder": - + await ProcessPlaceOrder(); break; - case "GetOrders": - + case "GetOpenOrders": + await ProcessGetOpenOrders(); + break; + case "CancelOrder": + await ProcessCancelOrder(); break; case "GetPrice": await ProcessGetPrice(); break; + case "SubscribePrice": + var sub = await ProcessSubscribePrice(); + Console.ReadLine(); + await sub.CloseAsync(); + break; default: Console.WriteLine("> Unknown command"); break; @@ -37,16 +58,90 @@ namespace ConsoleClient } } + static async Task ProcessPlaceOrder() + { + var exchange = GetInput("Exchange?"); + var symbol = GetInput("Symbol?"); + var side = GetInput("Buy/Sell?"); + var type = GetInput("Limit/Market?"); + var quantity = GetDecimalInput("Quantity?"); + decimal? price = null; + if (type != "Market") + price = GetDecimalInput("Price?"); + var result = await _exchanges[exchange].PlaceOrder(symbol, side, type, quantity, price); + if (result.Success) + Console.WriteLine("Order placed, ID: " + result.Data); + else + Console.WriteLine("Failed to place order: " + result.Error); + } + + static async Task ProcessGetOpenOrders() + { + var exchange = GetInput("Exchange?"); + Console.WriteLine("Requesting open orders..."); + var orders = await _exchanges[exchange].GetOpenOrders(); + if (!orders.Any()) + Console.WriteLine("No open orders found"); + else + { + foreach(var openOrder in orders) + Console.WriteLine($"> {openOrder.OrderTime} - {openOrder.Symbol} {openOrder.OrderType} {openOrder.OrderSide} {openOrder.QuantityFilled}/{openOrder.Quantity} @ {openOrder.Price}"); + } + } + + static async Task ProcessCancelOrder() + { + var exchange = GetInput("Exchange?"); + var symbol = GetInput("Symbol?"); + var id = GetInput("Order id?"); + var result = await _exchanges[exchange].CancelOrder(symbol, id); + if (result) + Console.WriteLine("Order canceled"); + else + Console.WriteLine("Order cancel failed: " + result.Error); + } + static async Task ProcessGetPrice() { - Console.WriteLine("> Exchange?"); - var exchange = Console.ReadLine(); - - Console.WriteLine("> Symbol?"); - var symbol = Console.ReadLine(); - + var exchange = GetInput("Exchange?"); + var symbol = GetInput("Symbol?"); + Console.WriteLine("Requesting price..."); var price = await _exchanges[exchange].GetPrice(symbol); Console.WriteLine($"> {exchange} price for {symbol}: {price}"); } + + static async Task ProcessSubscribePrice() + { + var exchange = GetInput("Exchange?"); + var symbol = GetInput("Symbol?"); + Console.WriteLine("Subscribing price..."); + return await _exchanges[exchange].SubscribePrice(symbol, price => HandlePriceUpdate(exchange,symbol, price)); + } + + static void HandlePriceUpdate(string exchange, string symbol, decimal price) + { + Console.Clear(); + Console.WriteLine($"> {exchange} price for {symbol}: {price}"); + Console.WriteLine("Press enter to stop live price updates"); + } + + static decimal GetDecimalInput(string question) + { + while (true) + { + Console.WriteLine("> " + question); + var response = Console.ReadLine(); + if (decimal.TryParse(response, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var answer)) + return answer; + else + Console.WriteLine("Invalid decimal value"); + } + } + + static string GetInput(string question) + { + Console.WriteLine("> " + question); + return Console.ReadLine(); + } } }