diff --git a/Bitget.Net.UnitTests/BitgetRestIntegrationTests.cs b/Bitget.Net.UnitTests/BitgetRestIntegrationTests.cs index 33930250..4d55dd7b 100644 --- a/Bitget.Net.UnitTests/BitgetRestIntegrationTests.cs +++ b/Bitget.Net.UnitTests/BitgetRestIntegrationTests.cs @@ -134,6 +134,29 @@ public async Task TestFuturesTrading() await RunAndCheckResult(client => client.FuturesApiV2.Trading.GetClosedTriggerOrdersAsync(Enums.BitgetProductTypeV2.UsdtFutures, Enums.V2.TriggerPlanTypeFilter.Trigger, default, default, default, default, default, default, default, default, default), true, true, "data"); } + [Test] + public async Task TestUnifiedExchangeData() + { + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetFuturesSymbolsAsync(Enums.Uta.ProductCategory.UsdtFutures, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetSpotSymbolsAsync(default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetMarginSymbolsAsync(default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetSpotTickersAsync(default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetFuturesTickersAsync(Enums.Uta.ProductCategory.UsdtFutures, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetOrderBookAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetRecentTradesAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetProofOfReservesAsync(default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetOpenInterestAsync(Enums.Uta.ProductCategory.UsdtFutures, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetKlinesAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", Enums.Uta.KlineUaInterval.OneDay, default, default, default, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetKlineHistoryAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", Enums.Uta.KlineUaInterval.OneDay, default, default, default, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetFundingRateAsync("ETHUSDT", default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetFundingRateHistoryAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", default, default, default), false, true, "data.resultList"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetDiscountRateAsync(default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetMarginLoanInterestRatesAsync("ETH", default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetPositionTiersAsync(Enums.Uta.ProductCategory.UsdtFutures, "ETHUSDT", default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetOpenInterestLimitAsync(Enums.Uta.ProductCategory.UsdtFutures, default, default), false, true, "data"); + await RunAndCheckResult(client => client.UnifiedApi.ExchangeData.GetIndexComponentsAsync("ETHUSDT", default), false, true, "data"); + } + [Test] public async Task TestOrderBooks() { @@ -141,4 +164,4 @@ public async Task TestOrderBooks() await TestOrderBook(new BitgetFuturesSymbolOrderBook(Enums.BitgetProductTypeV2.UsdtFutures, "ETHUSDT")); } } -} +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/BitgetSocketIntegrationTests.cs b/Bitget.Net.UnitTests/BitgetSocketIntegrationTests.cs index 44f2499e..4419de0f 100644 --- a/Bitget.Net.UnitTests/BitgetSocketIntegrationTests.cs +++ b/Bitget.Net.UnitTests/BitgetSocketIntegrationTests.cs @@ -1,4 +1,5 @@ using Bitget.Net.Clients; +using Bitget.Net.Objects.Models; using Bitget.Net.Objects.Models.V2; using Bitget.Net.Objects.Options; using CryptoExchange.Net.Testing; @@ -37,6 +38,9 @@ public async Task TestSubscriptions() await RunAndCheckUpdate((client, updateHandler) => client.FuturesApiV2.SubscribeToBalanceUpdatesAsync(Enums.BitgetProductTypeV2.UsdtFutures, default, default), false, true); await RunAndCheckUpdate((client, updateHandler) => client.FuturesApiV2.SubscribeToTickerUpdatesAsync(Enums.BitgetProductTypeV2.UsdtFutures, "ETHUSDT", updateHandler, default), true, false); - } + + await RunAndCheckUpdate((client, updateHandler) => client.UnifiedApi.SubscribeToAccountUpdatesAsync(default, default), false, true); + await RunAndCheckUpdate((client, updateHandler) => client.UnifiedApi.SubscribeToTickerUpdatesAsync(Enums.Uta.ProductCategory.Spot, "ETHUSDT", updateHandler, default), true, false); + } } } diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/CancelWithdrawal.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/CancelWithdrawal.txt new file mode 100644 index 00000000..31a6ac09 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/CancelWithdrawal.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/cancel-withdrawal +true +BodyParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1740000000000, + "data": "success" +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountConfig.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountConfig.txt new file mode 100644 index 00000000..33c43e52 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountConfig.txt @@ -0,0 +1,81 @@ +GET +/api/v3/account/settings +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1753787749280, + "data": { + "uid": "1111111111", + "accountMode": "hybrid", + "assetMode": "multi_assets", + "accountLevel": "advanced", + "holdMode": "one_way_mode", + "stpMode": "none", + "symbolConfigList": [ + { + "category": "USDT-FUTURES", + "symbol": "BGBUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "BMTUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "1000SATSUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "FUNUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "1000BONKUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "marginMode": "crossed", + "leverage": "1" + }, + { + "category": "USDT-FUTURES", + "symbol": "IOTAUSDT", + "marginMode": "crossed", + "leverage": "20" + }, + { + "category": "USDT-FUTURES", + "symbol": "C98USDT", + "marginMode": "crossed", + "leverage": "20" + } + ], + "coinConfigList": [ + { + "coin": "USDT", + "leverage": "6" + }, + { + "coin": "SHIB", + "leverage": "2" + }, + { + "coin": "BTC", + "leverage": "3" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountInfo.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountInfo.txt new file mode 100644 index 00000000..e7454994 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetAccountInfo.txt @@ -0,0 +1,26 @@ +GET +/api/v3/account/info +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1744617600000, + "data": { + "userId": "123456789", + "inviterId": "987654321", + "parentId": "", + "channelCode": "6258", + "channel": "official", + "ips": "192.168.1.1,192.168.1.2", + "permType": "read-and-write", + "permissions": [ + "uta_mgt", + "uta_trade", + "withdraw", + "copy_futures_position", + "copy_futures_order" + ], + "regisTime": "1704067200000" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetBalances.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetBalances.txt new file mode 100644 index 00000000..f634b26c --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetBalances.txt @@ -0,0 +1,42 @@ +GET +/api/v3/account/assets +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1746687063471, + "data": { + "accountEquity": "11.13919278", + "usdtEquity": "11.13921165", + "btcEquity": "0.00011256", + "unrealisedPnl": "0", + "usdtUnrealisedPnl": "0", + "btcUnrealizedPnl": "0", + "effEquity": "6.19299777", + "mmr": "0", + "imr": "0", + "mgnRatio": "0", + "positionMgnRatio": "0", + "assets": [ + { + "coin": "USDT", + "equity": "6.19300826", + "usdValue": "6.19299777", + "balance": "6.19300826", + "available": "6.19300826", + "debt": "0", + "locked": "0" + }, + { + "coin": "BGB", + "equity": "1.15582129", + "usdValue": "4.94618029", + "balance": "1.15582129", + "available": "1.15582129", + "debt": "0", + "locked": "0" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetConvertRecords.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetConvertRecords.txt new file mode 100644 index 00000000..fd1d4007 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetConvertRecords.txt @@ -0,0 +1,30 @@ +GET +/api/v3/account/convert-records +true +UriParams: {"fromAsset": "123","toAsset": "123"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730369634178, + "data": { + "list": [ + { + "fromCoin": "USDT", + "fromCoinSize": "281.72276656", + "toCoin": "ETH", + "toCoinSize": "0.0986029682", + "price": "0.0003499", + "ts": "1730359119358" + }, + { + "fromCoin": "USDT", + "fromCoinSize": "3305.13434913", + "toCoin": "ETH", + "toCoinSize": "1.1567970221", + "price": "0.00035", + "ts": "1730359063138" + } + ], + "cursor": "1235780967957364737" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeductStatus.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeductStatus.txt new file mode 100644 index 00000000..579a9492 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeductStatus.txt @@ -0,0 +1,12 @@ +GET +/api/v3/account/deduct-info +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1746687063471, + "data": { + "deduct": "on" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeltaInfo.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeltaInfo.txt new file mode 100644 index 00000000..46b7472b --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDeltaInfo.txt @@ -0,0 +1,20 @@ +GET +/api/v3/account/delta-info +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1740000000000, + "data": { + "deltaEquityRatio": "0.15", + "deltaThreshold": "0.2", + "positionThreshold": "0.05", + "list": [ + { + "coin": "BTC", + "positionRatio": "0.03" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositAddress.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositAddress.txt new file mode 100644 index 00000000..30fc6d9e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositAddress.txt @@ -0,0 +1,16 @@ +GET +/api/v3/account/deposit-address +true +UriParams: {"coin": "123"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189276579, + "data": { + "address": "0x51xxx", + "chain": "erc20", + "coin": "USDT", + "tag": null, + "url": "" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositRecords.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositRecords.txt new file mode 100644 index 00000000..a7dd3fae --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetDepositRecords.txt @@ -0,0 +1,25 @@ +GET +/api/v3/account/deposit-records +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1740481864545, + "data": [ + { + "orderId": "1278112570963742720", + "recordId": "1278112570963742720", + "coin": "usdt", + "type": "deposit", + "dest": "internal_transfer", + "size": "1", + "status": "success", + "fromAddress": "0x51xxx", + "toAddress": "0x51xxx", + "chain": "erc20", + "createdTime": "1740451703778", + "updatedTime": "1740451703778" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFee.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFee.txt new file mode 100644 index 00000000..16e8730e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFee.txt @@ -0,0 +1,13 @@ +GET +/api/v3/account/fee-rate +true +UriParams: {"category": "SPOT","symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1751972326323, + "data": { + "makerFeeRate": "0.0008", + "takerFeeRate": "0.0008" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFinancialRecords.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFinancialRecords.txt new file mode 100644 index 00000000..9e23cb0d --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFinancialRecords.txt @@ -0,0 +1,25 @@ +GET +/api/v3/account/financial-records +true +UriParams: {"category": "MARGIN"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1750135478641, + "data": { + "list": [ + { + "category": "Margin", + "id": "13111111111111111", + "symbol": "BTCUSDT", + "coin": "BTC", + "type": "ORDER_DEALT_IN", + "amount": "0.00531168", + "fee": "-0.00000531", + "balance": "55.10017801", + "ts": "1745853486185" + } + ], + "cursor": "122222222222222222" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFundingBalances.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFundingBalances.txt new file mode 100644 index 00000000..02f3a7cf --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetFundingBalances.txt @@ -0,0 +1,23 @@ +GET +/api/v3/account/funding-assets +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1750396239013, + "data": [ + { + "coin": "BGB", + "available": "0.01", + "frozen": "0", + "balance": "0.01" + }, + { + "coin": "USDT", + "available": "0.04", + "frozen": "0", + "balance": "0.04" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetMaxTransferable.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetMaxTransferable.txt new file mode 100644 index 00000000..40acdff1 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetMaxTransferable.txt @@ -0,0 +1,14 @@ +GET +/api/v3/account/max-transferable +true +UriParams: {"coin": "123"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189435812, + "data": { + "coin": "USDT", + "maxTransfer": "1", + "borrowMaxTransfer": "1" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetOpenInterestLimit.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetOpenInterestLimit.txt new file mode 100644 index 00000000..bc7ce5a8 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetOpenInterestLimit.txt @@ -0,0 +1,15 @@ +GET +/api/v3/account/open-interest-limit +true +UriParams: {"category": "USDT-FUTURES","symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1764170997805, + "data": { + "symbol": "BTCUSDT", + "singleUserLimit": "2766.30748", + "masterSubLimit": "9173.8782", + "marketMakerLimit": "0" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetPaymentAssets.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetPaymentAssets.txt new file mode 100644 index 00000000..754803d5 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetPaymentAssets.txt @@ -0,0 +1,19 @@ +GET +/api/v3/account/payment-coins +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189435812, + "data": { + "paymentCoinList": [ + { + "coin": "ETH", + "size": "0.12", + "amount": "293.5" + } + ], + "maxSelection": "1" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetRepayableAssets.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetRepayableAssets.txt new file mode 100644 index 00000000..82b76f94 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetRepayableAssets.txt @@ -0,0 +1,19 @@ +GET +/api/v3/account/repayable-coins +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189435812, + "data": { + "repayableCoinList": [ + { + "coin": "USDT", + "size": "147214.04781004", + "amount": "147102.60677584" + } + ], + "maxSelection": "1" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetSwitchToClassicStatus.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetSwitchToClassicStatus.txt new file mode 100644 index 00000000..2757810c --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetSwitchToClassicStatus.txt @@ -0,0 +1,13 @@ +GET +/api/v3/account/switch-status +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1746687063471, + "data": { + "status": "fail", + "reason": "upgrade_disabled" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetTransferableAssets.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetTransferableAssets.txt new file mode 100644 index 00000000..e93bdf80 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetTransferableAssets.txt @@ -0,0 +1,12 @@ +GET +/api/v3/account/transferable-coins +true +UriParams: {"fromType": "spot","toType": "uta"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189276579, + "data": [ + "ETH" + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawAddressBook.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawAddressBook.txt new file mode 100644 index 00000000..58b3d918 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawAddressBook.txt @@ -0,0 +1,25 @@ +GET +/api/v3/account/withdraw-address +true +UriParams: { } +{ + "code": "00000", + "msg": "success", + "requestTime": 1740000000000, + "data": { + "addressList": [ + { + "coin": "BTC", + "chain": "BTC", + "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf", + "countryCode": "", + "label": "My BTC Wallet", + "memo": "", + "type": "regular", + "internalType": "", + "createdTime": "1740000000000" + } + ], + "cursor": "1740000000000" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawalRecords.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawalRecords.txt new file mode 100644 index 00000000..1582186e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/GetWithdrawalRecords.txt @@ -0,0 +1,29 @@ +GET +/api/v3/account/withdrawal-records +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1740481864545, + "data": [ + { + "orderId": "1278112570963742720", + "clientOid": "12121212112", + "recordId": "1278112570963742720", + "coin": "usdt", + "type": "deposit", + "dest": "internal_transfer", + "size": "100", + "status": "success", + "fromAddress": "0x51xxx", + "toAddress": "0x51xxx", + "chain": "erc20", + "fee": "10", + "confirm": "5", + "tag": "", + "createdTime": "1740451703778", + "updatedTime": "1740451703778" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/Repay.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Repay.txt new file mode 100644 index 00000000..555ce7d9 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Repay.txt @@ -0,0 +1,13 @@ +POST +/api/v3/account/repay +true +BodyParams: {"repayableCoinList": ["123"],"paymentCoinList": ["123"]} +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": { + "result": "YES", + "repayAmount":"4345" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetAccountMode.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetAccountMode.txt new file mode 100644 index 00000000..d8077654 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetAccountMode.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/adjust-account-mode +true +BodyParams: {"mode": "advanced" } +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": null +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetDepositAccount.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetDepositAccount.txt new file mode 100644 index 00000000..16010193 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetDepositAccount.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/deposit-account +true +BodyParams: {"coin": "123","accountType": "unified"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1753848186558, + "data": "success" +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetHoldMode.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetHoldMode.txt new file mode 100644 index 00000000..b61db1ba --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetHoldMode.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/set-hold-mode +true +BodyParams: {"holdMode": "one_way_mode"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": "success" +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetLeverage.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetLeverage.txt new file mode 100644 index 00000000..f5d730a9 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SetLeverage.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/set-leverage +true +BodyParams: {"category": "USDT-FUTURES","symbol": "ETHUSDT","leverage": 0.1} +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": "success" +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchDeduct.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchDeduct.txt new file mode 100644 index 00000000..e65a56ad --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchDeduct.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/switch-deduct +true +BodyParams: {"deduct": true} +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": true +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchToClassicMode.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchToClassicMode.txt new file mode 100644 index 00000000..2cba7f56 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/SwitchToClassicMode.txt @@ -0,0 +1,10 @@ +POST +/api/v3/account/switch +true +BodyParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1728625799912, + "data": null +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/Transfer.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Transfer.txt new file mode 100644 index 00000000..b6005cb3 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Transfer.txt @@ -0,0 +1,12 @@ +POST +/api/v3/account/transfer +true +BodyParams: {"fromType": "spot","toType": "uta","coin": "123","amount": 0.1} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189276579, + "data": { + "transferId":"111111111111" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Account/Withdraw.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Withdraw.txt new file mode 100644 index 00000000..fb27035e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Account/Withdraw.txt @@ -0,0 +1,14 @@ +POST +/api/v3/account/withdrawal +true +BodyParams: {"coin": "123","transferType": "on_chain","address": "123","size": 0.1} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730189276579, + "data": { + "orderId": "111111111111", + "clientOid": "111111111111" + + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetDiscountRate.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetDiscountRate.txt new file mode 100644 index 00000000..13ed04f7 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetDiscountRate.txt @@ -0,0 +1,24 @@ +GET +/api/v3/market/discount-rate +false +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730911874605, + "data": [ + { + "coin": "ETH", + "list": [ + { + "tierStartValue": "0", + "discountRate": "0.99" + }, + { + "tierStartValue": "40000", + "discountRate": "0.98" + } + ] + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRate.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRate.txt new file mode 100644 index 00000000..cc20db28 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRate.txt @@ -0,0 +1,19 @@ +GET +/api/v3/market/current-fund-rate +false +UriParams: {"symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1743059269376, + "data": [ + { + "symbol": "BTCUSDT", + "fundingRate": "0.000071", + "fundingRateInterval": "8", + "nextUpdate": "1743062400000", + "minFundingRate": "-0.003", + "maxFundingRate": "0.003" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRateHistory.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRateHistory.txt new file mode 100644 index 00000000..78c0d5a3 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFundingRateHistory.txt @@ -0,0 +1,23 @@ +GET +/api/v3/market/history-fund-rate +false +UriParams: {"category": "SPOT","symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1754908278922, + "data": { + "resultList": [ + { + "symbol": "BTCUSDT", + "fundingRate": "0.0001", + "fundingRateTimestamp": "1754899200000" + }, + { + "symbol": "BTCUSDT", + "fundingRate": "0.0001", + "fundingRateTimestamp": "1754870400000" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesSymbols.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesSymbols.txt new file mode 100644 index 00000000..d07be5fa --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesSymbols.txt @@ -0,0 +1,49 @@ +GET +/api/v3/market/instruments +false +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1770531054230, + "data": [ + { + "symbol": "BTCUSDT", + "category": "USDT-FUTURES", + "baseCoin": "BTC", + "quoteCoin": "USDT", + "isRwa": "NO", + "buyLimitPriceRatio": "0.05", + "sellLimitPriceRatio": "0.05", + "feeRateUpRatio": "0.005", + "makerFeeRate": "0.0002", + "takerFeeRate": "0.0006", + "openCostUpRatio": "0.01", + "minOrderQty": "0.0001", + "maxOrderQty": "1200", + "pricePrecision": "1", + "quantityPrecision": "4", + "quotePrecision": "", + "priceMultiplier": "0.1", + "quantityMultiplier": "0.0001", + "type": "perpetual", + "minOrderAmount": "5", + "maxSymbolOrderNum": "", + "maxProductOrderNum": "400", + "maxPositionNum": "200", + "status": "online", + "offTime": "-1", + "limitOpenTime": "-1", + "deliveryTime": "", + "deliveryStartTime": "", + "deliveryPeriod": "", + "launchTime": "0", + "fundInterval": "8", + "minLeverage": "1", + "maxLeverage": "150", + "maintainTime": "", + "symbolType": "crypto", + "maxMarketOrderQty": "220" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesTickers.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesTickers.txt new file mode 100644 index 00000000..7ec7f321 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetFuturesTickers.txt @@ -0,0 +1,34 @@ +GET +/api/v3/market/tickers +false +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1765444282767, + "data": [ + { + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "ts": "1765444282230", + "lastPrice": "90216.3", + "openPrice24h": "92629", + "highPrice24h": "94477.8", + "lowPrice24h": "89350.1", + "ask1Price": "90216.4", + "bid1Price": "90216.3", + "bid1Size": "11.0845", + "ask1Size": "4.2309", + "price24hPcnt": "-0.02605", + "volume24h": "50772.839", + "turnover24h": "4667820987.88478", + "indexPrice": "90247.5410266912815894", + "markPrice": "90216.4", + "fundingRate": "0.000047", + "openInterest": "27606.0718", + "deliveryStartTime": "", + "deliveryTime": "", + "deliveryStatus": "" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetIndexComponents.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetIndexComponents.txt new file mode 100644 index 00000000..78f9c13a --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetIndexComponents.txt @@ -0,0 +1,50 @@ +GET +/api/v3/market/index-components +false +UriParams: {"symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1767159256214, + "data": { + "symbol": "BTCUSDT", + "componentList": [ + { + "exchange": "BITGET_FUTURE", + "spotPair": "BTC/USDT", + "equivalentPrice": "88432.1", + "weight": "0.4696" + }, + { + "exchange": "GATEIO", + "spotPair": "BTC/USDT", + "equivalentPrice": "88467", + "weight": "0.164" + }, + { + "exchange": "BINANCE", + "spotPair": "BTC/USDT", + "equivalentPrice": "88456.65", + "weight": "0.1434" + }, + { + "exchange": "MEXC", + "spotPair": "BTC/USDT", + "equivalentPrice": "88457.1", + "weight": "0.0992" + }, + { + "exchange": "BITGET", + "spotPair": "BTC/USDT", + "equivalentPrice": "88469.77", + "weight": "0.0768" + }, + { + "exchange": "OKX", + "spotPair": "BTC/USDT", + "equivalentPrice": "88463", + "weight": "0.0468" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlineHistory.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlineHistory.txt new file mode 100644 index 00000000..5af724cd --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlineHistory.txt @@ -0,0 +1,29 @@ +GET +/api/v3/market/history-candles +false +UriParams: {"category": "SPOT","symbol": "ETHUSDT","interval": "1m"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695865864944, + "data": [ + [ + "1687708800000", + "27176.93", + "27177.43", + "27166.93", + "27177.43", + "2990.08", + "81246917.3294" + ], + [ + "1688313600000", + "27177.43", + "27177.43", + "24000", + "24001", + "2989.1", + "72450031.0448" + ] + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlines.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlines.txt new file mode 100644 index 00000000..f2a9e026 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetKlines.txt @@ -0,0 +1,29 @@ +GET +/api/v3/market/candles +false +UriParams: {"category": "SPOT","symbol": "ETHUSDT","interval": "1m"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695865864944, + "data": [ + [ + "1687708800000", + "27176.93", + "27177.43", + "27166.93", + "27177.43", + "2990.08", + "81246917.3294" + ], + [ + "1688313600000", + "27177.43", + "27177.43", + "24000", + "24001", + "2989.1", + "72450031.0448" + ] + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetMarginLoanInterestRates.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetMarginLoanInterestRates.txt new file mode 100644 index 00000000..b65dfe0e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetMarginLoanInterestRates.txt @@ -0,0 +1,14 @@ +GET +/api/v3/market/margin-loans +false +UriParams: {"coin": "123"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730912814587, + "data": { + "dailyInterest": "0.1", + "annualInterest": "0.00416667", + "limit": "3000" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterest.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterest.txt new file mode 100644 index 00000000..7555b98b --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterest.txt @@ -0,0 +1,18 @@ +GET +/api/v3/market/open-interest +false +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730969652387, + "data": { + "list": [ + { + "symbol": "BTCUSDT", + "openInterest": "2243.019" + } + ], + "ts": "1730969652411" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterestLimit.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterestLimit.txt new file mode 100644 index 00000000..9800986e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOpenInterestLimit.txt @@ -0,0 +1,19 @@ +GET +/api/v3/market/oi-limit +false +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1741665165571, + "data": [{ + "symbol": "BTCUSDT", + "notionalValue": "1000000", + "totalNotionalValue": "5000000" + }, + { + "symbol": "ETHUSDT", + "notionalValue": "1000000", + "totalNotionalValue": "5000000" + }] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOrderBook.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOrderBook.txt new file mode 100644 index 00000000..d08a4d7b --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetOrderBook.txt @@ -0,0 +1,44 @@ +GET +/api/v3/market/orderbook +false +UriParams: {"category": "SPOT","symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730969017897, + "data": { + "a": [ + [ + 73000.0, + 0.007 + ], + [ + 74000.0, + 0.007 + ], + [ + 75000.0, + 0.007 + ], + [ + 75123.0, + 5.615 + ] + ], + "b": [ + [ + 71213.8, + 1.836 + ], + [ + 71213.3, + 10.000 + ], + [ + 71212.8, + 10.000 + ] + ], + "ts": "1730969017964" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetPositionTiers.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetPositionTiers.txt new file mode 100644 index 00000000..b623b960 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetPositionTiers.txt @@ -0,0 +1,18 @@ +GET +/api/v3/market/position-tier +false +UriParams: {"category": "SPOT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1731146663643, + "data": [ + { + "tier": "1", + "minTierValue": "0", + "maxTierValue": "100000", + "leverage": "125", + "mmr": "0.004" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetProofOfReserves.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetProofOfReserves.txt new file mode 100644 index 00000000..d2bb04dd --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetProofOfReserves.txt @@ -0,0 +1,39 @@ +GET +/api/v3/market/proof-of-reserves +false +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1753845058586, + "data": { + "merkleRootHash": "e0dff99bbe2c2dcb", + "totalReserveRatio": "175%", + "list": [ + { + "coin": "BTC", + "userAssets": "9530.89", + "platformAssets": "29679.59", + "reserveRatio": "311%" + }, + { + "coin": "USDT", + "userAssets": "1948633388.98", + "platformAssets": "1985576297.93", + "reserveRatio": "102%" + }, + { + "coin": "ETH", + "userAssets": "195465.81", + "platformAssets": "294561.45", + "reserveRatio": "151%" + }, + { + "coin": "USDC", + "userAssets": "58830275.64", + "platformAssets": "157216065.76", + "reserveRatio": "267%" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetRecentTrades.txt b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetRecentTrades.txt new file mode 100644 index 00000000..f1f49a07 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/ExchangeData/GetRecentTrades.txt @@ -0,0 +1,29 @@ +GET +/api/v3/market/fills +false +UriParams: {"category": "SPOT","symbol": "ETHUSDT"} +{ + "code": "00000", + "data": [ + { + "execId": "1", + "execLinkId": "12345877111", + "price": "29990.5", + "size": "0.0166", + "side": "sell", + "ts": "1627116776464", + "isRPI": "no" + }, + { + "execId": "2", + "execLinkId": "12345877112", + "price": "30007.0", + "size": "0.0166", + "side": "buy", + "ts": "1627116600875", + "isRPI": "yes" + } + ], + "msg": "success", + "requestTime": 1690313813709 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelAllOrders.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelAllOrders.txt new file mode 100644 index 00000000..70273dfa --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelAllOrders.txt @@ -0,0 +1,19 @@ +POST +/api/v3/trade/cancel-symbol-order +true +BodyParams: {"category": "SPOT"} +{ + "code": "00000", + "data": { + "list": [ + { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "code": "24056", + "msg": "notExisted" + } + ] + }, + "msg": "success", + "requestTime": 1627293504612 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelOrder.txt new file mode 100644 index 00000000..947f36e9 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelOrder.txt @@ -0,0 +1,13 @@ +POST +/api/v3/trade/cancel-order +true +BodyParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695806875837, + "data": { + "clientOid": "121211212122", + "orderId": "111111111111111111" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelStrategyOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelStrategyOrder.txt new file mode 100644 index 00000000..5a6cd9c0 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/CancelStrategyOrder.txt @@ -0,0 +1,10 @@ +POST +/api/v3/trade/cancel-strategy-order +true +BodyParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695806875837, + "data": null +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/ClosePositions.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/ClosePositions.txt new file mode 100644 index 00000000..bf28cffd --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/ClosePositions.txt @@ -0,0 +1,19 @@ +POST +/api/v3/trade/close-positions +true +BodyParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "data": { + "list": [ + { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "code": "24056", + "msg": "notExisted" + } + ] + }, + "msg": "success", + "requestTime": 1627293504612 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditOrder.txt new file mode 100644 index 00000000..e08d1b69 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditOrder.txt @@ -0,0 +1,13 @@ +POST +/api/v3/trade/modify-order +true +BodyParams: {} +{ + "code": "00000", + "data": { + "orderId": "121212121212", + "clientOid": "BITGET#1627293504612" + }, + "msg": "success", + "requestTime": 1627293504612 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditStrategyOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditStrategyOrder.txt new file mode 100644 index 00000000..2277554e --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/EditStrategyOrder.txt @@ -0,0 +1,13 @@ +POST +/api/v3/trade/modify-strategy-order +true +BodyParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695806875837, + "data": { + "clientOid": "121211212122", + "orderId": "121211212122" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetClosedStrategyOrders.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetClosedStrategyOrders.txt new file mode 100644 index 00000000..7f0c0cf6 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetClosedStrategyOrders.txt @@ -0,0 +1,37 @@ +GET +/api/v3/trade/history-strategy-orders +true +UriParams: {"category": "SPOT","type": "tpsl"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730186730084, + "data": { + "list": [ + { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "qty": "0.01", + "posSide": "long", + "status": "success", + "tpTriggerBy": "market", + "slTriggerBy": "market", + "takeProfit": "110000", + "stopLoss": "90000", + "tpOrderType": "market", + "slOrderType": "market", + "tpLimitPrice": "91000", + "slLimitPrice": "111000", + "triggerBy": "market", + "triggerPrice": "100000", + "triggerOrderType": "limit", + "triggerOrderPrice": "100500", + "createdTime": "1730186725663", + "updatedTime": "1730186725691" + } + ], + "cursor": "1233319323918499840" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetMaxOpenAvailable.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetMaxOpenAvailable.txt new file mode 100644 index 00000000..4b470778 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetMaxOpenAvailable.txt @@ -0,0 +1,19 @@ +GET +/api/v3/account/max-open-available +true +UriParams: {"category": "USDT-FUTURES","symbol": "ETHUSDT","orderType": "limit","side": "buy","size": 0.1} +{ + "code": "00000", + "msg": "success", + "requestTime": 1741851607871, + "data": { + "available": "52.008255", + "maxOpen": "", + "buyOpenCost": "", + "sellOpenCost": "", + "maxBuyOpen": "", + "maxSellOpen": "", + "maxBuyAvailable": "", + "maxSellAvailable": "" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenOrders.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenOrders.txt new file mode 100644 index 00000000..7e867934 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenOrders.txt @@ -0,0 +1,52 @@ +GET +/api/v3/trade/unfilled-orders +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730186730084, + "data": { + "list": [ + { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "orderType": "limit", + "side": "buy", + "price": "45000", + "qty": "0.01", + "amount": "0", + "cumExecQty": "0", + "cumExecValue": "0", + "avgPrice": "0", + "timeInForce": "gtc", + "orderStatus": "live", + "posSide": "long", + "holdMode": "hedge_mode", + "delegateType": "normal", + "reduceOnly": "NO", + "marginMode": "crossed", + "stpMode": "none", + "takeProfit": "", + "stopLoss": "", + "tpTriggerBy": "", + "slTriggerBy": "", + "tpOrderType": "", + "slOrderType": "", + "tpLimitPrice": "", + "slLimitPrice": "", + "feeDetail": [ + { + "feeCoin": null, + "fee": null + } + ], + "createdTime": "1730186725663", + "updatedTime": "1730186725691" + } + ], + "cursor": "1235058132196622336" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenStrategyOrders.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenStrategyOrders.txt new file mode 100644 index 00000000..e20e40ef --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOpenStrategyOrders.txt @@ -0,0 +1,34 @@ +GET +/api/v3/trade/unfilled-strategy-orders +true +UriParams: {"category": "SPOT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730186730084, + "data": [ + { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "qty": "0.01", + "posSide": "long", + "status": "pending", + "tpTriggerBy": "market", + "slTriggerBy": "market", + "takeProfit": "110000", + "stopLoss": "90000", + "tpOrderType": "market", + "slOrderType": "market", + "tpLimitPrice": "91000", + "slLimitPrice": "111000", + "triggerBy": "market", + "triggerPrice": "100000", + "triggerOrderType": "limit", + "triggerOrderPrice": "100500", + "createdTime": "1730186725663", + "updatedTime": "1730186725691" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOrder.txt new file mode 100644 index 00000000..0bfc1683 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetOrder.txt @@ -0,0 +1,49 @@ +GET +/api/v3/trade/order-info +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730369201783, + "data": { + "orderId": "111111111111111111", + "clientOid": "111111111111111111", + "category": "SPOT", + "symbol": "ETHUSDT", + "orderType": "market", + "side": "buy", + "price": "0", + "qty": "0", + "amount": "100", + "cumExecQty": "0.0372", + "cumExecValue": "99.853356", + "avgPrice": "2684.23", + "timeInForce": "gtc", + "orderStatus": "filled", + "posSide": "", + "holdMode": "", + "tradeSide": "open", + "reduceOnly": "NO", + "marginMode": "crossed", + "stpMode": "none", + "takeProfit": "", + "stopLoss": "", + "tpTriggerBy": "", + "slTriggerBy": "", + "tpOrderType": "", + "slOrderType": "", + "tpLimitPrice": "", + "slLimitPrice": "", + "feeDetail": [ + { + "feeCoin": "ETH", + "fee": "0.00000744" + } + ], + "cancelReason": "", + "execType": "", + "createdTime": "1730295766596", + "updatedTime": "1730295766691" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionAdlRank.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionAdlRank.txt new file mode 100644 index 00000000..4e92e187 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionAdlRank.txt @@ -0,0 +1,17 @@ +GET +/api/v3/position/adlRank +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1754035547922, + "data": [ + { + "symbol": "MOVEUSDT", + "marginCoin": "USDT", + "adlRank": "0.4872", + "holdSide": "long" + } + ] +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionHistory.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionHistory.txt new file mode 100644 index 00000000..98242551 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositionHistory.txt @@ -0,0 +1,34 @@ +GET +/api/v3/position/history-position +true +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1730186957802, + "data": { + "list": [ + { + "positionId": "1111111111111111111", + "category": "USDT-FUTURES", + "symbol": "EOSUSDT", + "marginCoin": "USDT", + "holdMode": "one_way_mode", + "posSide": "long", + "marginMode": "crossed", + "openPriceAvg": "1960.001", + "closePriceAvg": "1959.999", + "openTotalPos": "58", + "closeTotalPos": "58", + "cumRealisedPnl": "-0.116", + "netProfit": "-45.588", + "totalFunding": "0", + "openFeeTotal": "-22.7360116", + "closeFeeTotal": "-22.7359884", + "createdTime": "1729928018076", + "updatedTime": "1729929656321" + } + ], + "cursor": "1111111111111111111" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositions.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositions.txt new file mode 100644 index 00000000..8314a7d5 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetPositions.txt @@ -0,0 +1,40 @@ +GET +/api/v3/position/current-position +true +UriParams: {"category": "USDT-FUTURES"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1753103840140, + "data": { + "list": [ + { + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "marginCoin": "USDT", + "holdMode": "hedge_mode", + "posSide": "long", + "marginMode": "crossed", + "positionBalance": "4701531.84941582", + "available": "119.2068", + "frozen": "0", + "total": "119.2068", + "leverage": "3", + "curRealisedPnl": "0", + "avgPrice": "108674", + "positionStatus": "normal", + "unrealisedPnl": "1124573.04243999", + "liquidationPrice": "43099.9", + "mmr": "0.015", + "profitRate": "0.2391929010498401", + "markPrice": "118097", + "breakEvenPrice": "109208.6", + "totalFunding": "-53076.32433032", + "openFeeTotal": "-2842.86603479", + "closeFeeTotal": "0", + "createdTime": "1736378720620", + "updatedTime": "1753102803148" + } + ] + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetUserTrades.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetUserTrades.txt new file mode 100644 index 00000000..770ebb0d --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/GetUserTrades.txt @@ -0,0 +1,39 @@ +GET +/api/v3/trade/fills +true +UriParams: {} +{ + "code": "00000", + "msg": "success", + "requestTime": 1750142995229, + "data": { + "list": [ + { + "execId": "131111111111111111", + "execLinkId": "131111111111111111", + "orderId": "131111111111111111", + "clientOid": "131111111111111111", + "category": "USDT-FUTURES", + "symbol": "BTCUSDT", + "orderType": "market", + "side": "sell", + "execPrice": "106950.1", + "execQty": "0.01", + "execValue": "1069.501", + "tradeScope": "taker", + "tradeSide": "open", + "feeDetail": [ + { + "feeCoin": "USDT", + "fee": "0.6417006" + } + ], + "createdTime": "1750141421721", + "updatedTime": "1750141421728", + "execPnl": "-0.002", + "isRPI": "no" + } + ], + "cursor": "131111111111111111" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceOrder.txt new file mode 100644 index 00000000..5cd2a1d7 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceOrder.txt @@ -0,0 +1,13 @@ +POST +/api/v3/trade/place-order +true +BodyParams: {"category": "SPOT","symbol": "ETHUSDT","side": "buy","orderType": "limit","qty": 0.1} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695806875837, + "data": { + "clientOid": "121211212122", + "orderId": "121211212122" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceStrategyOrder.txt b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceStrategyOrder.txt new file mode 100644 index 00000000..83593948 --- /dev/null +++ b/Bitget.Net.UnitTests/Endpoints/Unified/Trading/PlaceStrategyOrder.txt @@ -0,0 +1,13 @@ +POST +/api/v3/trade/place-strategy-order +true +BodyParams: {"category": "USDT-FUTURES","symbol": "ETHUSDT"} +{ + "code": "00000", + "msg": "success", + "requestTime": 1695806875837, + "data": { + "clientOid": "121211212122", + "orderId": "121211212122" + } +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/RestRequestTests.cs b/Bitget.Net.UnitTests/RestRequestTests.cs index 8bc6f66d..a9dc323d 100644 --- a/Bitget.Net.UnitTests/RestRequestTests.cs +++ b/Bitget.Net.UnitTests/RestRequestTests.cs @@ -1,4 +1,6 @@ using Bitget.Net.Clients; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; using Bitget.Net.Enums.V2; using Bitget.Net.Objects; using Bitget.Net.Objects.Models.V2; @@ -95,8 +97,8 @@ public async Task ValidateSpotExchangeDataCalls() await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetVipFeeRatesAsync(), "GetVipFeeRates"); await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetTickersAsync(), "GetTickers"); await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetOrderBookAsync("ETHUSDT"), "GetOrderBook"); - await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetKlinesAsync("ETHUSDT", KlineInterval.OneDay), "GetKlines"); - await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetHistoricalKlinesAsync("ETHUSDT", KlineInterval.OneDay, DateTime.UtcNow), "GetHistoricalKlines"); + await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetKlinesAsync("ETHUSDT", Enums.V2.KlineInterval.OneDay), "GetKlines"); + await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetHistoricalKlinesAsync("ETHUSDT", Enums.V2.KlineInterval.OneDay, DateTime.UtcNow), "GetHistoricalKlines"); await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetRecentTradesAsync("ETHUSDT"), "GetRecentTrades"); await tester.ValidateAsync(client => client.SpotApiV2.ExchangeData.GetTradesAsync("ETHUSDT"), "GetTrades"); @@ -213,9 +215,100 @@ public async Task ValidateFuturesTradingCalls() await tester.ValidateAsync(client => client.FuturesApiV2.Trading.GetOpenTriggerOrdersAsync(Enums.BitgetProductTypeV2.UsdtFutures, TriggerPlanTypeFilter.Trigger), "GetOpenTriggerOrders2"); await tester.ValidateAsync(client => client.FuturesApiV2.Trading.GetClosedTriggerOrdersAsync(Enums.BitgetProductTypeV2.UsdtFutures, TriggerPlanTypeFilter.Trigger), "GetClosedTriggerOrders"); await tester.ValidateAsync(client => client.FuturesApiV2.Trading.CancelTriggerOrdersAsync(Enums.BitgetProductTypeV2.UsdtFutures, CancelTriggerPlanTypeFilter.Trigger), "CancelTriggerOrders"); - await tester.ValidateAsync(client => client.FuturesApiV2.Trading.SetPositionTpSlAsync(Enums.BitgetProductTypeV2.CoinFutures, "123", "123", PositionSide.Oneway), "SetPositionTpSl", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.FuturesApiV2.Trading.SetPositionTpSlAsync(Enums.BitgetProductTypeV2.CoinFutures, "123", "123", Enums.V2.PositionSide.Oneway), "SetPositionTpSl", nestedJsonProperty: "data"); } + [Test] + public async Task ValidateUnifiedAccountCalls() + { + var client = new BitgetRestClient(opts => + { + opts.AutoTimestamp = false; + opts.ApiCredentials = new BitgetCredentials("123", "456", "789"); + }); + var tester = new RestRequestValidator(client, "Endpoints/Unified/Account", "https://api.bitget.com", IsAuthenticated, nestedPropertyForCompare: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetBalancesAsync(), "GetBalances", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetFundingBalancesAsync(), "GetFundingBalances", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetAccountConfigAsync(), "GetAccountConfig", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.SetLeverageAsync(ProductCategory.UsdtFutures, "ETHUSDT", 0.1m), "SetLeverage"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.SetHoldModeAsync(HoldingMode.OneWayMode), "SetHoldMode"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetFinancialRecordsAsync(ProductCategory.Margin), "GetFinancialRecords", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetRepayableAssetsAsync(), "GetRepayableAssets", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetPaymentAssetsAsync(), "GetPaymentAssets", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.RepayAsync(["123"], ["123"]), "Repay", nestedJsonProperty: "data", ignoreProperties: ["result"]); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetConvertRecordsAsync("123", "123"), "GetConvertRecords", nestedJsonProperty: "data"); + //await tester.ValidateAsync(client => client.UnifiedApi.Account.SwitchDeductAsync(true), "SwitchDeduct", ignoreParamValidation: ["deduct"]); + await tester.ValidateAsync(client => client.UnifiedApi.Account.SetDepositAccountAsync("123", UtaAccountType.Unified), "SetDepositAccount"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetDeductStatusAsync(), "GetDeductStatus", nestedJsonProperty: "data", ignoreProperties: ["deduct"]); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetFeeAsync(ProductCategory.Spot, "ETHUSDT"), "GetFee", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.SwitchToClassicModeAsync(), "SwitchToClassicMode"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetSwitchToClassicStatusAsync(), "GetSwitchToClassicStatus", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetMaxTransferableAsync("123"), "GetMaxTransferable", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetOpenInterestLimitAsync(ProductCategory.UsdtFutures, "ETHUSDT"), "GetOpenInterestLimit", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetAccountInfoAsync(), "GetAccountInfo", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetDeltaInfoAsync(), "GetDeltaInfo", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.SetAccountModeAsync(AccountLevel.Advanced), "SetAccountMode"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetTransferableAssetsAsync(TransferAccountType.Spot, TransferAccountType.Uta), "GetTransferableAssets", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.TransferAsync(TransferAccountType.Spot, TransferAccountType.Uta, "123", 0.1m), "Transfer", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetDepositAddressAsync("123"), "GetDepositAddress", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetDepositRecordsAsync(), "GetDepositRecords", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.WithdrawAsync("123", TransferType.OnChain, "123", 0.1m), "Withdraw", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetWithdrawalRecordsAsync(), "GetWithdrawalRecords", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.GetWithdrawAddressBookAsync(), "GetWithdrawAddressBook", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Account.CancelWithdrawalAsync(), "CancelWithdrawal"); + } + + [Test] + public async Task ValidateUnifiedExchangeDataCalls() + { + var client = new BitgetRestClient(opts => + { + opts.AutoTimestamp = false; + }); + var tester = new RestRequestValidator(client, "Endpoints/Unified/ExchangeData", "https://api.bitget.com", IsAuthenticated, nestedPropertyForCompare: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetFuturesSymbolsAsync(ProductCategory.UsdtFutures), "GetFuturesSymbols", nestedJsonProperty: "data", ignoreProperties: ["isRwa"]); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetFuturesTickersAsync(ProductCategory.UsdtFutures), "GetFuturesTickers", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetOrderBookAsync(ProductCategory.Spot, "ETHUSDT"), "GetOrderBook", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetRecentTradesAsync(ProductCategory.Spot, "ETHUSDT"), "GetRecentTrades", nestedJsonProperty: "data", ignoreProperties: ["isRPI"]); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetOpenInterestAsync(ProductCategory.UsdtFutures), "GetOpenInterest", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetKlinesAsync(ProductCategory.Spot, "ETHUSDT", KlineUaInterval.OneMinute), "GetKlines", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetKlineHistoryAsync(ProductCategory.Spot, "ETHUSDT", KlineUaInterval.OneMinute), "GetKlineHistory", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetFundingRateAsync("ETHUSDT"), "GetFundingRate", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetFundingRateHistoryAsync(ProductCategory.Spot, "ETHUSDT"), "GetFundingRateHistory", nestedJsonProperty: "data.resultList"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetDiscountRateAsync(), "GetDiscountRate", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetMarginLoanInterestRatesAsync("123"), "GetMarginLoanInterestRates", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetPositionTiersAsync(ProductCategory.Spot), "GetPositionTiers", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetOpenInterestLimitAsync(ProductCategory.UsdtFutures), "GetOpenInterestLimit", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.ExchangeData.GetIndexComponentsAsync("ETHUSDT"), "GetIndexComponents", nestedJsonProperty: "data"); + } + + [Test] + public async Task ValidateUnifiedTradingCalls() + { + var client = new BitgetRestClient(opts => + { + opts.AutoTimestamp = false; + opts.ApiCredentials = new BitgetCredentials("123", "456", "789"); + }); + var tester = new RestRequestValidator(client, "Endpoints/Unified/Trading", "https://api.bitget.com", IsAuthenticated, nestedPropertyForCompare: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.PlaceOrderAsync(ProductCategory.Spot, "ETHUSDT", OrderSide.Buy, OrderType.Limit, 0.1m), "PlaceOrder", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.EditOrderAsync(), "EditOrder", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.CancelOrderAsync(), "CancelOrder", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.CancelAllOrdersAsync(ProductCategory.Spot), "CancelAllOrders", nestedJsonProperty: "data.list"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.ClosePositionsAsync(ProductCategory.UsdtFutures), "ClosePositions", nestedJsonProperty: "data.list"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetOrderAsync(), "GetOrder", nestedJsonProperty: "data", ignoreProperties: ["reduceOnly"]); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetOpenOrdersAsync(), "GetOpenOrders", nestedJsonProperty: "data", ignoreProperties: ["reduceOnly"]); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetUserTradesAsync(), "GetUserTrades", nestedJsonProperty: "data", ignoreProperties: ["isRPI"]); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetPositionsAsync(ProductCategory.UsdtFutures), "GetPositions", nestedJsonProperty: "data.list"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetPositionHistoryAsync(ProductCategory.UsdtFutures), "GetPositionHistory", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetPositionAdlRankAsync(), "GetPositionAdlRank", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetMaxOpenAvailableAsync(ProductCategory.UsdtFutures, "ETHUSDT", OrderType.Limit, OrderSide.Buy, 0.1m), "GetMaxOpenAvailable", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.PlaceStrategyOrderAsync(ProductCategory.UsdtFutures, "ETHUSDT"), "PlaceStrategyOrder", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.EditStrategyOrderAsync(), "EditStrategyOrder", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.CancelStrategyOrderAsync(), "CancelStrategyOrder"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetOpenStrategyOrdersAsync(ProductCategory.Spot), "GetOpenStrategyOrders", nestedJsonProperty: "data"); + await tester.ValidateAsync(client => client.UnifiedApi.Trading.GetClosedStrategyOrdersAsync(ProductCategory.Spot, StrategyType.TpSl), "GetClosedStrategyOrders", nestedJsonProperty: "data"); + } [Test] public async Task ValidateBrokerCalls() diff --git a/Bitget.Net.UnitTests/SocketSubscriptionTests.cs b/Bitget.Net.UnitTests/SocketSubscriptionTests.cs index ccb18f20..23265040 100644 --- a/Bitget.Net.UnitTests/SocketSubscriptionTests.cs +++ b/Bitget.Net.UnitTests/SocketSubscriptionTests.cs @@ -1,6 +1,8 @@ using Bitget.Net.Clients; using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; using Bitget.Net.Objects; +using Bitget.Net.Objects.Models; using Bitget.Net.Objects.Models.V2; using Bitget.Net.Objects.Options; using CryptoExchange.Net.Authentication; @@ -99,5 +101,30 @@ public async Task ValidateFuturesSubscriptions() await tester.ValidateAsync((client, handler) => client.FuturesApiV2.SubscribeToPositionHistoryUpdatesAsync(Enums.BitgetProductTypeV2.UsdtFutures, handler), "PositionClose", ignoreProperties: new List { "deduction", "reduceOnly" }); await tester.ValidateAsync((client, handler) => client.FuturesApiV2.SubscribeToEquityUpdatesAsync(Enums.BitgetProductTypeV2.UsdtFutures, handler), "Equity"); } + + [Test] + public async Task ValidateUnifiedSubscriptions() + { + var logger = new LoggerFactory(); + logger.AddProvider(new TraceLoggerProvider()); + + var client = new BitgetSocketClient(Options.Create(new BitgetSocketOptions + { + ApiCredentials = new BitgetCredentials().WithHMAC("123", "456", "789"), + OutputOriginalData = true + }), logger); + var tester = new SocketSubscriptionValidator(client, "Subscriptions/Unified", "https://api.bitget.com", "data"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToTickerUpdatesAsync(ProductCategory.UsdtFutures, "BTCUSDT", handler), "Ticker"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToKlineUpdatesAsync(ProductCategory.UsdtFutures, "BTCUSDT", KlineUaInterval.OneDay, handler), "Kline"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToOrderBookUpdatesAsync(ProductCategory.UsdtFutures, "BTCUSDT", 1, handler), "Book", ignoreProperties: ["maxDepth"]); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToTradeUpdatesAsync(ProductCategory.UsdtFutures, "BTCUSDT", handler), "Trades"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToAccountUpdatesAsync(handler), "Account"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToPositionUpdatesAsync(handler), "Position"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToOrderUpdatesAsync(handler), "Order"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToUserTradeUpdatesAsync(handler), "UserTrade"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToFastUserTradeUpdatesAsync(handler), "FastUserTrade"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToStrategyOrderUpdatesAsync(handler), "StrategyOrder"); + await tester.ValidateAsync((client, handler) => client.UnifiedApi.SubscribeToAdlUpdatesAsync(handler), "Adl"); + } } } diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Account.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Account.txt new file mode 100644 index 00000000..8985e635 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Account.txt @@ -0,0 +1,50 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "account" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "account" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "account" + }, + "data": [{ + "unrealisedPnL": "-10116.55", + "totalEquity": "4976919.05", + "positionMgnRatio": "0", + "mmr": "408.08", + "effEquity": "4847952.35", + "imr": "17795.97", + "mgnRatio": "0", + "coin": [{ + "debts": "0", + "balance": "0.9992", + "available": "0.9992", + "borrow": "0", + "locked": "0", + "equity": "0.9992", + "coin": "ETH", + "usdValue": "2488.667472" + }, { + "debts": "0", + "balance": "52.00819", + "available": "52.00819", + "borrow": "0", + "locked": "0", + "equity": "52.00819", + "coin": "BTC", + "usdValue": "4630564.31304974" + }, { + "debts": "0", + "balance": "354411.45536458", + "available": "344282.65536458", + "borrow": "0", + "locked": "0", + "equity": "344282.65536458", + "coin": "USDT", + "usdValue": "343866.07335159" + }] + }], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Adl.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Adl.txt new file mode 100644 index 00000000..64ccea09 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Adl.txt @@ -0,0 +1,23 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "adl-notification" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "adl-notification" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "adl-notification" + }, + "data": [ + { + "symbol": "BTCUSDT", + "side": "buy", + "status": "triggered", + "price": "88291.2", + "amount": "2.35", + "ts": "1740546523244" + } + ], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Book.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Book.txt new file mode 100644 index 00000000..fe2a5c2f --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Book.txt @@ -0,0 +1,32 @@ +> { "op": "subscribe", "args": [{ "instType": "usdt-futures", "topic": "books1", "instId": "BTCUSDT" }]} +< { "event": "subscribe", "arg": { "instType": "usdt-futures", "topic": "books1", "instId": "BTCUSDT" }} += +{ + "data": [ + { + "a": [ + [ + "99756.7", + "23.9774" + ] + ], + "b": [ + [ + "99756.6", + "0.0128" + ] + ], + "pseq": 0, + "seq": 1304314508780744705, + "maxDepth": "50", + "ts": "1746698732562" + } + ], + "arg": { + "instType": "usdt-futures", + "symbol": "BTCUSDT", + "topic": "books1" + }, + "action": "snapshot", + "ts": 1746698732563 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/FastUserTrade.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/FastUserTrade.txt new file mode 100644 index 00000000..d04fe2db --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/FastUserTrade.txt @@ -0,0 +1,29 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "fast-fill" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "fast-fill" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "fast-fill" + }, + "data": + { + "symbol": "BTCUSDT", + "updatedTime": "1736378720623", + "side": "buy", + "orderId": "1288888888888888888", + "execTime": "1736378720623", + "tradeScope": "taker", + "execId": "1288888888888888888", + "execPrice": "94993", + "holdSide": "long", + "category": "usdt-futures", + "execQty": "0.01", + "clientOid": "1288888888888888889" + } + , + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Kline.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Kline.txt new file mode 100644 index 00000000..2f0a0d2b --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Kline.txt @@ -0,0 +1,24 @@ +> { "op": "subscribe", "args": [{ "instType": "usdt-futures", "topic": "kline", "instId": "BTCUSDT", "interval": "1D" }]} +< { "event": "subscribe", "arg": { "instType": "usdt-futures", "topic": "kline", "instId": "BTCUSDT", "interval": "1D" }} += +{ + "action": "snapshot", + "arg": { + "instType": "usdt-futures", + "topic": "kline", + "instId": "BTCUSDT", + "interval": "1D" + }, + "data":[ + { + "volume": "0.423", + "high": "400005", + "low": "276670", + "start": "1710518400000", + "close": "400005", + "turnover": "148190.38375", + "open": "276670" + } + ], + "ts": 1695715383039 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Order.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Order.txt new file mode 100644 index 00000000..d39da53e --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Order.txt @@ -0,0 +1,50 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "order" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "order" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "order" + }, + "data": [ + { + "category": "usdt-futures", + "symbol": "BTCUSDT", + "orderId": "xxx", + "clientOid": "xxx", + "price": "", + "qty": "0.001", + "amount": "1000", + "holdMode": "hedge_mode", + "holdSide": "long", + "delegateType": "normal", + "tradeSide": "open", + "orderType": "market", + "timeInForce": "gtc", + "side": "buy", + "marginMode": "crossed", + "marginCoin": "USDT", + "reduceOnly": "no", + "cumExecQty": "0.001", + "cumExecValue": "83.1315", + "avgPrice": "83131.5", + "totalProfit": "0", + "orderStatus": "filled", + "cancelReason": "", + "leverage": "20", + "feeDetail": [ + { + "feeCoin": "USDT", + "fee": "0.0332526" + } + ], + "createdTime": "1742367838101", + "updatedTime": "1742367838115", + "stpMode": "none" + } + ], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Position.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Position.txt new file mode 100644 index 00000000..02b4c9e4 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Position.txt @@ -0,0 +1,41 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "position" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "position" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "position" + }, + "data": [ + { + "symbol": "BTCUSDT", + "leverage": "20", + "openFeeTotal": "", + "mmr": "", + "breakEvenPrice": "", + "available": "0", + "liqPrice": "", + "marginMode": "crossed", + "unrealisedPnl": "0", + "markPrice": "94987.1", + "createdTime": "1736378720620", + "avgPrice": "0", + "totalFundingFee": "0", + "updatedTime": "1736378720620", + "marginCoin": "USDT", + "frozen": "0", + "profitRate": "", + "closeFeeTotal": "", + "marginSize": "0", + "curRealisedPnl": "0", + "size": "0", + "positionStatus": "ended", + "posSide": "long", + "holdMode": "hedge_mode" + } + ], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/StrategyOrder.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/StrategyOrder.txt new file mode 100644 index 00000000..1a64fbc4 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/StrategyOrder.txt @@ -0,0 +1,43 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "strategy-order" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "strategy-order" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "strategy-order", + "symbol": "default" + }, + "data": [ + { + "category": "usdt-futures", + "symbol": "BTCUSDT", + "orderId": "111111111111111111", + "clientOid": "myorder001", + "qty": "0.01", + "side": "buy", + "posSide": "long", + "reduceOnly": "no", + "type": "tpsl", + "status": "pending", + "triggerType": "takeProfit", + "tpTriggerBy": "market", + "slTriggerBy": "market", + "takeProfit": "110000", + "stopLoss": "90000", + "tpOrderType": "market", + "slOrderType": "market", + "tpLimitPrice": "", + "slLimitPrice": "", + "triggerBy": "market", + "triggerPrice": "100000", + "triggerOrderType": "limit", + "triggerOrderPrice": "100500", + "createdTime": "1730186725663", + "updatedTime": "1730186725691" + } + ], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Ticker.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Ticker.txt new file mode 100644 index 00000000..5796e7d6 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Ticker.txt @@ -0,0 +1,27 @@ +> { "op": "subscribe", "args": [{ "instType": "usdt-futures", "topic": "ticker", "instId": "BTCUSDT" }]} +< { "event": "subscribe", "arg": { "instType": "usdt-futures", "topic": "ticker", "instId": "BTCUSDT" }} += +{ + "action": "snapshot", + "arg": { + "instType": "usdt-futures", + "topic": "ticker", + "instId": "BTCUSDT" + }, + "data": [ + { + "bid1Price": "99999", + "lowPrice24h": "98200", + "ask1Size": "188.312553", + "volume24h": "37.722858", + "price24hPcnt": "0.01833", + "highPrice24h": "100000", + "turnover24h": "3750302.979626", + "bid1Size": "186.183209", + "ask1Price": "100000", + "openPrice24h": "0", + "lastPrice": "100000" + } + ], + "ts": 1695715383039 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/Trades.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/Trades.txt new file mode 100644 index 00000000..0ecd1564 --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/Trades.txt @@ -0,0 +1,23 @@ +> { "op": "subscribe", "args": [{ "instType": "usdt-futures", "topic": "publicTrade", "instId": "BTCUSDT" }]} +< { "event": "subscribe", "arg": { "instType": "usdt-futures", "topic": "publicTrade", "instId": "BTCUSDT" }} += +{ + "action": "snapshot", + "arg": { + "instType": "usdt-futures", + "topic": "publicTrade", + "instId": "BTCUSDT" + }, + "data": [ + { + "p": "100000", + "S": "buy", + "T": "1736348770627", + "v": "0.00118", + "i": "1260903622036942849", + "L": "1234568787787878787", + "isRPI": "no" + } + ], + "ts": 1695715383039 +} \ No newline at end of file diff --git a/Bitget.Net.UnitTests/Subscriptions/Unified/UserTrade.txt b/Bitget.Net.UnitTests/Subscriptions/Unified/UserTrade.txt new file mode 100644 index 00000000..2a9c788d --- /dev/null +++ b/Bitget.Net.UnitTests/Subscriptions/Unified/UserTrade.txt @@ -0,0 +1,41 @@ +> { "op":"login", "args":[{ "apiKey":"1213", "passphrase":"789", "timestamp":"|1|", "sign":"|2|" }]} +< { "event":"login", "code":"0", "msg":"" } +> { "op": "subscribe", "args": [{ "instType": "UTA", "topic": "fill" }]} +< { "event": "subscribe", "arg": { "instType": "UTA", "topic": "fill" }} += +{ + "action": "snapshot", + "arg": { + "instType": "UTA", + "topic": "fill" + }, + "data": [ + { + "symbol": "BTCUSDT", + "orderType": "market", + "updatedTime": "1736378720623", + "side": "buy", + "orderId": "1288888888888888888", + "execPnl": "0", + "feeDetail": [ + { + "feeCoin": "USDT", + "fee": "0.569958" + } + ], + "execTime": "1736378720623", + "tradeScope": "taker", + "tradeSide": "open", + "execId": "1288888888888888888", + "execLinkId": "1288888888888888888", + "execPrice": "94993", + "holdSide": "long", + "execValue": "949.93", + "category": "usdt-futures", + "execQty": "0.01", + "clientOid": "1288888888888888889", + "isRPI": "no" + } + ], + "ts": 1695717225146 +} \ No newline at end of file diff --git a/Bitget.Net/Bitget.Net.csproj b/Bitget.Net/Bitget.Net.csproj index 8a9094bd..cbef7c09 100644 --- a/Bitget.Net/Bitget.Net.csproj +++ b/Bitget.Net/Bitget.Net.csproj @@ -56,7 +56,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Bitget.Net/BitgetEnvironment.cs b/Bitget.Net/BitgetEnvironment.cs index b868c3cf..4d0d8bff 100644 --- a/Bitget.Net/BitgetEnvironment.cs +++ b/Bitget.Net/BitgetEnvironment.cs @@ -59,7 +59,7 @@ public BitgetEnvironment() : base(TradeEnvironmentNames.Live) /// /// Demo trading environment /// - public static BitgetEnvironment DemoTrading { get; } = new BitgetEnvironment("demo", BitgetApiAddresses.Default.RestBaseAddress, BitgetApiAddresses.Default.SocketBaseAddress); + public static BitgetEnvironment DemoTrading { get; } = new BitgetEnvironment("demo", BitgetApiAddresses.Demo.RestBaseAddress, BitgetApiAddresses.Demo.SocketBaseAddress); /// /// Create a custom environment diff --git a/Bitget.Net/BitgetErrors.cs b/Bitget.Net/BitgetErrors.cs index 57ffc8bf..66a0aba7 100644 --- a/Bitget.Net/BitgetErrors.cs +++ b/Bitget.Net/BitgetErrors.cs @@ -148,5 +148,51 @@ internal static class BitgetErrors new ErrorInfo(ErrorType.RateLimitRequest, false, "Request rate limit reached", "30006", "30007"), ]); + + public static ErrorMapping UnifiedErrors { get; } = new ErrorMapping( + [ + new ErrorInfo(ErrorType.Unauthorized, false, "Region not allowed", "40000"), + new ErrorInfo(ErrorType.Unauthorized, false, "Unauthorized", "25620"), + new ErrorInfo(ErrorType.Unauthorized, false, "Invalid credentials", "40006", "40009", "30005", "30011", "30012", "30015"), + + new ErrorInfo(ErrorType.InvalidTimestamp, false, "Timestamp expired", "40008"), + new ErrorInfo(ErrorType.InvalidTimestamp, true, "Invalid timestamp", "30013", "30014"), + + new ErrorInfo(ErrorType.SystemError, true, "System error", "25000", "40015"), + new ErrorInfo(ErrorType.SystemError, true, "Operation timeout", "25001"), + new ErrorInfo(ErrorType.SystemError, true, "Concurrency error, try again", "25003"), + + new ErrorInfo(ErrorType.RateLimitRequest, false, "Request rate limit", "429", "25004"), + new ErrorInfo(ErrorType.RateLimitOrder, false, "Max number of tp/sl orders reached", "25599"), + new ErrorInfo(ErrorType.RateLimitOrder, false, "Max number of open orders reached", "40761"), + + new ErrorInfo(ErrorType.UnavailableSymbol, false, "Symbol doesn't support API trading", "25013", "22004"), + new ErrorInfo(ErrorType.UnavailableSymbol, false, "Symbol not available", "25101", "25102", "25104", "25105", "25108", "22056", "40844", "40845"), + + new ErrorInfo(ErrorType.UnknownSymbol, false, "Symbol does not exist", "25100"), + new ErrorInfo(ErrorType.UnknownAsset, false, "Asset does not exist", "25201"), + new ErrorInfo(ErrorType.UnknownOrder, false, "Unknown order", "25204"), + + new ErrorInfo(ErrorType.NoPosition, false, "Position not found", "25601"), + + new ErrorInfo(ErrorType.MissingParameter, false, "Parameter not set", "40811", "40813"), + new ErrorInfo(ErrorType.InvalidParameter, false, "Parameter validation failed", "25200", "40017", "95011", "40808"), + new ErrorInfo(ErrorType.InvalidPrice, false, "Price value not in range", "25205", "25206", "22046", "22047", "40815", "40816", "40820", "40821"), + new ErrorInfo(ErrorType.InvalidPrice, false, "Price tick invalid", "25244"), + new ErrorInfo(ErrorType.InvalidQuantity, false, "Quantity not in range", "25207", "25208"), + new ErrorInfo(ErrorType.InvalidQuantity, false, "Quantity step not valid", "25610", "22038"), + new ErrorInfo(ErrorType.InvalidQuantity, false, "Quantity less than min order quantity", "25611", "13008", "22034"), + + new ErrorInfo(ErrorType.InvalidStopParameters, false, "Tp/sl not valid", "25579", "25580", "25581", "25582", "25583", "25584", "25585", "25586", + "25587", "25588", "25589", "25590", "25591", "25592", "25602", "25603", "25604", "25605", "25606", "25607", "25608", "25609", "25650", + "25651", "25652", "25653", "40829", "40830", "40831", "40832", "40833", "40834", "40835", "40836"), + + new ErrorInfo(ErrorType.InsufficientBalance, false, "Insufficient balance", "25202", "25203", "25228", "25231", "40798", "40800"), + + new ErrorInfo(ErrorType.MaxPosition, false, "Order quantity exceeds the maximum open quantity", "25230"), + + new ErrorInfo(ErrorType.DuplicateClientOrderId, false, "Duplicate client order id", "25212"), + ] + ); } } diff --git a/Bitget.Net/Clients/BitgetRestClient.cs b/Bitget.Net/Clients/BitgetRestClient.cs index 9206afa3..b99cebc0 100644 --- a/Bitget.Net/Clients/BitgetRestClient.cs +++ b/Bitget.Net/Clients/BitgetRestClient.cs @@ -1,4 +1,5 @@ using Bitget.Net.Interfaces.Clients; +using Bitget.Net.Interfaces.Clients.UnifiedApi; using Bitget.Net.Objects.Options; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Clients; @@ -19,6 +20,8 @@ public class BitgetRestClient : BaseRestClient public Interfaces.Clients.BrokerApiV2.IBitgetRestClientBrokerApi BrokerV2 { get; } + /// + public IBitgetRestClientUnifiedApi UnifiedApi { get; } /// /// Create a new instance of BitgetRestClient @@ -43,6 +46,7 @@ public BitgetRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, I FuturesApiV2 = AddApiClient(new FuturesApiV2.BitgetRestClientFuturesApi(_logger, httpClient, this, options.Value)); CopyTradingFuturesV2 = AddApiClient(new CopyTradingApiV2.BitgetRestClientCopyTradingApi(_logger, httpClient, this, options.Value)); BrokerV2 = AddApiClient(new BrokerApiV2.BitgetRestClientBrokerApi(_logger, httpClient, this, options.Value)); + UnifiedApi = AddApiClient(new UnifiedApi.BitgetRestClientUnifiedApi(_logger, httpClient, this, options.Value)); } /// diff --git a/Bitget.Net/Clients/BitgetSocketClient.cs b/Bitget.Net/Clients/BitgetSocketClient.cs index 90b7c9c8..d253c311 100644 --- a/Bitget.Net/Clients/BitgetSocketClient.cs +++ b/Bitget.Net/Clients/BitgetSocketClient.cs @@ -1,4 +1,6 @@ -using Bitget.Net.Interfaces.Clients; +using Bitget.Net.Clients.UnifiedApi; +using Bitget.Net.Interfaces.Clients; +using Bitget.Net.Interfaces.Clients.UnifiedApi; using Bitget.Net.Objects.Options; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Clients; @@ -15,6 +17,8 @@ public class BitgetSocketClient : BaseSocketClient public Interfaces.Clients.FuturesApiV2.IBitgetSocketClientFuturesApi FuturesApiV2 { get; set; } + /// + public IBitgetSocketClientUnifiedApi UnifiedApi { get; set; } #region ctor @@ -38,6 +42,7 @@ public BitgetSocketClient(IOptions options, ILoggerFactory? SpotApiV2 = AddApiClient(new SpotApiV2.BitgetSocketClientSpotApi(_logger, options.Value)); FuturesApiV2 = AddApiClient(new FuturesApiV2.BitgetSocketClientFuturesApi(_logger, options.Value)); + UnifiedApi = AddApiClient(new BitgetSocketClientUnifiedApi(_logger, options.Value)); } #endregion diff --git a/Bitget.Net/Clients/BitgetUserClientProvider.cs b/Bitget.Net/Clients/BitgetUserClientProvider.cs index d941fe41..0f6e37f4 100644 --- a/Bitget.Net/Clients/BitgetUserClientProvider.cs +++ b/Bitget.Net/Clients/BitgetUserClientProvider.cs @@ -85,7 +85,7 @@ private IBitgetRestClient CreateRestClient(string userIdentifier, BitgetCredenti if (credentials != null) { client.SetApiCredentials(credentials); - _restClients.TryAdd(userIdentifier, client); + _restClients[userIdentifier] = client; } return client; } @@ -97,7 +97,7 @@ private IBitgetSocketClient CreateSocketClient(string userIdentifier, BitgetCred if (credentials != null) { client.SetApiCredentials(credentials); - _socketClients.TryAdd(userIdentifier, client); + _socketClients[userIdentifier] = client; } return client; } diff --git a/Bitget.Net/Clients/FuturesApiV2/BitgetRestClientFuturesApiShared.cs b/Bitget.Net/Clients/FuturesApiV2/BitgetRestClientFuturesApiShared.cs index c600cc0d..ce91b267 100644 --- a/Bitget.Net/Clients/FuturesApiV2/BitgetRestClientFuturesApiShared.cs +++ b/Bitget.Net/Clients/FuturesApiV2/BitgetRestClientFuturesApiShared.cs @@ -6,6 +6,7 @@ using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Errors; using CryptoExchange.Net.SharedApis; +using ContractType = Bitget.Net.Enums.V2.ContractType; namespace Bitget.Net.Clients.FuturesApiV2 { diff --git a/Bitget.Net/Clients/MessageHandlers/BitgetSocketUnifiedMessageConverter.cs b/Bitget.Net/Clients/MessageHandlers/BitgetSocketUnifiedMessageConverter.cs new file mode 100644 index 00000000..eb9da880 --- /dev/null +++ b/Bitget.Net/Clients/MessageHandlers/BitgetSocketUnifiedMessageConverter.cs @@ -0,0 +1,89 @@ +using Bitget.Net.Objects.Socket; +using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Converters.SystemTextJson.MessageHandlers; +using System.Net.WebSockets; +using System.Text.Json; + +namespace Bitget.Net.Clients.MessageHandlers +{ + internal class BitgetSocketUnifiedMessageConverter : JsonSocketMessageHandler + { + private static readonly HashSet _typeUpdates = new HashSet() + { + "snapshot", + "update" + }; + + public override JsonSerializerOptions Options { get; } = SerializerOptions.WithConverters(BitgetExchange._serializerContext); + + public BitgetSocketUnifiedMessageConverter() + { + AddTopicMapping(x => x.Args?.InstrumentId); + AddTopicMapping(x => x.Args.InstrumentId); + AddTopicMapping(x => x.Id); + } + + protected override MessageTypeDefinition[] TypeEvaluators { get; } = [ + + new MessageTypeDefinition { + ForceIfFound = true, + Fields = [ + new PropertyFieldReference("id"), + ], + TypeIdentifierCallback = x => x.FieldValue("id")! + }, + + new MessageTypeDefinition { + Fields = [ + new PropertyFieldReference("event"), + new PropertyFieldReference("instType") { Depth = 2 }, + new PropertyFieldReference("topic") { Depth = 2 }, + ], + TypeIdentifierCallback = x => $"{x.FieldValue("event")}{x.FieldValue("instType")}{x.FieldValue("topic")}" + }, + + new MessageTypeDefinition { + Fields = [ + new PropertyFieldReference("action").WithFilterConstraint(_typeUpdates), + new PropertyFieldReference("instType") { Depth = 2 }, + new PropertyFieldReference("topic") { Depth = 2 }, + ], + TypeIdentifierCallback = x => $"{x.FieldValue("instType")}{x.FieldValue("topic")}" + }, + + + new MessageTypeDefinition { + ForceIfFound = true, + Fields = [ + new PropertyFieldReference("event").WithEqualConstraint("login"), + ], + StaticIdentifier = "login", + }, + + new MessageTypeDefinition { + Fields = [ + new PropertyFieldReference("event").WithEqualConstraint("error"), + new PropertyFieldReference("instType") { Depth = 2 }, + new PropertyFieldReference("topic") { Depth = 2 }, + ], + TypeIdentifierCallback = x => $"error{x.FieldValue("instType")}{x.FieldValue("topic")}" + }, + + new MessageTypeDefinition { + Fields = [ + new PropertyFieldReference("event").WithEqualConstraint("error"), + ], + StaticIdentifier = "error", + }, + ]; + + protected override string? GetTypeIdentifierNonJson(ReadOnlySpan data, WebSocketMessageType? webSocketMessageType) + { + if (data.Length == 4) + return "pong"; + + return null; + } + } +} diff --git a/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApi.cs b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApi.cs new file mode 100644 index 00000000..406afbcf --- /dev/null +++ b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApi.cs @@ -0,0 +1,103 @@ +using Bitget.Net.Clients.MessageHandlers; +using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Interfaces.Clients.UnifiedApi; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Options; +using CryptoExchange.Net; +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Clients; +using CryptoExchange.Net.Converters.MessageParsing; +using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Errors; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.Logging; +using System.Net.Http.Headers; + +namespace Bitget.Net.Clients.UnifiedApi +{ + /// + internal partial class BitgetRestClientUnifiedApi : RestApiClient, IBitgetRestClientUnifiedApi + { + protected override ErrorMapping ErrorMapping => BitgetErrors.UnifiedErrors; + /// + public IBitgetRestClientUnifiedApiAccount Account { get; } + /// + public IBitgetRestClientUnifiedApiExchangeData ExchangeData { get; } + /// + public IBitgetRestClientUnifiedApiTrading Trading { get; } + + /// + public string ExchangeName => "Bitget"; + + /// + public new BitgetRestOptions ClientOptions => (BitgetRestOptions)base.ClientOptions; + + protected override IRestMessageHandler MessageHandler { get; } = new BitgetRestMessageHandler(BitgetErrors.RestErrors); + + internal BitgetRestClientUnifiedApi(ILogger logger, HttpClient? httpClient, BitgetRestClient baseClient, BitgetRestOptions options) + : base(logger, httpClient, options.Environment.RestBaseAddress, options, options.UnifiedOptions) + { + Account = new BitgetRestClientUnifiedApiAccount(this); + ExchangeData = new BitgetRestClientUnifiedApiExchangeData(this); + Trading = new BitgetRestClientUnifiedApiTrading(this); + + StandardRequestHeaders = new Dictionary + { + { "X-CHANNEL-API-CODE", LibraryHelpers.GetClientReference(() => options.ChannelCode, ExchangeName) }, + { "locale", options.Locale } + }; + + if (options.Environment.Name == BitgetEnvironment.DemoTrading.Name) + StandardRequestHeaders.Add("paptrading", "1"); + } + + /// + protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(BitgetExchange._serializerContext)); + + /// + protected override BitgetAuthenticationProviderV2 CreateAuthenticationProvider(BitgetCredentials credentials) + => new BitgetAuthenticationProviderV2(credentials); + + /// + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + => BitgetExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); + + internal Task> SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? requestHeaders = null) where T : class + => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight, requestHeaders); + + internal async Task> SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? requestHeaders = null) where T : class + { + var result = await base.SendAsync>(baseAddress, definition, parameters, cancellationToken, requestHeaders, weight).ConfigureAwait(false); + if (!result.Success) + return result.As(default); + + if (result.Data.Code != 0) + return result.AsError(new ServerError(result.Data.Code.ToString(), GetErrorInfo(result.Data.Code, result.Data.Message!))); + + return result.As(result.Data.Data); + } + + internal Task SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? requestHeaders = null) + => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight, requestHeaders); + + internal async Task SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? requestHeaders = null) + { + var result = await base.SendAsync(baseAddress, definition, parameters, cancellationToken, requestHeaders, weight).ConfigureAwait(false); + if (!result.Success) + return result.AsDataless(); + + if (result.Data.Code != 0) + return result.AsDatalessError(new ServerError(result.Data.Code.ToString(), GetErrorInfo(result.Data.Code, result.Data.Message!))); + + return result.AsDataless(); + } + + /// + protected override Task> GetServerTimestampAsync() + => ExchangeData.GetServerTimeAsync(); + + } +} diff --git a/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiAccount.cs b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiAccount.cs new file mode 100644 index 00000000..a586ab8a --- /dev/null +++ b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiAccount.cs @@ -0,0 +1,560 @@ +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; +using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Interfaces.Clients.UnifiedApi; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.RateLimiting.Guards; + +namespace Bitget.Net.Clients.UnifiedApi +{ + /// + internal class BitgetRestClientUnifiedApiAccount : IBitgetRestClientUnifiedApiAccount + { + private static readonly RequestDefinitionCache _definitions = new RequestDefinitionCache(); + private readonly BitgetRestClientUnifiedApi _baseClient; + + internal BitgetRestClientUnifiedApiAccount(BitgetRestClientUnifiedApi baseClient) + { + _baseClient = baseClient; + } + + #region Get Balances + + /// + public async Task> GetBalancesAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/assets", BitgetExchange.RateLimiter.Overall, 1, true, + limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Funding Balances + + /// + public async Task> GetFundingBalancesAsync(string? asset = null, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("coin", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/funding-assets", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Account Config + + /// + public async Task> GetAccountConfigAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/settings", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Set Leverage + + /// + public async Task SetLeverageAsync( + ProductCategory category, + string symbol, + decimal leverage, + string? asset = null, + PositionSide? positionSide = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddString("leverage", leverage); + parameters.AddOptional("coin", asset); + parameters.AddOptionalEnum("posSide", positionSide); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/set-leverage", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Set Hold Mode + + /// + public async Task SetHoldModeAsync(HoldingMode holdMode, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("holdMode", holdMode); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/set-hold-mode", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Financial Recods + + /// + public async Task> GetFinancialRecordsAsync( + ProductCategory category, + string? asset = null, + string? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("coin", asset); + parameters.AddOptional("type", type); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/financial-records", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Repayable Assets + + /// + public async Task> GetRepayableAssetsAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/repayable-coins", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Payment Assets + + /// + public async Task> GetPaymentAssetsAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/payment-coins", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Repay + + /// + public async Task> RepayAsync( + IEnumerable repayableAssets, + IEnumerable paymentAssets, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("repayableCoinList", repayableAssets.ToArray()); + parameters.Add("paymentCoinList", paymentAssets.ToArray()); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/repay", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Convert Records + + /// + public async Task> GetConvertRecordsAsync( + string fromAsset, + string toAsset, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("fromAsset", fromAsset); + parameters.Add("toAsset", toAsset); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/convert-records", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Switch Deduct + + /// + public async Task SwitchDeductAsync(bool deduct, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("deduct", deduct ? "on" : "off"); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/switch-deduct", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Set Deposit Account + + /// + public async Task SetDepositAccountAsync( + string asset, + UtaAccountType accountType, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("coin", asset); + parameters.AddEnum("accountType", accountType); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/deposit-account", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Deduct Status + + /// + public async Task> GetDeductStatusAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/deduct-info", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Fee + + /// + public async Task> GetFeeAsync( + ProductCategory category, + string symbol, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/fee-rate", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(3, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Switch To Classic Mode + + /// + public async Task SwitchToClassicModeAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/switch", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Switch To Classic Status + + /// + public async Task> GetSwitchToClassicStatusAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/switch-status", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Max Transferable + + /// + public async Task> GetMaxTransferableAsync(string asset, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("coin", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/max-transferable", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(3, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Open Interest Limit + + /// + public async Task> GetOpenInterestLimitAsync( + ProductCategory category, + string symbol, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/open-interest-limit", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Account Info + + /// + public async Task> GetAccountInfoAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/info", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Delta Info + + /// + public async Task> GetDeltaInfoAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/delta-info", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Set Account Mode + + /// + public async Task SetAccountModeAsync( + AccountLevel mode, + string? subAccountId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("mode", mode); + parameters.AddOptional("targetUid", subAccountId); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/adjust-account-mode", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Transferable Assets + + /// + public async Task> GetTransferableAssetsAsync( + Enums.V2.TransferAccountType fromType, + Enums.V2.TransferAccountType toType, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("fromType", fromType); + parameters.AddEnum("toType", toType); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/transferable-coins", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Transfer + + /// + public async Task> TransferAsync( + Enums.V2.TransferAccountType fromType, + Enums.V2.TransferAccountType toType, + string asset, + decimal quantity, + string? symbol = null, + bool? allowBorrow = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("fromType", fromType); + parameters.AddEnum("toType", toType); + parameters.Add("coin", asset); + parameters.AddString("amount", quantity); + parameters.AddOptional("symbol", symbol); + parameters.AddOptionalBoolString("allowBorrow", allowBorrow); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/transfer", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Deposit Address + + /// + public async Task> GetDepositAddressAsync( + string asset, + string? network = null, + decimal? quantity = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("coin", asset); + parameters.AddOptional("chain", network); + parameters.AddOptionalString("size", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/deposit-address", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Deposit Records + + /// + public async Task> GetDepositRecordsAsync( + string? asset = null, + string? orderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("coin", asset); + parameters.AddOptional("orderId", orderId); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/deposit-records", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Withdraw + + /// + public async Task> WithdrawAsync( + string asset, + Enums.V2.TransferType transferType, + string address, + decimal quantity, + string? network = null, + string? innerWithdrawType = null, + string? areaCode = null, + string? tag = null, + string? remark = null, + string? clientOrderId = null, + string? memberCode = null, + string? identityType = null, + string? companyName = null, + string? firstName = null, + string? lastName = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("coin", asset); + parameters.AddEnum("transferType", transferType); + parameters.Add("address", address); + parameters.AddString("size", quantity); + parameters.AddOptional("chain", network); + parameters.AddOptional("innerToType", innerWithdrawType); + parameters.AddOptional("areaCode", areaCode); + parameters.AddOptional("tag", tag); + parameters.AddOptional("remark", remark); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptional("memberCode", memberCode); + parameters.AddOptional("identityType", identityType); + parameters.AddOptional("companyName", companyName); + parameters.AddOptional("firstName", firstName); + parameters.AddOptional("lastName", lastName); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/withdrawal", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Withdrawal Records + + /// + public async Task> GetWithdrawalRecordsAsync( + string? asset = null, + string? orderId = null, + string? clientOrderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("coin", asset); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/withdrawal-records", BitgetExchange.RateLimiter.Overall, 1, true); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Withdraw Address Book + + /// + public async Task> GetWithdrawAddressBookAsync( + string? asset = null, + AddressBookType? type = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("coin", asset); + parameters.AddOptionalEnum("type", type); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/withdraw-address", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Cancel Withdrawal + + /// + public async Task CancelWithdrawalAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/account/cancel-withdrawal", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + } +} diff --git a/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiExchangeData.cs b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiExchangeData.cs new file mode 100644 index 00000000..ec670710 --- /dev/null +++ b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiExchangeData.cs @@ -0,0 +1,360 @@ +using CryptoExchange.Net.Objects; +using CryptoExchange.Net; +using Bitget.Net.Objects.Models.V2; +using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Enums.Uta; +using CryptoExchange.Net.RateLimiting.Guards; +using Bitget.Net.Interfaces.Clients.UnifiedApi; +using Bitget.Net.Objects.Models; + +namespace Bitget.Net.Clients.UnifiedApi +{ + /// + internal class BitgetRestClientUnifiedApiExchangeData : IBitgetRestClientUnifiedApiExchangeData + { + private readonly BitgetRestClientUnifiedApi _baseClient; + private static readonly RequestDefinitionCache _definitions = new RequestDefinitionCache(); + + internal BitgetRestClientUnifiedApiExchangeData(BitgetRestClientUnifiedApi baseClient) + { + _baseClient = baseClient; + } + + /// + public async Task> GetServerTimeAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v2/public/time", BitgetExchange.RateLimiter.Overall, 1, false, preventCaching: true, + limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result.As(result.Data?.ServerTime ?? default); + } + + #region Get Tickers + + /// + public async Task> GetSpotTickersAsync( + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", ProductCategory.Spot); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/tickers", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Tickers + + /// + public async Task> GetFuturesTickersAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/tickers", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Spot Symbols + + /// + public async Task> GetSpotSymbolsAsync( + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", ProductCategory.Spot); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/instruments", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Margin Symbols + + /// + public async Task> GetMarginSymbolsAsync( + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", ProductCategory.Margin); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/instruments", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Futures Symbols + + /// + public async Task> GetFuturesSymbolsAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/instruments", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Order Book + + /// + public async Task> GetOrderBookAsync( + ProductCategory category, + string symbol, + int? limit = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddOptional("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/orderbook", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Recent Trades + + /// + public async Task> GetRecentTradesAsync( + ProductCategory category, + string symbol, + int? limit = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddOptional("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/fills", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Proof Of Reserves + + /// + public async Task> GetProofOfReservesAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/proof-of-reserves", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Open Interest + + /// + public async Task> GetOpenInterestAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/open-interest", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Klines + + /// + public async Task> GetKlinesAsync( + ProductCategory category, + string symbol, + KlineUaInterval interval, + KlineType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddEnum("interval", interval); + parameters.AddOptionalEnum("type", type); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/candles", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Kline History + + /// + public async Task> GetKlineHistoryAsync( + ProductCategory category, + string symbol, + KlineUaInterval interval, + KlineType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddEnum("interval", interval); + parameters.AddOptionalEnum("type", type); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/history-candles", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Funding Rate + + /// + public async Task> GetFundingRateAsync(string symbol, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/current-fund-rate", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Funding Rate History + + /// + public async Task> GetFundingRateHistoryAsync( + ProductCategory category, + string symbol, + int? page = null, + int? pageSize = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddOptional("cursor", page); + parameters.AddOptional("limit", pageSize); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/history-fund-rate", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result.As(result.Data?.ResultList); + } + + #endregion + + #region Get Discount Rate + + /// + public async Task> GetDiscountRateAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/discount-rate", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Margin Loan Interest Rates + + /// + public async Task> GetMarginLoanInterestRatesAsync(string asset, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("coin", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/margin-loans", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Position Tiers + + /// + public async Task> GetPositionTiersAsync( + ProductCategory category, + string? symbol = null, + string? asset = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + parameters.AddOptional("coin", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/position-tier", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Open Interest Limit + + /// + public async Task> GetOpenInterestLimitAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/oi-limit", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Index Components + + /// + public async Task> GetIndexComponentsAsync(string symbol, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/market/index-components", BitgetExchange.RateLimiter.Overall, 1, false, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + } +} diff --git a/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiTrading.cs b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiTrading.cs new file mode 100644 index 00000000..feb7adbb --- /dev/null +++ b/Bitget.Net/Clients/UnifiedApi/BitgetRestClientUnifiedApiTrading.cs @@ -0,0 +1,475 @@ +using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Objects.Models.V2; +using Bitget.Net.Enums.Uta; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.RateLimiting.Guards; +using CryptoExchange.Net.Objects.Errors; +using Bitget.Net.Interfaces.Clients.UnifiedApi; +using Bitget.Net.Objects.Models; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Clients.UnifiedApi +{ + /// + internal class BitgetRestClientUnifiedApiTrading : IBitgetRestClientUnifiedApiTrading + { + private static readonly RequestDefinitionCache _definitions = new RequestDefinitionCache(); + private readonly BitgetRestClientUnifiedApi _baseClient; + + internal BitgetRestClientUnifiedApiTrading(BitgetRestClientUnifiedApi baseClient) + { + _baseClient = baseClient; + } + + #region Place Order + + /// + public async Task> PlaceOrderAsync( + ProductCategory category, + string symbol, + OrderSide side, + OrderType orderType, + decimal quantity, + decimal? price = null, + TimeInForce? timeInForce = null, + PositionSide? positionSide = null, + string? clientOrderId = null, + bool? reduceOnly = null, + StpMode? stpMode = null, + PriceTriggerType? tpTriggerBy = null, + PriceTriggerType? slTriggerBy = null, + decimal? tpTriggerPrice = null, + decimal? slTriggerPrice = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + MarginMode? marginMode = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddEnum("side", side); + parameters.AddEnum("orderType", orderType); + parameters.AddString("qty", quantity); + parameters.AddOptional("price", price); + parameters.AddOptionalEnum("timeInForce", timeInForce); + parameters.AddOptionalEnum("posSide", positionSide); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptional("reduceOnly", reduceOnly == null ? null : reduceOnly.Value ? "yes" : "no"); + parameters.AddOptionalEnum("stpMode", stpMode); + parameters.AddOptionalEnum("tpTriggerBy", tpTriggerBy); + parameters.AddOptionalEnum("slTriggerBy", slTriggerBy); + parameters.AddOptional("takeProfit", tpTriggerPrice); + parameters.AddOptional("stopLoss", slTriggerPrice); + parameters.AddOptionalEnum("tpOrderType", tpOrderType); + parameters.AddOptionalEnum("slOrderType", slOrderType); + parameters.AddOptional("tpLimitPrice", tpLimitPrice); + parameters.AddOptional("slLimitPrice", slLimitPrice); + parameters.AddOptionalEnum("marginMode", marginMode); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/place-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Edit Order + + /// + public async Task> EditOrderAsync( + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + decimal? price = null, + bool? autoCancel = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptionalString("qty", quantity); + parameters.AddOptionalString("price", price); + parameters.AddOptional("autoCancel", autoCancel == null ? null : autoCancel.Value ? "yes" : "no"); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/modify-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Cancel Order + + /// + public async Task> CancelOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/cancel-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Cancel All Orders + + /// + public async Task> CancelAllOrdersAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/cancel-symbol-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result.As(result.Data?.List); + } + + #endregion + + #region Close Positions + + /// + public async Task> ClosePositionsAsync( + ProductCategory category, + string? symbol = null, + PositionSide? positionSide = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + parameters.AddOptionalEnum("posSide", positionSide); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/close-positions", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result.As(result.Data?.List); + } + + #endregion + + #region Get Order + + /// + public async Task> GetOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/trade/order-info", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Open Orders + + /// + public async Task> GetOpenOrdersAsync( + ProductCategory? category = null, + string? symbol = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptionalEnum("category", category); + parameters.AddOptional("symbol", symbol); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/trade/unfilled-orders", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get User Trades + + /// + public async Task> GetUserTradesAsync( + ProductCategory? category = null, + string? orderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptionalEnum("category", category); + parameters.AddOptional("orderId", orderId); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/trade/fills", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Positions + + /// + public async Task> GetPositionsAsync( + ProductCategory category, + string? symbol = null, + PositionSide? positionSide = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + parameters.AddOptionalEnum("posSide", positionSide); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/position/current-position", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result.As(result.Data?.List); + } + + #endregion + + #region Get Position History + + /// + public async Task> GetPositionHistoryAsync( + ProductCategory category, + string? symbol = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptional("symbol", symbol); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/position/history-position", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Position Adl Rank + + /// + public async Task> GetPositionAdlRankAsync(CancellationToken ct = default) + { + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/position/adlRank", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(1, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Max Open Available + + /// + public async Task> GetMaxOpenAvailableAsync( + ProductCategory category, + string symbol, + OrderType orderType, + OrderSide side, + decimal quantity, + decimal? price = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddEnum("orderType", orderType); + parameters.AddEnum("side", side); + parameters.AddString("size", quantity); + parameters.AddOptionalString("price", price); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/account/max-open-available", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(5, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Place Strategy Order + + /// + public async Task> PlaceStrategyOrderAsync( + ProductCategory category, + string symbol, + StrategyType? type = null, + string? clientOrderId = null, + TpslMode? tpslMode = null, + decimal? quantity = null, + OrderSide? side = null, + PositionSide? positionSide = null, + bool? reduceOnly = null, + TriggerPriceType? tpTriggerBy = null, + TriggerPriceType? slTriggerBy = null, + decimal? takeProfit = null, + decimal? stopLoss = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + TriggerPriceType? triggerBy = null, + decimal? triggerPrice = null, + OrderType? triggerOrderType = null, + decimal? triggerOrderPrice = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.Add("symbol", symbol); + parameters.AddOptionalEnum("type", type); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptionalEnum("tpslMode", tpslMode); + parameters.AddOptionalString("qty", quantity); + parameters.AddOptionalEnum("side", side); + parameters.AddOptionalEnum("posSide", positionSide); + parameters.AddOptionalBoolString("reduceOnly", reduceOnly); + parameters.AddOptionalEnum("tpTriggerBy", tpTriggerBy); + parameters.AddOptionalEnum("slTriggerBy", slTriggerBy); + parameters.AddOptionalString("takeProfit", takeProfit); + parameters.AddOptionalString("stopLoss", stopLoss); + parameters.AddOptionalEnum("tpOrderType", tpOrderType); + parameters.AddOptionalEnum("slOrderType", slOrderType); + parameters.AddOptionalString("tpLimitPrice", tpLimitPrice); + parameters.AddOptionalString("slLimitPrice", slLimitPrice); + parameters.AddOptionalEnum("triggerBy", triggerBy); + parameters.AddOptionalString("triggerPrice", triggerPrice); + parameters.AddOptionalEnum("triggerOrderType", triggerOrderType); + parameters.AddOptionalString("triggerOrderPrice", triggerOrderPrice); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/place-strategy-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Edit Strategy Order + + /// + public async Task> EditStrategyOrderAsync( + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + TriggerPriceType? tpTriggerBy = null, + TriggerPriceType? slTriggerBy = null, + decimal? takeProfit = null, + decimal? stopLoss = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + TriggerPriceType? triggerBy = null, + decimal? triggerPrice = null, + OrderType? triggerOrderType = null, + decimal? triggerOrderPrice = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptionalString("qty", quantity); + parameters.AddOptionalEnum("tpTriggerBy", tpTriggerBy); + parameters.AddOptionalEnum("slTriggerBy", slTriggerBy); + parameters.AddOptionalString("takeProfit", takeProfit); + parameters.AddOptionalString("stopLoss", stopLoss); + parameters.AddOptionalEnum("tpOrderType", tpOrderType); + parameters.AddOptionalEnum("slOrderType", slOrderType); + parameters.AddOptionalString("tpLimitPrice", tpLimitPrice); + parameters.AddOptionalString("slLimitPrice", slLimitPrice); + parameters.AddOptionalEnum("triggerBy", triggerBy); + parameters.AddOptionalString("triggerPrice", triggerPrice); + parameters.AddOptionalEnum("triggerOrderType", triggerOrderType); + parameters.AddOptionalString("triggerOrderPrice", triggerOrderPrice); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/modify-strategy-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Cancel Strategy Order + + /// + public async Task CancelStrategyOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, "/api/v3/trade/cancel-strategy-order", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Open Strategy Orders + + /// + public async Task> GetOpenStrategyOrdersAsync( + ProductCategory category, + StrategyType? type = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptionalEnum("type", type); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/trade/unfilled-strategy-orders", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + #region Get Closed Strategy Orders + + /// + public async Task> GetClosedStrategyOrdersAsync( + ProductCategory category, + StrategyType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddEnum("category", category); + parameters.AddOptionalEnum("type", type); + parameters.AddOptionalMillisecondsString("startTime", startTime); + parameters.AddOptionalMillisecondsString("endTime", endTime); + parameters.AddOptional("limit", limit); + parameters.AddOptional("cursor", cursor); + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/trade/history-strategy-orders", BitgetExchange.RateLimiter.Overall, 1, true, limitGuard: new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); + var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + return result; + } + + #endregion + + } +} diff --git a/Bitget.Net/Clients/UnifiedApi/BitgetSocketClientUnifiedApi.cs b/Bitget.Net/Clients/UnifiedApi/BitgetSocketClientUnifiedApi.cs new file mode 100644 index 00000000..f5af79fa --- /dev/null +++ b/Bitget.Net/Clients/UnifiedApi/BitgetSocketClientUnifiedApi.cs @@ -0,0 +1,367 @@ +using Bitget.Net.Clients.MessageHandlers; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; +using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Interfaces.Clients.UnifiedApi; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using Bitget.Net.Objects.Options; +using Bitget.Net.Objects.Socket; +using Bitget.Net.Objects.Socket.Queries; +using Bitget.Net.Objects.Socket.Subscriptions; +using CryptoExchange.Net; +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Clients; +using CryptoExchange.Net.Converters.MessageParsing; +using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Errors; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Sockets; +using CryptoExchange.Net.Sockets.Default; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System.Net.WebSockets; + +namespace Bitget.Net.Clients.UnifiedApi +{ + /// + internal partial class BitgetSocketClientUnifiedApi : SocketApiClient, IBitgetSocketClientUnifiedApi + { + internal new BitgetSocketOptions ClientOptions => (BitgetSocketOptions)base.ClientOptions; + + protected override ErrorMapping ErrorMapping => BitgetErrors.UnifiedErrors; + + #region ctor + internal BitgetSocketClientUnifiedApi(ILogger logger, BitgetSocketOptions options) : + base(logger, options.Environment.SocketBaseAddress, options, options.UnifiedOptions) + { + RateLimiter = BitgetExchange.RateLimiter.Websocket; + + RegisterPeriodicQuery( + "Ping", + TimeSpan.FromSeconds(30), + x => new BitgetPingQuery(), + (connection, result) => + { + if (result.Error?.ErrorType == ErrorType.Timeout) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); + } + #endregion + + /// + protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(BitgetExchange._serializerContext)); + + public override ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType) => new BitgetSocketUnifiedMessageConverter(); + + /// + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + => BitgetExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); + + /// + public Task> SubscribeToTickerUpdatesAsync(ProductCategory type, string symbol, Action> handler, CancellationToken ct = default) + => SubscribeToTickerUpdatesAsync(type, new[] { symbol }, handler, ct); + + /// + public async Task> SubscribeToTickerUpdatesAsync(ProductCategory type, IEnumerable symbols, Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/public"), symbols.Select(s => new Dictionary + { + { "instType", EnumConverter.GetString(type).ToLowerInvariant() }, + { "topic", "ticker" }, + { "symbol", s }, + }).ToArray(), + symbols, false, handler, ct).ConfigureAwait(false); + } + + /// + public Task> SubscribeToKlineUpdatesAsync(ProductCategory type, string symbol, KlineUaInterval interval, Action> handler, CancellationToken ct = default) + => SubscribeToKlineUpdatesAsync(type, new[] { symbol }, interval, handler, ct); + + /// + public async Task> SubscribeToKlineUpdatesAsync(ProductCategory type, IEnumerable symbols, KlineUaInterval interval, Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/public"), symbols.Select(s => new Dictionary + { + { "instType", EnumConverter.GetString(type).ToLowerInvariant() }, + { "topic", "kline" }, + { "symbol", s }, + { "interval", EnumConverter.GetString(interval) }, + }).ToArray(), + symbols, false, handler, ct).ConfigureAwait(false); + } + + /// + public Task> SubscribeToOrderBookUpdatesAsync(ProductCategory type, string symbol, int? limit, Action> handler, CancellationToken ct = default) + => SubscribeToOrderBookUpdatesAsync(type, new[] { symbol }, limit, handler, ct); + + /// + public async Task> SubscribeToOrderBookUpdatesAsync(ProductCategory type, IEnumerable symbols, int? limit, Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/public"), symbols.Select(s => new Dictionary + { + { "instType", EnumConverter.GetString(type).ToLowerInvariant() }, + { "topic", "books" + limit?.ToString() }, + { "symbol", s }, + }).ToArray(), + symbols, false, handler, ct).ConfigureAwait(false); + } + + /// + public Task> SubscribeToTradeUpdatesAsync(ProductCategory type, string symbol, Action> handler, CancellationToken ct = default) + => SubscribeToTradeUpdatesAsync(type, new[] { symbol }, handler, ct); + + /// + public async Task> SubscribeToTradeUpdatesAsync(ProductCategory type, IEnumerable symbols, Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/public"), symbols.Select(s => new Dictionary + { + { "instType", EnumConverter.GetString(type).ToLowerInvariant() }, + { "topic", "publicTrade" }, + { "symbol", s }, + }).ToArray(), + symbols, false, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToLiquidationUpdatesAsync(ProductCategory type, Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/public"), [new Dictionary + { + { "instType", EnumConverter.GetString(type).ToLowerInvariant() }, + { "topic", "liquidation" } + }], + null, false, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToAccountUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "account" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToPositionUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "position" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToOrderUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "order" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToUserTradeUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "fill" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToFastUserTradeUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "fast-fill" }, + { "symbol", "default" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToStrategyOrderUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "strategy-order" }, + { "symbol", "default" } + }], + null, true, handler, ct).ConfigureAwait(false); + } + + /// + public async Task> SubscribeToAdlUpdatesAsync(Action> handler, CancellationToken ct = default) + { + return await SubscribeInternalAsync(BaseAddress.AppendPath("v3/ws/private"), [new Dictionary + { + { "instType", "UTA" }, + { "topic", "adl-notification" }, + }], + null, true, handler, ct).ConfigureAwait(false); + } + + #region Place Order + + /// + public async Task> PlaceOrderAsync( + ProductCategory category, + string symbol, + OrderSide side, + OrderType orderType, + decimal quantity, + decimal? price = null, + TimeInForce? timeInForce = null, + PositionSide? positionSide = null, + string? clientOrderId = null, + bool? reduceOnly = null, + StpMode? stpMode = null, + PriceTriggerType? tpTriggerBy = null, + PriceTriggerType? slTriggerBy = null, + decimal? tpTriggerPrice = null, + decimal? slTriggerPrice = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + MarginMode? marginMode = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("symbol", symbol); + parameters.AddEnum("side", side); + parameters.AddEnum("orderType", orderType); + parameters.AddString("qty", quantity); + parameters.AddOptional("price", price); + parameters.AddOptionalEnum("timeInForce", timeInForce); + parameters.AddOptionalEnum("posSide", positionSide); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptional("reduceOnly", reduceOnly == null ? null : reduceOnly.Value ? "yes" : "no"); + parameters.AddOptionalEnum("stpMode", stpMode); + parameters.AddOptionalEnum("tpTriggerBy", tpTriggerBy); + parameters.AddOptionalEnum("slTriggerBy", slTriggerBy); + parameters.AddOptional("takeProfit", tpTriggerPrice); + parameters.AddOptional("stopLoss", slTriggerPrice); + parameters.AddOptionalEnum("tpOrderType", tpOrderType); + parameters.AddOptionalEnum("slOrderType", slOrderType); + parameters.AddOptional("tpLimitPrice", tpLimitPrice); + parameters.AddOptional("slLimitPrice", slLimitPrice); + parameters.AddOptionalEnum("marginMode", marginMode); + + var query = new BitgetIdQuery(this, new BitgetIdSocketRequest + { + Id = ExchangeHelpers.NextId().ToString(), + Category = category, + Op = "trade", + Topic = "place-order", + ApiCode = LibraryHelpers.GetClientReference(() => ClientOptions.ChannelCode, BitgetExchange.ExchangeName), + Args = [parameters] + }, true); + + var result = await QueryAsync(BaseAddress.AppendPath("v3/ws/private"), query, ct).ConfigureAwait(false); + return result.As(result.Data?.SingleOrDefault()); + } + + #endregion + + #region Edit Order + + /// + public async Task> EditOrderAsync( + ProductCategory category, + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + decimal? price = null, + bool? autoCancel = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + parameters.AddOptionalString("qty", quantity); + parameters.AddOptional("price", price); + parameters.AddOptional("autoCancel", autoCancel == null ? null : autoCancel.Value ? "yes" : "no"); + + var query = new BitgetIdQuery(this, new BitgetIdSocketRequest + { + Id = ExchangeHelpers.NextId().ToString(), + Category = category, + Op = "trade", + Topic = "modify-order", + Args = [parameters] + }, true); + + var result = await QueryAsync(BaseAddress.AppendPath("v3/ws/private"), query, ct).ConfigureAwait(false); + return result.As(result.Data?.SingleOrDefault()); + } + + #endregion + + #region Cancel Order + + /// + public async Task> CancelOrderAsync( + ProductCategory category, + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddOptional("orderId", orderId); + parameters.AddOptional("clientOid", clientOrderId); + + var query = new BitgetIdQuery(this, new BitgetIdSocketRequest + { + Id = ExchangeHelpers.NextId().ToString(), + Category = category, + Op = "trade", + Topic = "cancel-order", + Args = [parameters] + }, true); + + var result = await QueryAsync(BaseAddress.AppendPath("v3/ws/private"), query, ct).ConfigureAwait(false); + return result.As(result.Data?.SingleOrDefault()); + } + + #endregion + + private async Task> SubscribeInternalAsync( + string url, + Dictionary[] request, + IEnumerable? symbols, + bool authenticated, + Action> handler, + CancellationToken ct) + { + var subscription = new BitgetSubscription(_logger, this, request, symbols?.ToArray(), handler, authenticated); + return await SubscribeAsync(url, subscription, ct).ConfigureAwait(false); + } + + /// + protected override BitgetAuthenticationProviderV2 CreateAuthenticationProvider(BitgetCredentials credentials) + => new BitgetAuthenticationProviderV2(credentials); + + } +} diff --git a/Bitget.Net/Converters/BitgetSourceGenerationContext.cs b/Bitget.Net/Converters/BitgetSourceGenerationContext.cs index 4a169194..77dd08f4 100644 --- a/Bitget.Net/Converters/BitgetSourceGenerationContext.cs +++ b/Bitget.Net/Converters/BitgetSourceGenerationContext.cs @@ -5,6 +5,73 @@ namespace Bitget.Net.Converters { + [JsonSerializable(typeof(BitgetIdSocketRequest))] + [JsonSerializable(typeof(BitgetSocketResponse))] + + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + [JsonSerializable(typeof(BitgetSocketUpdate))] + + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(BitgetResponse))] + [JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(BitgetFuturesPlaceOrderRequest[]))] [JsonSerializable(typeof(BitgetPlaceOrderRequest[]))] diff --git a/Bitget.Net/Enums/Uta/AccountLevel.cs b/Bitget.Net/Enums/Uta/AccountLevel.cs new file mode 100644 index 00000000..f9fdd22a --- /dev/null +++ b/Bitget.Net/Enums/Uta/AccountLevel.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Account level +/// +[JsonConverter(typeof(EnumConverter))] +public enum AccountLevel +{ + /// + /// ["advanced"] Advanced mode + /// + [Map("advanced")] + Advanced, + /// + /// ["basic"] Basic mode + /// + [Map("basic")] + Basic, + /// + /// ["isolated"] Isolated margin mode + /// + [Map("isolated")] + IsolatedMargin, + /// + /// ["delta"] Delta-neutral mode + /// + [Map("delta")] + Delta, +} diff --git a/Bitget.Net/Enums/Uta/AccountMode.cs b/Bitget.Net/Enums/Uta/AccountMode.cs new file mode 100644 index 00000000..bacd2dfe --- /dev/null +++ b/Bitget.Net/Enums/Uta/AccountMode.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Account mode +/// +[JsonConverter(typeof(EnumConverter))] +public enum AccountMode +{ + /// + /// ["hybrid"] Hybrid mode + /// + [Map("hybrid")] + Hybrid, + /// + /// ["unified"] Unified mode + /// + [Map("unified")] + Unified, + /// + /// ["upgrading"] Unified upgrading + /// + [Map("upgrading")] + Upgrading, + /// + /// ["switching"] Class switching + /// + [Map("switching")] + Switching, +} diff --git a/Bitget.Net/Enums/Uta/AddressBookType.cs b/Bitget.Net/Enums/Uta/AddressBookType.cs new file mode 100644 index 00000000..7a8a3f8b --- /dev/null +++ b/Bitget.Net/Enums/Uta/AddressBookType.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Address book entry type +/// +[JsonConverter(typeof(EnumConverter))] +public enum AddressBookType +{ + /// + /// ["EVM"] EVM + /// + [Map("EVM")] + Evm, + /// + /// ["regular"] Regular + /// + [Map("regular")] + Regular, + /// + /// ["universal"] Universal + /// + [Map("universal")] + Universal, + /// + /// ["internal"] Internal + /// + [Map("internal")] + Internal, +} diff --git a/Bitget.Net/Enums/Uta/ExecutionType.cs b/Bitget.Net/Enums/Uta/ExecutionType.cs new file mode 100644 index 00000000..c51cab80 --- /dev/null +++ b/Bitget.Net/Enums/Uta/ExecutionType.cs @@ -0,0 +1,38 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Execution type +/// +[JsonConverter(typeof(EnumConverter))] +public enum ExecutionType +{ + /// + /// ["normal"] Normal trade + /// + [Map("normal")] + Normal, + /// + /// ["offset"] Netting of hedged positions + /// + [Map("offset")] + Offset, + /// + /// ["reduce"] Forced reduction + /// + [Map("reduce")] + Reduce, + /// + /// ["liquidation"] Liquidation + /// + [Map("liquidation")] + Liquidation, + /// + /// ["delivery"] Delivery + /// + [Map("delivery")] + Delivery, +} diff --git a/Bitget.Net/Enums/Uta/HoldingMode.cs b/Bitget.Net/Enums/Uta/HoldingMode.cs new file mode 100644 index 00000000..4a64641f --- /dev/null +++ b/Bitget.Net/Enums/Uta/HoldingMode.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Holding mode +/// +[JsonConverter(typeof(EnumConverter))] +public enum HoldingMode +{ + /// + /// ["one_way_mode"] One way mode + /// + [Map("one_way_mode")] + OneWayMode, + /// + /// ["hedge_mode"] Hedge mode + /// + [Map("hedge_mode")] + HedgeMode, +} diff --git a/Bitget.Net/Enums/Uta/KlineInterval.cs b/Bitget.Net/Enums/Uta/KlineInterval.cs new file mode 100644 index 00000000..af520d1b --- /dev/null +++ b/Bitget.Net/Enums/Uta/KlineInterval.cs @@ -0,0 +1,63 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Kline interval +/// +[JsonConverter(typeof(EnumConverter))] +public enum KlineUaInterval +{ + /// + /// ["1m"] 1 minute + /// + [Map("1m")] + OneMinute = 60, + /// + /// ["3m"] 3 minutes + /// + [Map("3m")] + ThreeMinutes = 60 * 3, + /// + /// ["5m"] 5 minutes + /// + [Map("5m")] + FiveMinutes = 60 * 5, + /// + /// ["15m"] 15 minutes + /// + [Map("15m")] + FifteenMinutes = 60 * 15, + /// + /// ["30m"] 30 minutes + /// + [Map("30m")] + ThirtyMinutes = 60 * 30, + /// + /// ["1H"] 1 hour + /// + [Map("1H")] + OneHour = 60 * 60, + /// + /// ["4H"] 4 hours + /// + [Map("4H")] + FourHours = 60 * 60 * 4, + /// + /// ["6H"] 6 hours + /// + [Map("6H")] + SixHours = 60 * 60 * 6, + /// + /// ["12H"] 12 hours + /// + [Map("12H")] + TwelveHours = 60 * 60 * 12, + /// + /// ["1D"] 1 day + /// + [Map("1D")] + OneDay = 60 * 60 * 24, +} diff --git a/Bitget.Net/Enums/Uta/KlineType.cs b/Bitget.Net/Enums/Uta/KlineType.cs new file mode 100644 index 00000000..eb3c7e54 --- /dev/null +++ b/Bitget.Net/Enums/Uta/KlineType.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Kline type +/// +[JsonConverter(typeof(EnumConverter))] +public enum KlineType +{ + /// + /// ["market"] Market + /// + [Map("market")] + Market, + /// + /// ["mark"] Mark + /// + [Map("mark")] + Mark, + /// + /// ["index"] Index + /// + [Map("index")] + Index, + /// + /// ["premium"] Premium + /// + [Map("premium")] + Premium, +} diff --git a/Bitget.Net/Enums/Uta/PermissionType.cs b/Bitget.Net/Enums/Uta/PermissionType.cs new file mode 100644 index 00000000..30a3f0b9 --- /dev/null +++ b/Bitget.Net/Enums/Uta/PermissionType.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums; + +/// +/// Permission type +/// +[JsonConverter(typeof(EnumConverter))] +public enum PermissionType +{ + /// + /// ["read-and-write"] Read write + /// + [Map("read-and-write")] + ReadWrite, + /// + /// ["read-only"] Read only + /// + [Map("read-only")] + ReadOnly, +} diff --git a/Bitget.Net/Enums/Uta/PriceTriggerType.cs b/Bitget.Net/Enums/Uta/PriceTriggerType.cs new file mode 100644 index 00000000..f0f5ee60 --- /dev/null +++ b/Bitget.Net/Enums/Uta/PriceTriggerType.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Trigger price type +/// +[JsonConverter(typeof(EnumConverter))] +public enum PriceTriggerType +{ + /// + /// ["market"] Market price + /// + [Map("market")] + Market, + /// + /// ["mark"] Mark price + /// + [Map("mark")] + Mark, +} diff --git a/Bitget.Net/Enums/Uta/ProductCategory.cs b/Bitget.Net/Enums/Uta/ProductCategory.cs new file mode 100644 index 00000000..ed8821d0 --- /dev/null +++ b/Bitget.Net/Enums/Uta/ProductCategory.cs @@ -0,0 +1,38 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Product category +/// +[JsonConverter(typeof(EnumConverter))] +public enum ProductCategory +{ + /// + /// ["SPOT"] Spot + /// + [Map("SPOT", "spot")] + Spot, + /// + /// ["MARGIN"] Margin + /// + [Map("MARGIN", "margin")] + Margin, + /// + /// ["USDT-FUTURES"] USDT futures + /// + [Map("USDT-FUTURES", "usdt-futures")] + UsdtFutures, + /// + /// ["COIN-FUTURES"] Coin futures + /// + [Map("COIN-FUTURES", "coin-futures")] + CoinFutures, + /// + /// ["USDC-FUTURES"] USDC futures + /// + [Map("USDC-FUTURES", "usdc-futures")] + UsdcFutures, +} diff --git a/Bitget.Net/Enums/Uta/StpMode.cs b/Bitget.Net/Enums/Uta/StpMode.cs new file mode 100644 index 00000000..51cb12cc --- /dev/null +++ b/Bitget.Net/Enums/Uta/StpMode.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// STP mode +/// +[JsonConverter(typeof(EnumConverter))] +public enum StpMode +{ + /// + /// ["none"] None + /// + [Map("none")] + None, + /// + /// ["cancel_taker"] Cancel taker + /// + [Map("cancel_taker")] + CancelTaker, + /// + /// ["cancel_maker"] Cancel maker + /// + [Map("cancel_maker")] + CancelMaker, + /// + /// ["cancel_both"] Cancel both + /// + [Map("cancel_both")] + CancelBoth, +} diff --git a/Bitget.Net/Enums/Uta/StrategyStatus.cs b/Bitget.Net/Enums/Uta/StrategyStatus.cs new file mode 100644 index 00000000..a959f765 --- /dev/null +++ b/Bitget.Net/Enums/Uta/StrategyStatus.cs @@ -0,0 +1,38 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums; + +/// +/// Strategy order status +/// +[JsonConverter(typeof(EnumConverter))] +public enum StrategyStatus +{ + /// + /// ["pending"] Pending + /// + [Map("pending")] + Pending, + /// + /// ["success"] Success + /// + [Map("success")] + Success, + /// + /// ["failed"] Failed + /// + [Map("failed")] + Failed, + /// + /// ["cancelled"] Cancelled + /// + [Map("cancelled")] + Cancelled, + /// + /// ["submitting"] Submitting + /// + [Map("submitting")] + Submitting, +} diff --git a/Bitget.Net/Enums/Uta/StrategyType.cs b/Bitget.Net/Enums/Uta/StrategyType.cs new file mode 100644 index 00000000..33e67e5f --- /dev/null +++ b/Bitget.Net/Enums/Uta/StrategyType.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Strategy type +/// +[JsonConverter(typeof(EnumConverter))] +public enum StrategyType +{ + /// + /// ["tpsl"] Take profit / Stop loss order + /// + [Map("tpsl")] + TpSl, + /// + /// ["trigger"] Trigger order + /// + [Map("trigger")] + Trigger +} diff --git a/Bitget.Net/Enums/Uta/SwitchStatus.cs b/Bitget.Net/Enums/Uta/SwitchStatus.cs new file mode 100644 index 00000000..1fb8aaf3 --- /dev/null +++ b/Bitget.Net/Enums/Uta/SwitchStatus.cs @@ -0,0 +1,28 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Switch status +/// +[JsonConverter(typeof(EnumConverter))] +public enum SwitchStatus +{ + /// + /// ["fail"] Failed + /// + [Map("fail")] + Failed, + /// + /// ["process"] Process + /// + [Map("process")] + Processing, + /// + /// ["success"] Successful + /// + [Map("success")] + Success, +} diff --git a/Bitget.Net/Enums/Uta/SymbolStatus.cs b/Bitget.Net/Enums/Uta/SymbolStatus.cs new file mode 100644 index 00000000..e7a427b9 --- /dev/null +++ b/Bitget.Net/Enums/Uta/SymbolStatus.cs @@ -0,0 +1,43 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Symbol status +/// +[JsonConverter(typeof(EnumConverter))] +public enum InstrumentStatus +{ + /// + /// ["online"] Online + /// + [Map("online")] + Online, + /// + /// ["listed"] Listed but not yet online + /// + [Map("listed")] + Listed, + /// + /// ["limit_open"] Restrict opening positions + /// + [Map("limit_open")] + LimitOpen, + /// + /// ["limit_close"] Restrict closing positions + /// + [Map("limit_close")] + LimitClose, + /// + /// ["offline"] Offline + /// + [Map("offline")] + Offline, + /// + /// ["restrictedAPI"] API restricted + /// + [Map("restrictedAPI")] + ApiRestricted, +} diff --git a/Bitget.Net/Enums/Uta/SymbolType.cs b/Bitget.Net/Enums/Uta/SymbolType.cs new file mode 100644 index 00000000..585d8869 --- /dev/null +++ b/Bitget.Net/Enums/Uta/SymbolType.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Symbol type +/// +[JsonConverter(typeof(EnumConverter))] +public enum SymbolType +{ + /// + /// ["crypto"] Crypto + /// + [Map("crypto")] + Crypto, + /// + /// ["metal"] Metal + /// + [Map("metal")] + Metal, + /// + /// ["stock"] Stock + /// + [Map("stock")] + Stock, + /// + /// ["commodity"] Commodity + /// + [Map("commodity")] + Commodity, +} diff --git a/Bitget.Net/Enums/Uta/TpslMode.cs b/Bitget.Net/Enums/Uta/TpslMode.cs new file mode 100644 index 00000000..3d81fdfe --- /dev/null +++ b/Bitget.Net/Enums/Uta/TpslMode.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// TP/SL mode +/// +[JsonConverter(typeof(EnumConverter))] +public enum TpslMode +{ + /// + /// ["full"] Full + /// + [Map("full")] + Full, + /// + /// ["partial"] Partial take profit / stop loss order + /// + [Map("partial")] + Partial +} diff --git a/Bitget.Net/Enums/Uta/TriggerType.cs b/Bitget.Net/Enums/Uta/TriggerType.cs new file mode 100644 index 00000000..33818a9f --- /dev/null +++ b/Bitget.Net/Enums/Uta/TriggerType.cs @@ -0,0 +1,23 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Trigger type +/// +[JsonConverter(typeof(EnumConverter))] +public enum TriggerType +{ + /// + /// ["takeProfit"] Take profit + /// + [Map("takeProfit")] + TakeProfit, + /// + /// ["stopLoss"] Stop loss + /// + [Map("stopLoss")] + StopLoss +} diff --git a/Bitget.Net/Enums/Uta/UtaAccountType.cs b/Bitget.Net/Enums/Uta/UtaAccountType.cs new file mode 100644 index 00000000..83d6885b --- /dev/null +++ b/Bitget.Net/Enums/Uta/UtaAccountType.cs @@ -0,0 +1,28 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums; + +/// +/// Account type +/// +[JsonConverter(typeof(EnumConverter))] +public enum UtaAccountType +{ + /// + /// ["funding"] Funding account + /// + [Map("funding")] + Funding, + /// + /// ["unified"] Unified account + /// + [Map("unified")] + Unified, + /// + /// ["otc"] OTC account + /// + [Map("otc")] + Otc, +} diff --git a/Bitget.Net/Enums/Uta/WithdrawStatus.cs b/Bitget.Net/Enums/Uta/WithdrawStatus.cs new file mode 100644 index 00000000..facfdb79 --- /dev/null +++ b/Bitget.Net/Enums/Uta/WithdrawStatus.cs @@ -0,0 +1,28 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Enums.Uta; + +/// +/// Withdraw status +/// +[JsonConverter(typeof(EnumConverter))] +public enum WithdrawStatus +{ + /// + /// ["success"] Success + /// + [Map("success")] + Success, + /// + /// ["pending"] Pending + /// + [Map("pending")] + Pending, + /// + /// ["fail"] Failed + /// + [Map("fail")] + Failed, +} diff --git a/Bitget.Net/Enums/V2/DeliveryStatus.cs b/Bitget.Net/Enums/V2/DeliveryStatus.cs index 95b0a75f..63745c56 100644 --- a/Bitget.Net/Enums/V2/DeliveryStatus.cs +++ b/Bitget.Net/Enums/V2/DeliveryStatus.cs @@ -24,6 +24,11 @@ public enum DeliveryStatus /// ["delivery_period"] Delivery, opening, closing, and canceling orders are prohibited /// [Map("delivery_period")] - DeliveryPeriod + DeliveryPeriod, + /// + /// ["delivery_config_period"] New pair configuration + /// + [Map("delivery_config_period")] + New, } } diff --git a/Bitget.Net/Enums/V2/TransferAccountType.cs b/Bitget.Net/Enums/V2/TransferAccountType.cs index f70a0dfd..df455f9d 100644 --- a/Bitget.Net/Enums/V2/TransferAccountType.cs +++ b/Bitget.Net/Enums/V2/TransferAccountType.cs @@ -44,6 +44,11 @@ public enum TransferAccountType /// ["isolated_margin"] Isolated margin account /// [Map("isolated_margin")] - IsolatedMargin + IsolatedMargin, + /// + /// ["uta"] Unified trading account + /// + [Map("uta")] + Uta } } diff --git a/Bitget.Net/Interfaces/Clients/FuturesApiV2/IBitgetRestClientFuturesApiExchangeData.cs b/Bitget.Net/Interfaces/Clients/FuturesApiV2/IBitgetRestClientFuturesApiExchangeData.cs index 05633fa2..f4cac234 100644 --- a/Bitget.Net/Interfaces/Clients/FuturesApiV2/IBitgetRestClientFuturesApiExchangeData.cs +++ b/Bitget.Net/Interfaces/Clients/FuturesApiV2/IBitgetRestClientFuturesApiExchangeData.cs @@ -150,7 +150,7 @@ public interface IBitgetRestClientFuturesApiExchangeData /// ["limit"] Max number of results /// Cancellation token /// - Task> GetKlinesAsync(BitgetProductTypeV2 productType, string symbol, BitgetFuturesKlineInterval interval, KlineType? klineType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetKlinesAsync(BitgetProductTypeV2 productType, string symbol, BitgetFuturesKlineInterval interval, Enums.V2.KlineType? klineType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get historical market price kline/candlestick data diff --git a/Bitget.Net/Interfaces/Clients/IBitgetRestClient.cs b/Bitget.Net/Interfaces/Clients/IBitgetRestClient.cs index 6a0166af..2a5ffde6 100644 --- a/Bitget.Net/Interfaces/Clients/IBitgetRestClient.cs +++ b/Bitget.Net/Interfaces/Clients/IBitgetRestClient.cs @@ -1,6 +1,7 @@ using Bitget.Net.Interfaces.Clients.CopyTradingApiV2; using Bitget.Net.Interfaces.Clients.FuturesApiV2; using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Interfaces.Clients.UnifiedApi; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces.Clients; using CryptoExchange.Net.Objects.Options; @@ -27,5 +28,10 @@ public interface IBitgetRestClient : IRestClient /// /// IBitgetRestClientCopyTradingApi CopyTradingFuturesV2 { get; } + /// + /// UTA API endpoints + /// + /// + IBitgetRestClientUnifiedApi UnifiedApi{ get; } } } diff --git a/Bitget.Net/Interfaces/Clients/IBitgetSocketClient.cs b/Bitget.Net/Interfaces/Clients/IBitgetSocketClient.cs index 0b839160..fdb557be 100644 --- a/Bitget.Net/Interfaces/Clients/IBitgetSocketClient.cs +++ b/Bitget.Net/Interfaces/Clients/IBitgetSocketClient.cs @@ -1,5 +1,6 @@ using Bitget.Net.Interfaces.Clients.FuturesApiV2; using Bitget.Net.Interfaces.Clients.SpotApiV2; +using Bitget.Net.Interfaces.Clients.UnifiedApi; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces.Clients; using CryptoExchange.Net.Objects.Options; @@ -20,6 +21,11 @@ public interface IBitgetSocketClient : ISocketClient /// Futures streams /// /// - IBitgetSocketClientFuturesApi FuturesApiV2 { get; set; } + IBitgetSocketClientFuturesApi FuturesApiV2 { get; set; } + /// + /// UTA API endpoints + /// + /// + IBitgetSocketClientUnifiedApi UnifiedApi { get; } } } \ No newline at end of file diff --git a/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApi.cs b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApi.cs new file mode 100644 index 00000000..067b369a --- /dev/null +++ b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApi.cs @@ -0,0 +1,28 @@ +using CryptoExchange.Net.Interfaces.Clients; + +namespace Bitget.Net.Interfaces.Clients.UnifiedApi +{ + /// + /// Unified API endpoints + /// + public interface IBitgetRestClientUnifiedApi : IRestApiClient, IDisposable + { + /// + /// Endpoints related to account settings, info or actions + /// + /// + public IBitgetRestClientUnifiedApiAccount Account { get; } + + /// + /// Endpoints related to retrieving market and system data + /// + /// + public IBitgetRestClientUnifiedApiExchangeData ExchangeData { get; } + + /// + /// Endpoints related to account settings, info or actions + /// + /// + public IBitgetRestClientUnifiedApiTrading Trading { get; } + } +} diff --git a/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiAccount.cs b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiAccount.cs new file mode 100644 index 00000000..65ced7da --- /dev/null +++ b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiAccount.cs @@ -0,0 +1,530 @@ +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using CryptoExchange.Net.Objects; + +namespace Bitget.Net.Interfaces.Clients.UnifiedApi +{ + /// + /// Bitget account endpoints. Account endpoints include balance info, withdraw/deposit info and requesting and account settings + /// + public interface IBitgetRestClientUnifiedApiAccount + { + /// + /// Get balances + /// + /// Docs:
+ ///
+ /// Endpoint:
+ /// GET /api/v3/account/assets
+ ///
+ ///
+ /// Cancellation token + Task> GetBalancesAsync(CancellationToken ct = default); + + /// + /// Get funding assets + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/funding-assets
+ /// + ///
+ /// ["coin"] Filter by asset, for example `ETH` + /// Cancellation token + Task> GetFundingBalancesAsync(string? asset = null, CancellationToken ct = default); + + /// + /// Get account config + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/settings
+ /// + ///
+ /// Cancellation token + Task> GetAccountConfigAsync(CancellationToken ct = default); + + /// + /// Set leverage + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/set-leverage
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["leverage"] Leverage + /// ["coin"] The asset, for example `ETH` + /// ["posSide"] Position side + /// Cancellation token + Task SetLeverageAsync( + ProductCategory category, + string symbol, + decimal leverage, + string? asset = null, + PositionSide? positionSide = null, + CancellationToken ct = default); + + /// + /// Set holding mode + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/set-hold-mode
+ /// + ///
+ /// ["holdMode"] Holding mode + /// Cancellation token + Task SetHoldModeAsync(HoldingMode holdMode, CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/financial-records
+ /// + ///
+ /// ["category"] Category + /// ["coin"] Filter by asset, for example `ETH` + /// ["type"] Filter by type + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetFinancialRecordsAsync( + ProductCategory category, + string? asset = null, + string? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Get repayable assets + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/repayable-coins
+ /// + ///
+ /// Cancellation token + Task> GetRepayableAssetsAsync(CancellationToken ct = default); + + /// + /// Get payment assets + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/payment-coins
+ /// + ///
+ /// Cancellation token + Task> GetPaymentAssetsAsync(CancellationToken ct = default); + + /// + /// Manual repayment + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/repay
+ /// + ///
+ /// ["repayableCoinList"] Repayable asset list + /// ["paymentCoinList"] Payment asset list + /// Cancellation token + Task> RepayAsync( + IEnumerable repayableAssets, + IEnumerable paymentAssets, + CancellationToken ct = default); + + /// + /// Get convert records + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/convert-records
+ /// + ///
+ /// ["fromAsset"] The from asset, for example `ETH` + /// ["toAsset"] The target asset, for example `ETH` + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetConvertRecordsAsync( + string fromAsset, + string toAsset, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Switch deduct mode + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/switch-deduct
+ /// + ///
+ /// ["deduct"] Deduct enabled + /// Cancellation token + Task SwitchDeductAsync(bool deduct, CancellationToken ct = default); + + /// + /// Set deposit account for an asset + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/deposit-account
+ /// + ///
+ /// ["coin"] The asset, for example `ETH` + /// ["accountType"] Account type + /// Cancellation token + Task SetDepositAccountAsync( + string asset, + UtaAccountType accountType, + CancellationToken ct = default); + + /// + /// Get BGB deduct status + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/deduct-info
+ /// + ///
+ /// Cancellation token + Task> GetDeductStatusAsync(CancellationToken ct = default); + + /// + /// Get fee rates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/fee-rate
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetFeeAsync( + ProductCategory category, + string symbol, + CancellationToken ct = default); + + /// + /// Switch to classic account mode + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/switch
+ /// + ///
+ /// Cancellation token + Task SwitchToClassicModeAsync(CancellationToken ct = default); + + /// + /// Get switch to classic account mode status + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/switch-status
+ /// + ///
+ /// Cancellation token + Task> GetSwitchToClassicStatusAsync(CancellationToken ct = default); + + /// + /// Get max transferable quantity for an asset + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/max-transferable
+ /// + ///
+ /// ["coin"] The asset, for example `ETH` + /// Cancellation token + Task> GetMaxTransferableAsync(string asset, CancellationToken ct = default); + + /// + /// Get max open interest + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/open-interest-limit
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetOpenInterestLimitAsync( + ProductCategory category, + string symbol, + CancellationToken ct = default); + + /// + /// Get account info + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/info
+ /// + ///
+ /// Cancellation token + Task> GetAccountInfoAsync(CancellationToken ct = default); + + /// + /// Get delta info + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/delta-info
+ /// + ///
+ /// Cancellation token + Task> GetDeltaInfoAsync(CancellationToken ct = default); + + /// + /// Set account mode + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/adjust-account-mode
+ /// + ///
+ /// ["mode"] New mode + /// ["targetUid"] Sub account id + /// Cancellation token + Task SetAccountModeAsync( + AccountLevel mode, + string? subAccountId = null, + CancellationToken ct = default); + + /// + /// Get transferable assets + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/transferable-coins
+ /// + ///
+ /// ["fromType"] From type + /// ["toType"] To type + /// Cancellation token + Task> GetTransferableAssetsAsync( + Enums.V2.TransferAccountType fromType, + Enums.V2.TransferAccountType toType, + CancellationToken ct = default); + + /// + /// Transfer + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/transfer
+ /// + ///
+ /// ["fromType"] From type + /// ["toType"] To type + /// ["coin"] The asset, for example `ETH` + /// ["amount"] Quantity + /// ["symbol"] Isolated margin symbol + /// ["allowBorrow"] Allow borrowing for transfer + /// Cancellation token + Task> TransferAsync( + Enums.V2.TransferAccountType fromType, + Enums.V2.TransferAccountType toType, + string asset, + decimal quantity, + string? symbol = null, + bool? allowBorrow = null, + CancellationToken ct = default); + + /// + /// Get deposit address + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/deposit-address
+ /// + ///
+ /// ["coin"] The asset, for example `ETH` + /// ["chain"] Network + /// ["size"] Quantity for BTC lightning deposit + /// Cancellation token + Task> GetDepositAddressAsync( + string asset, + string? network = null, + decimal? quantity = null, + CancellationToken ct = default); + + /// + /// Get deposit records + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/deposit-records
+ /// + ///
+ /// ["coin"] Filter by asset, for example `ETH` + /// ["orderId"] Filter by order id + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetDepositRecordsAsync( + string? asset = null, + string? orderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Withdraw + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/withdrawal
+ /// + ///
+ /// ["coin"] The asset, for example `ETH` + /// ["transferType"] Transfer type + /// ["address"] Target address + /// ["size"] Quantity + /// ["chain"] Network + /// ["innerToType"] Inner withdrawal type + /// ["areaCode"] Area code for mobile + /// ["tag"] Tag + /// ["remark"] Remark + /// ["clientOid"] Client order id + /// ["memberCode"] Member code + /// ["identityType"] Identity type + /// ["companyName"] Company name + /// ["firstName"] First name + /// ["lastName"] Last name + /// Cancellation token + Task> WithdrawAsync( + string asset, + Enums.V2.TransferType transferType, + string address, + decimal quantity, + string? network = null, + string? innerWithdrawType = null, + string? areaCode = null, + string? tag = null, + string? remark = null, + string? clientOrderId = null, + string? memberCode = null, + string? identityType = null, + string? companyName = null, + string? firstName = null, + string? lastName = null, + CancellationToken ct = default); + + /// + /// Get withdrawal records + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/withdrawal-records
+ /// + ///
+ /// ["coin"] Filter by asset, for example `ETH` + /// ["orderId"] Filter by order id + /// ["clientOid"] Filter by client order id + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetWithdrawalRecordsAsync( + string? asset = null, + string? orderId = null, + string? clientOrderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Get withdrawal address book + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/withdraw-address
+ /// + ///
+ /// ["coin"] Filter by asset, for example `ETH` + /// ["type"] Filter by type + /// ["limit"] Max number of results, max 10 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetWithdrawAddressBookAsync( + string? asset = null, + AddressBookType? type = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Cancel a pending withdrawal + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/account/cancel-withdrawal
+ /// + ///
+ /// ["orderId"] Cancel by order id + /// ["clientOid"] Cancel by client order id + /// Cancellation token + Task CancelWithdrawalAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default); + + } +} diff --git a/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiExchangeData.cs b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiExchangeData.cs new file mode 100644 index 00000000..29883a76 --- /dev/null +++ b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiExchangeData.cs @@ -0,0 +1,335 @@ +using Bitget.Net.Enums.Uta; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using CryptoExchange.Net.Objects; + +namespace Bitget.Net.Interfaces.Clients.UnifiedApi +{ + /// + /// Bitget exchange data endpoints. Exchange data includes market data (tickers, order books, etc) and system status. + /// + public interface IBitgetRestClientUnifiedApiExchangeData + { + /// + /// Get the server time + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v2/public/time + /// + ///
+ /// Cancellation token + /// + Task> GetServerTimeAsync(CancellationToken ct = default); + + /// + /// Get supported futures symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/instruments
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetFuturesSymbolsAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get supported spot symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/instruments
+ /// + ///
+ /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetSpotSymbolsAsync( + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get supported margin symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/instruments
+ /// + ///
+ /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetMarginSymbolsAsync( + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get spot tickers + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/tickers
+ /// + ///
+ /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetSpotTickersAsync( + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get futures tickers + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/tickers
+ /// + ///
+ /// ["category"] Futures category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetFuturesTickersAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get order book snapshot + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/orderbook
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["limit"] Max number of results, max 200 + /// Cancellation token + Task> GetOrderBookAsync( + ProductCategory category, + string symbol, + int? limit = null, + CancellationToken ct = default); + + /// + /// Get the most recent trades + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/fills
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["limit"] Max number of results, max 100 + /// Cancellation token + Task> GetRecentTradesAsync( + ProductCategory category, + string symbol, + int? limit = null, + CancellationToken ct = default); + + /// + /// Get exchange's proof of reserves + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/proof-of-reserves
+ /// + ///
+ /// Cancellation token + Task> GetProofOfReservesAsync(CancellationToken ct = default); + + /// + /// Get open interest for symbol(s) + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/open-interest
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetOpenInterestAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get klines/candlestick data + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/candles
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["interval"] Kline interval + /// ["type"] Kline type + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 1000 + /// Cancellation token + Task> GetKlinesAsync( + ProductCategory category, + string symbol, + KlineUaInterval interval, + KlineType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + CancellationToken ct = default); + + /// + /// Get kline history + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/history-candles
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["interval"] Kline interval + /// ["type"] Kline type + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// Cancellation token + Task> GetKlineHistoryAsync( + ProductCategory category, + string symbol, + KlineUaInterval interval, + KlineType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + CancellationToken ct = default); + + /// + /// Get current funding rate + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/current-fund-rate
+ /// + ///
+ /// ["symbol"] The symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetFundingRateAsync(string symbol, CancellationToken ct = default); + + /// + /// Get funding rate history + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/history-fund-rate
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["cursor"] Page + /// ["limit"] Page size, max 100 + /// Cancellation token + Task> GetFundingRateHistoryAsync( + ProductCategory category, + string symbol, + int? page = null, + int? pageSize = null, + CancellationToken ct = default); + + /// + /// Get margin loan discount rate + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/discount-rate
+ /// + ///
+ /// Cancellation token + Task> GetDiscountRateAsync(CancellationToken ct = default); + + /// + /// Get margin loan interest rates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/margin-loans
+ /// + ///
+ /// ["coin"] The asset, for example `ETH` + /// Cancellation token + Task> GetMarginLoanInterestRatesAsync(string asset, CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/position-tier
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["coin"] The asset, for example `ETH` + /// Cancellation token + Task> GetPositionTiersAsync( + ProductCategory category, + string? symbol = null, + string? asset = null, + CancellationToken ct = default); + + /// + /// Get open interest limit + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/oi-limit
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetOpenInterestLimitAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default); + + /// + /// Get index components + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/market/index-components
+ /// + ///
+ /// ["symbol"] The symbol, for example `ETHUSDT` + /// Cancellation token + Task> GetIndexComponentsAsync(string symbol, CancellationToken ct = default); + + } +} diff --git a/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiTrading.cs b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiTrading.cs new file mode 100644 index 00000000..05a6db57 --- /dev/null +++ b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetRestClientUnifiedApiTrading.cs @@ -0,0 +1,449 @@ +using Bitget.Net.Objects.Models.V2; +using Bitget.Net.Enums.Uta; +using CryptoExchange.Net.Objects; +using Bitget.Net.Objects.Models; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Interfaces.Clients.UnifiedApi +{ + /// + /// Bitget trading endpoints, placing and managing orders. + /// + public interface IBitgetRestClientUnifiedApiTrading + { + /// + /// Place a new order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/place-order
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["side"] Order side + /// ["orderType"] Order type + /// ["qty"] Quantity. In quote asset for market buy orders + /// ["price"] Order limit price + /// ["timeInForce"] Time in force + /// ["posSide"] Position side + /// ["clientOid"] Client order id + /// ["reduceOnly"] Reduce only + /// ["stpMode"] Stp mode + /// ["tpTriggerBy"] Take profit trigger type + /// ["slTriggerBy"] Stop loss trigger type + /// ["takeProfit"] Take profit trigger price + /// ["stopLoss"] Stop loss trigger price + /// ["tpOrderType"] Take profit order type + /// ["slOrderType"] Stop loss order type + /// ["tpLimitPrice"] Take profit limit price + /// ["slLimitPrice"] Stop loss limit price + /// ["marginMode"] Margin mode + /// Cancellation token + Task> PlaceOrderAsync( + ProductCategory category, + string symbol, + OrderSide side, + OrderType orderType, + decimal quantity, + decimal? price = null, + TimeInForce? timeInForce = null, + PositionSide? positionSide = null, + string? clientOrderId = null, + bool? reduceOnly = null, + StpMode? stpMode = null, + PriceTriggerType? tpTriggerBy = null, + PriceTriggerType? slTriggerBy = null, + decimal? tpTriggerPrice = null, + decimal? slTriggerPrice = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + MarginMode? marginMode = null, + CancellationToken ct = default); + + /// + /// Edit an open order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/modify-order
+ /// + ///
+ /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// ["qty"] New quantity + /// ["price"] New price + /// ["autoCancel"] Will the original order be canceled if the order modification fails + /// Cancellation token + Task> EditOrderAsync( + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + decimal? price = null, + bool? autoCancel = null, + CancellationToken ct = default); + + /// + /// Cancel an open order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/cancel-order
+ /// + ///
+ /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// Cancellation token + Task> CancelOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default); + + /// + /// Cancel all orders matching the parameters + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/cancel-symbol-order
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// Cancellation token + Task> CancelAllOrdersAsync( + ProductCategory category, + string? symbol = null, + CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/close-positions
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["posSide"] Position side + /// Cancellation token + Task> ClosePositionsAsync( + ProductCategory category, + string? symbol = null, + PositionSide? positionSide = null, + CancellationToken ct = default); + + /// + /// Get order by id + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/trade/order-info
+ /// + ///
+ /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// Cancellation token + Task> GetOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/trade/unfilled-orders
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetOpenOrdersAsync( + ProductCategory? category = null, + string? symbol = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Get user trades + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/trade/fills
+ /// + ///
+ /// ["category"] Category + /// ["orderId"] Filter by order id + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetUserTradesAsync( + ProductCategory? category = null, + string? orderId = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Get open positions + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/position/current-position
+ /// + ///
+ /// ["category"] Product category + /// ["symbol"] Filter by symbol, for example `ETHUSDT` + /// ["posSide"] Filter by position side + /// Cancellation token + Task> GetPositionsAsync( + ProductCategory category, + string? symbol = null, + PositionSide? positionSide = null, + CancellationToken ct = default); + + /// + /// Get position history + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/position/history-position
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetPositionHistoryAsync( + ProductCategory category, + string? symbol = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + /// + /// Get ADL ranking + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/position/adlRank
+ /// + ///
+ /// Cancellation token + Task> GetPositionAdlRankAsync(CancellationToken ct = default); + + /// + /// Get max open available + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/account/max-open-available
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["orderType"] Order type + /// ["side"] Order side + /// ["size"] Order quantity + /// ["price"] Order price + /// Cancellation token + Task> GetMaxOpenAvailableAsync( + ProductCategory category, + string symbol, + OrderType orderType, + OrderSide side, + decimal quantity, + decimal? price = null, + CancellationToken ct = default); + + /// + /// Place a new strategy order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/place-strategy-order
+ /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["type"] Type of strategy order + /// ["clientOid"] Client order id + /// ["tpslMode"] TP/SL mode + /// ["qty"] Order quantity + /// ["side"] Order side + /// ["posSide"] Position side + /// ["reduceOnly"] Reduce only + /// ["tpTriggerBy"] Take profit trigger by + /// ["slTriggerBy"] Stop loss trigger by + /// ["takeProfit"] Take profit trigger price + /// ["stopLoss"] Stop loss trigger price + /// ["tpOrderType"] Take profit order type + /// ["slOrderType"] Stop loss order type + /// ["tpLimitPrice"] Take profit limit price + /// ["slLimitPrice"] Stop loss limit price + /// ["triggerBy"] Trigger order trigger price type + /// ["triggerPrice"] Trigger price + /// ["triggerOrderType"] Trigger order type + /// ["triggerOrderPrice"] Trigger order price + /// Cancellation token + Task> PlaceStrategyOrderAsync( + ProductCategory category, + string symbol, + StrategyType? type = null, + string? clientOrderId = null, + TpslMode? tpslMode = null, + decimal? quantity = null, + OrderSide? side = null, + PositionSide? positionSide = null, + bool? reduceOnly = null, + TriggerPriceType? tpTriggerBy = null, + TriggerPriceType? slTriggerBy = null, + decimal? takeProfit = null, + decimal? stopLoss = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + TriggerPriceType? triggerBy = null, + decimal? triggerPrice = null, + OrderType? triggerOrderType = null, + decimal? triggerOrderPrice = null, + CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/modify-strategy-order
+ /// + ///
+ /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// ["qty"] Partial Tp/sl quantity + /// /// ["tpTriggerBy"] Take profit trigger by + /// ["slTriggerBy"] Stop loss trigger by + /// ["takeProfit"] Take profit trigger price + /// ["stopLoss"] Stop loss trigger price + /// ["tpOrderType"] Take profit order type + /// ["slOrderType"] Stop loss order type + /// ["tpLimitPrice"] Take profit limit price + /// ["slLimitPrice"] Stop loss limit price + /// ["triggerBy"] Trigger order trigger price type + /// ["triggerPrice"] Trigger price + /// ["triggerOrderType"] Trigger order type + /// ["triggerOrderPrice"] Trigger order price + /// Cancellation token + Task> EditStrategyOrderAsync( + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + TriggerPriceType? tpTriggerBy = null, + TriggerPriceType? slTriggerBy = null, + decimal? takeProfit = null, + decimal? stopLoss = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + TriggerPriceType? triggerBy = null, + decimal? triggerPrice = null, + OrderType? triggerOrderType = null, + decimal? triggerOrderPrice = null, + CancellationToken ct = default); + + /// + /// Cancel a strategy order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/cancel-strategy-order
+ /// + ///
+ /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// Cancellation token + Task CancelStrategyOrderAsync( + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default); + + /// + /// Get open strategy orders + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/trade/unfilled-strategy-orders
+ /// + ///
+ /// ["category"] Category + /// ["type"] Filter by type + /// Cancellation token + Task> GetOpenStrategyOrdersAsync( + ProductCategory category, + StrategyType? type = null, + CancellationToken ct = default); + + /// + /// + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/trade/history-strategy-orders
+ /// + ///
+ /// ["category"] Category + /// ["type"] Filter by type + /// ["startTime"] Filter by start time + /// ["endTime"] Filter by end time + /// ["limit"] Max number of results, max 100 + /// ["cursor"] Pagination cursor + /// Cancellation token + Task> GetClosedStrategyOrdersAsync( + ProductCategory category, + StrategyType? type = null, + DateTime? startTime = null, + DateTime? endTime = null, + int? limit = null, + string? cursor = null, + CancellationToken ct = default); + + } +} diff --git a/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetSocketClientUnifiedApi.cs b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetSocketClientUnifiedApi.cs new file mode 100644 index 00000000..86524430 --- /dev/null +++ b/Bitget.Net/Interfaces/Clients/UnifiedApi/IBitgetSocketClientUnifiedApi.cs @@ -0,0 +1,359 @@ +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using CryptoExchange.Net.Interfaces.Clients; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Sockets; + +namespace Bitget.Net.Interfaces.Clients.UnifiedApi +{ + /// + /// Bitget spot streams + /// + public interface IBitgetSocketClientUnifiedApi : ISocketApiClient, IDisposable + { + /// + /// Subscribe to ticker updates for a symbol + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: ticker) + /// + ///
+ /// Symbol type + /// The symbol, for example `ETHUSDT` + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToTickerUpdatesAsync(ProductCategory type, string symbol, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to ticker updates for symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: ticker) + /// + ///
+ /// Symbol type + /// The symbols, for example `ETHUSDT` + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToTickerUpdatesAsync(ProductCategory type, IEnumerable symbols, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to kline updates for a symbol + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: kline) + /// + ///
+ /// Symbol type + /// The symbol, for example `ETHUSDT` + /// Kline interval + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToKlineUpdatesAsync(ProductCategory type, string symbol, KlineUaInterval interval, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to kline updates for a symbol + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: kline) + /// + ///
+ /// Symbol type + /// The symbols, for example `ETHUSDT` + /// Kline interval + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToKlineUpdatesAsync(ProductCategory type, IEnumerable symbols, KlineUaInterval interval, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to book updates for a symbol + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: depth) + /// + ///
+ /// Symbol type + /// The symbol, for example `ETHUSDT` + /// The depth, 1, 5, 50 or null for incremental updates + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToOrderBookUpdatesAsync(ProductCategory type, string symbol, int? depth, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to book updates for symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: depth) + /// + ///
+ /// Symbol type + /// The symbols, for example `ETHUSDT` + /// The depth, 1, 5, 50 or null for incremental updates + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToOrderBookUpdatesAsync(ProductCategory type, IEnumerable symbols, int? depth, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to trade updates for a symbol + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: publicTrade) + /// + ///
+ /// Symbol type + /// The symbol, for example `ETHUSDT` + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToTradeUpdatesAsync(ProductCategory type, string symbol, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to trade updates for symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: publicTrade) + /// + ///
+ /// Symbol type + /// The symbols, for example `ETHUSDT` + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToTradeUpdatesAsync(ProductCategory type, IEnumerable symbols, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to liquidation updates for symbols + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/public (channel: liquidation) + /// + ///
+ /// Symbol type + /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToLiquidationUpdatesAsync(ProductCategory type, Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to account balance updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: account) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToAccountUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to position updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: position) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToPositionUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to user order updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: order) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToOrderUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to user trade updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: fill) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToUserTradeUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to user trade updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: fast-fill) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToFastUserTradeUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to user strategy order updates + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: strategy-order) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToStrategyOrderUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Subscribe to user ADL notifications + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (channel: adl-notification) + /// + ///
+ /// The handler for the data + /// Cancellation token for closing this subscription + /// + Task> SubscribeToAdlUpdatesAsync(Action> handler, CancellationToken ct = default); + + /// + /// Place a new order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// WSS /v3/ws/private (topic: place-order) + /// + ///
+ /// ["category"] Category + /// ["symbol"] The symbol, for example `ETHUSDT` + /// ["side"] Order side + /// ["orderType"] Order type + /// ["qty"] Quantity + /// ["price"] Order limit price + /// ["timeInForce"] Time in force + /// ["posSide"] Position side + /// ["clientOid"] Client order id + /// ["reduceOnly"] Reduce only + /// ["stpMode"] Stp mode + /// ["tpTriggerBy"] Take profit trigger type + /// ["slTriggerBy"] Stop loss trigger type + /// ["takeProfit"] Take profit trigger price + /// ["stopLoss"] Stop loss trigger price + /// ["tpOrderType"] Take profit order type + /// ["slOrderType"] Stop loss order type + /// ["tpLimitPrice"] Take profit limit price + /// ["slLimitPrice"] Stop loss limit price + /// ["marginMode"] Margin mode + /// Cancellation token + public Task> PlaceOrderAsync( + ProductCategory category, + string symbol, + OrderSide side, + OrderType orderType, + decimal quantity, + decimal? price = null, + TimeInForce? timeInForce = null, + PositionSide? positionSide = null, + string? clientOrderId = null, + bool? reduceOnly = null, + StpMode? stpMode = null, + PriceTriggerType? tpTriggerBy = null, + PriceTriggerType? slTriggerBy = null, + decimal? tpTriggerPrice = null, + decimal? slTriggerPrice = null, + OrderType? tpOrderType = null, + OrderType? slOrderType = null, + decimal? tpLimitPrice = null, + decimal? slLimitPrice = null, + MarginMode? marginMode = null, + CancellationToken ct = default); + + /// + /// Edit an open order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/modify-order
+ /// + ///
+ /// ["category"] Order id, either this or clientOrderId should be provided + /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// ["qty"] New quantity + /// ["price"] New price + /// ["autoCancel"] Will the original order be canceled if the order modification fails + /// Cancellation token + Task> EditOrderAsync( + ProductCategory category, + string? orderId = null, + string? clientOrderId = null, + decimal? quantity = null, + decimal? price = null, + bool? autoCancel = null, + CancellationToken ct = default); + + /// + /// Cancel an open order + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// POST /api/v3/trade/cancel-order
+ /// + ///
+ /// ["category"] Category + /// ["orderId"] Order id, either this or clientOrderId should be provided + /// ["clientOid"] Client order id, either this or orderId should be provided + /// Cancellation token + Task> CancelOrderAsync( + ProductCategory category, + string? orderId = null, + string? clientOrderId = null, + CancellationToken ct = default); + } +} diff --git a/Bitget.Net/Interfaces/IBitgetOrderBookFactory.cs b/Bitget.Net/Interfaces/IBitgetOrderBookFactory.cs index 708e9e31..aee74015 100644 --- a/Bitget.Net/Interfaces/IBitgetOrderBookFactory.cs +++ b/Bitget.Net/Interfaces/IBitgetOrderBookFactory.cs @@ -1,4 +1,5 @@ using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; using Bitget.Net.Objects.Options; using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.SharedApis; @@ -10,6 +11,10 @@ namespace Bitget.Net.Interfaces /// public interface IBitgetOrderBookFactory : IExchangeService { + /// + /// Unified API order book factory methods + /// + public IOrderBookFactory Unified { get; } /// /// Spot order book factory methods /// @@ -54,5 +59,14 @@ public interface IBitgetOrderBookFactory : IExchangeService /// Book options /// ISymbolOrderBook CreateFutures(BitgetProductTypeV2 productType, string symbol, Action? options = null); + + /// + /// Create a SymbolOrderBook for a symbol using the unified API + /// + /// The symbol category + /// The symbol + /// Book options + /// + ISymbolOrderBook CreateUnified(ProductCategory category, string symbol, Action? options = null); } } \ No newline at end of file diff --git a/Bitget.Net/Objects/BitgetApiAddresses.cs b/Bitget.Net/Objects/BitgetApiAddresses.cs index 1f671032..1bcb9232 100644 --- a/Bitget.Net/Objects/BitgetApiAddresses.cs +++ b/Bitget.Net/Objects/BitgetApiAddresses.cs @@ -22,5 +22,14 @@ public class BitgetApiAddresses RestBaseAddress = "https://api.bitget.com", SocketBaseAddress = "wss://ws.bitget.com", }; + + /// + /// The addresses to connect to the bitget.com demo trading API + /// + public static BitgetApiAddresses Demo = new BitgetApiAddresses + { + RestBaseAddress = "https://api.bitget.com", + SocketBaseAddress = "wss://wspap.bitget.com", + }; } } diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAccountConfig.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountConfig.cs new file mode 100644 index 00000000..329da554 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountConfig.cs @@ -0,0 +1,99 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Account config +/// +public record BitgetUaAccountConfig +{ + /// + /// ["uid"] Unique id + /// + [JsonPropertyName("uid")] + public decimal Uid { get; set; } + /// + /// ["accountMode"] Account mode + /// + [JsonPropertyName("accountMode")] + public AccountMode AccountMode { get; set; } + /// + /// ["assetMode"] Asset mode + /// + [JsonPropertyName("assetMode")] + public string AssetMode { get; set; } = string.Empty; + /// + /// ["accountLevel"] Account level + /// + [JsonPropertyName("accountLevel")] + public AccountLevel AccountLevel { get; set; } + /// + /// ["holdMode"] Hold mode + /// + [JsonPropertyName("holdMode")] + public HoldingMode HoldMode { get; set; } + /// + /// ["stpMode"] Self trade prevention mode + /// + [JsonPropertyName("stpMode")] + public StpMode StpMode { get; set; } + /// + /// ["symbolConfigList"] Symbol configurations + /// + [JsonPropertyName("symbolConfigList")] + public BitgetUaAccountInfoSymbol[] SymbolConfigs { get; set; } = []; + /// + /// ["coinConfigList"] Asset configurations + /// + [JsonPropertyName("coinConfigList")] + public BitgetUaAccountInfoAsset[] AssetConfigs { get; set; } = []; +} + +/// +/// +/// +public record BitgetUaAccountInfoSymbol +{ + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["marginMode"] Margin mode + /// + [JsonPropertyName("marginMode")] + public MarginMode MarginMode { get; set; } + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal Leverage { get; set; } +} + +/// +/// Asset info +/// +public record BitgetUaAccountInfoAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal Leverage { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAccountInfo.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountInfo.cs new file mode 100644 index 00000000..2e4d0e19 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountInfo.cs @@ -0,0 +1,58 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Account info +/// +public record BitgetUaAccountInfo +{ + /// + /// ["userId"] User id + /// + [JsonPropertyName("userId")] + public string UserId { get; set; } = string.Empty; + /// + /// ["inviterId"] Inviter id + /// + [JsonPropertyName("inviterId")] + public string InviterId { get; set; } = string.Empty; + /// + /// ["parentId"] Parent id + /// + [JsonPropertyName("parentId")] + public string ParentId { get; set; } = string.Empty; + /// + /// ["channelCode"] Channel code + /// + [JsonPropertyName("channelCode")] + public string ChannelCode { get; set; } = string.Empty; + /// + /// ["channel"] Channel + /// + [JsonPropertyName("channel")] + public string Channel { get; set; } = string.Empty; + /// + /// ["ips"] Ips + /// + [JsonPropertyName("ips")] + public string Ips { get; set; } = string.Empty; + /// + /// ["permType"] Permission type + /// + [JsonPropertyName("permType")] + public PermissionType PermissionType { get; set; } + /// + /// ["permissions"] Permissions + /// + [JsonPropertyName("permissions")] + public string[] Permissions { get; set; } = []; + /// + /// ["regisTime"] Registration time + /// + [JsonPropertyName("regisTime")] + public DateTime RegistrationTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAccountUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountUpdate.cs new file mode 100644 index 00000000..5a6dfc83 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAccountUpdate.cs @@ -0,0 +1,100 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Account update +/// +public record BitgetUaAccountUpdate +{ + /// + /// ["unrealisedPnL"] Unrealised profit and loss + /// + [JsonPropertyName("unrealisedPnL")] + public decimal UnrealisedPnL { get; set; } + /// + /// ["totalEquity"] Total equity + /// + [JsonPropertyName("totalEquity")] + public decimal TotalEquity { get; set; } + /// + /// ["positionMgnRatio"] Position mgn ratio + /// + [JsonPropertyName("positionMgnRatio")] + public decimal PositionMgnRatio { get; set; } + /// + /// ["mmr"] Maintenance margin + /// + [JsonPropertyName("mmr")] + public decimal Mmr { get; set; } + /// + /// ["effEquity"] Effective equity + /// + [JsonPropertyName("effEquity")] + public decimal EffectiveEquity { get; set; } + /// + /// ["imr"] Initial margin rate + /// + [JsonPropertyName("imr")] + public decimal Imr { get; set; } + /// + /// ["mgnRatio"] Margin ratio + /// + [JsonPropertyName("mgnRatio")] + public decimal MarginRatio { get; set; } + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public BitgetUaAccountUpdateAsset[] Asset { get; set; } = []; +} + +/// +/// Account asset +/// +public record BitgetUaAccountUpdateAsset +{ + /// + /// ["debts"] Debts + /// + [JsonPropertyName("debts")] + public decimal Debts { get; set; } + /// + /// ["balance"] Balance + /// + [JsonPropertyName("balance")] + public decimal Balance { get; set; } + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["borrow"] Borrow + /// + [JsonPropertyName("borrow")] + public decimal Borrow { get; set; } + /// + /// ["locked"] Locked + /// + [JsonPropertyName("locked")] + public decimal Locked { get; set; } + /// + /// ["equity"] Equity + /// + [JsonPropertyName("equity")] + public decimal Equity { get; set; } + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["usdValue"] Usd value + /// + [JsonPropertyName("usdValue")] + public decimal UsdValue { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAddressBook.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAddressBook.cs new file mode 100644 index 00000000..26a3eec9 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAddressBook.cs @@ -0,0 +1,75 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// Withdrawal address book +/// +public record BitgetUaAddressBook +{ + /// + /// ["addressList"] Addresses + /// + [JsonPropertyName("addressList")] + public BitgetUaAddressBookEntry[] Addresses { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; +} + +/// +/// Book entry +/// +public record BitgetUaAddressBookEntry +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["chain"] Network + /// + [JsonPropertyName("chain")] + public string Network { get; set; } = string.Empty; + /// + /// ["address"] Address + /// + [JsonPropertyName("address")] + public string Address { get; set; } = string.Empty; + /// + /// ["countryCode"] Country code + /// + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } + /// + /// ["label"] Label + /// + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; + /// + /// ["memo"] Memo + /// + [JsonPropertyName("memo")] + public string? Memo { get; set; } + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public AddressBookType Type { get; set; } + /// + /// ["internalType"] Internal type + /// + [JsonPropertyName("internalType")] + public string? InternalType { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAdlRank.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAdlRank.cs new file mode 100644 index 00000000..fec9452d --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAdlRank.cs @@ -0,0 +1,34 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// ADL rank +/// +public record BitgetUaAdlRank +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["marginCoin"] Margin asset + /// + [JsonPropertyName("marginCoin")] + public string MarginAsset { get; set; } = string.Empty; + /// + /// ["adlRank"] Adl rank + /// + [JsonPropertyName("adlRank")] + public decimal AdlRank { get; set; } + /// + /// ["holdSide"] Hold side + /// + [JsonPropertyName("holdSide")] + public PositionSide PositionSide { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaAdlUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaAdlUpdate.cs new file mode 100644 index 00000000..32a138b0 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaAdlUpdate.cs @@ -0,0 +1,44 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// ADL update +/// +public record BitgetUaAdlUpdate +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + /// + /// ["price"] Price + /// + [JsonPropertyName("price")] + public decimal Price { get; set; } + /// + /// ["amount"] Quantity + /// + [JsonPropertyName("amount")] + public decimal Quantity { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaBalances.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaBalances.cs new file mode 100644 index 00000000..c65b7dc1 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaBalances.cs @@ -0,0 +1,115 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Balance info +/// +public record BitgetUaBalances +{ + /// + /// ["accountEquity"] Account equity + /// + [JsonPropertyName("accountEquity")] + public decimal AccountEquity { get; set; } + /// + /// ["usdtEquity"] Usdt equity + /// + [JsonPropertyName("usdtEquity")] + public decimal UsdtEquity { get; set; } + /// + /// ["btcEquity"] Btc equity + /// + [JsonPropertyName("btcEquity")] + public decimal BtcEquity { get; set; } + /// + /// ["unrealisedPnl"] Unrealised profit and loss + /// + [JsonPropertyName("unrealisedPnl")] + public decimal UnrealisedPnl { get; set; } + /// + /// ["usdtUnrealisedPnl"] Usdt unrealised profit and loss + /// + [JsonPropertyName("usdtUnrealisedPnl")] + public decimal UsdtUnrealisedPnl { get; set; } + /// + /// ["btcUnrealizedPnl"] Btc unrealized profit and loss + /// + [JsonPropertyName("btcUnrealizedPnl")] + public decimal BtcUnrealizedPnl { get; set; } + /// + /// ["effEquity"] Effective equity + /// + [JsonPropertyName("effEquity")] + public decimal EffectiveEquity { get; set; } + /// + /// ["mmr"] Maintenance margin rate + /// + [JsonPropertyName("mmr")] + public decimal Mmr { get; set; } + /// + /// ["imr"] Initial margin rate + /// + [JsonPropertyName("imr")] + public decimal Imr { get; set; } + /// + /// ["mgnRatio"] Margin ratio + /// + [JsonPropertyName("mgnRatio")] + public decimal MarginRatio { get; set; } + /// + /// ["positionMgnRatio"] Position margin ratio + /// + [JsonPropertyName("positionMgnRatio")] + public decimal PositionMarginRatio { get; set; } + /// + /// ["assets"] Assets + /// + [JsonPropertyName("assets")] + public BitgetUaBalancesAsset[] Assets { get; set; } = []; +} + +/// +/// Asset balance +/// +public record BitgetUaBalancesAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["equity"] Equity + /// + [JsonPropertyName("equity")] + public decimal Equity { get; set; } + /// + /// ["usdValue"] Usd value + /// + [JsonPropertyName("usdValue")] + public decimal UsdValue { get; set; } + /// + /// ["balance"] Balance + /// + [JsonPropertyName("balance")] + public decimal Balance { get; set; } + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["debt"] Debt + /// + [JsonPropertyName("debt")] + public decimal Debt { get; set; } + /// + /// ["locked"] Locked + /// + [JsonPropertyName("locked")] + public decimal Locked { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaBatchResult.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaBatchResult.cs new file mode 100644 index 00000000..82e6bfeb --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaBatchResult.cs @@ -0,0 +1,42 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +internal record BitgetUaBatchResultWrapper +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaBatchResult[] List { get; set; } = []; +} + +/// +/// Batch result +/// +public record BitgetUaBatchResult +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["code"] Code + /// + [JsonPropertyName("code")] + public int Code { get; set; } + /// + /// ["msg"] Msg + /// + [JsonPropertyName("msg")] + public string? Msg { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaBookUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaBookUpdate.cs new file mode 100644 index 00000000..f9b7d860 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaBookUpdate.cs @@ -0,0 +1,41 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Objects.Models.V2; +using CryptoExchange.Net.Converters; +using CryptoExchange.Net.Converters.SystemTextJson; + +namespace Bitget.Net.Objects.Models; + +/// +/// Order book update +/// +public record BitgetUaBookUpdate +{ + /// + /// ["a"] Asks + /// + [JsonPropertyName("a")] + public BitgetOrderBookEntry[] Asks { get; set; } = []; + /// + /// ["b"] Bids + /// + [JsonPropertyName("b")] + public BitgetOrderBookEntry[] Bids { get; set; } = []; + /// + /// ["seq"] Sequence + /// + [JsonPropertyName("seq")] + public long Sequence { get; set; } + /// + /// ["pseq"] Previous sequence + /// + [JsonPropertyName("pseq")] + public long PreviousSequence { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaConvertRecords.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaConvertRecords.cs new file mode 100644 index 00000000..f62b893c --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaConvertRecords.cs @@ -0,0 +1,60 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Convert records +/// +public record BitgetUaConvertRecords +{ + /// + /// ["list"] Records + /// + [JsonPropertyName("list")] + public BitgetUaConvertRecord[] Records { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; +} + +/// +/// Convert record +/// +public record BitgetUaConvertRecord +{ + /// + /// ["fromCoin"] From asset + /// + [JsonPropertyName("fromCoin")] + public string FromAsset { get; set; } = string.Empty; + /// + /// ["fromCoinSize"] From asset quantity + /// + [JsonPropertyName("fromCoinSize")] + public decimal FromAssetQuantity { get; set; } + /// + /// ["toCoin"] To asset + /// + [JsonPropertyName("toCoin")] + public string ToAsset { get; set; } = string.Empty; + /// + /// ["toCoinSize"] To asset quantity + /// + [JsonPropertyName("toCoinSize")] + public decimal ToAssetQuantity { get; set; } + /// + /// ["price"] Price + /// + [JsonPropertyName("price")] + public decimal Price { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaDeductStatus.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaDeductStatus.cs new file mode 100644 index 00000000..cf1400e6 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaDeductStatus.cs @@ -0,0 +1,18 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Deduct status +/// +public record BitgetUaDeductStatus +{ + /// + /// ["deduct"] Deduct + /// + [JsonPropertyName("deduct")] + public bool Deduct { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaDeltaInfo.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaDeltaInfo.cs new file mode 100644 index 00000000..dd066eb7 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaDeltaInfo.cs @@ -0,0 +1,50 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Delta info +/// +public record BitgetUaDeltaInfo +{ + /// + /// ["deltaEquityRatio"] Delta equity ratio + /// + [JsonPropertyName("deltaEquityRatio")] + public decimal DeltaEquityRatio { get; set; } + /// + /// ["deltaThreshold"] Delta threshold + /// + [JsonPropertyName("deltaThreshold")] + public decimal DeltaThreshold { get; set; } + /// + /// ["positionThreshold"] Position threshold + /// + [JsonPropertyName("positionThreshold")] + public decimal PositionThreshold { get; set; } + /// + /// ["list"] Assets + /// + [JsonPropertyName("list")] + public BitgetUaDeltaInfoAsset[] Assets { get; set; } = []; +} + +/// +/// Delta asset +/// +public record BitgetUaDeltaInfoAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["positionRatio"] Position ratio + /// + [JsonPropertyName("positionRatio")] + public decimal PositionRatio { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaDeposit.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaDeposit.cs new file mode 100644 index 00000000..7081674a --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaDeposit.cs @@ -0,0 +1,73 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Deposit info +/// +public record BitgetUaDeposit +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["recordId"] Record id + /// + [JsonPropertyName("recordId")] + public string RecordId { get; set; } = string.Empty; + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + /// + /// ["dest"] Destination + /// + [JsonPropertyName("dest")] + public string Destination { get; set; } = string.Empty; + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + /// + /// ["fromAddress"] From address + /// + [JsonPropertyName("fromAddress")] + public string FromAddress { get; set; } = string.Empty; + /// + /// ["toAddress"] To address + /// + [JsonPropertyName("toAddress")] + public string ToAddress { get; set; } = string.Empty; + /// + /// ["chain"] Network + /// + [JsonPropertyName("chain")] + public string Network { get; set; } = string.Empty; + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaDepositAddress.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaDepositAddress.cs new file mode 100644 index 00000000..77294f43 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaDepositAddress.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Deposit address +/// +public record BitgetUaDepositAddress +{ + /// + /// ["address"] Address + /// + [JsonPropertyName("address")] + public string Address { get; set; } = string.Empty; + /// + /// ["chain"] Network + /// + [JsonPropertyName("chain")] + public string Network { get; set; } = string.Empty; + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["tag"] Tag + /// + [JsonPropertyName("tag")] + public string? Tag { get; set; } + /// + /// ["url"] Url + /// + [JsonPropertyName("url")] + public string? Url { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaDiscountRates.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaDiscountRates.cs new file mode 100644 index 00000000..00ab28e2 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaDiscountRates.cs @@ -0,0 +1,40 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Discount rate +/// +public record BitgetUaDiscountRates +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaDiscountRateValue[] List { get; set; } = []; +} + +/// +/// Rate value +/// +public record BitgetUaDiscountRateValue +{ + /// + /// ["tierStartValue"] Tier start value + /// + [JsonPropertyName("tierStartValue")] + public decimal TierStartValue { get; set; } + /// + /// ["discountRate"] Discount rate + /// + [JsonPropertyName("discountRate")] + public decimal DiscountRate { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFastUserTrade.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFastUserTrade.cs new file mode 100644 index 00000000..c414875a --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFastUserTrade.cs @@ -0,0 +1,76 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Trade info +/// +public record BitgetUaFastUserTrade +{ + /// + /// ["execId"] Trade id + /// + [JsonPropertyName("execId")] + public string TradeId { get; set; } = string.Empty; + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client order id + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["holdSide"] Position side + /// + [JsonPropertyName("holdSide")] + public PositionSide PositionSide { get; set; } + /// + /// ["execPrice"] Trade price + /// + [JsonPropertyName("execPrice")] + public decimal Price { get; set; } + /// + /// ["execQty"] Quantity + /// + [JsonPropertyName("execQty")] + public decimal Quantity { get; set; } + /// + /// ["tradeScope"] Trade scope + /// + [JsonPropertyName("tradeScope")] + public Role TradeScope { get; set; } + /// + /// ["execTime"] Trade time + /// + [JsonPropertyName("execTime")] + public DateTime? Timestamp { get; set; } + /// + /// ["updatedTime"] Updated time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdatedTime { get; set; } +} + + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFeeRate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFeeRate.cs new file mode 100644 index 00000000..7a9fbee2 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFeeRate.cs @@ -0,0 +1,23 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Fee rates +/// +public record BitgetUaFeeRate +{ + /// + /// ["makerFeeRate"] Maker fee rate + /// + [JsonPropertyName("makerFeeRate")] + public decimal MakerFeeRate { get; set; } + /// + /// ["takerFeeRate"] Taker fee rate + /// + [JsonPropertyName("takerFeeRate")] + public decimal TakerFeeRate { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFinancialRecordPage.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFinancialRecordPage.cs new file mode 100644 index 00000000..56551914 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFinancialRecordPage.cs @@ -0,0 +1,75 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// Financial record page +/// +public record BitgetUaFinancialRecordPage +{ + /// + /// ["list"] Records + /// + [JsonPropertyName("list")] + public BitgetUaFinancialRecord[] Records { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public decimal Cursor { get; set; } +} + +/// +/// Financial record +/// +public record BitgetUaFinancialRecord +{ + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["id"] Id + /// + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + /// + /// ["amount"] Quantity + /// + [JsonPropertyName("amount")] + public decimal Quantity { get; set; } + /// + /// ["fee"] Fee + /// + [JsonPropertyName("fee")] + public decimal Fee { get; set; } + /// + /// ["balance"] Balance + /// + [JsonPropertyName("balance")] + public decimal Balance { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFundingAsset.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingAsset.cs new file mode 100644 index 00000000..f2e501ca --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingAsset.cs @@ -0,0 +1,33 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaFundingAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["frozen"] Frozen + /// + [JsonPropertyName("frozen")] + public decimal Frozen { get; set; } + /// + /// ["balance"] Balance + /// + [JsonPropertyName("balance")] + public decimal Balance { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRate.cs new file mode 100644 index 00000000..173124a4 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRate.cs @@ -0,0 +1,43 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Funding rate +/// +public record BitgetUaFundingRate +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["fundingRate"] Funding rate + /// + [JsonPropertyName("fundingRate")] + public decimal FundingRate { get; set; } + /// + /// ["fundingRateInterval"] Funding rate interval + /// + [JsonPropertyName("fundingRateInterval")] + public int FundingRateInterval { get; set; } + /// + /// ["nextUpdate"] Next update + /// + [JsonPropertyName("nextUpdate")] + public DateTime NextUpdate { get; set; } + /// + /// ["minFundingRate"] Min funding rate + /// + [JsonPropertyName("minFundingRate")] + public decimal MinFundingRate { get; set; } + /// + /// ["maxFundingRate"] Max funding rate + /// + [JsonPropertyName("maxFundingRate")] + public decimal MaxFundingRate { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRateHistory.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRateHistory.cs new file mode 100644 index 00000000..fa546bf0 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFundingRateHistory.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +internal record BitgetUaFundingRateHistoryWrapper +{ + /// + /// ["resultList"] Result list + /// + [JsonPropertyName("resultList")] + public BitgetUaFundingRateHistory[] ResultList { get; set; } = []; +} + +/// +/// Funding rate history +/// +public record BitgetUaFundingRateHistory +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["fundingRate"] Funding rate + /// + [JsonPropertyName("fundingRate")] + public decimal FundingRate { get; set; } + /// + /// ["fundingRateTimestamp"] Funding rate timestamp + /// + [JsonPropertyName("fundingRateTimestamp")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesSymbol.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesSymbol.cs new file mode 100644 index 00000000..776e0925 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesSymbol.cs @@ -0,0 +1,194 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaFuturesSymbol +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["baseCoin"] Base asset + /// + [JsonPropertyName("baseCoin")] + public string BaseAsset { get; set; } = string.Empty; + /// + /// ["quoteCoin"] Quote asset + /// + [JsonPropertyName("quoteCoin")] + public string QuoteAsset { get; set; } = string.Empty; + /// + /// ["isRwa"] Is rwa + /// + [JsonPropertyName("isRwa")] + public bool IsRwa { get; set; } + /// + /// ["buyLimitPriceRatio"] Buy limit price ratio + /// + [JsonPropertyName("buyLimitPriceRatio")] + public decimal BuyLimitPriceRatio { get; set; } + /// + /// ["sellLimitPriceRatio"] Sell limit price ratio + /// + [JsonPropertyName("sellLimitPriceRatio")] + public decimal SellLimitPriceRatio { get; set; } + /// + /// ["feeRateUpRatio"] Fee rate up ratio + /// + [JsonPropertyName("feeRateUpRatio")] + public decimal FeeRateUpRatio { get; set; } + /// + /// ["makerFeeRate"] Maker fee rate + /// + [JsonPropertyName("makerFeeRate")] + public decimal MakerFeeRate { get; set; } + /// + /// ["takerFeeRate"] Taker fee rate + /// + [JsonPropertyName("takerFeeRate")] + public decimal TakerFeeRate { get; set; } + /// + /// ["openCostUpRatio"] Open cost up ratio + /// + [JsonPropertyName("openCostUpRatio")] + public decimal OpenCostUpRatio { get; set; } + /// + /// ["minOrderQty"] Min order quantity + /// + [JsonPropertyName("minOrderQty")] + public decimal MinOrderQuantity { get; set; } + /// + /// ["maxOrderQty"] Max order quantity + /// + [JsonPropertyName("maxOrderQty")] + public decimal MaxOrderQuantity { get; set; } + /// + /// ["pricePrecision"] Price precision + /// + [JsonPropertyName("pricePrecision")] + public int PricePrecision { get; set; } + /// + /// ["quantityPrecision"] Quantity precision + /// + [JsonPropertyName("quantityPrecision")] + public int QuantityPrecision { get; set; } + /// + /// ["quotePrecision"] Quote precision + /// + [JsonPropertyName("quotePrecision")] + public int? QuotePrecision { get; set; } + /// + /// ["priceMultiplier"] Price multiplier + /// + [JsonPropertyName("priceMultiplier")] + public decimal PriceMultiplier { get; set; } + /// + /// ["quantityMultiplier"] Quantity multiplier + /// + [JsonPropertyName("quantityMultiplier")] + public decimal QuantityMultiplier { get; set; } + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public ContractType Type { get; set; } + /// + /// ["minOrderAmount"] Min order value + /// + [JsonPropertyName("minOrderAmount")] + public decimal MinOrderValue { get; set; } + /// + /// ["maxSymbolOrderNum"] Max symbol orders + /// + [JsonPropertyName("maxSymbolOrderNum")] + public int? MaxSymbolOrders { get; set; } + /// + /// ["maxProductOrderNum"] Max product orders + /// + [JsonPropertyName("maxProductOrderNum")] + public int? MaxProductOrders { get; set; } + /// + /// ["maxPositionNum"] Max positions + /// + [JsonPropertyName("maxPositionNum")] + public int? MaxPositions { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public InstrumentStatus Status { get; set; } + /// + /// ["offTime"] Trading halt time + /// + [JsonPropertyName("offTime")] + public DateTime? OfflineTime { get; set; } + /// + /// ["limitOpenTime"] Restricted open time + /// + [JsonPropertyName("limitOpenTime")] + public DateTime? LimitOpenTime { get; set; } + /// + /// ["deliveryTime"] Delivery time + /// + [JsonPropertyName("deliveryTime")] + public DateTime? DeliveryTime { get; set; } + /// + /// ["deliveryStartTime"] Delivery start time + /// + [JsonPropertyName("deliveryStartTime")] + public DateTime? DeliveryStartTime { get; set; } + /// + /// ["deliveryPeriod"] Delivery period + /// + [JsonPropertyName("deliveryPeriod")] + public DeliveryPeriod? DeliveryPeriod { get; set; } + /// + /// ["launchTime"] Launch time + /// + [JsonPropertyName("launchTime")] + public DateTime? LaunchTime { get; set; } + /// + /// ["fundInterval"] Fund interval + /// + [JsonPropertyName("fundInterval")] + public int FundInterval { get; set; } + /// + /// ["minLeverage"] Min leverage + /// + [JsonPropertyName("minLeverage")] + public decimal MinLeverage { get; set; } + /// + /// ["maxLeverage"] Max leverage + /// + [JsonPropertyName("maxLeverage")] + public decimal MaxLeverage { get; set; } + /// + /// ["maintainTime"] Maintenance time + /// + [JsonPropertyName("maintainTime")] + public DateTime MaintainTime { get; set; } + /// + /// ["symbolType"] Symbol type + /// + [JsonPropertyName("symbolType")] + public SymbolType SymbolType { get; set; } + /// + /// ["maxMarketOrderQty"] Max market order quantity + /// + [JsonPropertyName("maxMarketOrderQty")] + public decimal MaxMarketOrderQuantity { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesTicker.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesTicker.cs new file mode 100644 index 00000000..f559aa51 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaFuturesTicker.cs @@ -0,0 +1,119 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaFuturesTicker +{ + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } + /// + /// ["lastPrice"] Last price + /// + [JsonPropertyName("lastPrice")] + public decimal LastPrice { get; set; } + /// + /// ["openPrice24h"] Open price 24h + /// + [JsonPropertyName("openPrice24h")] + public decimal OpenPrice { get; set; } + /// + /// ["highPrice24h"] High price 24h + /// + [JsonPropertyName("highPrice24h")] + public decimal HighPrice { get; set; } + /// + /// ["lowPrice24h"] Low price 24h + /// + [JsonPropertyName("lowPrice24h")] + public decimal LowPrice { get; set; } + /// + /// ["ask1Price"] Best ask price + /// + [JsonPropertyName("ask1Price")] + public decimal BestAskPrice { get; set; } + /// + /// ["bid1Price"] Best bid price + /// + [JsonPropertyName("bid1Price")] + public decimal BestBidPrice { get; set; } + /// + /// ["bid1Size"] Best bid quantity + /// + [JsonPropertyName("bid1Size")] + public decimal BestBidQuantity { get; set; } + /// + /// ["ask1Size"] Best ask quantity + /// + [JsonPropertyName("ask1Size")] + public decimal BestAskQuantity { get; set; } + /// + /// ["price24hPcnt"] Price change percentage 24h + /// + [JsonPropertyName("price24hPcnt")] + public decimal PriceChangePercentage { get; set; } + /// + /// ["volume24h"] Volume 24h + /// + [JsonPropertyName("volume24h")] + public decimal Volume { get; set; } + /// + /// ["turnover24h"] Turnover 24h + /// + [JsonPropertyName("turnover24h")] + public decimal Turnover { get; set; } + /// + /// ["indexPrice"] Index price + /// + [JsonPropertyName("indexPrice")] + public decimal IndexPrice { get; set; } + /// + /// ["markPrice"] Mark price + /// + [JsonPropertyName("markPrice")] + public decimal MarkPrice { get; set; } + /// + /// ["fundingRate"] Funding rate + /// + [JsonPropertyName("fundingRate")] + public decimal? FundingRate { get; set; } + /// + /// ["openInterest"] Open interest + /// + [JsonPropertyName("openInterest")] + public decimal OpenInterest { get; set; } + /// + /// ["deliveryStartTime"] Delivery start time + /// + [JsonPropertyName("deliveryStartTime")] + public DateTime? DeliveryStartTime { get; set; } + /// + /// ["deliveryTime"] Delivery time + /// + [JsonPropertyName("deliveryTime")] + public DateTime? DeliveryTime { get; set; } + /// + /// ["deliveryStatus"] Delivery status + /// + [JsonPropertyName("deliveryStatus")] + public DeliveryStatus? DeliveryStatus { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaIndexComponents.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaIndexComponents.cs new file mode 100644 index 00000000..6147ba01 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaIndexComponents.cs @@ -0,0 +1,50 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Index components +/// +public record BitgetUaIndexComponents +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["componentList"] Components + /// + [JsonPropertyName("componentList")] + public BitgetUaIndexComponent[] Components { get; set; } = []; +} + +/// +/// Index component +/// +public record BitgetUaIndexComponent +{ + /// + /// ["exchange"] Exchange + /// + [JsonPropertyName("exchange")] + public string Exchange { get; set; } = string.Empty; + /// + /// ["spotPair"] Spot pair + /// + [JsonPropertyName("spotPair")] + public string SpotPair { get; set; } = string.Empty; + /// + /// ["equivalentPrice"] Equivalent price + /// + [JsonPropertyName("equivalentPrice")] + public decimal EquivalentPrice { get; set; } + /// + /// ["weight"] Weight + /// + [JsonPropertyName("weight")] + public decimal Weight { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaKline.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaKline.cs new file mode 100644 index 00000000..0b4f05be --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaKline.cs @@ -0,0 +1,51 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using CryptoExchange.Net.Converters; +using CryptoExchange.Net.Converters.SystemTextJson; + +namespace Bitget.Net.Objects.Models; + +/// +/// Kline/candlestick +/// +[JsonConverter(typeof(ArrayConverter))] +public record BitgetUaKline +{ + /// + /// Open timestamp + /// + [ArrayProperty(0), JsonConverter(typeof(DateTimeConverter))] + public DateTime OpenTime { get; set; } + /// + /// Open price + /// + [ArrayProperty(1)] + public decimal OpenPrice { get; set; } + /// + /// Highest price + /// + [ArrayProperty(2)] + public decimal HighPrice { get; set; } + /// + /// Lowest price + /// + [ArrayProperty(3)] + public decimal LowPrice { get; set; } + /// + /// Close price + /// + [ArrayProperty(4)] + public decimal ClosePrice { get; set; } + /// + /// Volume in base asset + /// + [ArrayProperty(5)] + public decimal Volume { get; set; } + /// + /// Volume in quote asset + /// + [ArrayProperty(6)] + public decimal QuoteVolume { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaKlineUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaKlineUpdate.cs new file mode 100644 index 00000000..e3380661 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaKlineUpdate.cs @@ -0,0 +1,50 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using CryptoExchange.Net.Converters; +using CryptoExchange.Net.Converters.SystemTextJson; + +namespace Bitget.Net.Objects.Models; + +/// +/// Kline/candlestick +/// +public record BitgetUaKlineUpdate +{ + /// + /// Open timestamp + /// + [JsonPropertyName("start")] + public DateTime OpenTime { get; set; } + /// + /// Open price + /// + [JsonPropertyName("open")] + public decimal OpenPrice { get; set; } + /// + /// Highest price + /// + [JsonPropertyName("high")] + public decimal HighPrice { get; set; } + /// + /// Lowest price + /// + [JsonPropertyName("low")] + public decimal LowPrice { get; set; } + /// + /// Close price + /// + [JsonPropertyName("close")] + public decimal ClosePrice { get; set; } + /// + /// Volume in base asset + /// + [JsonPropertyName("volume")] + public decimal Volume { get; set; } + /// + /// Volume in quote asset + /// + [JsonPropertyName("turnover")] + public decimal QuoteVolume { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaLiquidationUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaLiquidationUpdate.cs new file mode 100644 index 00000000..bb5ec0ae --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaLiquidationUpdate.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Liquidation update +/// +public record BitgetUaLiquidationUpdate +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["price"] Price + /// + [JsonPropertyName("price")] + public decimal Price { get; set; } + /// + /// ["amount"] Quantity + /// + [JsonPropertyName("amount")] + public decimal Quantity { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaLoanInterestRate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaLoanInterestRate.cs new file mode 100644 index 00000000..bdffec8a --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaLoanInterestRate.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Interest rate +/// +public record BitgetUaLoanInterestRate +{ + /// + /// ["dailyInterest"] Daily interest + /// + [JsonPropertyName("dailyInterest")] + public decimal DailyInterest { get; set; } + /// + /// ["annualInterest"] Annual interest + /// + [JsonPropertyName("annualInterest")] + public decimal AnnualInterest { get; set; } + /// + /// ["limit"] Limit + /// + [JsonPropertyName("limit")] + public decimal Limit { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaMarginSymbol.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaMarginSymbol.cs new file mode 100644 index 00000000..1905bfe4 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaMarginSymbol.cs @@ -0,0 +1,153 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaMarginSymbol +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["baseCoin"] Base asset + /// + [JsonPropertyName("baseCoin")] + public string BaseAsset { get; set; } = string.Empty; + /// + /// ["quoteCoin"] Quote asset + /// + [JsonPropertyName("quoteCoin")] + public string QuoteAsset { get; set; } = string.Empty; + /// + /// ["buyLimitPriceRatio"] Buy limit price ratio + /// + [JsonPropertyName("buyLimitPriceRatio")] + public decimal BuyLimitPriceRatio { get; set; } + /// + /// ["sellLimitPriceRatio"] Sell limit price ratio + /// + [JsonPropertyName("sellLimitPriceRatio")] + public decimal SellLimitPriceRatio { get; set; } + /// + /// ["minOrderQty"] Min order quantity + /// + [JsonPropertyName("minOrderQty")] + public decimal MinOrderQuantity { get; set; } + /// + /// ["maxOrderQty"] Max order quantity + /// + [JsonPropertyName("maxOrderQty")] + public decimal MaxOrderQuantity { get; set; } + /// + /// ["pricePrecision"] Price precision + /// + [JsonPropertyName("pricePrecision")] + public int PricePrecision { get; set; } + /// + /// ["quantityPrecision"] Quantity precision + /// + [JsonPropertyName("quantityPrecision")] + public int QuantityPrecision { get; set; } + /// + /// ["quotePrecision"] Quote precision + /// + [JsonPropertyName("quotePrecision")] + public int QuotePrecision { get; set; } + /// + /// ["minOrderAmount"] Min order value + /// + [JsonPropertyName("minOrderAmount")] + public decimal MinOrderValue { get; set; } + /// + /// ["maxSymbolOrderNum"] Max symbol orders + /// + [JsonPropertyName("maxSymbolOrderNum")] + public int? MaxSymbolOrders { get; set; } + /// + /// ["maxProductOrderNum"] Max product orders + /// + [JsonPropertyName("maxProductOrderNum")] + public int? MaxProductOrders { get; set; } + /// + /// ["maxPositionNum"] Max positions + /// + [JsonPropertyName("maxPositionNum")] + public int MaxPositionNum { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public InstrumentStatus Status { get; set; } + /// + /// ["maintainTime"] Maintenance time + /// + [JsonPropertyName("maintainTime")] + public DateTime? MaintainTime { get; set; } + /// + /// ["isIsolatedBaseBorrowable"] Is isolated base borrowable + /// + [JsonPropertyName("isIsolatedBaseBorrowable")] + public bool IsIsolatedBaseBorrowable { get; set; } + /// + /// ["isIsolatedQuotedBorrowable"] Is isolated quoted borrowable + /// + [JsonPropertyName("isIsolatedQuotedBorrowable")] + public bool IsIsolatedQuotedBorrowable { get; set; } + /// + /// ["warningRiskRatio"] Warning risk ratio + /// + [JsonPropertyName("warningRiskRatio")] + public decimal WarningRiskRatio { get; set; } + /// + /// ["liquidationRiskRatio"] Liquidation risk ratio + /// + [JsonPropertyName("liquidationRiskRatio")] + public decimal LiquidationRiskRatio { get; set; } + /// + /// ["maxCrossedLeverage"] Max crossed leverage + /// + [JsonPropertyName("maxCrossedLeverage")] + public decimal MaxCrossedLeverage { get; set; } + /// + /// ["maxIsolatedLeverage"] Max isolated leverage + /// + [JsonPropertyName("maxIsolatedLeverage")] + public decimal MaxIsolatedLeverage { get; set; } + /// + /// ["userMinBorrow"] User min borrow + /// + [JsonPropertyName("userMinBorrow")] + public decimal UserMinBorrow { get; set; } + /// + /// ["areaSymbol"] Area symbol + /// + [JsonPropertyName("areaSymbol")] + public bool AreaSymbol { get; set; } + /// + /// ["maxLeverage"] Max leverage + /// + [JsonPropertyName("maxLeverage")] + public decimal MaxLeverage { get; set; } + /// + /// ["symbolType"] Symbol type + /// + [JsonPropertyName("symbolType")] + public SymbolType SymbolType { get; set; } + /// + /// ["launchTime"] Launch time + /// + [JsonPropertyName("launchTime")] + public DateTime? LaunchTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaMaxOpenAvailable.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaMaxOpenAvailable.cs new file mode 100644 index 00000000..6466a65d --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaMaxOpenAvailable.cs @@ -0,0 +1,53 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Max open available info +/// +public record BitgetUaMaxOpenAvailable +{ + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["maxOpen"] Max open + /// + [JsonPropertyName("maxOpen")] + public decimal? MaxOpen { get; set; } + /// + /// ["buyOpenCost"] Buy open cost + /// + [JsonPropertyName("buyOpenCost")] + public decimal? BuyOpenCost { get; set; } + /// + /// ["sellOpenCost"] Sell open cost + /// + [JsonPropertyName("sellOpenCost")] + public decimal? SellOpenCost { get; set; } + /// + /// ["maxBuyOpen"] Max buy open + /// + [JsonPropertyName("maxBuyOpen")] + public decimal? MaxBuyOpen { get; set; } + /// + /// ["maxSellOpen"] Max sell open + /// + [JsonPropertyName("maxSellOpen")] + public decimal? MaxSellOpen { get; set; } + /// + /// ["maxBuyAvailable"] Max buy available + /// + [JsonPropertyName("maxBuyAvailable")] + public decimal? MaxBuyAvailable { get; set; } + /// + /// ["maxSellAvailable"] Max sell available + /// + [JsonPropertyName("maxSellAvailable")] + public decimal? MaxSellAvailable { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaMaxTransferable.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaMaxTransferable.cs new file mode 100644 index 00000000..4da12443 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaMaxTransferable.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Max transferable quantity for an asset +/// +public record BitgetUaMaxTransferable +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["maxTransfer"] Max transfer + /// + [JsonPropertyName("maxTransfer")] + public decimal MaxTransfer { get; set; } + /// + /// ["borrowMaxTransfer"] Borrow max transfer + /// + [JsonPropertyName("borrowMaxTransfer")] + public decimal BorrowMaxTransfer { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterest.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterest.cs new file mode 100644 index 00000000..7030c66a --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterest.cs @@ -0,0 +1,40 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Open interest symbol list +/// +public record BitgetUaOpenInterest +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaOpenInterestSymbol[] List { get; set; } = []; + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } +} + +/// +/// Open interest +/// +public record BitgetUaOpenInterestSymbol +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["openInterest"] Open interest + /// + [JsonPropertyName("openInterest")] + public decimal OpenInterest { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterestLimit.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterestLimit.cs new file mode 100644 index 00000000..7f84341b --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaOpenInterestLimit.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Open interest limit +/// +public record BitgetUaOpenInterestLimit +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["notionalValue"] Notional value + /// + [JsonPropertyName("notionalValue")] + public decimal NotionalValue { get; set; } + /// + /// ["totalNotionalValue"] Total notional value + /// + [JsonPropertyName("totalNotionalValue")] + public decimal TotalNotionalValue { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaOrder.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaOrder.cs new file mode 100644 index 00000000..1504bc4b --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaOrder.cs @@ -0,0 +1,239 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Orders +/// +public record BitgetUaOrders +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaOrder[] List { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } +} + +/// +/// Order info +/// +public record BitgetUaOrder +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["orderType"] Order type + /// + [JsonPropertyName("orderType")] + public OrderType OrderType { get; set; } + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["price"] Price + /// + [JsonPropertyName("price")] + public decimal? Price { get; set; } + /// + /// ["qty"] Quantity + /// + [JsonPropertyName("qty")] + public decimal Quantity { get; set; } + /// + /// ["amount"] Quote quantity + /// + [JsonPropertyName("amount")] + public decimal QuoteQuantity { get; set; } + /// + /// ["cumExecQty"] Quantity executed + /// + [JsonPropertyName("cumExecQty")] + public decimal QuantityFilled { get; set; } + /// + /// ["cumExecValue"] Quote quantity filled + /// + [JsonPropertyName("cumExecValue")] + public decimal QuoteQuantityFilled { get; set; } + /// + /// ["avgPrice"] Average price + /// + [JsonPropertyName("avgPrice")] + public decimal? AveragePrice { get; set; } + /// + /// ["timeInForce"] Time in force + /// + [JsonPropertyName("timeInForce")] + public TimeInForce TimeInForce { get; set; } + /// + /// ["orderStatus"] Order status + /// + [JsonPropertyName("orderStatus")] + public OrderStatus Status { get; set; } + /// + /// ["posSide"] Position side + /// + [JsonPropertyName("posSide")] + public PositionSide? PositionSide { get; set; } + [JsonInclude, JsonPropertyName("holdSide")] + internal PositionSide? HoldSide + { + set => PositionSide = value; + } + + /// + /// ["holdMode"] Hold mode + /// + [JsonPropertyName("holdMode")] + public HoldingMode? HoldMode { get; set; } + /// + /// ["tradeSide"] Trade side + /// + [JsonPropertyName("tradeSide")] + public TradeSide? TradeSide { get; set; } + /// + /// ["reduceOnly"] Reduce only + /// + [JsonPropertyName("reduceOnly")] + public bool ReduceOnly { get; set; } + /// + /// ["marginMode"] Margin mode + /// + [JsonPropertyName("marginMode")] + public MarginMode MarginMode { get; set; } + /// + /// ["marginCoin"] Margin asset + /// + [JsonPropertyName("marginCoin")] + public string? MarginAsset { get; set; } + /// + /// ["totalProfit"] Total profit + /// + [JsonPropertyName("totalProfit")] + public decimal? TotalProfit { get; set; } + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal? Leverage { get; set; } + /// + /// ["stpMode"] Stp mode + /// + [JsonPropertyName("stpMode")] + public StpMode StpMode { get; set; } + /// + /// ["takeProfit"] Take profit + /// + [JsonPropertyName("takeProfit")] + public decimal? TakeProfit { get; set; } + /// + /// ["stopLoss"] Stop loss + /// + [JsonPropertyName("stopLoss")] + public decimal? StopLoss { get; set; } + /// + /// ["tpTriggerBy"] Take profit trigger by + /// + [JsonPropertyName("tpTriggerBy")] + public TriggerPriceType? TpTriggerBy { get; set; } + /// + /// ["slTriggerBy"] Stop loss trigger by + /// + [JsonPropertyName("slTriggerBy")] + public TriggerPriceType? SlTriggerBy { get; set; } + /// + /// ["tpOrderType"] Take profit order type + /// + [JsonPropertyName("tpOrderType")] + public OrderType? TpOrderType { get; set; } + /// + /// ["slOrderType"] Stop loss order type + /// + [JsonPropertyName("slOrderType")] + public OrderType? SlOrderType { get; set; } + /// + /// ["tpLimitPrice"] Take profit limit price + /// + [JsonPropertyName("tpLimitPrice")] + public decimal? TpLimitPrice { get; set; } + /// + /// ["slLimitPrice"] Stop loss limit price + /// + [JsonPropertyName("slLimitPrice")] + public decimal? SlLimitPrice { get; set; } + /// + /// ["feeDetail"] Fee detail + /// + [JsonPropertyName("feeDetail")] + public BitgetUaOrderFee[] FeeDetail { get; set; } = []; + /// + /// ["cancelReason"] Cancel reason + /// + [JsonPropertyName("cancelReason")] + public string? CancelReason { get; set; } + /// + /// ["delegateType"] Delegate type + /// + [JsonPropertyName("delegateType")] + public string? DelegateType { get; set; } + /// + /// ["execType"] Exec type + /// + [JsonPropertyName("execType")] + public ExecutionType? ExecType { get; set; } + /// + /// ["createdTime"] Created time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Updated time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + +/// +/// Fee info +/// +public record BitgetUaOrderFee +{ + /// + /// ["feeCoin"] Fee asset + /// + [JsonPropertyName("feeCoin")] + public string FeeAsset { get; set; } = string.Empty; + /// + /// ["fee"] Fee + /// + [JsonPropertyName("fee")] + public decimal? Fee { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaOrderBook.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaOrderBook.cs new file mode 100644 index 00000000..d638a96c --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaOrderBook.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Objects.Models.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Order book snapshot +/// +public record BitgetUaOrderBook +{ + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } + + /// + /// ["a"] Asks + /// + [JsonPropertyName("a")] + public BitgetOrderBookEntry[] Asks { get; set; } = []; + /// + /// ["b"] Bids + /// + [JsonPropertyName("b")] + public BitgetOrderBookEntry[] Bids { get; set; } = []; +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaOrderResult.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaOrderResult.cs new file mode 100644 index 00000000..365b0539 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaOrderResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Order result +/// +public record BitgetUaOrderResult +{ + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaPaymentAssets.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaPaymentAssets.cs new file mode 100644 index 00000000..7c46013d --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaPaymentAssets.cs @@ -0,0 +1,45 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Payment assets +/// +public record BitgetUaPaymentAssets +{ + /// + /// ["paymentCoinList"] Payment assets + /// + [JsonPropertyName("paymentCoinList")] + public BitgetUaPaymentAsset[] PaymentAssets { get; set; } = []; + /// + /// ["maxSelection"] Max selection + /// + [JsonPropertyName("maxSelection")] + public int MaxSelection { get; set; } +} + +/// +/// Payment asset +/// +public record BitgetUaPaymentAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["amount"] USD value + /// + [JsonPropertyName("amount")] + public decimal UsdValue { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaPosition.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaPosition.cs new file mode 100644 index 00000000..0d1281a3 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaPosition.cs @@ -0,0 +1,149 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +internal record BitgetUaPositionWrapper +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaPosition[] List { get; set; } = []; +} + +/// +/// Position info +/// +public record BitgetUaPosition +{ + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["marginCoin"] Margin asset + /// + [JsonPropertyName("marginCoin")] + public string MarginAsset { get; set; } = string.Empty; + /// + /// ["holdMode"] Hold mode + /// + [JsonPropertyName("holdMode")] + public HoldingMode HoldMode { get; set; } + /// + /// ["posSide"] Position side + /// + [JsonPropertyName("posSide")] + public PositionSide? PositionSide { get; set; } + /// + /// ["marginMode"] Margin mode + /// + [JsonPropertyName("marginMode")] + public MarginMode MarginMode { get; set; } + /// + /// ["positionBalance"] Position balance + /// + [JsonPropertyName("positionBalance")] + public decimal PositionBalance { get; set; } + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["frozen"] Frozen + /// + [JsonPropertyName("frozen")] + public decimal Frozen { get; set; } + /// + /// ["total"] Total + /// + [JsonPropertyName("total")] + public decimal Total { get; set; } + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal Leverage { get; set; } + /// + /// ["curRealisedPnl"] Realized profit and loss + /// + [JsonPropertyName("curRealisedPnl")] + public decimal RealisedPnl { get; set; } + /// + /// ["avgPrice"] Average entry price + /// + [JsonPropertyName("avgPrice")] + public decimal AveragePrice { get; set; } + /// + /// ["positionStatus"] Position status + /// + [JsonPropertyName("positionStatus")] + public string PositionStatus { get; set; } = string.Empty; + /// + /// ["unrealisedPnl"] Unrealised profit and loss + /// + [JsonPropertyName("unrealisedPnl")] + public decimal UnrealisedPnl { get; set; } + /// + /// ["liquidationPrice"] Liquidation price + /// + [JsonPropertyName("liquidationPrice")] + public decimal LiquidationPrice { get; set; } + /// + /// ["mmr"] Mmr + /// + [JsonPropertyName("mmr")] + public decimal Mmr { get; set; } + /// + /// ["profitRate"] Profit rate + /// + [JsonPropertyName("profitRate")] + public decimal ProfitRate { get; set; } + /// + /// ["markPrice"] Mark price + /// + [JsonPropertyName("markPrice")] + public decimal MarkPrice { get; set; } + /// + /// ["breakEvenPrice"] Break even price + /// + [JsonPropertyName("breakEvenPrice")] + public decimal BreakEvenPrice { get; set; } + /// + /// ["totalFunding"] Total funding + /// + [JsonPropertyName("totalFunding")] + public decimal TotalFunding { get; set; } + /// + /// ["openFeeTotal"] Open fee total + /// + [JsonPropertyName("openFeeTotal")] + public decimal OpenFeeTotal { get; set; } + /// + /// ["closeFeeTotal"] Close fee total + /// + [JsonPropertyName("closeFeeTotal")] + public decimal CloseFeeTotal { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaPositionHistory.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionHistory.cs new file mode 100644 index 00000000..73b9e6d9 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionHistory.cs @@ -0,0 +1,122 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Position history +/// +public record BitgetUaPositionHistory +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaPositionHistoryEntry[] List { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; +} + +/// +/// Position history entry +/// +public record BitgetUaPositionHistoryEntry +{ + /// + /// ["positionId"] Position id + /// + [JsonPropertyName("positionId")] + public string PositionId { get; set; } = string.Empty; + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["marginCoin"] Margin asset + /// + [JsonPropertyName("marginCoin")] + public string MarginAsset { get; set; } = string.Empty; + /// + /// ["holdMode"] Hold mode + /// + [JsonPropertyName("holdMode")] + public HoldingMode HoldMode { get; set; } + /// + /// ["posSide"] Pos side + /// + [JsonPropertyName("posSide")] + public PositionSide? PosSide { get; set; } + /// + /// ["marginMode"] Margin mode + /// + [JsonPropertyName("marginMode")] + public MarginMode MarginMode { get; set; } + /// + /// ["openPriceAvg"] Open price average + /// + [JsonPropertyName("openPriceAvg")] + public decimal OpenPriceAverage { get; set; } + /// + /// ["closePriceAvg"] Close price average + /// + [JsonPropertyName("closePriceAvg")] + public decimal ClosePriceAverage { get; set; } + /// + /// ["openTotalPos"] Open total pos + /// + [JsonPropertyName("openTotalPos")] + public decimal OpenTotalPos { get; set; } + /// + /// ["closeTotalPos"] Close total pos + /// + [JsonPropertyName("closeTotalPos")] + public decimal CloseTotalPos { get; set; } + /// + /// ["cumRealisedPnl"] Realised pnl + /// + [JsonPropertyName("cumRealisedPnl")] + public decimal RealisedPnl { get; set; } + /// + /// ["netProfit"] Net profit + /// + [JsonPropertyName("netProfit")] + public decimal NetProfit { get; set; } + /// + /// ["totalFunding"] Total funding + /// + [JsonPropertyName("totalFunding")] + public decimal TotalFunding { get; set; } + /// + /// ["openFeeTotal"] Open fee total + /// + [JsonPropertyName("openFeeTotal")] + public decimal OpenFeeTotal { get; set; } + /// + /// ["closeFeeTotal"] Close fee total + /// + [JsonPropertyName("closeFeeTotal")] + public decimal CloseFeeTotal { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaPositionTier.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionTier.cs new file mode 100644 index 00000000..49f48b2f --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionTier.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Position tier +/// +public record BitgetUaPositionTier +{ + /// + /// ["tier"] Tier + /// + [JsonPropertyName("tier")] + public int Tier { get; set; } + /// + /// ["minTierValue"] Min tier value + /// + [JsonPropertyName("minTierValue")] + public decimal MinTierValue { get; set; } + /// + /// ["maxTierValue"] Max tier value + /// + [JsonPropertyName("maxTierValue")] + public decimal MaxTierValue { get; set; } + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal Leverage { get; set; } + /// + /// ["mmr"] Maintenance margin ratio + /// + [JsonPropertyName("mmr")] + public decimal Mmr { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaPositionUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionUpdate.cs new file mode 100644 index 00000000..a9a5bc2c --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaPositionUpdate.cs @@ -0,0 +1,134 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaPositionUpdate +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["leverage"] Leverage + /// + [JsonPropertyName("leverage")] + public decimal Leverage { get; set; } + /// + /// ["openFeeTotal"] Open fee total + /// + [JsonPropertyName("openFeeTotal")] + public decimal? OpenFeeTotal { get; set; } + /// + /// ["mmr"] Maintenance margin rate + /// + [JsonPropertyName("mmr")] + public decimal? Mmr { get; set; } + /// + /// ["breakEvenPrice"] Break even price + /// + [JsonPropertyName("breakEvenPrice")] + public decimal? BreakEvenPrice { get; set; } + /// + /// ["available"] Available + /// + [JsonPropertyName("available")] + public decimal Available { get; set; } + /// + /// ["liqPrice"] Liquidation price + /// + [JsonPropertyName("liqPrice")] + public decimal? LiquidationPrice { get; set; } + /// + /// ["marginMode"] Margin mode + /// + [JsonPropertyName("marginMode")] + public MarginMode MarginMode { get; set; } + /// + /// ["unrealisedPnl"] Unrealised profit and loss + /// + [JsonPropertyName("unrealisedPnl")] + public decimal UnrealisedPnl { get; set; } + /// + /// ["markPrice"] Mark price + /// + [JsonPropertyName("markPrice")] + public decimal MarkPrice { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["avgPrice"] Average entry price + /// + [JsonPropertyName("avgPrice")] + public decimal AveragePrice { get; set; } + /// + /// ["totalFundingFee"] Total funding fee + /// + [JsonPropertyName("totalFundingFee")] + public decimal TotalFundingFee { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } + /// + /// ["marginCoin"] Margin asset + /// + [JsonPropertyName("marginCoin")] + public string MarginAsset { get; set; } = string.Empty; + /// + /// ["frozen"] Frozen + /// + [JsonPropertyName("frozen")] + public decimal Frozen { get; set; } + /// + /// ["profitRate"] Profit rate + /// + [JsonPropertyName("profitRate")] + public decimal? ProfitRate { get; set; } + /// + /// ["closeFeeTotal"] Close fee total + /// + [JsonPropertyName("closeFeeTotal")] + public decimal? CloseFeeTotal { get; set; } + /// + /// ["marginSize"] Margin quantity + /// + [JsonPropertyName("marginSize")] + public decimal MarginQuantity { get; set; } + /// + /// ["curRealisedPnl"] Realised profit and loss + /// + [JsonPropertyName("curRealisedPnl")] + public decimal RealisedPnl { get; set; } + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["positionStatus"] Position status + /// + [JsonPropertyName("positionStatus")] + public string PositionStatus { get; set; } = string.Empty; + /// + /// ["posSide"] Position side + /// + [JsonPropertyName("posSide")] + public PositionSide? PositionSide { get; set; } + /// + /// ["holdMode"] Hold mode + /// + [JsonPropertyName("holdMode")] + public HoldingMode HoldMode { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaProofOfReserves.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaProofOfReserves.cs new file mode 100644 index 00000000..a6cf36d1 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaProofOfReserves.cs @@ -0,0 +1,55 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Proof of reserves +/// +public record BitgetUaProofOfReserves +{ + /// + /// ["merkleRootHash"] Merkle root hash + /// + [JsonPropertyName("merkleRootHash")] + public string MerkleRootHash { get; set; } = string.Empty; + /// + /// ["totalReserveRatio"] Total reserve ratio + /// + [JsonPropertyName("totalReserveRatio")] + public string TotalReserveRatio { get; set; } = string.Empty; + /// + /// ["list"] Assets + /// + [JsonPropertyName("list")] + public BitgetUaProofOfReservesAsset[] Assets { get; set; } = []; +} + +/// +/// Asset info +/// +public record BitgetUaProofOfReservesAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["userAssets"] User assets + /// + [JsonPropertyName("userAssets")] + public decimal UserAssets { get; set; } + /// + /// ["platformAssets"] Platform assets + /// + [JsonPropertyName("platformAssets")] + public decimal PlatformAssets { get; set; } + /// + /// ["reserveRatio"] Reserve ratio + /// + [JsonPropertyName("reserveRatio")] + public string ReserveRatio { get; set; } = string.Empty; +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaRepayResult.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaRepayResult.cs new file mode 100644 index 00000000..a2e8a3d5 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaRepayResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Repayment result +/// +public record BitgetUaRepayResult +{ + /// + /// ["result"] Result success + /// + [JsonPropertyName("result")] + public bool Result { get; set; } + /// + /// ["repayAmount"] Repay quantity + /// + [JsonPropertyName("repayAmount")] + public decimal RepayQuantity { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaRepayableAssets.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaRepayableAssets.cs new file mode 100644 index 00000000..f0a59b83 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaRepayableAssets.cs @@ -0,0 +1,45 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Repayable assets +/// +public record BitgetUaRepayableAssets +{ + /// + /// ["repayableCoinList"] Assets + /// + [JsonPropertyName("repayableCoinList")] + public BitgetUaRepayableAsset[] Assets { get; set; } = []; + /// + /// ["maxSelection"] Max selection + /// + [JsonPropertyName("maxSelection")] + public int MaxSelection { get; set; } +} + +/// +/// Asset +/// +public record BitgetUaRepayableAsset +{ + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["amount"] Usd value + /// + [JsonPropertyName("amount")] + public decimal UsdValue { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaSpotSymbol.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaSpotSymbol.cs new file mode 100644 index 00000000..cea9f9b8 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaSpotSymbol.cs @@ -0,0 +1,113 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaSpotSymbol +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["baseCoin"] Base asset + /// + [JsonPropertyName("baseCoin")] + public string BaseAsset { get; set; } = string.Empty; + /// + /// ["quoteCoin"] Quote asset + /// + [JsonPropertyName("quoteCoin")] + public string QuoteAsset { get; set; } = string.Empty; + /// + /// ["buyLimitPriceRatio"] Buy limit price ratio + /// + [JsonPropertyName("buyLimitPriceRatio")] + public decimal BuyLimitPriceRatio { get; set; } + /// + /// ["sellLimitPriceRatio"] Sell limit price ratio + /// + [JsonPropertyName("sellLimitPriceRatio")] + public decimal SellLimitPriceRatio { get; set; } + /// + /// ["minOrderQty"] Min order quantity + /// + [JsonPropertyName("minOrderQty")] + public decimal MinOrderQuantity { get; set; } + /// + /// ["maxOrderQty"] Max order quantity + /// + [JsonPropertyName("maxOrderQty")] + public decimal MaxOrderQuantity { get; set; } + /// + /// ["pricePrecision"] Price precision + /// + [JsonPropertyName("pricePrecision")] + public int PricePrecision { get; set; } + /// + /// ["quantityPrecision"] Quantity precision + /// + [JsonPropertyName("quantityPrecision")] + public int QuantityPrecision { get; set; } + /// + /// ["quotePrecision"] Quote precision + /// + [JsonPropertyName("quotePrecision")] + public int QuotePrecision { get; set; } + /// + /// ["minOrderAmount"] Min order value + /// + [JsonPropertyName("minOrderAmount")] + public decimal MinOrderValue { get; set; } + /// + /// ["maxSymbolOrderNum"] Max symbol orders + /// + [JsonPropertyName("maxSymbolOrderNum")] + public int? MaxSymbolOrders { get; set; } + /// + /// ["maxProductOrderNum"] Max product orders + /// + [JsonPropertyName("maxProductOrderNum")] + public int? MaxProductOrders { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public InstrumentStatus Status { get; set; } + /// + /// ["maintainTime"] Maintenance time + /// + [JsonPropertyName("maintainTime")] + public DateTime? MaintainTime { get; set; } + /// + /// ["maxPositionNum"] Max positions + /// + [JsonPropertyName("maxPositionNum")] + public int? MaxPositions { get; set; } + /// + /// ["symbolType"] Symbol type + /// + [JsonPropertyName("symbolType")] + public SymbolType SymbolType { get; set; } + /// + /// ["launchTime"] Launch time + /// + [JsonPropertyName("launchTime")] + public DateTime? LaunchTime { get; set; } + /// + /// ["areaSymbol"] Is area restricted + /// + [JsonPropertyName("areaSymbol")] + public bool? AreaSymbol { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaSpotTicker.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaSpotTicker.cs new file mode 100644 index 00000000..1d37eebe --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaSpotTicker.cs @@ -0,0 +1,83 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaSpotTicker +{ + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } + /// + /// ["lastPrice"] Last price + /// + [JsonPropertyName("lastPrice")] + public decimal LastPrice { get; set; } + /// + /// ["openPrice24h"] Open price 24h + /// + [JsonPropertyName("openPrice24h")] + public decimal OpenPrice { get; set; } + /// + /// ["highPrice24h"] High price 24h + /// + [JsonPropertyName("highPrice24h")] + public decimal HighPrice { get; set; } + /// + /// ["lowPrice24h"] Low price 24h + /// + [JsonPropertyName("lowPrice24h")] + public decimal LowPrice { get; set; } + /// + /// ["ask1Price"] Best ask price + /// + [JsonPropertyName("ask1Price")] + public decimal BestAskPrice { get; set; } + /// + /// ["bid1Price"] Best bid price + /// + [JsonPropertyName("bid1Price")] + public decimal BestBidPrice { get; set; } + /// + /// ["bid1Size"] Best bid quantity + /// + [JsonPropertyName("bid1Size")] + public decimal BestBidQuantity { get; set; } + /// + /// ["ask1Size"] Best ask quantity + /// + [JsonPropertyName("ask1Size")] + public decimal BestAskQuantity { get; set; } + /// + /// ["price24hPcnt"] Price change percentage 24h + /// + [JsonPropertyName("price24hPcnt")] + public decimal PriceChangePercentage { get; set; } + /// + /// ["volume24h"] Volume 24h + /// + [JsonPropertyName("volume24h")] + public decimal Volume { get; set; } + /// + /// ["turnover24h"] Turnover 24h + /// + [JsonPropertyName("turnover24h")] + public decimal Turnover { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaStrategyOrder.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaStrategyOrder.cs new file mode 100644 index 00000000..64c3499a --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaStrategyOrder.cs @@ -0,0 +1,157 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Orders +/// +public record BitgetUaStrategyOrders +{ + /// + /// ["list"] Orders + /// + [JsonPropertyName("list")] + public BitgetUaStrategyOrder[] Orders { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } +} + +/// +/// Strategy order +/// +public record BitgetUaStrategyOrder +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["qty"] Quantity + /// + [JsonPropertyName("qty")] + public decimal? Quantity { get; set; } + /// + /// ["posSide"] Position side + /// + [JsonPropertyName("posSide")] + public PositionSide? PositionSide { get; set; } + /// + /// ["side"] Order side + /// + [JsonPropertyName("side")] + public OrderSide? Side { get; set; } + /// + /// Reduce only + /// + [JsonPropertyName("reduceOnly")] + public bool ReduceOnly { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public StrategyStatus Status { get; set; } + /// + /// ["type"] Strategy type + /// + [JsonPropertyName("type")] + public StrategyType? Type { get; set; } + /// + /// ["tpTriggerBy"] Take profit trigger by + /// + [JsonPropertyName("tpTriggerBy")] + public PriceTriggerType? TpTriggerBy { get; set; } + /// + /// ["slTriggerBy"] Sl trigger by + /// + [JsonPropertyName("slTriggerBy")] + public PriceTriggerType? SlTriggerBy { get; set; } + /// + /// ["takeProfit"] Take profit + /// + [JsonPropertyName("takeProfit")] + public decimal? TakeProfit { get; set; } + /// + /// ["stopLoss"] Stop loss + /// + [JsonPropertyName("stopLoss")] + public decimal? StopLoss { get; set; } + /// + /// ["tpOrderType"] Tp order type + /// + [JsonPropertyName("tpOrderType")] + public OrderType? TpOrderType { get; set; } + /// + /// ["slOrderType"] Sl order type + /// + [JsonPropertyName("slOrderType")] + public OrderType? SlOrderType { get; set; } + /// + /// ["tpLimitPrice"] Tp limit price + /// + [JsonPropertyName("tpLimitPrice")] + public decimal? TpLimitPrice { get; set; } + /// + /// ["slLimitPrice"] Sl limit price + /// + [JsonPropertyName("slLimitPrice")] + public decimal? SlLimitPrice { get; set; } + /// + /// ["triggerType"] Trigger type + /// + [JsonPropertyName("triggerType")] + public TriggerType? TriggerType { get; set; } + /// + /// ["triggerBy"] Trigger by + /// + [JsonPropertyName("triggerBy")] + public PriceTriggerType? TriggerBy { get; set; } + /// + /// ["triggerPrice"] Trigger price + /// + [JsonPropertyName("triggerPrice")] + public decimal? TriggerPrice { get; set; } + /// + /// ["triggerOrderType"] Trigger order type + /// + [JsonPropertyName("triggerOrderType")] + public OrderType? TriggerOrderType { get; set; } + /// + /// ["triggerOrderPrice"] Trigger order price + /// + [JsonPropertyName("triggerOrderPrice")] + public decimal? TriggerOrderPrice { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaSwitchStatus.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaSwitchStatus.cs new file mode 100644 index 00000000..6c9c1842 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaSwitchStatus.cs @@ -0,0 +1,23 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// Switch status +/// +public record BitgetUaSwitchStatus +{ + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public SwitchStatus Status { get; set; } + /// + /// ["reason"] Reason + /// + [JsonPropertyName("reason")] + public string Reason { get; set; } = string.Empty; +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaTickerUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaTickerUpdate.cs new file mode 100644 index 00000000..036208d4 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaTickerUpdate.cs @@ -0,0 +1,68 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// +/// +public record BitgetUaTickerUpdate +{ + /// + /// ["bid1Price"] Best bid price + /// + [JsonPropertyName("bid1Price")] + public decimal BestBidPrice { get; set; } + /// + /// ["lowPrice24h"] Low price 24h + /// + [JsonPropertyName("lowPrice24h")] + public decimal LowPrice { get; set; } + /// + /// ["ask1Size"] Best ask quantity + /// + [JsonPropertyName("ask1Size")] + public decimal BestAskQuantity { get; set; } + /// + /// ["volume24h"] Volume 24h + /// + [JsonPropertyName("volume24h")] + public decimal Volume { get; set; } + /// + /// ["price24hPcnt"] Price change percentage 24h + /// + [JsonPropertyName("price24hPcnt")] + public decimal PriceChangePercentage { get; set; } + /// + /// ["highPrice24h"] High price 24h + /// + [JsonPropertyName("highPrice24h")] + public decimal HighPrice { get; set; } + /// + /// ["turnover24h"] Turnover 24h + /// + [JsonPropertyName("turnover24h")] + public decimal Turnover { get; set; } + /// + /// ["bid1Size"] Best bid quantity + /// + [JsonPropertyName("bid1Size")] + public decimal BestBidQuantity { get; set; } + /// + /// ["ask1Price"] Best ask price + /// + [JsonPropertyName("ask1Price")] + public decimal BestAskPrice { get; set; } + /// + /// ["openPrice24h"] Open price 24h + /// + [JsonPropertyName("openPrice24h")] + public decimal OpenPrice { get; set; } + /// + /// ["lastPrice"] Last price + /// + [JsonPropertyName("lastPrice")] + public decimal LastPrice { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaTrade.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaTrade.cs new file mode 100644 index 00000000..0fab39ab --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaTrade.cs @@ -0,0 +1,49 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Trade info +/// +public record BitgetUaTrade +{ + /// + /// ["execId"] Trade id + /// + [JsonPropertyName("execId")] + public string TradeId { get; set; } = string.Empty; + /// + /// ["execLinkId"] Trade link id + /// + [JsonPropertyName("execLinkId")] + public string TradeLinkId { get; set; } = string.Empty; + /// + /// ["price"] Price + /// + [JsonPropertyName("price")] + public decimal Price { get; set; } + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["ts"] Timestamp + /// + [JsonPropertyName("ts")] + public DateTime Timestamp { get; set; } + /// + /// ["isRPI"] Is RPI trade + /// + [JsonPropertyName("isRPI")] + public bool IsRPI { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaTradeUpdate.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaTradeUpdate.cs new file mode 100644 index 00000000..cc222a4d --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaTradeUpdate.cs @@ -0,0 +1,48 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// Trade update +/// +public record BitgetUaTradeUpdate +{ + /// + /// ["p"] Price + /// + [JsonPropertyName("p")] + public decimal Price { get; set; } + /// + /// ["S"] Side + /// + [JsonPropertyName("S")] + public OrderSide Side { get; set; } + /// + /// ["T"] Timestamp + /// + [JsonPropertyName("T")] + public DateTime Timestamp { get; set; } + /// + /// ["v"] Quantity + /// + [JsonPropertyName("v")] + public decimal Quantity { get; set; } + /// + /// ["i"] Trade id + /// + [JsonPropertyName("i")] + public string TradeId { get; set; } = string.Empty; + /// + /// ["L"] Trade link id + /// + [JsonPropertyName("L")] + public string TradeLinkId { get; set; } = string.Empty; + /// + /// ["isRPI"] Is RPI + /// + [JsonPropertyName("isRPI")] + public bool IsRPI { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaTransferId.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaTransferId.cs new file mode 100644 index 00000000..59771164 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaTransferId.cs @@ -0,0 +1,18 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Transfer id +/// +public record BitgetUaTransferId +{ + /// + /// ["transferId"] Transfer id + /// + [JsonPropertyName("transferId")] + public string TransferId { get; set; } = string.Empty; +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaUserOpenInterestLimit.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaUserOpenInterestLimit.cs new file mode 100644 index 00000000..40dd6f76 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaUserOpenInterestLimit.cs @@ -0,0 +1,33 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// User max open interest limit +/// +public record BitgetUaUserOpenInterestLimit +{ + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["singleUserLimit"] Single user limit + /// + [JsonPropertyName("singleUserLimit")] + public decimal SingleUserLimit { get; set; } + /// + /// ["masterSubLimit"] Master sub limit + /// + [JsonPropertyName("masterSubLimit")] + public decimal MasterSubLimit { get; set; } + /// + /// ["marketMakerLimit"] Market maker limit + /// + [JsonPropertyName("marketMakerLimit")] + public decimal MarketMakerLimit { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaUserTrades.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaUserTrades.cs new file mode 100644 index 00000000..e61bddd4 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaUserTrades.cs @@ -0,0 +1,133 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Enums.V2; + +namespace Bitget.Net.Objects.Models; + +/// +/// User trades +/// +public record BitgetUaUserTrades +{ + /// + /// ["list"] List + /// + [JsonPropertyName("list")] + public BitgetUaUserTrade[] List { get; set; } = []; + /// + /// ["cursor"] Cursor + /// + [JsonPropertyName("cursor")] + public decimal Cursor { get; set; } +} + +/// +/// Trade info +/// +public record BitgetUaUserTrade +{ + /// + /// ["execId"] Trade id + /// + [JsonPropertyName("execId")] + public string TradeId { get; set; } = string.Empty; + /// + /// ["execLinkId"] Trade link id + /// + [JsonPropertyName("execLinkId")] + public string TradeLinkId { get; set; } = string.Empty; + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client order id + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["category"] Category + /// + [JsonPropertyName("category")] + public ProductCategory Category { get; set; } + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + /// + /// ["orderType"] Order type + /// + [JsonPropertyName("orderType")] + public OrderType OrderType { get; set; } + /// + /// ["side"] Side + /// + [JsonPropertyName("side")] + public OrderSide Side { get; set; } + /// + /// ["execPrice"] Trade price + /// + [JsonPropertyName("execPrice")] + public decimal Price { get; set; } + /// + /// ["execQty"] Quantity + /// + [JsonPropertyName("execQty")] + public decimal Quantity { get; set; } + /// + /// ["execValue"] Trade value + /// + [JsonPropertyName("execValue")] + public decimal Value { get; set; } + /// + /// ["tradeScope"] Trade scope + /// + [JsonPropertyName("tradeScope")] + public Role TradeScope { get; set; } + /// + /// ["tradeSide"] Trade side + /// + [JsonPropertyName("tradeSide")] + public TradeSide TradeSide { get; set; } + /// + /// ["holdSize"] Position side + /// + [JsonPropertyName("holdSide")] + public PositionSide? PositionSide { get; set; } + /// + /// ["feeDetail"] Fee detail + /// + [JsonPropertyName("feeDetail")] + public BitgetUaOrderFee[] FeeDetail { get; set; } = []; + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + [JsonInclude, JsonPropertyName("execTime")] + internal DateTime TradeTime + { + set => CreateTime = value; + } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } + /// + /// ["execPnl"] Profit and loss + /// + [JsonPropertyName("execPnl")] + public decimal? Pnl { get; set; } + /// + /// ["isRPI"] Is RPI + /// + [JsonPropertyName("isRPI")] + public bool IsRPI { get; set; } +} + + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawRecord.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawRecord.cs new file mode 100644 index 00000000..ab935f22 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawRecord.cs @@ -0,0 +1,93 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums.Uta; + +namespace Bitget.Net.Objects.Models; + +/// +/// Withdrawal record +/// +public record BitgetUaWithdrawRecord +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } + /// + /// ["recordId"] Record id + /// + [JsonPropertyName("recordId")] + public string RecordId { get; set; } = string.Empty; + /// + /// ["coin"] Asset + /// + [JsonPropertyName("coin")] + public string Asset { get; set; } = string.Empty; + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + /// + /// ["dest"] Destination + /// + [JsonPropertyName("dest")] + public string Destination { get; set; } = string.Empty; + /// + /// ["size"] Quantity + /// + [JsonPropertyName("size")] + public decimal Quantity { get; set; } + /// + /// ["status"] Status + /// + [JsonPropertyName("status")] + public WithdrawStatus Status { get; set; } + /// + /// ["fromAddress"] From address + /// + [JsonPropertyName("fromAddress")] + public string FromAddress { get; set; } = string.Empty; + /// + /// ["toAddress"] To address + /// + [JsonPropertyName("toAddress")] + public string ToAddress { get; set; } = string.Empty; + /// + /// ["chain"] Network + /// + [JsonPropertyName("chain")] + public string Network { get; set; } = string.Empty; + /// + /// ["fee"] Fee + /// + [JsonPropertyName("fee")] + public decimal Fee { get; set; } + /// + /// ["confirm"] Confirmations + /// + [JsonPropertyName("confirm")] + public int? Confirm { get; set; } + /// + /// ["tag"] Tag + /// + [JsonPropertyName("tag")] + public string? Tag { get; set; } + /// + /// ["createdTime"] Create time + /// + [JsonPropertyName("createdTime")] + public DateTime CreateTime { get; set; } + /// + /// ["updatedTime"] Update time + /// + [JsonPropertyName("updatedTime")] + public DateTime? UpdateTime { get; set; } +} + diff --git a/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawResult.cs b/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawResult.cs new file mode 100644 index 00000000..8f157f32 --- /dev/null +++ b/Bitget.Net/Objects/Models/Uta/BitgetUaWithdrawResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Text.Json.Serialization; +using Bitget.Net.Enums; + +namespace Bitget.Net.Objects.Models; + +/// +/// Withdraw result +/// +public record BitgetUaWithdrawResult +{ + /// + /// ["orderId"] Order id + /// + [JsonPropertyName("orderId")] + public string OrderId { get; set; } = string.Empty; + /// + /// ["clientOid"] Client oid + /// + [JsonPropertyName("clientOid")] + public string? ClientOrderId { get; set; } +} + diff --git a/Bitget.Net/Objects/Options/BitgetRestOptions.cs b/Bitget.Net/Objects/Options/BitgetRestOptions.cs index 51981bc5..6278ef50 100644 --- a/Bitget.Net/Objects/Options/BitgetRestOptions.cs +++ b/Bitget.Net/Objects/Options/BitgetRestOptions.cs @@ -53,6 +53,11 @@ public BitgetRestOptions() /// public RestApiOptions BrokerOptions { get; private set; } = new RestApiOptions(); + /// + /// UTA API options + /// + public RestApiOptions UnifiedOptions { get; private set; } = new RestApiOptions(); + internal BitgetRestOptions Set(BitgetRestOptions targetOptions) { targetOptions = base.Set(targetOptions); @@ -61,6 +66,7 @@ internal BitgetRestOptions Set(BitgetRestOptions targetOptions) targetOptions.SpotOptions = SpotOptions.Set(targetOptions.SpotOptions); targetOptions.CopyTradingOptions = CopyTradingOptions.Set(targetOptions.CopyTradingOptions); targetOptions.BrokerOptions = BrokerOptions.Set(targetOptions.BrokerOptions); + targetOptions.UnifiedOptions = UnifiedOptions.Set(targetOptions.UnifiedOptions); return targetOptions; } } diff --git a/Bitget.Net/Objects/Options/BitgetSocketOptions.cs b/Bitget.Net/Objects/Options/BitgetSocketOptions.cs index 031b4d82..020d17aa 100644 --- a/Bitget.Net/Objects/Options/BitgetSocketOptions.cs +++ b/Bitget.Net/Objects/Options/BitgetSocketOptions.cs @@ -25,6 +25,11 @@ public BitgetSocketOptions() Default?.Set(this); } + /// + /// Channel code + /// + public string? ChannelCode { get; set; } + /// /// Spot API options /// @@ -35,11 +40,18 @@ public BitgetSocketOptions() /// public SocketApiOptions FuturesOptions { get; private set; } = new SocketApiOptions(); + /// + /// UTA API options + /// + public SocketApiOptions UnifiedOptions { get; private set; } = new SocketApiOptions(); + internal BitgetSocketOptions Set(BitgetSocketOptions targetOptions) { targetOptions = base.Set(targetOptions); + targetOptions.ChannelCode = ChannelCode; targetOptions.SpotOptions = SpotOptions.Set(targetOptions.SpotOptions); targetOptions.FuturesOptions = FuturesOptions.Set(targetOptions.FuturesOptions); + targetOptions.UnifiedOptions = UnifiedOptions.Set(targetOptions.UnifiedOptions); return targetOptions; } } diff --git a/Bitget.Net/Objects/Socket/BitgetIdSocketRequest.cs b/Bitget.Net/Objects/Socket/BitgetIdSocketRequest.cs new file mode 100644 index 00000000..42184875 --- /dev/null +++ b/Bitget.Net/Objects/Socket/BitgetIdSocketRequest.cs @@ -0,0 +1,22 @@ +using Bitget.Net.Enums.Uta; +using CryptoExchange.Net.Objects; +using System.Text.Json.Serialization; + +namespace Bitget.Net.Objects.Socket +{ + internal class BitgetIdSocketRequest + { + [JsonPropertyName("op")] + public string Op { get; set; } = string.Empty; + [JsonPropertyName("id"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Id { get; set; } = string.Empty; + [JsonPropertyName("topic"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Topic { get; set; } = string.Empty; + [JsonPropertyName("apiCode"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string ApiCode { get; set; } = string.Empty; + [JsonPropertyName("category"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public ProductCategory? Category { get; set; } + [JsonPropertyName("args")] + public ParameterCollection[] Args { get; set; } = []; + } +} diff --git a/Bitget.Net/Objects/Socket/BitgetSocketResponse.cs b/Bitget.Net/Objects/Socket/BitgetSocketResponse.cs new file mode 100644 index 00000000..d07a8439 --- /dev/null +++ b/Bitget.Net/Objects/Socket/BitgetSocketResponse.cs @@ -0,0 +1,29 @@ +using System.Text.Json.Serialization; + +namespace Bitget.Net.Objects.Socket +{ + internal class BitgetSocketResponse + { + [JsonPropertyName("event")] + public string Event { get; set; } = null!; + [JsonPropertyName("id")] + public string Id { get; set; } = null!; + [JsonPropertyName("topic")] + public string Topic { get; set; } = null!; + [JsonPropertyName("arg")] + public BitgetSocketArgs Args { get; set; } = null!; + [JsonPropertyName("code")] + public int? Code { get; set; } + [JsonPropertyName("msg")] + public string? Message { get; set; } + [JsonPropertyName("ts")] + public DateTime? Timestamp { get; set; } + + } + + internal class BitgetSocketResponse : BitgetSocketResponse + { + [JsonPropertyName("args")] + public T Data { get; set; } = default!; + } +} diff --git a/Bitget.Net/Objects/Socket/BitgetSocketUpdate.cs b/Bitget.Net/Objects/Socket/BitgetSocketUpdate.cs index 85b201b9..b70a1002 100644 --- a/Bitget.Net/Objects/Socket/BitgetSocketUpdate.cs +++ b/Bitget.Net/Objects/Socket/BitgetSocketUpdate.cs @@ -8,8 +8,20 @@ internal class BitgetSocketArgs public string IntstrumentType { get; set; } = null!; [JsonPropertyName("channel")] public string Channel { get; set; } = null!; + [JsonPropertyName("topic")] + public string Topic + { + get => Channel; + set => Channel = value; + } [JsonPropertyName("instId")] public string InstrumentId { get; set; } = null!; + [JsonPropertyName("symbol")] + public string Symbol + { + get => InstrumentId; + set => InstrumentId = value; + } } internal class BitgetSocketUpdate diff --git a/Bitget.Net/Objects/Socket/Queries/BitgetIdQuery.cs b/Bitget.Net/Objects/Socket/Queries/BitgetIdQuery.cs new file mode 100644 index 00000000..9b7def7b --- /dev/null +++ b/Bitget.Net/Objects/Socket/Queries/BitgetIdQuery.cs @@ -0,0 +1,35 @@ +using CryptoExchange.Net.Clients; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Sockets; +using CryptoExchange.Net.Sockets.Default; +using CryptoExchange.Net.Sockets.Default.Routing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bitget.Net.Objects.Socket.Queries +{ + internal class BitgetIdQuery : Query + { + private readonly ParameterCollection[] _args; + private readonly SocketApiClient _client; + + public BitgetIdQuery(SocketApiClient client, BitgetIdSocketRequest request, bool authenticated, int weight = 1) : base(request, authenticated, weight) + { + _args = request.Args; + _client = client; + + MessageRouter = MessageRouter.CreateWithoutTopicFilter>(request.Id, HandleMessage); + } + + public CallResult HandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitgetSocketResponse message) + { + if (message.Code != null) + return new CallResult(new ServerError(message.Code.Value.ToString(), _client.GetErrorInfo(message.Code.Value, message.Message!)), originalData); + + return new CallResult(message.Data, originalData, null); + } + } +} diff --git a/Bitget.Net/Objects/Socket/Queries/BitgetQuery.cs b/Bitget.Net/Objects/Socket/Queries/BitgetQuery.cs index c4d79e42..f1330acb 100644 --- a/Bitget.Net/Objects/Socket/Queries/BitgetQuery.cs +++ b/Bitget.Net/Objects/Socket/Queries/BitgetQuery.cs @@ -19,12 +19,14 @@ public BitgetQuery(SocketApiClient client, BitgetSocketRequest request, bool aut var routes = new List(); foreach (var arg in _args) { + var topic = arg.TryGetValue("channel", out var channel) ? channel : arg["topic"]; + routes.Add(MessageRoute.CreateWithOptionalTopicFilter( - $"{request.Op}{arg["instType"]}{arg["channel"]}", + $"{request.Op}{arg["instType"]}{topic}", GetRouteIdentifier(arg), HandleMessage)); routes.Add(MessageRoute.CreateWithOptionalTopicFilter( - $"error{arg["instType"]}{arg["channel"]}", + $"error{arg["instType"]}{topic}", GetRouteIdentifier(arg), HandleMessage)); } diff --git a/Bitget.Net/Objects/Socket/Subscriptions/BitgetSubscription.cs b/Bitget.Net/Objects/Socket/Subscriptions/BitgetSubscription.cs index e9d17cc6..f5e33bb2 100644 --- a/Bitget.Net/Objects/Socket/Subscriptions/BitgetSubscription.cs +++ b/Bitget.Net/Objects/Socket/Subscriptions/BitgetSubscription.cs @@ -28,7 +28,8 @@ public BitgetSubscription(ILogger logger, SocketApiClient client, Dictionary arg) { - return $"{arg["instType"]}{arg["channel"]}"; + var subject = arg.TryGetValue("channel", out var channel) ? channel : arg["topic"]; + return $"{arg["instType"]}{subject}"; } protected override Query? GetSubQuery(SocketConnection connection) => new BitgetQuery(_client, new BitgetSocketRequest { Args = _args, Op = "subscribe" }, false) { RequiredResponses = _args.Count() }; diff --git a/Bitget.Net/SymbolOrderBooks/BitgetOrderBookFactory.cs b/Bitget.Net/SymbolOrderBooks/BitgetOrderBookFactory.cs index 0d568cf0..ef197156 100644 --- a/Bitget.Net/SymbolOrderBooks/BitgetOrderBookFactory.cs +++ b/Bitget.Net/SymbolOrderBooks/BitgetOrderBookFactory.cs @@ -1,4 +1,5 @@ using Bitget.Net.Enums; +using Bitget.Net.Enums.Uta; using Bitget.Net.Interfaces; using Bitget.Net.Interfaces.Clients; using Bitget.Net.Objects.Options; @@ -21,6 +22,8 @@ public class BitgetOrderBookFactory : IBitgetOrderBookFactory /// public string ExchangeName => BitgetExchange.ExchangeName; + /// + public IOrderBookFactory Unified { get; } /// public IOrderBookFactory Spot { get; } /// @@ -77,5 +80,13 @@ public ISymbolOrderBook CreateFutures(BitgetProductTypeV2 productType, string sy options, _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService()); + + /// + public ISymbolOrderBook CreateUnified(ProductCategory category, string symbol, Action? options = null) + => new BitgetUnifiedSymbolOrderBook(category, + symbol, + options, + _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService()); } } diff --git a/Bitget.Net/SymbolOrderBooks/BitgetUnifiedSymbolOrderBook.cs b/Bitget.Net/SymbolOrderBooks/BitgetUnifiedSymbolOrderBook.cs new file mode 100644 index 00000000..7716f19d --- /dev/null +++ b/Bitget.Net/SymbolOrderBooks/BitgetUnifiedSymbolOrderBook.cs @@ -0,0 +1,133 @@ +using Bitget.Net.Clients; +using Bitget.Net.Enums.Uta; +using Bitget.Net.Interfaces.Clients; +using Bitget.Net.Objects.Models; +using Bitget.Net.Objects.Models.V2; +using Bitget.Net.Objects.Options; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.OrderBook; +using Microsoft.Extensions.Logging; + +namespace Bitget.Net.SymbolOrderBooks +{ + /// + /// Live order book implementation + /// + public class BitgetUnifiedSymbolOrderBook : SymbolOrderBook + { + private readonly IBitgetSocketClient _socketClient; + private bool _initial = true; + private readonly bool _clientOwner; + private readonly ProductCategory _category; + + /// + /// Create a new order book instance + /// + /// The symbol category + /// The symbol the order book is for + /// Option configuration delegate + public BitgetUnifiedSymbolOrderBook(ProductCategory category, string symbol, Action? optionsDelegate = null) + : this(category, symbol, optionsDelegate, null, null) + { + _clientOwner = true; + } + + /// + /// Create a new order book instance + /// + /// The symbol category + /// The symbol the order book is for + /// Option configuration delegate + /// Logger + /// Socket client instance + public BitgetUnifiedSymbolOrderBook(ProductCategory category, + string symbol, + Action? optionsDelegate, + ILoggerFactory? logger, + IBitgetSocketClient? socketClient) : base(logger, "Bitget", "Unified", symbol) + { + var options = BitgetOrderBookOptions.Default.Copy(); + if (optionsDelegate != null) + optionsDelegate(options); + Initialize(options); + + _category = category; + _socketClient = socketClient ?? new BitgetSocketClient(); + _clientOwner = socketClient == null; + _skipSequenceCheckFirstUpdateAfterSnapshotSet = true; + + Levels = options?.Limit; + } + + /// + protected override async Task> DoStartAsync(CancellationToken ct) + { + CallResult result; + if (Levels != null) + result = await _socketClient.UnifiedApi.SubscribeToOrderBookUpdatesAsync(_category, Symbol, Levels.Value, ProcessUpdate).ConfigureAwait(false); + else + result = await _socketClient.UnifiedApi.SubscribeToOrderBookUpdatesAsync(_category, Symbol, null, ProcessUpdate).ConfigureAwait(false); + if (!result) + return result; + + if (ct.IsCancellationRequested) + { + await result.Data.CloseAsync().ConfigureAwait(false); + return result.AsError(new CancellationRequestedError()); + } + + Status = OrderBookStatus.Syncing; + + var setResult = await WaitForSetOrderBookAsync(TimeSpan.FromMilliseconds(10000), ct).ConfigureAwait(false); + if (!setResult) + await result.Data.CloseAsync().ConfigureAwait(false); + + return setResult ? result : new CallResult(setResult.Error!); + } + + /// + protected override void DoReset() + { + _initial = true; + } + + private void ProcessUpdate(DataEvent data) + { + var eventData = data.Data.Single(); + if (Levels != null) + { + SetSnapshot(eventData.Sequence, eventData.Bids, eventData.Asks, data.DataTime, data.DataTimeLocal); + } + else + { + if (_initial) + { + _initial = false; + SetSnapshot(eventData.Sequence, eventData.Bids, eventData.Asks, data.DataTime, data.DataTimeLocal); + } + else + { + UpdateOrderBook(eventData.PreviousSequence, eventData.Sequence, eventData.Bids, eventData.Asks, data.DataTime, data.DataTimeLocal); + } + } + } + + /// + protected override async Task> DoResyncAsync(CancellationToken ct) + { + return await WaitForSetOrderBookAsync(TimeSpan.FromSeconds(10), ct).ConfigureAwait(false); + } + + /// + /// Dispose + /// + protected override void Dispose(bool disposing) + { + if (_clientOwner) + _socketClient?.Dispose(); + + base.Dispose(disposing); + } + } +} diff --git a/README.md b/README.md index 499ac811..5b3733dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ![.Bitget.Net](https://github.com/JKorf/Bitget.Net/blob/main/Bitget.Net/Icon/icon.png?raw=true) Bitget.Net -[![.NET](https://img.shields.io/github/actions/workflow/status/JKorf/Bitget.Net/dotnet.yml?style=for-the-badge)](https://github.com/JKorf/Bitget.Net/actions/workflows/dotnet.yml) ![License](https://img.shields.io/github/license/JKorf/Bitget.Net?style=for-the-badge) +[![.NET](https://img.shields.io/github/actions/workflow/status/JKorf/Bitget.Net/dotnet.yml?style=for-the-badge)](https://github.com/JKorf/Bitget.Net/actions/workflows/dotnet.yml) ![License](https://img.shields.io/github/license/JKorf/Bitget.Net?style=for-the-badge) ![Since](https://img.shields.io/badge/since-2023-brightgreen?style=for-the-badge) Bitget.Net is a strongly typed client library for accessing the [Bitget REST and Websocket API](https://bitgetlimited.github.io/apidoc/en/spot). ## Features @@ -134,7 +134,7 @@ A Discord server is available [here](https://discord.gg/MSpeEtSY8t). Feel free t ## Supported functionality -*Both V1 API and V2 are currently supported* +*Both V2 API and V3/UTA are currently supported* ### V2 #### Spot @@ -166,30 +166,22 @@ A Discord server is available [here](https://discord.gg/MSpeEtSY8t). Feel free t |Rest Isolated|✓|`restClient.SpotApiV2.Margin`| |Websocket|✓|`socketClient.SpotApiV2`| -### V1 +### UTA #### Spot |API|Supported|Location| |--|--:|--| -|Rest Public|✓|`restClient.SpotApi.ExchangeData`| -|Rest Market|✓|`restClient.SpotApi.ExchangeData`| -|Rest Wallet|✓|`restClient.SpotApi.Account`| -|Rest Account|✓|`restClient.SpotApi.Account`| -|Rest Trade|✓|`restClient.SpotApi.Trading`| +|Rest Market|✓|`restClient.UnifiedApi.ExchangeData`| +|Rest Account|✓|`restClient.UnifiedApi.Account`| +|Rest Trade|✓|`restClient.UnifiedApi.Trading`| +|Rest Strategy|✓|`restClient.UnifiedApi.Trading`| +|Rest Copy Trading|X|| +|Rest Earn|X|| +|Rest Tax|X|| +|Rest Crypto Loans|X|| +|Rest Inst Loan|X|| |Rest P2P|X|| -|Rest Sub-Account|X|| -|Rest Convert|X|| -|Websocket Public|✓|`socketClient.SpotApi`| -|Websocket Private|✓|`socketClient.SpotApi`| - -#### Futures USDT/Coin -|API|Supported|Location| -|--|--:|--| -|Rest Market|✓|`restClient.FuturesApi.ExchangeData`| -|Rest Account|✓|`restClient.FuturesApi.Account`| -|Rest Trade|✓|`restClient.FuturesApi.Trading`| -|Websocket Public|✓|`socketClient.FuturesApi`| -|Websocket Private|✓|`socketClient.FuturesApi`| - +|Websocket Public|✓|`socketClient.UnifiedApi`| +|Websocket Private|✓|`socketClient.UnifiedApi`| ## Support the project Any support is greatly appreciated.