1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-11 16:32:57 +00:00

Updated examples

This commit is contained in:
Jkorf
2026-06-03 10:13:34 +02:00
parent d64c1171a3
commit cc25a405c6
12 changed files with 366 additions and 408 deletions
+292 -153
View File
@@ -1,164 +1,303 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Binance.Net;
using Binance.Net.Clients;
using Bybit.Net;
using Bybit.Net.Clients;
using ConsoleClient.Exchanges;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.SharedApis;
namespace ConsoleClient
var binanceRest = new BinanceRestClient(options =>
{
internal class Program
options.ApiCredentials = new BinanceCredentials("KEY", "SECRET");
});
var bybitRest = new BybitRestClient(options =>
{
options.ApiCredentials = new BybitCredentials("KEY", "SECRET");
});
var binanceSocket = new BinanceSocketClient(options =>
{
options.ApiCredentials = new BinanceCredentials("KEY", "SECRET");
});
var bybitSocket = new BybitSocketClient(options =>
{
options.ApiCredentials = new BybitCredentials("KEY", "SECRET");
});
var exchanges = new Dictionary<string, ExchangeClients>(StringComparer.OrdinalIgnoreCase)
{
["binance"] = new ExchangeClients(
"Binance",
binanceRest.SpotApi.SharedClient,
binanceRest.SpotApi.SharedClient,
binanceRest.SpotApi.SharedClient,
binanceRest.SpotApi.SharedClient,
binanceSocket.SpotApi.SharedClient),
["bybit"] = new ExchangeClients(
"Bybit",
bybitRest.V5Api.SharedClient,
bybitRest.V5Api.SharedClient,
bybitRest.V5Api.SharedClient,
bybitRest.V5Api.SharedClient,
bybitSocket.V5SpotApi.SharedClient)
};
PrintHelp();
while (true)
{
Console.Write("> ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
continue;
var commandArgs = input.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var command = commandArgs[0].ToLowerInvariant();
try
{
static Dictionary<string, IExchange> _exchanges = new Dictionary<string, IExchange>
switch (command)
{
{ "Binance", new Exchanges.BinanceExchange() },
{ "Bybit", new Exchanges.BybitExchange() }
};
static async Task Main(string[] args)
{
BinanceRestClient.SetDefaultOptions(options =>
{
options.ApiCredentials = new BinanceCredentials("APIKEY", "APISECRET");
});
BybitRestClient.SetDefaultOptions(options =>
{
options.ApiCredentials = new BybitCredentials("APIKEY", "APISECRET");
});
while (true)
{
Console.WriteLine("> Available commands: PlaceOrder, GetBalances, GetOpenOrders, CancelOrder, GetPrice, SubscribePrice");
var input = Console.ReadLine();
switch (input)
{
case "PlaceOrder":
await ProcessPlaceOrder();
break;
case "GetBalances":
await ProcessGetBalances();
break;
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;
}
}
}
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 ProcessGetBalances()
{
var exchange = GetInput("Exchange?");
Console.WriteLine("Requesting balances...");
var balances = await _exchanges[exchange].GetBalances();
foreach (var balance in balances.Where(b => b.Value != 0))
Console.WriteLine($"> {balance.Key}: {balance.Value}");
}
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()
{
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<UpdateSubscription> 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();
case "help":
PrintHelp();
break;
case "exit":
case "quit":
return;
case "prices":
await PrintPricesAsync(commandArgs);
break;
case "stream":
await StreamTickerAsync(commandArgs);
break;
case "orderbook":
await PrintOrderBookAsync(commandArgs);
break;
case "balances":
await PrintBalancesAsync(commandArgs);
break;
case "open-orders":
await PrintOpenOrdersAsync(commandArgs);
break;
case "place-limit":
await PlaceLimitOrderAsync(commandArgs);
break;
case "cancel-order":
await CancelOrderAsync(commandArgs);
break;
default:
Console.WriteLine("Unknown command. Type `help` for examples.");
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"Command failed: {ex.Message}");
}
}
async Task PrintPricesAsync(string[] args)
{
var symbol = GetSymbol(args, 1);
var tasks = exchanges.Values.Select(async exchange =>
{
var result = await exchange.TickerRest.GetSpotTickerAsync(new GetTickerRequest(symbol));
if (!result.Success)
{
Console.WriteLine($"{exchange.Name,-8} error: {result.Error}");
return;
}
Console.WriteLine($"{exchange.Name,-8} {result.Data.Symbol,-12} last={result.Data.LastPrice}");
});
await Task.WhenAll(tasks);
}
async Task StreamTickerAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var symbol = GetSymbol(args, 2);
using var cts = new CancellationTokenSource();
var result = await exchange.TickerSocket.SubscribeToTickerUpdatesAsync(
new SubscribeTickerRequest(symbol),
update => Console.WriteLine($"{exchange.Name,-8} {update.Data.Symbol,-12} last={update.Data.LastPrice}"),
cts.Token);
if (!result.Success)
{
Console.WriteLine($"Subscription failed: {result.Error}");
return;
}
Console.WriteLine("Streaming ticker updates. Press Enter to stop.");
Console.ReadLine();
cts.Cancel();
await result.Data.CloseAsync();
}
async Task PrintOrderBookAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var symbol = GetSymbol(args, 2);
var result = await exchange.OrderBookRest.GetOrderBookAsync(new GetOrderBookRequest(symbol, limit: 5));
if (!result.Success)
{
Console.WriteLine($"Order book request failed: {result.Error}");
return;
}
Console.WriteLine($"{exchange.Name} {symbol.BaseAsset}/{symbol.QuoteAsset} top of book");
for (var i = 0; i < Math.Min(5, Math.Min(result.Data.Bids.Length, result.Data.Asks.Length)); i++)
Console.WriteLine($"bid {result.Data.Bids[i].Price,15} | ask {result.Data.Asks[i].Price,15}");
}
async Task PrintBalancesAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var result = await exchange.BalanceRest.GetBalancesAsync(new GetBalancesRequest(TradingMode.Spot));
if (!result.Success)
{
Console.WriteLine($"Balances request failed: {result.Error}");
Console.WriteLine("Set API credentials in environment variables before calling private endpoints.");
return;
}
foreach (var balance in result.Data.Where(x => x.Total != 0).OrderBy(x => x.Asset))
Console.WriteLine($"{balance.Asset,-8} available={balance.Available} total={balance.Total}");
}
async Task PrintOpenOrdersAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var symbol = GetSymbol(args, 2);
var result = await exchange.OrderRest.GetOpenSpotOrdersAsync(new GetOpenOrdersRequest(symbol));
if (!result.Success)
{
Console.WriteLine($"Open orders request failed: {result.Error}");
return;
}
if (result.Data.Length == 0)
{
Console.WriteLine("No open orders.");
return;
}
foreach (var order in result.Data)
Console.WriteLine($"{order.OrderId,-24} {order.Side,-4} {order.OrderType,-6} {order.Status,-12} {order.OrderQuantity?.QuantityInBaseAsset} @ {order.OrderPrice}");
}
async Task PlaceLimitOrderAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var symbol = GetSymbol(args, 2);
var side = ParseSide(args.ElementAtOrDefault(4));
var quantity = ParseDecimal(args.ElementAtOrDefault(5), "quantity");
var price = ParseDecimal(args.ElementAtOrDefault(6), "price");
var request = new PlaceSpotOrderRequest(
symbol,
side,
SharedOrderType.Limit,
SharedQuantity.Base(quantity),
price,
SharedTimeInForce.GoodTillCanceled,
exchange.OrderRest.GenerateClientOrderId());
var validationError = exchange.OrderRest.PlaceSpotOrderOptions.ValidateRequest(
exchange.Name,
request,
TradingMode.Spot,
exchange.OrderRest.SupportedTradingModes,
exchange.OrderRest.SpotSupportedOrderTypes,
exchange.OrderRest.SpotSupportedTimeInForce,
exchange.OrderRest.SpotSupportedOrderQuantity);
if (validationError != null)
{
Console.WriteLine($"Order request is not valid for {exchange.Name}: {validationError}");
return;
}
var result = await exchange.OrderRest.PlaceSpotOrderAsync(request);
Console.WriteLine(result.Success
? $"Order placed. Id: {result.Data.Id}"
: $"Order failed: {result.Error}");
}
async Task CancelOrderAsync(string[] args)
{
var exchange = GetExchange(args, 1);
var symbol = GetSymbol(args, 2);
var orderId = args.ElementAtOrDefault(4);
if (string.IsNullOrWhiteSpace(orderId))
throw new ArgumentException("Missing order id. Example: cancel-order binance BTC USDT 123456");
var result = await exchange.OrderRest.CancelSpotOrderAsync(new CancelOrderRequest(symbol, orderId));
Console.WriteLine(result.Success
? $"Order canceled. Id: {result.Data.Id}"
: $"Cancel failed: {result.Error}");
}
ExchangeClients GetExchange(string[] args, int index)
{
var name = args.ElementAtOrDefault(index);
if (name == null || !exchanges.TryGetValue(name, out var exchange))
throw new ArgumentException($"Unknown exchange `{name}`. Use one of: {string.Join(", ", exchanges.Keys)}");
return exchange;
}
SharedSymbol GetSymbol(string[] args, int index)
{
var baseAsset = args.ElementAtOrDefault(index) ?? "BTC";
var quoteAsset = args.ElementAtOrDefault(index + 1) ?? "USDT";
return new SharedSymbol(TradingMode.Spot, baseAsset.ToUpperInvariant(), quoteAsset.ToUpperInvariant());
}
static decimal ParseDecimal(string? value, string name)
{
if (!decimal.TryParse(value, out var result))
throw new ArgumentException($"Invalid {name} value `{value}`.");
return result;
}
static SharedOrderSide ParseSide(string? value)
{
return value?.ToLowerInvariant() switch
{
"buy" => SharedOrderSide.Buy,
"sell" => SharedOrderSide.Sell,
_ => throw new ArgumentException("Side should be `buy` or `sell`.")
};
}
static void PrintHelp()
{
Console.WriteLine("CryptoExchange.Net SharedApis console example");
Console.WriteLine();
Console.WriteLine("Public market data:");
Console.WriteLine(" prices [base] [quote] e.g. prices BTC USDT");
Console.WriteLine(" stream [exchange] [base] [quote] e.g. stream binance ETH USDT");
Console.WriteLine(" orderbook [exchange] [base] [quote] e.g. orderbook bybit BTC USDT");
Console.WriteLine();
Console.WriteLine("Private endpoints, credentials required:");
Console.WriteLine(" balances [exchange]");
Console.WriteLine(" open-orders [exchange] [base] [quote]");
Console.WriteLine(" place-limit [exchange] [base] [quote] [buy|sell] [quantity] [price] --live");
Console.WriteLine(" cancel-order [exchange] [base] [quote] [order-id]");
Console.WriteLine();
Console.WriteLine("Other:");
Console.WriteLine(" help");
Console.WriteLine(" exit");
Console.WriteLine();
}
internal record ExchangeClients(
string Name,
ISpotTickerRestClient TickerRest,
IOrderBookRestClient OrderBookRest,
IBalanceRestClient BalanceRest,
ISpotOrderRestClient OrderRest,
ITickerSocketClient TickerSocket);