diff --git a/FtxApi/Client.cs b/FtxApi/Client.cs index 665c1f7..00c5b05 100644 --- a/FtxApi/Client.cs +++ b/FtxApi/Client.cs @@ -2,21 +2,22 @@ { public class Client { + public string Subaccount { get; } public string ApiKey { get; } - public string ApiSecret { get; } public Client() { ApiKey = ""; ApiSecret = ""; + Subaccount = ""; } - public Client(string apiKey, string apiSecret) + public Client(string apiKey, string apiSecret, string subaccount) { ApiKey = apiKey; ApiSecret = apiSecret; + Subaccount = subaccount; } - } } \ No newline at end of file diff --git a/FtxApi/Enums/OrderType.cs b/FtxApi/Enums/OrderType.cs index 9e937e9..00893bf 100644 --- a/FtxApi/Enums/OrderType.cs +++ b/FtxApi/Enums/OrderType.cs @@ -2,7 +2,10 @@ { public enum OrderType : byte { - limit, - market + Limit, + Market, + Stop, + TrailingStop, + TakeProfit, } } \ No newline at end of file diff --git a/FtxApi/Enums/SideType.cs b/FtxApi/Enums/SideType.cs index 6dd8c43..50460f4 100644 --- a/FtxApi/Enums/SideType.cs +++ b/FtxApi/Enums/SideType.cs @@ -1,8 +1,8 @@ namespace FtxApi.Enums { - public enum SideType : byte + public enum SideType { - buy, - sell + Buy, + Sell } } \ No newline at end of file diff --git a/FtxApi/FtxApi.csproj b/FtxApi/FtxApi.csproj index 8d74bd5..3535cbb 100644 --- a/FtxApi/FtxApi.csproj +++ b/FtxApi/FtxApi.csproj @@ -1,12 +1,17 @@  - netcoreapp3.1 Library false + net5.0;net5.0-windows + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + + @@ -15,18 +20,19 @@ - + - - + + - + - - + + + \ No newline at end of file diff --git a/FtxApi/FtxRestApi.cs b/FtxApi/FtxRestApi.cs index 76d7e1a..e8a9c4d 100644 --- a/FtxApi/FtxRestApi.cs +++ b/FtxApi/FtxRestApi.cs @@ -5,11 +5,19 @@ using System.Security.Cryptography; using System.Text; using System.Text.Json; +using System.IO; +using System.Text.Json; +using System.Threading; using System.Threading.Tasks; +using System.Web; using FtxApi.Enums; +using FtxApi.Logging; using FtxApi.Models; using FtxApi.Models.LeveragedTokens; using FtxApi.Models.Markets; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace FtxApi { @@ -23,15 +31,20 @@ public class FtxRestApi private readonly HMACSHA256 _hashMaker; + private readonly string _subAccount; + private long _nonce; - + + private static readonly ILog Log = LogProvider.GetCurrentClassLogger(); + public FtxRestApi(Client client) { _client = client; + _subAccount = _client.Subaccount; _httpClient = new HttpClient { BaseAddress = new Uri(Url), - Timeout = TimeSpan.FromSeconds(30) + Timeout = TimeSpan.FromMinutes(10) }; _hashMaker = new HMACSHA256(Encoding.UTF8.GetBytes(_client.ApiSecret)); @@ -45,7 +58,7 @@ public async Task>> GetCoinsAsync() var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } #endregion @@ -57,7 +70,7 @@ public async Task>> GetAllFuturesAsync() var resultString = $"api/futures"; var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>>(result); + return result != null ? JsonConvert.DeserializeObject>>(result) : null; } public async Task> GetFutureAsync(string future) @@ -66,7 +79,7 @@ public async Task> GetFutureAsync(string future) var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>(result); + return result != null ? JsonConvert.DeserializeObject>(result) : null; } public async Task> GetFutureStatsAsync(string future) @@ -75,39 +88,132 @@ public async Task> GetFutureStatsAsync(string future) var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>(result); + return result != null ? JsonConvert.DeserializeObject>(result) : null; } - public async Task> GetFundingRatesAsync(DateTime start, DateTime end) + public async Task>> GetExpiredFutures() + { + var resultString = $"api/expired_futures"; + + var result = await CallAsync(HttpMethod.Get, resultString); + return result != null ? JsonConvert.DeserializeObject>>(result) : null; + } + + public async Task> GetFundingRatesAsync(string market, DateTime start, DateTime end) { List allResults = new List(); int resultLength; do { - var resultString = $"api/funding_rates?start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var resultString = + $"api/funding_rates?future{market}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var result = await CallAsync(HttpMethod.Get, resultString); + //var deserializedResult = JsonConvert.DeserializeAsync>>(result); + var deserializedResult = JsonConvert.DeserializeObject>>(result); + + var rates = deserializedResult?.Result; + resultLength = rates?.Count ?? 0; + + if (resultLength != 0) + { + allResults.AddRange(rates); + end = rates.Last().Time.ToUniversalTime() + .AddMinutes(-1); //Set the end time to the earliest retrieved to get more + } + } while (resultLength == 500); + + return allResults; + } + + public async Task> GetFundingRatesAsync(DateTime start, DateTime end) + { + var allResults = new List(); + var resultLength = 0; + + do + { + var resultString = + $"api/funding_rates?start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; var result = await CallAsync(HttpMethod.Get, resultString); - var deserializedResult = JsonSerializer.Deserialize>>(result); + if (result == null) return null; + var deserializedResult = JsonConvert.DeserializeObject>>(result); + + if (deserializedResult == null) continue; var rates = deserializedResult.Result; resultLength = rates.Count(); - if(resultLength != 0) + if (resultLength != 0) { allResults.AddRange(rates); - end = rates.Last().Time.ToUniversalTime().AddMinutes(-1); //Set the end time to the earliest retrieved to get more + end = rates.Last().Time.ToUniversalTime() + .AddMinutes(-1); //Set the end time to the earliest retrieved to get more } - } while(resultLength == 500); + } while (resultLength == 500); + return allResults; } - public async Task>> GetHistoricalPricesAsync(string futureName, int resolution, int limit, DateTime start, DateTime end) + public async Task> GetHistoricalPricesAsync(string marketName, int resolution, DateTime start, + DateTime end) { - var resultString = $"api/futures/{futureName}/mark_candles?resolution={resolution}&limit={limit}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var allResults = new List(); + var resultLength = 0; - var result = await CallAsync(HttpMethod.Get, resultString); + do + { + var resultString = + $"api/markets/{marketName}/candles?resolution={resolution}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var result = await CallAsync(HttpMethod.Get, resultString); + + if (result == null) throw new ArgumentNullException(nameof(result)); + + var deserializedResult = JsonConvert.DeserializeObject>>(result); + + if (deserializedResult == null) continue; + + var rates = deserializedResult.Result; + resultLength = rates.Count(); + + if (resultLength != 0) + { + allResults.AddRange(rates); + end = rates.Last().StartTime.ToUniversalTime() + .AddMinutes(-1); //Set the end time to the earliest retrieved to get more + } + } while (resultLength == 500); + + return allResults; + } + + public async Task> GetHistoricalIndexAsync(string indexName, int resolution, DateTime start, + DateTime end) + { + var allResults = new List(); + var resultLength = 0; + + do + { + var resultString = + $"api/indexes/{indexName}/candles?resolution={resolution}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var result = await CallAsync(HttpMethod.Get, resultString); + var deserializedResult = JsonConvert.DeserializeObject>>(result); + + if (deserializedResult == null) continue; + + var rates = deserializedResult.Result; + resultLength = rates.Count(); - return JsonSerializer.Deserialize>>(result); + if (resultLength != 0) + { + allResults.AddRange(rates); + end = rates.Last().StartTime.ToUniversalTime() + .AddMinutes(-1); //Set the end time to the earliest retrieved to get more + } + } while (resultLength == 500); + + return allResults; } #endregion @@ -120,7 +226,7 @@ public async Task>> GetMarketsAsync() var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task> GetSingleMarketsAsync(string marketName) @@ -129,7 +235,7 @@ public async Task> GetSingleMarketsAsync(string marketName) var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } public async Task> GetMarketOrderBookAsync(string marketName, int depth = 20) @@ -138,16 +244,40 @@ public async Task> GetMarketOrderBookAsync(string marketNam var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } - public async Task>> GetMarketTradesAsync(string marketName, int limit, DateTime start, DateTime end) + public async Task> GetMarketTradesAsync(string marketName, DateTime start, + DateTime end) { - var resultString = $"api/markets/{marketName}/trades?limit={limit}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + List allResults = new List(); + int resultLength = 0; - var result = await CallAsync(HttpMethod.Get, resultString); + do + { + var resultString = + $"api/markets/{marketName}/trades?&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var result = await CallAsync(HttpMethod.Get, resultString); + + if (result == null || !result.Any()) return allResults; + + var deserializedResult = JsonConvert.DeserializeObject>>(result); + + var rates = deserializedResult?.Result; + if (rates != null) + { + resultLength = rates.Count; + + if (resultLength != 0) + { + allResults.AddRange(rates); + end = rates.Last().Time.ToUniversalTime() + .AddMinutes(-1); //Set the end time to the earliest retrieved to get more + } + } + } while (resultLength == 5000); - return JsonSerializer.Deserialize>>(result); + return allResults; } #endregion @@ -158,33 +288,38 @@ public async Task> GetAccountInfoAsync() { var resultString = $"api/account"; var sign = GenerateSignature(HttpMethod.Get, "/api/account", ""); - var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - - return JsonSerializer.Deserialize>(result); + if (result == null) return null; + return JsonConvert.DeserializeObject>(result); } public async Task>> GetPositionsAsync() { var resultString = $"api/positions"; - var sign = GenerateSignature(HttpMethod.Get, "/api/positions", ""); - var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); + var query = HttpUtility.ParseQueryString(string.Empty); + query["showAvgPrice"] = "true"; + var queryString = query.ToString(); - return JsonSerializer.Deserialize>>(result); + var showAvgPriceEndpoint = $"{resultString}?{queryString}"; + + var sign = GenerateSignature(HttpMethod.Get, $"/{showAvgPriceEndpoint}", ""); + + var result = await CallAsyncSign(HttpMethod.Get, showAvgPriceEndpoint, sign, ""); + return result == null ? null : JsonConvert.DeserializeObject>>(result); } public async Task ChangeAccountLeverageAsync(int leverage) { var resultString = $"api/account/leverage"; - + var body = $"{{\"leverage\": {leverage}}}"; var sign = GenerateSignature(HttpMethod.Post, "/api/account/leverage", body); var result = await CallAsyncSign(HttpMethod.Post, resultString, sign, body); - return JsonSerializer.Deserialize(result); + return JsonConvert.DeserializeObject(result); } #endregion @@ -194,12 +329,12 @@ public async Task ChangeAccountLeverageAsync(int leverage) public async Task>> GetCoinAsync() { var resultString = $"api/wallet/coins"; - + var sign = GenerateSignature(HttpMethod.Get, "/api/wallet/coins", ""); var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task>> GetBalancesAsync() @@ -208,20 +343,30 @@ public async Task>> GetBalancesAsync() var sign = GenerateSignature(HttpMethod.Get, "/api/wallet/balances", ""); + var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); + return result == null ? null : JsonConvert.DeserializeObject>>(result); + } + + public async Task>> GetAllBalancesAsync() + { + var resultString = $"api/wallet/balances"; + + var sign = GenerateSignature(HttpMethod.Get, "/api/wallet/all_balances", ""); + var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task> GetDepositAddressAsync(string coin) { var resultString = $"api/wallet/deposit_address/{coin}"; - + var sign = GenerateSignature(HttpMethod.Get, $"/api/wallet/deposit_address/{coin}", ""); var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } public async Task>> GetDepositHistoryAsync() @@ -232,7 +377,7 @@ public async Task>> GetDepositHistoryAsync() var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task>> GetWithdrawalHistoryAsync() @@ -243,114 +388,192 @@ public async Task>> GetWithdrawalHistoryAsync( var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } - public async Task> RequestWithdrawalAsync(string coin, decimal size, string addr, string tag, string pass, string code) + public async Task> RequestWithdrawalAsync(string coin, decimal size, string addr, + string tag, string pass, string code) { var resultString = $"api/wallet/withdrawals"; - var body = $"{{"+ - $"\"coin\": \"{coin}\"," + - $"\"size\": {size},"+ - $"\"address\": \"{addr}\","+ - $"\"tag\": {tag},"+ - $"\"password\": \"{pass}\","+ - $"\"code\": {code}" + - "}"; + var body = $"{{" + + $"\"coin\": \"{coin}\"," + + $"\"size\": {size}," + + $"\"address\": \"{addr}\"," + + $"\"tag\": {tag}," + + $"\"password\": \"{pass}\"," + + $"\"code\": {code}" + + "}"; var sign = GenerateSignature(HttpMethod.Post, "/api/wallet/withdrawals", body); var result = await CallAsyncSign(HttpMethod.Post, resultString, sign, body); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } #endregion #region Orders - public async Task> PlaceOrderAsync(string instrument, SideType side, decimal price, OrderType orderType, decimal amount, bool reduceOnly = false) + public async Task> PlaceOrderAsync(string instrument, SideType side, decimal? price, + OrderType orderType, decimal amount, string clientId = "", bool ioc = false, bool postOnly = false, + bool reduceOnly = false) { var path = $"api/orders"; - var body = - $"{{\"market\": \"{instrument}\"," + - $"\"side\": \"{side}\"," + - $"\"price\": {price}," + - $"\"type\": \"{orderType}\"," + - $"\"size\": {amount}," + - $"\"reduceOnly\": {reduceOnly.ToString().ToLower()}}}"; + var body = new CreateOrder( + instrument, + side, + price, + orderType, + amount, + clientId, + ioc, + postOnly, + reduceOnly); - var sign = GenerateSignature(HttpMethod.Post, "/api/orders", body); - var result = await CallAsyncSign(HttpMethod.Post, path, sign, body); + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); - return JsonSerializer.Deserialize>(result); + var sign = GenerateSignature(HttpMethod.Post, "/api/orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); + + return JsonConvert.DeserializeObject>(result); } - public async Task> PlaceStopOrderAsync(string instrument, SideType side, decimal triggerPrice, decimal amount, bool reduceOnly = false) + public async Task> PlaceStopOrderAsync(string instrument, SideType side, + OrderType orderType, + decimal triggerPrice, decimal amount, bool reduceOnly = false) { var path = $"api/conditional_orders"; - var body = - $"{{\"market\": \"{instrument}\"," + - $"\"side\": \"{side}\"," + - $"\"triggerPrice\": {triggerPrice}," + - $"\"type\": \"stop\"," + - $"\"size\": {amount}," + - $"\"reduceOnly\": {reduceOnly.ToString().ToLower()}}}"; + var body = new CreateOrder + { + Market = instrument, + Side = side, + TriggerPrice = triggerPrice, + Type = orderType, + Size = amount, + ReduceOnly = reduceOnly, + RetryUntilFilled = false + }; + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); - var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", body); - var result = await CallAsyncSign(HttpMethod.Post, path, sign, body); + var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } - public async Task> PlaceTrailingStopOrderAsync(string instrument, SideType side, decimal trailValue, decimal amount, bool reduceOnly = false) + public async Task> PlaceStopLimitOrderAsync(string instrument, SideType side, + OrderType orderType, + decimal triggerPrice, decimal orderPrice, decimal amount, bool reduceOnly = false) { var path = $"api/conditional_orders"; + var body = new CreateOrder + { + Market = instrument, + Side = side, + TriggerPrice = triggerPrice, + OrderPrice = orderPrice, + Type = orderType, + Size = amount, + ReduceOnly = reduceOnly, + RetryUntilFilled = false + }; - var body = - $"{{\"market\": \"{instrument}\"," + - $"\"side\": \"{side}\"," + - $"\"trailValue\": {trailValue}," + - $"\"type\": \"trailingStop\"," + - $"\"size\": {amount}," + - $"\"reduceOnly\": {reduceOnly.ToString().ToLower()}}}"; + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); - var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", body); - var result = await CallAsyncSign(HttpMethod.Post, path, sign, body); + var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } - public async Task> PlaceTakeProfitOrderAsync(string instrument, SideType side, decimal triggerPrice, decimal amount, bool reduceOnly = false) + public async Task> PlaceTrailingStopOrderAsync(string instrument, SideType side, + OrderType orderType, + decimal trailValue, decimal amount, bool reduceOnly = false) { var path = $"api/conditional_orders"; - var body = - $"{{\"market\": \"{instrument}\"," + - $"\"side\": \"{side}\"," + - $"\"triggerPrice\": {triggerPrice}," + - $"\"type\": \"takeProfit\"," + - $"\"size\": {amount}," + - $"\"reduceOnly\": {reduceOnly.ToString().ToLower()}}}"; + var body = new CreateOrder + { + Market = instrument, + Side = side, + TrailValue = trailValue, + Type = orderType, + Size = amount, + ReduceOnly = reduceOnly, + RetryUntilFilled = false + }; + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); - var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", body); - var result = await CallAsyncSign(HttpMethod.Post, path, sign, body); + var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); + } + + public async Task> PlaceTakeProfitOrderAsync(string instrument, SideType side, + OrderType orderType, + decimal triggerPrice, decimal amount, bool reduceOnly = false) + { + var path = $"api/conditional_orders"; + var body = new CreateOrder + ( + instrument, + side, + orderType, + triggerPrice, + amount, + reduceOnly + ); + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); + + var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); + + return JsonConvert.DeserializeObject>(result); + } + + public async Task> PlaceTakeProfitLimitOrderAsync(string instrument, SideType side, + OrderType orderType, + decimal triggerPrice, decimal orderPrice, decimal amount, bool reduceOnly = false) + { + var path = $"api/conditional_orders"; + + var body = new CreateOrder + { + Market = instrument, + Side = side, + TriggerPrice = triggerPrice, + OrderPrice = orderPrice, + Type = orderType, + Size = amount, + ReduceOnly = reduceOnly, + RetryUntilFilled = false + }; + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); + + var sign = GenerateSignature(HttpMethod.Post, "/api/conditional_orders", serialize); + var result = await CallAsyncSign(HttpMethod.Post, path, sign, serialize); + + return JsonConvert.DeserializeObject>(result); } public async Task>> GetOpenOrdersAsync(string instrument) { - var path = $"api/orders?market={instrument}"; + var path = $"api/orders?Market={instrument}"; + + var sign = GenerateSignature(HttpMethod.Get, $"/api/orders?Market={instrument}", ""); - var sign = GenerateSignature(HttpMethod.Get, $"/api/orders?market={instrument}", ""); - var result = await CallAsyncSign(HttpMethod.Get, path, sign); - return JsonSerializer.Deserialize>>(result); + return result == null ? null : JsonConvert.DeserializeObject>>(result); } public async Task> GetOrderStatusAsync(string id) @@ -361,7 +584,7 @@ public async Task> GetOrderStatusAsync(string id) var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>(result); + return result == null ? null : JsonConvert.DeserializeObject>(result); } public async Task> GetOrderStatusByClientIdAsync(string clientOrderId) @@ -372,7 +595,7 @@ public async Task> GetOrderStatusByClientIdAsync(string clientO var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } public async Task> CancelOrderAsync(string id) @@ -383,7 +606,18 @@ public async Task> CancelOrderAsync(string id) var result = await CallAsyncSign(HttpMethod.Delete, resultString, sign); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); + } + + public async Task> CancelTriggerOrderAsync(string id) + { + var resultString = $"api/conditional_orders/{id}"; + + var sign = GenerateSignature(HttpMethod.Delete, $"/api/conditional_orders/{id}", ""); + + var result = await CallAsyncSign(HttpMethod.Delete, resultString, sign); + + return JsonConvert.DeserializeObject>(result); } public async Task> CancelOrderByClientIdAsync(string clientOrderId) @@ -394,20 +628,31 @@ public async Task> CancelOrderByClientIdAsync(string clientOrd var result = await CallAsyncSign(HttpMethod.Delete, resultString, sign); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } - public async Task> CancelAllOrdersAsync(string instrument) + public async Task> CancelAllOrdersAsync(string instrument, SideType? side, + bool? limitOrdersOnly, bool? conditionalOrdersOnly) { var resultString = $"api/orders"; - var body = $"{{\"market\": \"{instrument}\"}}"; + //var body = $"{{\"Market\": \"{instrument}\"}}"; + + var body = new CancelOrder + { + Market = instrument, + Side = side, + LimitOrdersOnly = limitOrdersOnly, + ConditionalOrdersOnly = conditionalOrdersOnly + }; + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); - var sign = GenerateSignature(HttpMethod.Delete, $"/api/orders", body); + var sign = GenerateSignature(HttpMethod.Delete, $"/api/orders", serialize); - var result = await CallAsyncSign(HttpMethod.Delete, resultString, sign, body); + var result = await CallAsyncSign(HttpMethod.Delete, resultString, sign, serialize); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } #endregion @@ -416,13 +661,14 @@ public async Task> CancelAllOrdersAsync(string instrument) public async Task>> GetFillsAsync(string market, int limit, DateTime start, DateTime end) { - var resultString = $"api/fills?market={market}&limit={limit}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var resultString = + $"api/fills?Market={market}&Limit={limit}&start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; var sign = GenerateSignature(HttpMethod.Get, $"/{resultString}", ""); var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return result == null ? null : JsonConvert.DeserializeObject>>(result); } #endregion @@ -431,26 +677,82 @@ public async Task>> GetFillsAsync(string market, int limit, public async Task>> GetFundingPaymentAsync(DateTime start, DateTime end) { - var resultString = $"api/funding_payments?start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; + var resultString = + $"api/funding_payments?start_time={Util.Util.GetSecondsFromEpochStart(start)}&end_time={Util.Util.GetSecondsFromEpochStart(end)}"; var sign = GenerateSignature(HttpMethod.Get, $"/{resultString}", ""); var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return result == null ? null : JsonConvert.DeserializeObject>>(result); } #endregion #region Leveraged Tokens + public async Task> ConvertRequestQuote(string fromCoin, string toCoin, + decimal sizeOfFromCoin) + { + var resultString = $"api/otc/quotes"; + + var body = new ConvertCoinRequest() + { + FromCoin = fromCoin, + ToCoin = toCoin, + Size = sizeOfFromCoin + }; + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); + + var sign = GenerateSignature(HttpMethod.Post, $"/{resultString}", serialize); + + var result = await CallAsyncSign(HttpMethod.Post, resultString, sign, serialize); + + return JsonConvert.DeserializeObject>(result); + } + + public async Task> ConvertGetQuoteStatus(long quoteId, string market = null) + { + var resultString = $"api/otc/quotes/{quoteId}"; + + var body = new QuoteStatusRequest() + { + Market = market + }; + + if (market == null) + { + body = null; + } + + var serialize = JsonConvert.SerializeObject(body, new StringEnumConverter(true)); + + var sign = GenerateSignature(HttpMethod.Get, $"/{resultString}", serialize); + + var result = await CallAsyncSign(HttpMethod.Get, resultString, sign, serialize); + + return JsonConvert.DeserializeObject>(result); + } + + public async Task> ConvertAcceptQuote(long? quoteId) + { + var resultString = $"api/otc/quotes/{quoteId}/accept"; + + var sign = GenerateSignature(HttpMethod.Post, $"/{resultString}", ""); + + var result = await CallAsyncSign(HttpMethod.Post, resultString, sign); + + return JsonConvert.DeserializeObject>(result); + } + public async Task>> GetLeveragedTokensListAsync() { var resultString = $"api/lt/tokens"; var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task> GetTokenInfoAsync(string tokenName) @@ -459,7 +761,7 @@ public async Task> GetTokenInfoAsync(string tokenName) var result = await CallAsync(HttpMethod.Get, resultString); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } public async Task>> GetLeveragedTokenBalancesAsync() @@ -470,7 +772,7 @@ public async Task>> GetLeveragedTokenBalan var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } public async Task>> GetLeveragedTokenCreationListAsync() @@ -481,20 +783,21 @@ public async Task>> GetLeveragedTokenCrea var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } - public async Task> RequestLeveragedTokenCreationAsync(string tokenName, decimal size) + public async Task> RequestLeveragedTokenCreationAsync(string tokenName, + decimal size) { var resultString = $"api/lt/{tokenName}/create"; - + var body = $"{{\"size\": {size}}}"; var sign = GenerateSignature(HttpMethod.Post, $"/api/lt/{tokenName}/create", body); var result = await CallAsyncSign(HttpMethod.Post, resultString, sign, body); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } public async Task>> GetLeveragedTokenRedemptionListAsync() @@ -505,10 +808,11 @@ public async Task>> GetLeveraged var result = await CallAsyncSign(HttpMethod.Get, resultString, sign); - return JsonSerializer.Deserialize>>(result); + return JsonConvert.DeserializeObject>>(result); } - public async Task> RequestLeveragedTokenRedemptionAsync(string tokenName, decimal size) + public async Task> RequestLeveragedTokenRedemptionAsync(string tokenName, + decimal size) { var resultString = $"api/lt/{tokenName}/redeem"; @@ -518,13 +822,37 @@ public async Task> RequestLeveragedTokenRede var result = await CallAsyncSign(HttpMethod.Post, resultString, sign, body); - return JsonSerializer.Deserialize>(result); + return JsonConvert.DeserializeObject>(result); } #endregion #region Util + public async Task>> GetExpiredFuturesAsync(CancellationToken cancellationToken) + { + var endPoint = $"api/expired_futures"; + var request = CreateRequest(HttpMethod.Get, endPoint); + + var options = new JsonSerializerOptions(); + + using var result = await _httpClient + .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + await using var contentStream = await result.Content.ReadAsStreamAsync(cancellationToken); + return await JsonSerializer.DeserializeAsync>>(contentStream, + cancellationToken: cancellationToken); + } + + private static HttpRequestMessage CreateRequest(HttpMethod method, string endpoint, string body = null) + { + var request = new HttpRequestMessage(method, $"{endpoint}"); + + if (body != null) + request.Content = new StringContent(body, Encoding.UTF8, "application/json"); + + return request; + } + private async Task CallAsync(HttpMethod method, string endpoint, string body = null) { var request = new HttpRequestMessage(method, endpoint); @@ -534,11 +862,32 @@ private async Task CallAsync(HttpMethod method, string endpoint, string request.Content = new StringContent(body, Encoding.UTF8, "application/json"); } - var response = await _httpClient.SendAsync(request).ConfigureAwait(false); + var cts = new CancellationTokenSource(); - var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var response = + await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token); + return await response.Content.ReadAsStringAsync(cts.Token); + } + // If the token has been canceled, it is not a timeout. + catch (TaskCanceledException ex) when (cts.IsCancellationRequested) + { + // Handle cancellation. + Log.Debug("Canceled: " + ex.Message); + } + catch (TaskCanceledException ex) + { + // Handle timeout. + Log.Debug("Timed out: " + ex.Message); + } + catch (Exception ex) + { + // Handle timeout. + Log.Debug("Error: " + ex.Message); + } - return result; + return null; } private async Task CallAsyncSign(HttpMethod method, string endpoint, string sign, string body = null) @@ -546,27 +895,58 @@ private async Task CallAsyncSign(HttpMethod method, string endpoint, str var request = new HttpRequestMessage(method, endpoint); if (body != null) - { request.Content = new StringContent(body, Encoding.UTF8, "application/json"); - } request.Headers.Add("FTX-KEY", _client.ApiKey); request.Headers.Add("FTX-SIGN", sign); request.Headers.Add("FTX-TS", _nonce.ToString()); - var response = await _httpClient.SendAsync(request).ConfigureAwait(false); + if (_subAccount != null) + request.Headers.Add("FTX-SUBACCOUNT", Uri.EscapeUriString(_subAccount)); - var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var cts = new CancellationTokenSource(); - return result; + try + { + var response = + await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token); + return await response.Content.ReadAsStringAsync(cts.Token); + } + // If the token has been canceled, it is not a timeout. + catch (TaskCanceledException ex) when (cts.IsCancellationRequested) + { + // Handle cancellation. + Log.Debug("Canceled: " + ex.Message); + } + catch (TaskCanceledException ex) + { + // Handle timeout. + Log.Debug("Timed out: " + ex.Message); + } + catch (Exception ex) + { + // Handle timeout. + Log.Debug("Error: " + ex.Message); + } + + return null; } private string GenerateSignature(HttpMethod method, string url, string requestBody) { _nonce = GetNonce(); var signature = $"{_nonce}{method.ToString().ToUpper()}{url}{requestBody}"; - var hash = _hashMaker.ComputeHash(Encoding.UTF8.GetBytes(signature)); - var hashStringBase64 = BitConverter.ToString(hash).Replace("-", string.Empty); + string hashStringBase64; + try + { + var hash = _hashMaker.ComputeHash(Encoding.UTF8.GetBytes(signature)); + hashStringBase64 = BitConverter.ToString(hash).Replace("-", string.Empty); + } + catch (AccessViolationException e) + { + Log.Error(e, "Hash maker access violation error AGAIN??"); + throw; + } return hashStringBase64.ToLower(); } @@ -575,12 +955,6 @@ private long GetNonce() return Util.Util.GetMillisecondsFromEpochStart(); } - private dynamic ParseResponce(string responce) - { - return (dynamic)responce; - } - - #endregion } } \ No newline at end of file diff --git a/FtxApi/Models/AcceptQuoteResponse.cs b/FtxApi/Models/AcceptQuoteResponse.cs new file mode 100644 index 0000000..fd0c4ba --- /dev/null +++ b/FtxApi/Models/AcceptQuoteResponse.cs @@ -0,0 +1,7 @@ +namespace FtxApi.Models +{ + public class AcceptQuoteResponse + { + + } +} \ No newline at end of file diff --git a/FtxApi/Models/AccountInfo.cs b/FtxApi/Models/AccountInfo.cs index f05d269..71e8abb 100644 --- a/FtxApi/Models/AccountInfo.cs +++ b/FtxApi/Models/AccountInfo.cs @@ -1,53 +1,53 @@ using System.Collections.Generic; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class AccountInfo { - [JsonPropertyName("backstopProvider")] + [JsonProperty("backstopProvider")] public bool BackstopProvider { get; set; } - [JsonPropertyName("collateral")] + [JsonProperty("collateral")] public decimal Collateral { get; set; } - [JsonPropertyName("freeCollateral")] + [JsonProperty("freeCollateral")] public decimal FreeCollateral { get; set; } - [JsonPropertyName("initialMarginRequirement")] + [JsonProperty("initialMarginRequirement")] public decimal InitialMarginRequirement { get; set; } - [JsonPropertyName("liquidating")] + [JsonProperty("liquidating")] public bool Liquidating { get; set; } - [JsonPropertyName("maintenanceMarginRequirement")] + [JsonProperty("maintenanceMarginRequirement")] public decimal MaintenanceMarginRequirement { get; set; } - [JsonPropertyName("makerFee")] + [JsonProperty("makerFee")] public decimal MakerFee { get; set; } - [JsonPropertyName("marginFraction")] + [JsonProperty("marginFraction")] public decimal? MarginFraction { get; set; } - [JsonPropertyName("openMarginFraction")] + [JsonProperty("openMarginFraction")] public decimal? OpenMarginFraction { get; set; } - [JsonPropertyName("takerFee")] + [JsonProperty("takerFee")] public decimal TakerFee { get; set; } - [JsonPropertyName("totalAccountValue")] + [JsonProperty("totalAccountValue")] public decimal TotalAccountValue { get; set; } - [JsonPropertyName("totalPositionSize")] + [JsonProperty("totalPositionSize")] public decimal TotalPositionSize { get; set; } - [JsonPropertyName("username")] + [JsonProperty("username")] public string Username { get; set; } - [JsonPropertyName("leverage")] + [JsonProperty("leverage")] public decimal Leverage { get; set; } - [JsonPropertyName("positions")] + [JsonProperty("positions")] public List Positions { get; set; } } } diff --git a/FtxApi/Models/AccountLeverage.cs b/FtxApi/Models/AccountLeverage.cs index eb2fe0f..6acb048 100644 --- a/FtxApi/Models/AccountLeverage.cs +++ b/FtxApi/Models/AccountLeverage.cs @@ -1,10 +1,10 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class AccountLeverage { - [JsonPropertyName("leverage")] + [JsonProperty("leverage")] public int Leverage { get; set; } } } diff --git a/FtxApi/Models/Balance.cs b/FtxApi/Models/Balance.cs index 0d61cf6..bc8fe1e 100644 --- a/FtxApi/Models/Balance.cs +++ b/FtxApi/Models/Balance.cs @@ -1,16 +1,15 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class Balance { - [JsonPropertyName("coin")] - public string Coin { get; set; } - - [JsonPropertyName("free")] - public decimal Free { get; set; } - - [JsonPropertyName("total")] - public decimal Total { get; set; } + [JsonProperty("coin")] public string Coin { get; set; } + [JsonProperty("free")] public decimal Free { get; set; } + [JsonProperty("spotBorrow")] public decimal SpotBorrow { get; set; } + [JsonProperty("total")] public decimal Total { get; set; } + [JsonProperty("usdValue")] public decimal UsdValue { get; set; } + [JsonProperty("availableWithoutBorrow")] + public decimal AvailableWithoutBorrow { get; set; } } -} +} \ No newline at end of file diff --git a/FtxApi/Models/CancelOrder.cs b/FtxApi/Models/CancelOrder.cs new file mode 100644 index 0000000..a309963 --- /dev/null +++ b/FtxApi/Models/CancelOrder.cs @@ -0,0 +1,20 @@ +using FtxApi.Enums; +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class CancelOrder + { + [JsonProperty("market", NullValueHandling = NullValueHandling.Ignore)] + public string Market { get; set; } + + [JsonProperty("side", NullValueHandling = NullValueHandling.Ignore)] + public SideType? Side { get; set; } + + [JsonProperty("conditionalOrdersOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? ConditionalOrdersOnly { get; set; } + + [JsonProperty("limitOrdersOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? LimitOrdersOnly { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/Candle.cs b/FtxApi/Models/Candle.cs index 766f28d..d12eb00 100644 --- a/FtxApi/Models/Candle.cs +++ b/FtxApi/Models/Candle.cs @@ -1,26 +1,34 @@ -using System; -using System.Text.Json.Serialization; +using Utf8Json; +using System; +using System.Globalization; +using FtxApi.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + namespace FtxApi.Models { public class Candle { - [JsonPropertyName("close")] - public decimal Close { get; set; } + [JsonProperty("close", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Close { get; set; } - [JsonPropertyName("high")] - public decimal High { get; set; } + [JsonProperty("high", NullValueHandling = NullValueHandling.Ignore)] + public decimal? High { get; set; } - [JsonPropertyName("low")] - public decimal Low { get; set; } + [JsonProperty("low", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Low { get; set; } - [JsonPropertyName("open")] - public decimal Open { get; set; } + [JsonProperty("open", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Open { get; set; } - [JsonPropertyName("startTime")] + [JsonProperty("startTime", NullValueHandling = NullValueHandling.Ignore)] public DateTime StartTime { get; set; } + + [JsonProperty("time", NullValueHandling = NullValueHandling.Ignore)] + public long? Time { get; set; } - [JsonPropertyName("volume")] - public decimal Volume { get; set; } + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Volume { get; set; } } -} +} \ No newline at end of file diff --git a/FtxApi/Models/Coin.cs b/FtxApi/Models/Coin.cs index cd2d3bb..8c92c73 100644 --- a/FtxApi/Models/Coin.cs +++ b/FtxApi/Models/Coin.cs @@ -1,22 +1,22 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class Coin { - [JsonPropertyName("canDeposit")] + [JsonProperty("canDeposit")] public bool CanDeposit { get; set; } - [JsonPropertyName("canWithdraw")] + [JsonProperty("canWithdraw")] public bool CanWithdraw { get; set; } - [JsonPropertyName("hasTag")] + [JsonProperty("hasTag")] public bool HasTag { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public string Id { get; set; } - [JsonPropertyName("name")] + [JsonProperty("name")] public string Name { get; set; } } } diff --git a/FtxApi/Models/ConvertAcceptResponse.cs b/FtxApi/Models/ConvertAcceptResponse.cs new file mode 100644 index 0000000..05fb837 --- /dev/null +++ b/FtxApi/Models/ConvertAcceptResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class ConvertAcceptResponse + { + [JsonProperty("success", NullValueHandling = NullValueHandling.Ignore)] + public string Success { get; set; } + + [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] + public string Result { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/ConvertCoinRequest.cs b/FtxApi/Models/ConvertCoinRequest.cs new file mode 100644 index 0000000..683f5d0 --- /dev/null +++ b/FtxApi/Models/ConvertCoinRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class ConvertCoinRequest + { + [JsonProperty("fromCoin", NullValueHandling = NullValueHandling.Ignore)] + public string FromCoin { get; set; } + + [JsonProperty("toCoin", NullValueHandling = NullValueHandling.Ignore)] + public string ToCoin { get; set; } + + [JsonProperty("size", NullValueHandling = NullValueHandling.Ignore)] + public decimal Size { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/CreateOrder.cs b/FtxApi/Models/CreateOrder.cs new file mode 100644 index 0000000..296fd05 --- /dev/null +++ b/FtxApi/Models/CreateOrder.cs @@ -0,0 +1,95 @@ +using System; +using FtxApi.Enums; +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class CreateOrder + { + [JsonProperty("market", NullValueHandling = NullValueHandling.Ignore)] + public string Market { get; set; } + + [JsonProperty("side", NullValueHandling = NullValueHandling.Ignore)] + public SideType Side { get; set; } + + [JsonProperty("price", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Price { get; set; } + + [JsonProperty("size", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Size { get; set; } + + [JsonProperty("triggerPrice", NullValueHandling = NullValueHandling.Ignore)] + public decimal? TriggerPrice { get; set; } + + [JsonProperty("orderPrice", NullValueHandling = NullValueHandling.Ignore)] + public decimal? OrderPrice { get; set; } + + [JsonProperty("trailValue", NullValueHandling = NullValueHandling.Ignore)] + public decimal? TrailValue { get; set; } + + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public OrderType Type { get; set; } + + [JsonProperty("ioc", NullValueHandling = NullValueHandling.Ignore)] + public bool? Ioc { get; set; } + + [JsonProperty("postOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? PostOnly { get; set; } + + [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] + public string ClientId { get; set; } + + [JsonProperty("reduceOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? ReduceOnly { get; set; } + + [JsonProperty("retryUntilFilled", NullValueHandling = NullValueHandling.Ignore)] + public bool? RetryUntilFilled { get; set; } + + public DateTime Timestamp { get; set; } + [JsonProperty("quoteSize", NullValueHandling = NullValueHandling.Ignore)] + public decimal? QuoteSize => (Price??0) * (Size??0); + + public CreateOrder(string market, SideType side, OrderType orderType, decimal triggerPrice, decimal amount, + bool reduceOnly = false) + { + Market = market; + Side = side; + Type = orderType; + TriggerPrice = triggerPrice; + Size = amount; + ReduceOnly = reduceOnly; + } + + public CreateOrder(string market, SideType side, OrderType orderType, decimal triggerPrice, decimal orderPrice, + decimal amount, + bool reduceOnly = false) + { + Market = market; + Side = side; + Type = orderType; + TriggerPrice = triggerPrice; + OrderPrice = orderPrice; + Size = amount; + ReduceOnly = reduceOnly; + } + + public CreateOrder(string market, SideType side, decimal? price, + OrderType orderType, decimal amount, string clientId = "", bool ioc = false, bool postOnly = false, + bool reduceOnly = false) + { + Market = market; + Side = side; + Price = price; + Type = orderType; + Size = amount; + ClientId = clientId; + Ioc = ioc; + PostOnly = postOnly; + ReduceOnly = reduceOnly; + } + + public CreateOrder() + { + } + } +} \ No newline at end of file diff --git a/FtxApi/Models/DepositAddress.cs b/FtxApi/Models/DepositAddress.cs index 454e179..17e3cb1 100644 --- a/FtxApi/Models/DepositAddress.cs +++ b/FtxApi/Models/DepositAddress.cs @@ -1,13 +1,13 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class DepositAddress { - [JsonPropertyName("address")] + [JsonProperty("address")] public string Address { get; set; } - [JsonPropertyName("tag")] + [JsonProperty("tag")] public string Tag { get; set; } } } diff --git a/FtxApi/Models/DepositHistory.cs b/FtxApi/Models/DepositHistory.cs index c99e85f..459d5b0 100644 --- a/FtxApi/Models/DepositHistory.cs +++ b/FtxApi/Models/DepositHistory.cs @@ -1,41 +1,41 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class DepositHistory { - [JsonPropertyName("coin")] + [JsonProperty("coin")] public string Coin { get; set; } - [JsonPropertyName("confirmations")] + [JsonProperty("confirmations")] public decimal Confirmations { get; set; } - [JsonPropertyName("confirmedTime")] + [JsonProperty("confirmedTime")] public DateTime ConfirmedTime { get; set; } - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("sentTime")] + [JsonProperty("sentTime")] public DateTime SentTime { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal Size { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time")] public DateTime Time { get; set; } - [JsonPropertyName("txid")] + [JsonProperty("txid")] public string TxId { get; set; } - [JsonPropertyName("notes")] + [JsonProperty("notes")] public string Notes { get; set; } } } diff --git a/FtxApi/Models/ExpiredFutures.cs b/FtxApi/Models/ExpiredFutures.cs new file mode 100644 index 0000000..6b114aa --- /dev/null +++ b/FtxApi/Models/ExpiredFutures.cs @@ -0,0 +1,80 @@ +using System; +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class ExpiredFutures + { + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + + [JsonProperty("underlying", NullValueHandling = NullValueHandling.Ignore)] + public string Underlying { get; set; } + + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public string Description { get; set; } + + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public FutureType? FutureType { get; set; } + + [JsonProperty("expiry", NullValueHandling = NullValueHandling.Ignore)] + public DateTimeOffset? Expiry { get; set; } + + [JsonProperty("perpetual", NullValueHandling = NullValueHandling.Ignore)] + public bool? Perpetual { get; set; } + + [JsonProperty("expired", NullValueHandling = NullValueHandling.Ignore)] + public bool? Expired { get; set; } + + [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] + public bool? Enabled { get; set; } + + [JsonProperty("postOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool? PostOnly { get; set; } + + [JsonProperty("priceIncrement", NullValueHandling = NullValueHandling.Ignore)] + public double? PriceIncrement { get; set; } + + [JsonProperty("sizeIncrement", NullValueHandling = NullValueHandling.Ignore)] + public long? SizeIncrement { get; set; } + + [JsonProperty("last", NullValueHandling = NullValueHandling.Ignore)] public double? Last { get; set; } + + [JsonProperty("bid", NullValueHandling = NullValueHandling.Ignore)] public double? Bid { get; set; } + + [JsonProperty("ask", NullValueHandling = NullValueHandling.Ignore)] public double? Ask { get; set; } + + [JsonProperty("index", NullValueHandling = NullValueHandling.Ignore)] + public double? Index { get; set; } + + [JsonProperty("mark", NullValueHandling = NullValueHandling.Ignore)] + public double? Mark { get; set; } + + [JsonProperty("imfFactor", NullValueHandling = NullValueHandling.Ignore)] + public double? ImfFactor { get; set; } + + [JsonProperty("lowerBound", NullValueHandling = NullValueHandling.Ignore)] + public double? LowerBound { get; set; } + + [JsonProperty("upperBound", NullValueHandling = NullValueHandling.Ignore)] + public double? UpperBound { get; set; } + + [JsonProperty("underlyingDescription", NullValueHandling = NullValueHandling.Ignore)] + public string UnderlyingDescription { get; set; } + + [JsonProperty("expiryDescription", NullValueHandling = NullValueHandling.Ignore)] + public string ExpiryDescription { get; set; } + + [JsonProperty("moveStart", NullValueHandling = NullValueHandling.Ignore)] + public DateTimeOffset? MoveStart { get; set; } + + [JsonProperty("marginPrice", NullValueHandling = NullValueHandling.Ignore)] + public double? MarginPrice { get; set; } + + [JsonProperty("positionLimitWeight", NullValueHandling = NullValueHandling.Ignore)] + public long? PositionLimitWeight { get; set; } + + [JsonProperty("group", NullValueHandling = NullValueHandling.Ignore)] public Group Group { get; set; } + + } +} \ No newline at end of file diff --git a/FtxApi/Models/Fill.cs b/FtxApi/Models/Fill.cs index 1f6e9c8..11a56d9 100644 --- a/FtxApi/Models/Fill.cs +++ b/FtxApi/Models/Fill.cs @@ -1,58 +1,58 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class Fill { - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("feeCurrency")] + [JsonProperty("feeCurrency")] public string FeeCurrency { get; set; } - [JsonPropertyName("feeRate")] + [JsonProperty("feeRate")] public decimal FeeRate { get; set; } - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("liquidity")] + [JsonProperty("liquidity")] public string Liquidity { get; set; } - [JsonPropertyName("market")] + [JsonProperty("Market")] public string Market { get; set; } - [JsonPropertyName("baseCurrency")] + [JsonProperty("baseCurrency")] public string BaseCurrency { get; set; } - [JsonPropertyName("quoteCurrency")] + [JsonProperty("quoteCurrency")] public string QuoteCurrency { get; set; } - [JsonPropertyName("orderId")] + [JsonProperty("orderId")] public decimal? OrderId { get; set; } - [JsonPropertyName("tradeId")] + [JsonProperty("tradeId")] public decimal? TradeId { get; set; } - [JsonPropertyName("price")] + [JsonProperty("price")] public decimal Price { get; set; } - [JsonPropertyName("side")] + [JsonProperty("side")] public string Side { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal Size { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time")] public DateTime Time { get; set; } - [JsonPropertyName("type")] + [JsonProperty("type")] public string Type { get; set; } } } diff --git a/FtxApi/Models/FtxResult.cs b/FtxApi/Models/FtxResult.cs index 037aec8..ecce804 100644 --- a/FtxApi/Models/FtxResult.cs +++ b/FtxApi/Models/FtxResult.cs @@ -1,14 +1,14 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class FtxResult { - [JsonPropertyName("success")] + [JsonProperty("success")] public bool Success { get; set; } - [JsonPropertyName("result")] + [JsonProperty("result")] public T Result { get; set; } } } diff --git a/FtxApi/Models/FundingPayment.cs b/FtxApi/Models/FundingPayment.cs index 3fdd3d5..39c9e5b 100644 --- a/FtxApi/Models/FundingPayment.cs +++ b/FtxApi/Models/FundingPayment.cs @@ -1,20 +1,20 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class FundingPayment { - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("payment")] + [JsonProperty("payment")] public decimal Payment { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time")] public DateTime Time { get; set; } } } diff --git a/FtxApi/Models/FundingRate.cs b/FtxApi/Models/FundingRate.cs index aba8771..cab42d1 100644 --- a/FtxApi/Models/FundingRate.cs +++ b/FtxApi/Models/FundingRate.cs @@ -1,17 +1,17 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class FundingRate { - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("rate")] + [JsonProperty("rate")] public decimal Rate { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time")] public DateTime Time { get; set; } } } diff --git a/FtxApi/Models/Future.cs b/FtxApi/Models/Future.cs index ad35851..06f44cb 100644 --- a/FtxApi/Models/Future.cs +++ b/FtxApi/Models/Future.cs @@ -1,82 +1,108 @@ -using System.Text.Json.Serialization; +using System; +using Newtonsoft.Json; namespace FtxApi.Models { public class Future { - [JsonPropertyName("ask")] - public decimal Ask { get; set; } - - [JsonPropertyName("bid")] - public decimal Bid { get; set; } + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } - [JsonPropertyName("change1h")] - public decimal Change1h { get; set; } + [JsonProperty("underlying", NullValueHandling = NullValueHandling.Ignore)] + public string Underlying { get; set; } - [JsonPropertyName("change24h")] - public decimal Change24h { get; set; } + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public string Description { get; set; } - [JsonPropertyName("changeBod")] - public decimal ChangeBod { get; set; } + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public FutureType FutureType { get; set; } - [JsonPropertyName("volumeUsd24h")] - public decimal VolumeUsd24h { get; set; } + [JsonProperty("expiry", NullValueHandling = NullValueHandling.Ignore)] + public DateTimeOffset? Expiry { get; set; } - [JsonPropertyName("volume")] - public decimal Volume { get; set; } + [JsonProperty("perpetual", NullValueHandling = NullValueHandling.Ignore)] + public bool Perpetual { get; set; } - [JsonPropertyName("description")] - public string Description { get; set; } + [JsonProperty("expired", NullValueHandling = NullValueHandling.Ignore)] + public bool Expired { get; set; } - [JsonPropertyName("enabled")] + [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] public bool Enabled { get; set; } - [JsonPropertyName("expired")] - public bool Expired { get; set; } + [JsonProperty("postOnly", NullValueHandling = NullValueHandling.Ignore)] + public bool PostOnly { get; set; } - [JsonPropertyName("expiry")] - public string Expiry { get; set; } + [JsonProperty("priceIncrement", NullValueHandling = NullValueHandling.Ignore)] + public double? PriceIncrement { get; set; } - [JsonPropertyName("index")] - public decimal Index { get; set; } + [JsonProperty("sizeIncrement", NullValueHandling = NullValueHandling.Ignore)] + public double? SizeIncrement { get; set; } - [JsonPropertyName("imfFactor")] - public decimal ImfFactor { get; set; } + [JsonProperty("last", NullValueHandling = NullValueHandling.Ignore)] + public double? Last { get; set; } - [JsonPropertyName("last")] - public decimal Last { get; set; } + [JsonProperty("bid", NullValueHandling = NullValueHandling.Ignore)] + public double? Bid { get; set; } - [JsonPropertyName("lowerBound")] - public decimal LowerBound { get; set; } + [JsonProperty("ask", NullValueHandling = NullValueHandling.Ignore)] + public double? Ask { get; set; } - [JsonPropertyName("mark")] - public decimal Mark { get; set; } + [JsonProperty("index", NullValueHandling = NullValueHandling.Ignore)] + public double Index { get; set; } - [JsonPropertyName("name")] - public string Name { get; set; } + [JsonProperty("mark", NullValueHandling = NullValueHandling.Ignore)] + public double Mark { get; set; } - [JsonPropertyName("perpetual")] - public bool Perpetual { get; set; } + [JsonProperty("imfFactor", NullValueHandling = NullValueHandling.Ignore)] + public double ImfFactor { get; set; } - [JsonPropertyName("positionLimitWeight")] - public decimal PositionLimitWeight { get; set; } + [JsonProperty("lowerBound", NullValueHandling = NullValueHandling.Ignore)] + public double LowerBound { get; set; } - [JsonPropertyName("postOnly")] - public bool PostOnly { get; set; } + [JsonProperty("upperBound", NullValueHandling = NullValueHandling.Ignore)] + public double UpperBound { get; set; } - [JsonPropertyName("priceIncrement")] - public decimal PriceIncrement { get; set; } + [JsonProperty("underlyingDescription", NullValueHandling = NullValueHandling.Ignore)] + public string UnderlyingDescription { get; set; } - [JsonPropertyName("sizeIcrement")] - public decimal SizeIncrement { get; set; } + [JsonProperty("expiryDescription", NullValueHandling = NullValueHandling.Ignore)] + public string ExpiryDescription { get; set; } - [JsonPropertyName("underlying")] - public string Underlying { get; set; } + [JsonProperty("moveStart", NullValueHandling = NullValueHandling.Ignore)] + public DateTimeOffset? MoveStart { get; set; } + + [JsonProperty("marginPrice", NullValueHandling = NullValueHandling.Ignore)] + public double? MarginPrice { get; set; } + + [JsonProperty("positionLimitWeight", NullValueHandling = NullValueHandling.Ignore)] + public double? PositionLimitWeight { get; set; } + + [JsonProperty("group", NullValueHandling = NullValueHandling.Ignore)] + public Group Group { get; set; } + + [JsonProperty("change1h", NullValueHandling = NullValueHandling.Ignore)] + public double? Change1H { get; set; } - [JsonPropertyName("upperBound")] - public decimal UpperBound { get; set; } + [JsonProperty("change24h", NullValueHandling = NullValueHandling.Ignore)] + public double? Change24H { get; set; } - [JsonPropertyName("type")] - public string Type { get; set; } + [JsonProperty("changeBod", NullValueHandling = NullValueHandling.Ignore)] + public double? ChangeBod { get; set; } + + [JsonProperty("volumeUsd24h", NullValueHandling = NullValueHandling.Ignore)] + public double? VolumeUsd24H { get; set; } + + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] + public double? Volume { get; set; } + + [JsonProperty("openInterest", NullValueHandling = NullValueHandling.Ignore)] + public double? OpenInterest { get; set; } + + [JsonProperty("openInterestUsd", NullValueHandling = NullValueHandling.Ignore)] + public double? OpenInterestUsd { get; set; } } + + public enum Group { Daily, Monthly, Perpetual, Prediction, Quarterly, Weekly }; + + public enum FutureType { Future, Move, Perpetual, Prediction }; } \ No newline at end of file diff --git a/FtxApi/Models/FutureStats.cs b/FtxApi/Models/FutureStats.cs index cb12e20..b2a4530 100644 --- a/FtxApi/Models/FutureStats.cs +++ b/FtxApi/Models/FutureStats.cs @@ -1,28 +1,29 @@ -using System.Text.Json.Serialization; + +using Newtonsoft.Json; namespace FtxApi.Models { public class FutureStats { - [JsonPropertyName("volume")] - public decimal Volume { get; set; } + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Volume { get; set; } - [JsonPropertyName("nextFundingRate")] - public decimal NextFundingRate { get; set; } + [JsonProperty("nextFundingRate", NullValueHandling = NullValueHandling.Ignore)] + public decimal? NextFundingRate { get; set; } - [JsonPropertyName("nextFundingTime")] + [JsonProperty("nextFundingTime", NullValueHandling = NullValueHandling.Ignore)] public string NextFundingTime { get; set; } - [JsonPropertyName("expirationPrice")] - public decimal ExpirationPrice { get; set; } + [JsonProperty("expirationPrice", NullValueHandling = NullValueHandling.Ignore)] + public decimal? ExpirationPrice { get; set; } - [JsonPropertyName("predictedExpirationPrice")] - public decimal PredictedExpirationPrice { get; set; } + [JsonProperty("predictedExpirationPrice", NullValueHandling = NullValueHandling.Ignore)] + public decimal? PredictedExpirationPrice { get; set; } - [JsonPropertyName("openInterest")] - public decimal OpenInterest { get; set; } + [JsonProperty("openInterest", NullValueHandling = NullValueHandling.Ignore)] + public decimal? OpenInterest { get; set; } - [JsonPropertyName("strikePrice")] - public decimal StrikePrice { get; set; } + [JsonProperty("strikePrice", NullValueHandling = NullValueHandling.Ignore)] + public decimal? StrikePrice { get; set; } } } diff --git a/FtxApi/Models/GetQuoteStatusResponse.cs b/FtxApi/Models/GetQuoteStatusResponse.cs new file mode 100644 index 0000000..15fb6cd --- /dev/null +++ b/FtxApi/Models/GetQuoteStatusResponse.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class GetQuoteStatusResponse + { + [JsonProperty("baseCoin", NullValueHandling = NullValueHandling.Ignore)] + public string BaseCoin { get; set; } + + [JsonProperty("cost", NullValueHandling = NullValueHandling.Ignore)] + public double? Cost { get; set; } + + [JsonProperty("expired", NullValueHandling = NullValueHandling.Ignore)] + public bool? Expired { get; set; } + + [JsonProperty("expiry", NullValueHandling = NullValueHandling.Ignore)] + public double? Expiry { get; set; } + + [JsonProperty("filled", NullValueHandling = NullValueHandling.Ignore)] + public bool? Filled { get; set; } + + [JsonProperty("fromCoin", NullValueHandling = NullValueHandling.Ignore)] + public string FromCoin { get; set; } + + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public long Id { get; set; } + + [JsonProperty("price", NullValueHandling = NullValueHandling.Ignore)] + public double? Price { get; set; } + + [JsonProperty("proceeds", NullValueHandling = NullValueHandling.Ignore)] + public double? Proceeds { get; set; } + + [JsonProperty("quoteCoin", NullValueHandling = NullValueHandling.Ignore)] + public string QuoteCoin { get; set; } + + [JsonProperty("side", NullValueHandling = NullValueHandling.Ignore)] + public string Side { get; set; } + + [JsonProperty("toCoin", NullValueHandling = NullValueHandling.Ignore)] + public string ToCoin { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/LeveragedTokens/LeveragedToken.cs b/FtxApi/Models/LeveragedTokens/LeveragedToken.cs index 23517d3..a51b7f8 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedToken.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedToken.cs @@ -1,37 +1,37 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedToken { - [JsonPropertyName("name")] + [JsonProperty("name")] public string Name { get; set; } - [JsonPropertyName("description")] + [JsonProperty("description")] public string Description { get; set; } - [JsonPropertyName("underlying")] + [JsonProperty("underlying")] public string Underlying { get; set; } - [JsonPropertyName("outstanding")] + [JsonProperty("outstanding")] public decimal Outstanding { get; set; } - [JsonPropertyName("pricePerShare")] + [JsonProperty("pricePerShare")] public decimal PricePerShare { get; set; } - [JsonPropertyName("positionPerShare")] + [JsonProperty("positionPerShare")] public decimal PositionPerShare { get; set; } - [JsonPropertyName("underlyingMark")] + [JsonProperty("underlyingMark")] public decimal UnderlyingMark { get; set; } - [JsonPropertyName("contractAddress")] + [JsonProperty("contractAddress")] public string ContractAddress { get; set; } - [JsonPropertyName("change1h")] + [JsonProperty("change1h")] public decimal Change1h { get; set; } - [JsonPropertyName("change24h")] + [JsonProperty("change24h")] public decimal Change24h { get; set; } } } diff --git a/FtxApi/Models/LeveragedTokens/LeveragedTokenBalance.cs b/FtxApi/Models/LeveragedTokens/LeveragedTokenBalance.cs index d10e9ab..863e9ca 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedTokenBalance.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedTokenBalance.cs @@ -1,13 +1,14 @@ -using System.Text.Json.Serialization; + +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedTokenBalance { - [JsonPropertyName("token")] + [JsonProperty("token")] public string Token { get; set; } - [JsonPropertyName("balance")] + [JsonProperty("balance")] public decimal Balance { get; set; } } } diff --git a/FtxApi/Models/LeveragedTokens/LeveragedTokenCreation.cs b/FtxApi/Models/LeveragedTokens/LeveragedTokenCreation.cs index 1158026..06e8c74 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedTokenCreation.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedTokenCreation.cs @@ -1,38 +1,38 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedTokenCreation { - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("token")] + [JsonProperty("token")] public string Token { get; set; } - [JsonPropertyName("requestedSize")] + [JsonProperty("requestedSize")] public decimal RequestedSize { get; set; } - [JsonPropertyName("pending")] + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonPropertyName("createdSize")] + [JsonProperty("createdSize")] public decimal CreatedSize { get; set; } - [JsonPropertyName("price")] + [JsonProperty("price")] public decimal Price { get; set; } - [JsonPropertyName("cost")] + [JsonProperty("cost")] public decimal Cost { get; set; } - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("requestedAt")] + [JsonProperty("requestedAt")] public DateTime RequestedAt { get; set; } - [JsonPropertyName("fulfilledAt")] + [JsonProperty("fulfilledAt")] public DateTime FulfilledAt { get; set; } } } diff --git a/FtxApi/Models/LeveragedTokens/LeveragedTokenCreationRequest.cs b/FtxApi/Models/LeveragedTokens/LeveragedTokenCreationRequest.cs index 0493317..beb6f20 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedTokenCreationRequest.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedTokenCreationRequest.cs @@ -1,29 +1,29 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedTokenCreationRequest { - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("token")] + [JsonProperty("token")] public string Token { get; set; } - [JsonPropertyName("requestedSize")] + [JsonProperty("requestedSize")] public decimal RequestedSize { get; set; } - [JsonPropertyName("pending")] + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonPropertyName("cost")] + [JsonProperty("cost")] public decimal Cost { get; set; } - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("requestedAt")] + [JsonProperty("requestedAt")] public DateTime RequestedAt { get; set; } } } diff --git a/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemption.cs b/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemption.cs index a650620..dd35da5 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemption.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemption.cs @@ -1,26 +1,26 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedTokenRedemption { - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("token")] + [JsonProperty("token")] public string Token { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal Size { get; set; } - [JsonPropertyName("projectedProceeds")] + [JsonProperty("projectedProceeds")] public decimal ProjectedProceeds { get; set; } - [JsonPropertyName("pending")] + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonPropertyName("requestedAt")] + [JsonProperty("requestedAt")] public DateTime RequestedAt { get; set; } } } diff --git a/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemptionRequest.cs b/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemptionRequest.cs index a2e3cf5..0d23164 100644 --- a/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemptionRequest.cs +++ b/FtxApi/Models/LeveragedTokens/LeveragedTokenRedemptionRequest.cs @@ -1,35 +1,35 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.LeveragedTokens { public class LeveragedTokenRedemptionRequest { - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("token")] + [JsonProperty("token")] public string Token { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal Size { get; set; } - [JsonPropertyName("pending")] + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonPropertyName("price")] + [JsonProperty("price")] public decimal Price { get; set; } - [JsonPropertyName("proceeds")] + [JsonProperty("proceeds")] public decimal Proceeds { get; set; } - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("requestedAt")] + [JsonProperty("requestedAt")] public DateTime RequestedAt { get; set; } - [JsonPropertyName("fulfilledAt")] + [JsonProperty("fulfilledAt")] public DateTime FulfilledAt { get; set; } } } diff --git a/FtxApi/Models/Markets/Market.cs b/FtxApi/Models/Markets/Market.cs index d825dc9..0f4593a 100644 --- a/FtxApi/Models/Markets/Market.cs +++ b/FtxApi/Models/Markets/Market.cs @@ -1,43 +1,43 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.Markets { public class Market { - [JsonPropertyName("type")] + [JsonProperty("type")] public string Type { get; set; } - [JsonPropertyName("name")] + [JsonProperty("name")] public string Name { get; set; } - [JsonPropertyName("underlying")] + [JsonProperty("underlying")] public string Underlying { get; set; } - [JsonPropertyName("baseCurrency")] + [JsonProperty("baseCurrency")] public string BaseCurreny { get; set; } - [JsonPropertyName("quoteCurrency")] + [JsonProperty("quoteCurrency")] public string QuoteCurrency { get; set; } - [JsonPropertyName("enabled")] + [JsonProperty("enabled")] public bool Enabled { get; set; } - [JsonPropertyName("ask")] + [JsonProperty("ask")] public decimal? Ask { get; set; } - [JsonPropertyName("bid")] + [JsonProperty("bid")] public decimal? Bid { get; set; } - [JsonPropertyName("last")] + [JsonProperty("last")] public decimal? Last { get; set; } - [JsonPropertyName("priceIncrement")] + [JsonProperty("priceIncrement")] public decimal? PriceIncrement { get; set; } - [JsonPropertyName("sizeIncrement")] + [JsonProperty("sizeIncrement")] public decimal? SizeIncrement { get; set; } } } diff --git a/FtxApi/Models/Markets/Orderbook.cs b/FtxApi/Models/Markets/Orderbook.cs index cbd29ca..1c29dc7 100644 --- a/FtxApi/Models/Markets/Orderbook.cs +++ b/FtxApi/Models/Markets/Orderbook.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.Markets { public class Orderbook { - [JsonPropertyName("bids")] + [JsonProperty("bids")] public List> Bids { get; set; } - [JsonPropertyName("asks")] + [JsonProperty("asks")] public List> Asks { get; set; } } } diff --git a/FtxApi/Models/Markets/Trade.cs b/FtxApi/Models/Markets/Trade.cs index cf0ce53..cd40c4c 100644 --- a/FtxApi/Models/Markets/Trade.cs +++ b/FtxApi/Models/Markets/Trade.cs @@ -1,28 +1,28 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models.Markets { public class Trade { - [JsonPropertyName("id")] - public decimal Id { get; set; } + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Id { get; set; } - [JsonPropertyName("liquidation")] - public bool Liquidation { get; set; } + [JsonProperty("liquidation", NullValueHandling = NullValueHandling.Ignore)] + public bool? Liquidation { get; set; } - [JsonPropertyName("price")] - public decimal Price { get; set; } + [JsonProperty("price", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Price { get; set; } - [JsonPropertyName("side")] + [JsonProperty("side", NullValueHandling = NullValueHandling.Ignore)] public string Side { get; set; } - [JsonPropertyName("size")] - public decimal Size { get; set; } + [JsonProperty("size", NullValueHandling = NullValueHandling.Ignore)] + public decimal? Size { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time", NullValueHandling = NullValueHandling.Ignore)] public DateTime Time { get; set; } } -} +} \ No newline at end of file diff --git a/FtxApi/Models/Order.cs b/FtxApi/Models/Order.cs index b88df74..6e974c2 100644 --- a/FtxApi/Models/Order.cs +++ b/FtxApi/Models/Order.cs @@ -1,55 +1,43 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.Json.Serialization; +using FtxApi.Enums; +using Newtonsoft.Json; namespace FtxApi.Models { public class Order { - [JsonPropertyName("createdAt")] - public DateTime CreatedAt { get; set; } + [JsonProperty("createdAt")] public DateTime? CreatedAt { get; set; } - [JsonPropertyName("filledSize")] - public decimal? FilledSize { get; set; } + [JsonProperty("filledSize")] public decimal? FilledSize { get; set; } - [JsonPropertyName("future")] - public string Future { get; set; } + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("id")] - public decimal? Id { get; set; } + [JsonProperty("id")] public decimal? Id { get; set; } - [JsonPropertyName("market")] - public string Market { get; set; } + [JsonProperty("Market")] public string Market { get; set; } - [JsonPropertyName("price")] - public decimal? Price { get; set; } + [JsonProperty("price")] public decimal? Price { get; set; } - [JsonPropertyName("remainingSize")] - public decimal? RemainingSize { get; set; } + [JsonProperty("remainingSize")] public decimal? RemainingSize { get; set; } - [JsonPropertyName("side")] - public string Side { get; set; } + [JsonProperty("side")] public SideType Side { get; set; } - [JsonPropertyName("size")] - public decimal? Size { get; set; } + [JsonProperty("size")] public decimal? Size { get; set; } - [JsonPropertyName("status")] - public string Status { get; set; } + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("type")] - public string Type { get; set; } + [JsonProperty("type")] public OrderType? Type { get; set; } - [JsonPropertyName("reduceOnly")] - public bool ReduceOnly { get; set; } + [JsonProperty("reduceOnly")] public bool? ReduceOnly { get; set; } - [JsonPropertyName("ioc")] - public bool Ioc { get; set; } + [JsonProperty("ioc")] public bool? Ioc { get; set; } - [JsonPropertyName("postOnly")] - public bool PostOnly { get; set; } + [JsonProperty("postOnly")] public bool? PostOnly { get; set; } - [JsonPropertyName("clientId")] - public string ClientId { get; set; } + [JsonProperty("clientId")] public string ClientId { get; set; } + + } -} +} \ No newline at end of file diff --git a/FtxApi/Models/OrderStatus.cs b/FtxApi/Models/OrderStatus.cs index babc320..b71e4b5 100644 --- a/FtxApi/Models/OrderStatus.cs +++ b/FtxApi/Models/OrderStatus.cs @@ -1,56 +1,56 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class OrderStatus { - [JsonPropertyName("createdAt")] + [JsonProperty("createdAt")] public DateTime CreatedAt { get; set; } - [JsonPropertyName("filledSize")] + [JsonProperty("filledSize")] public decimal? FilledSize { get; set; } - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal? Id { get; set; } - [JsonPropertyName("market")] + [JsonProperty("Market")] public string Market { get; set; } - [JsonPropertyName("price")] + [JsonProperty("price")] public decimal? Price { get; set; } - [JsonPropertyName("avgFillPrice")] + [JsonProperty("avgFillPrice")] public decimal? AvgFillPrice { get; set; } - [JsonPropertyName("remainingSize")] + [JsonProperty("remainingSize")] public decimal? RemainingSize { get; set; } - [JsonPropertyName("side")] + [JsonProperty("side")] public string Side { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal? Size { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("type")] + [JsonProperty("type")] public string Type { get; set; } - [JsonPropertyName("reduceOnly")] + [JsonProperty("reduceOnly")] public bool ReduceOnly { get; set; } - [JsonPropertyName("ioc")] + [JsonProperty("ioc")] public bool Ioc { get; set; } - [JsonPropertyName("postOnly")] + [JsonProperty("postOnly")] public bool PostOnly { get; set; } - [JsonPropertyName("clientId")] + [JsonProperty("clientId")] public string ClientId { get; set; } } } diff --git a/FtxApi/Models/Position.cs b/FtxApi/Models/Position.cs index ce2e6f2..27d6573 100644 --- a/FtxApi/Models/Position.cs +++ b/FtxApi/Models/Position.cs @@ -1,53 +1,56 @@  -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class Position { - [JsonPropertyName("collateralUsed")] + [JsonProperty("collateralUsed")] public decimal? CollateralUsed { get; set; } - [JsonPropertyName("cost")] + [JsonProperty("cost")] public decimal? Cost { get; set; } - [JsonPropertyName("entryPrice")] + [JsonProperty("entryPrice")] public decimal? EntryPrice { get; set; } - [JsonPropertyName("estimatedLiquidationPrice")] + [JsonProperty("estimatedLiquidationPrice")] public decimal? EstimatedLiquidationPrice { get; set; } - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("initialMarginRequirement")] + [JsonProperty("initialMarginRequirement")] public decimal? InitialMarginRequirement { get; set; } - [JsonPropertyName("longOrderSize")] + [JsonProperty("longOrderSize")] public decimal? LongOrderSize { get; set; } - [JsonPropertyName("maintenanceMarginRequirement")] + [JsonProperty("maintenanceMarginRequirement")] public decimal? MaintenanceMarginRequirement { get; set; } - [JsonPropertyName("netSize")] + [JsonProperty("netSize")] public decimal? NetSize { get; set; } - [JsonPropertyName("openSize")] + [JsonProperty("openSize")] public decimal? OpenSize { get; set; } - [JsonPropertyName("realizedPnl")] + [JsonProperty("realizedPnl")] public decimal? RealizedPnl { get; set; } - [JsonPropertyName("shortOrderSize")] + [JsonProperty("shortOrderSize")] public decimal? ShortOrderSize { get; set; } - [JsonPropertyName("side")] + [JsonProperty("side")] public string Side { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal? Size { get; set; } - [JsonPropertyName("unrealizedPnl")] + [JsonProperty("unrealizedPnl")] public decimal? UnrealizedPnl { get; set; } + + [JsonProperty("recentAverageOpenPrice")] + public decimal? AverageOpenPrice { get; set; } } } diff --git a/FtxApi/Models/QuoteStatusRequest.cs b/FtxApi/Models/QuoteStatusRequest.cs new file mode 100644 index 0000000..15d50e7 --- /dev/null +++ b/FtxApi/Models/QuoteStatusRequest.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class QuoteStatusRequest + { + [JsonProperty("market", NullValueHandling = NullValueHandling.Ignore)] + public string Market { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/RequestQuoteResponse.cs b/FtxApi/Models/RequestQuoteResponse.cs new file mode 100644 index 0000000..499dece --- /dev/null +++ b/FtxApi/Models/RequestQuoteResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace FtxApi.Models +{ + public class RequestQuoteResponse + { + [JsonProperty("quoteId", NullValueHandling = NullValueHandling.Ignore)] + public long QuoteId { get; set; } + } +} \ No newline at end of file diff --git a/FtxApi/Models/TriggerOrder.cs b/FtxApi/Models/TriggerOrder.cs index c124a8a..af7722c 100644 --- a/FtxApi/Models/TriggerOrder.cs +++ b/FtxApi/Models/TriggerOrder.cs @@ -1,58 +1,58 @@ using System; using System.Collections.Generic; using System.Text; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class TriggerOrder { - [JsonPropertyName("createdAt")] + [JsonProperty("createdAt")] public DateTime CreatedAt { get; set; } - [JsonPropertyName("future")] + [JsonProperty("future")] public string Future { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal? Id { get; set; } - [JsonPropertyName("market")] + [JsonProperty("Market")] public string Market { get; set; } - [JsonPropertyName("triggerPrice")] + [JsonProperty("triggerPrice")] public decimal? TriggerPrice { get; set; } - [JsonPropertyName("orderId")] + [JsonProperty("orderId")] public decimal? OrderId { get; set; } - [JsonPropertyName("side")] + [JsonProperty("side")] public string Side { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal? Size { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("type")] + [JsonProperty("type")] public string Type { get; set; } - [JsonPropertyName("orderPrice")] + [JsonProperty("orderPrice")] public decimal? OrderPrice { get; set; } - [JsonPropertyName("error")] + [JsonProperty("error")] public string Error { get; set; } - [JsonPropertyName("triggeredAt")] + [JsonProperty("triggeredAt")] public DateTime? TriggeredAt { get; set; } - [JsonPropertyName("reduceOnly")] + [JsonProperty("reduceOnly")] public bool ReduceOnly { get; set; } - [JsonPropertyName("orderType")] + [JsonProperty("orderType")] public string OrderType { get; set; } - [JsonPropertyName("retryUntilFilled")] + [JsonProperty("retryUntilFilled")] public bool RetryUntilFilled { get; set; } } } diff --git a/FtxApi/Models/WithdrawalHistory.cs b/FtxApi/Models/WithdrawalHistory.cs index 43047e2..df8dc6b 100644 --- a/FtxApi/Models/WithdrawalHistory.cs +++ b/FtxApi/Models/WithdrawalHistory.cs @@ -1,34 +1,34 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace FtxApi.Models { public class WithdrawalHistory { - [JsonPropertyName("coin")] + [JsonProperty("coin")] public string Coin { get; set; } - [JsonPropertyName("address")] + [JsonProperty("address")] public string Address { get; set; } - [JsonPropertyName("tag")] + [JsonProperty("tag")] public string Tag { get; set; } - [JsonPropertyName("fee")] + [JsonProperty("fee")] public decimal Fee { get; set; } - [JsonPropertyName("id")] + [JsonProperty("id")] public decimal Id { get; set; } - [JsonPropertyName("size")] + [JsonProperty("size")] public decimal Size { get; set; } - [JsonPropertyName("status")] + [JsonProperty("status")] public string Status { get; set; } - [JsonPropertyName("time")] + [JsonProperty("time")] public string Time { get; set; } - [JsonPropertyName("txid")] + [JsonProperty("txid")] public string TxId { get; set; } } } diff --git a/FtxApi/Util/FtxWebSockerRequestGenerator.cs b/FtxApi/Util/FtxWebSockerRequestGenerator.cs index e133044..44a0fd5 100644 --- a/FtxApi/Util/FtxWebSockerRequestGenerator.cs +++ b/FtxApi/Util/FtxWebSockerRequestGenerator.cs @@ -41,12 +41,12 @@ public static string GetUnsubscribeRequest(string channel) public static string GetSubscribeRequest(string channel, string instrument) { - return $"{{\"op\": \"subscribe\", \"channel\": \"{channel}\", \"market\": \"{instrument}\"}}"; + return $"{{\"op\": \"subscribe\", \"channel\": \"{channel}\", \"Market\": \"{instrument}\"}}"; } public static string GetUnsubscribeRequest(string channel, string instrument) { - return $"{{\"op\": \"unsubscribe\", \"channel\": \"{channel}\", \"market\": \"{instrument}\"}}"; + return $"{{\"op\": \"unsubscribe\", \"channel\": \"{channel}\", \"Market\": \"{instrument}\"}}"; } } } \ No newline at end of file diff --git a/FtxApi/Util/UnixTimestampConverter.cs b/FtxApi/Util/UnixTimestampConverter.cs new file mode 100644 index 0000000..780bcf0 --- /dev/null +++ b/FtxApi/Util/UnixTimestampConverter.cs @@ -0,0 +1,26 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace FtxApi.Util +{ + public class UnixTimestampConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(DateTime); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var t = long.Parse((string) reader.Value); + return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(t); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file