1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-10-27 00:17:31 +00:00
2025-08-18 11:03:26 +02:00

191 lines
8.5 KiB
C#

using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for an exchange endpoint
/// </summary>
public class EndpointOptions
{
/// <summary>
/// Required exchange-specific parameters
/// </summary>
public List<ParameterDescription> RequiredExchangeParameters { get; set; } = new List<ParameterDescription>();
/// <summary>
/// Optional exchange-specific parameters
/// </summary>
public List<ParameterDescription> OptionalExchangeParameters { get; set; } = new List<ParameterDescription>();
/// <summary>
/// Endpoint name
/// </summary>
public string EndpointName { get; set; }
/// <summary>
/// Information on the specific exchange request
/// </summary>
public string? RequestNotes { get; set; }
/// <summary>
/// Whether the call requires authentication
/// </summary>
public bool NeedsAuthentication { get; set; }
/// <summary>
/// Whether the call is supported by the exchange
/// </summary>
public bool Supported { get; set; } = true;
/// <summary>
/// ctor
/// </summary>
public EndpointOptions(string endpointName, bool needAuthentication)
{
EndpointName = endpointName;
NeedsAuthentication = needAuthentication;
}
/// <summary>
/// Validate a request
/// </summary>
/// <param name="exchange">Exchange name</param>
/// <param name="exchangeParameters">Provided exchange parameters</param>
/// <param name="tradingMode">Request trading mode</param>
/// <param name="supportedTradingModes">Supported trading modes</param>
/// <returns></returns>
public virtual Error? ValidateRequest(string exchange, ExchangeParameters? exchangeParameters, TradingMode? tradingMode, TradingMode[] supportedTradingModes)
{
if (tradingMode != null && !supportedTradingModes.Contains(tradingMode.Value))
return ArgumentError.Invalid("TradingMode", $"TradingMode.{tradingMode} is not supported, supported types: {string.Join(", ", supportedTradingModes)}");
foreach (var param in RequiredExchangeParameters)
{
if (!string.IsNullOrEmpty(param.Name))
{
if (ExchangeParameters.HasValue(exchangeParameters, exchange, param.Name!, param.ValueType) != true)
return ArgumentError.Invalid(param.Name!, $"Required exchange parameter `{param.Name}` for exchange `{exchange}` is missing or has incorrect type. Expected type is {param.ValueType.Name}. Example: {param.ExampleValue}");
}
else
{
if (param.Names!.All(x => ExchangeParameters.HasValue(exchangeParameters, exchange, x, param.ValueType) != true))
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of exchange parameters `{string.Join(", ", param.Names!)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}");
}
}
return null;
}
/// <inheritdoc />
public virtual string ToString(string exchange)
{
if (!Supported)
return $"{exchange} {EndpointName} NOT SUPPORTED";
var sb = new StringBuilder();
sb.AppendLine($"{exchange} {EndpointName}");
if (!string.IsNullOrEmpty(RequestNotes))
sb.AppendLine(RequestNotes);
sb.AppendLine($"Needs authentication: {NeedsAuthentication}");
sb.AppendLine($"Required exchange specific parameters: {string.Join(", ", RequiredExchangeParameters.Select(x => x.ToString()))}");
sb.AppendLine($"Optional exchange specific parameters: {string.Join(", ", OptionalExchangeParameters.Select(x => x.ToString()))}");
return sb.ToString();
}
}
/// <summary>
/// Options for an exchange endpoint
/// </summary>
/// <typeparam name="T">Type of data</typeparam>
#if NET5_0_OR_GREATER
public class EndpointOptions<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T> : EndpointOptions where T : SharedRequest
#else
public class EndpointOptions<T> : EndpointOptions where T : SharedRequest
#endif
{
/// <summary>
/// Required optional parameters in the request
/// </summary>
public List<ParameterDescription> RequiredOptionalParameters { get; set; } = new List<ParameterDescription>();
/// <summary>
/// Whether this accepts multiple symbols (Only applicable to request requiring symbol parameters)
/// </summary>
public bool SupportsMultipleSymbols { get; set; } = false;
/// <summary>
/// The max number of symbols which can be passed in a call (Only applicable to request requiring symbol parameters)
/// </summary>
public int? MaxSymbolCount { get; set; }
/// <summary>
/// ctor
/// </summary>
public EndpointOptions(bool needsAuthentication) : base(typeof(T).Name, needsAuthentication)
{
}
/// <summary>
/// Validate a request
/// </summary>
/// <param name="exchange">Exchange name</param>
/// <param name="request">The request</param>
/// <param name="tradingMode">Request trading mode</param>
/// <param name="supportedTradingModes">Supported trading modes</param>
/// <returns></returns>
public virtual Error? ValidateRequest(string exchange, T request, TradingMode? tradingMode, TradingMode[] supportedTradingModes)
{
foreach (var param in RequiredOptionalParameters)
{
if (!string.IsNullOrEmpty(param.Name))
{
if (typeof(T).GetProperty(param.Name)!.GetValue(request, null) == null)
return ArgumentError.Invalid(param.Name!, $"Required optional parameter `{param.Name}` for exchange `{exchange}` is missing. Example: {param.ExampleValue}");
}
else
{
if (param.Names!.All(x => typeof(T).GetProperty(param.Name!)!.GetValue(request, null) == null))
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of optional parameters `{string.Join(", ", param.Names!)}` for exchange `{exchange}` should be provided. Example: {param.ExampleValue}");
}
}
if (request is SharedSymbolRequest symbolsRequest)
{
if (symbolsRequest.Symbols != null)
{
if (!SupportsMultipleSymbols)
return ArgumentError.Invalid(nameof(SharedSymbolRequest.Symbols), $"Only a single symbol parameter is allowed, multiple symbols are not supported");
if (symbolsRequest.Symbols.Length > MaxSymbolCount)
return ArgumentError.Invalid(nameof(SharedSymbolRequest.Symbols), $"Max number of symbols is {MaxSymbolCount} but {symbolsRequest.Symbols.Length} were passed");
}
}
return ValidateRequest(exchange, request.ExchangeParameters, tradingMode, supportedTradingModes);
}
/// <inheritdoc />
public override string ToString(string exchange)
{
if (!Supported)
return $"{exchange} {EndpointName} NOT SUPPORTED";
var sb = new StringBuilder();
sb.AppendLine($"{exchange} {typeof(T).Name}");
sb.AppendLine($"Needs authentication: {NeedsAuthentication}");
if (!string.IsNullOrEmpty(RequestNotes))
sb.AppendLine(RequestNotes);
if (RequiredOptionalParameters.Any())
sb.AppendLine($"Required optional parameters: {string.Join(", ", RequiredOptionalParameters.Select(x => x.ToString()))}");
if (RequiredExchangeParameters.Any())
sb.AppendLine($"Required exchange specific parameters: {string.Join(", ", RequiredExchangeParameters.Select(x => x.ToString()))}");
if (OptionalExchangeParameters.Any())
sb.AppendLine($"Optional exchange specific parameters: {string.Join(", ", RequiredExchangeParameters.Select(x => x.ToString()))}");
return sb.ToString();
}
}
}