From 4556a6ab0f4a23b515f4ceceb7b9b1a54c012fdc Mon Sep 17 00:00:00 2001 From: arodus <18667020+arodus@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:35:23 +0100 Subject: [PATCH 1/7] Add support for inverse futures --- ...rseFuturesBrokerageHistoryProviderTests.cs | 56 +++++++++++ ...ybitInverseFuturesBrokerageTests.Stream.cs | 43 ++++++++ .../BybitInverseFuturesBrokerageTests.cs | 99 +++++++++++++++++++ .../Api/BybitPositionApiEndpoint.cs | 29 +++++- .../BybitBrokerage.Messaging.cs | 4 +- QuantConnect.BybitBrokerage/BybitBrokerage.cs | 21 ++-- .../Models/ByBitResponse.cs | 24 +++-- .../Models/Enums/PositionMode.cs | 33 +++++++ 8 files changed, 288 insertions(+), 21 deletions(-) create mode 100644 QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs create mode 100644 QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs create mode 100644 QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs create mode 100644 QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs new file mode 100644 index 0000000..c2b7f50 --- /dev/null +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs @@ -0,0 +1,56 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using System; +using NUnit.Framework; + +namespace QuantConnect.BybitBrokerage.Tests +{ + [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] + public class BybitInverseFuturesBrokerageHistoryProviderTests : BybitBrokerageHistoryProviderTests + { + private static readonly Symbol ETHUSD = Symbol.Create("ETHUSDT", SecurityType.CryptoFuture, Market.Bybit); + + + private static TestCaseData[] ValidHistory + { + get + { + return new[] + { + // valid + new TestCaseData(ETHUSD, Resolution.Tick, Time.OneMinute, TickType.Trade), + new TestCaseData(ETHUSD, Resolution.Minute, Time.OneHour, TickType.Trade), + new TestCaseData(ETHUSD, Resolution.Hour, Time.OneDay, TickType.Trade), + new TestCaseData(ETHUSD, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade), + new TestCaseData(ETHUSD, Resolution.Hour, Time.OneDay, TickType.OpenInterest) + }; + } + } + + + [Test, TestCaseSource(nameof(ValidHistory))] + public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) + { + base.GetsHistory(symbol, resolution, period, tickType); + } + + [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] + public override void GetEmptyHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) + { + base.GetEmptyHistory(symbol, resolution, period, tickType); + } + } +} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs new file mode 100644 index 0000000..0bdf798 --- /dev/null +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs @@ -0,0 +1,43 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using NUnit.Framework; + +namespace QuantConnect.BybitBrokerage.Tests +{ + [TestFixture] + public partial class BybitInverseFuturesBrokerageTests + { + private static TestCaseData[] TestParameters + { + get + { + return new[] + { + // valid parameters, for example + new TestCaseData(BTCUSD, Resolution.Tick, false), + new TestCaseData(BTCUSD, Resolution.Minute, true), + new TestCaseData(BTCUSD, Resolution.Second, true), + }; + } + } + + [Test, TestCaseSource(nameof(TestParameters))] + public override void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) + { + base.StreamsData(symbol, resolution, throwsException); + } + } +} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs new file mode 100644 index 0000000..16d00d3 --- /dev/null +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs @@ -0,0 +1,99 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using NUnit.Framework; +using QuantConnect.BybitBrokerage.Models.Enums; +using QuantConnect.Tests.Brokerages; + +namespace QuantConnect.BybitBrokerage.Tests; + +[TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] +public partial class BybitInverseFuturesBrokerageTests : BybitBrokerageTests +{ + private static Symbol BTCUSD = Symbol.Create("BTCUSD", SecurityType.CryptoFuture, "bybit"); + protected override Symbol Symbol { get; } = BTCUSD; + + protected override SecurityType SecurityType => SecurityType.Future; + protected override BybitProductCategory Category => BybitProductCategory.Inverse; + protected override decimal TakerFee => 0.00025m; + + protected override decimal GetDefaultQuantity() => 10m; + + + /// + /// Provides the data required to test each order type in various cases + /// + private static TestCaseData[] OrderParameters() + { + return new[] + { + new TestCaseData(new MarketOrderTestParameters(BTCUSD)).SetName("MarketOrder"), + new TestCaseData(new LimitOrderTestParameters(BTCUSD, 50000m, 10000m)).SetName("LimitOrder"), + new TestCaseData(new StopMarketOrderTestParameters(BTCUSD, 50000m, 10000m)).SetName("StopMarketOrder"), + new TestCaseData(new StopLimitOrderTestParameters(BTCUSD, 50000m, 10000m)).SetName("StopLimitOrder"), + new TestCaseData(new LimitIfTouchedOrderTestParameters(BTCUSD, 50000m, 20000)).SetName( + "LimitIfTouchedOrder") + }; + } + + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CancelOrders(OrderTestParameters parameters) + { + base.CancelOrders(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void LongFromZero(OrderTestParameters parameters) + { + base.LongFromZero(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CloseFromLong(OrderTestParameters parameters) + { + base.CloseFromLong(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void ShortFromZero(OrderTestParameters parameters) + { + base.ShortFromZero(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CloseFromShort(OrderTestParameters parameters) + { + base.CloseFromShort(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void ShortFromLong(OrderTestParameters parameters) + { + base.ShortFromLong(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void LongFromShort(OrderTestParameters parameters) + { + base.LongFromShort(parameters); + } + + [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] + public override void GetAccountHoldings() + { + base.GetAccountHoldings(); + } +} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs b/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs index c3e01ce..ba9eae5 100644 --- a/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs +++ b/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs @@ -48,10 +48,33 @@ public IEnumerable GetPositions(BybitProductCategory category { if (category == BybitProductCategory.Spot) return Array.Empty(); - var parameters = new KeyValuePair[] + var parameters = new List>(); + + if (category == BybitProductCategory.Linear) { - new("settleCoin", "USDT") - }; + parameters.Add(KeyValuePair.Create("settleCoin", "USDT")); + } + return FetchAll("/position/list", category, 200, parameters, true); } + + /// + /// It supports to switch the position mode for USDT perpetual and Inverse futures. + /// If you are in one-way Mode, you can only open one position on Buy or Sell side. If you are in hedge mode, you can open both Buy and Sell side positions simultaneously. + /// + /// The product category + /// The symbol for which the mode should be changed + /// The mode which should be set + public void SwitchPositionMode(BybitProductCategory category, Symbol symbol, PositionMode mode) + { + var ticker = SymbolMapper.GetBrokerageSymbol(symbol); + var requestBody = new + { + category, + mode = (int)mode, + symbol = ticker + }; + + ExecutePostRequest("/position/switch-mode", requestBody); + } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs index f13ddd0..fa1dd48 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs @@ -155,7 +155,7 @@ private void HandleOrderExecution(JToken message) var currency = tradeUpdate.Category switch { BybitProductCategory.Linear => "USDT", - BybitProductCategory.Inverse => GetBaseCurrency(symbol), + BybitProductCategory.Inverse => GetBaseCurrency(leanSymbol), BybitProductCategory.Spot => GetSpotFeeCurrency(leanSymbol, tradeUpdate), _ => throw new NotSupportedException($"category {tradeUpdate.Category} not implemented") }; @@ -186,7 +186,7 @@ static string GetSpotFeeCurrency(Symbol symbol, BybitTradeUpdate tradeUpdate) return tradeUpdate.Side == OrderSide.Buy ? quote : @base; } - static string GetBaseCurrency(string pair) + static string GetBaseCurrency(Symbol pair) { CurrencyPairUtil.DecomposeCurrencyPair(pair, out var baseCurrency, out _); return baseCurrency; diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.cs index b7534cc..3cadeb4 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs @@ -47,7 +47,7 @@ namespace QuantConnect.Brokerages.Bybit; [BrokerageFactory(typeof(BybitBrokerageFactory))] public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler { - private static readonly List SupportedBybitProductCategories = new() { BybitProductCategory.Spot, BybitProductCategory.Linear }; + private static readonly List SupportedBybitProductCategories = new() { BybitProductCategory.Spot, BybitProductCategory.Linear, BybitProductCategory.Inverse }; private static readonly List SuppotedSecurityTypes = new() { SecurityType.Crypto, SecurityType.CryptoFuture }; @@ -340,8 +340,8 @@ protected virtual bool CanSubscribe(Symbol symbol) if (baseCanSubscribe && symbol.SecurityType == SecurityType.CryptoFuture) { - //Can only subscribe to non-inverse pairs - return CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency) && quoteCurrency == "USDT"; + //Can only subscribe to non-future pairs + return CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency) && quoteCurrency is "USDT" or "USD"; } return baseCanSubscribe; @@ -526,13 +526,18 @@ private static BybitProductCategory GetBybitProductCategory(Symbol symbol) return BybitProductCategory.Spot; case SecurityType.CryptoFuture: - if (!CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency) || - quoteCurrency != "USDT") + if (CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency)) { - throw new ArgumentException($"Invalid symbol: {symbol}. Only linear futures are supported."); + if (quoteCurrency == "USDT") + { + return BybitProductCategory.Linear; + } + if (quoteCurrency == "USD") + { + return BybitProductCategory.Inverse; + } } - - return BybitProductCategory.Linear; + throw new ArgumentException($"Invalid symbol: {symbol}. Only linear futures are supported."); default: throw new ArgumentOutOfRangeException(nameof(symbol), symbol, "Not supported security type"); diff --git a/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs b/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs index fa2f32e..4ccfd47 100644 --- a/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs +++ b/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs @@ -22,8 +22,7 @@ namespace QuantConnect.Brokerages.Bybit.Models /// /// Bybits default http response message /// - /// - public class ByBitResponse + public class ByBitResponse { /// /// Success/Error code @@ -43,16 +42,25 @@ public class ByBitResponse /// [JsonProperty("retExtInfo")] public object ExtendedInfo { get; set; } - - /// - /// Business data result - /// - public T Result { get; set; } - + /// /// Current time /// [JsonConverter(typeof(BybitTimeConverter))] public DateTime Time { get; set; } } + + /// + /// Bybits default http data response message + /// + /// + public class ByBitResponse : ByBitResponse + { + /// + /// Business data result + /// + public T Result { get; set; } + + } + } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs new file mode 100644 index 0000000..04d9973 --- /dev/null +++ b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs @@ -0,0 +1,33 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Runtime.Serialization; + +namespace QuantConnect.BybitBrokerage.Models.Enums; + +/// +/// Bybit position mode +/// +public enum PositionMode +{ + /// + /// One way mode + /// + MergedSingle = 0, + /// + /// Hedge mode + /// + BothSides = 3, +} \ No newline at end of file From efbbb6f5d515ec7e73d43416ae210c09b3915d92 Mon Sep 17 00:00:00 2001 From: arodus <18667020+arodus@users.noreply.github.com> Date: Fri, 24 Nov 2023 20:45:09 +0100 Subject: [PATCH 2/7] Cleanup --- .../BybitInverseFuturesBrokerageHistoryProviderTests.cs | 4 +--- .../BybitInverseFuturesBrokerageTests.cs | 4 +--- QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs | 5 ++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs index c2b7f50..31f8523 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs @@ -23,7 +23,6 @@ public class BybitInverseFuturesBrokerageHistoryProviderTests : BybitBrokerageHi { private static readonly Symbol ETHUSD = Symbol.Create("ETHUSDT", SecurityType.CryptoFuture, Market.Bybit); - private static TestCaseData[] ValidHistory { get @@ -39,8 +38,7 @@ private static TestCaseData[] ValidHistory }; } } - - + [Test, TestCaseSource(nameof(ValidHistory))] public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs index 16d00d3..79b1938 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs @@ -31,7 +31,6 @@ public partial class BybitInverseFuturesBrokerageTests : BybitBrokerageTests protected override decimal GetDefaultQuantity() => 10m; - /// /// Provides the data required to test each order type in various cases /// @@ -47,8 +46,7 @@ private static TestCaseData[] OrderParameters() "LimitIfTouchedOrder") }; } - - + [Test, TestCaseSource(nameof(OrderParameters))] public override void CancelOrders(OrderTestParameters parameters) { diff --git a/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs index 04d9973..4cacb3d 100644 --- a/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs +++ b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs @@ -11,9 +11,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -using System.Runtime.Serialization; +*/ namespace QuantConnect.BybitBrokerage.Models.Enums; @@ -26,6 +24,7 @@ public enum PositionMode /// One way mode /// MergedSingle = 0, + /// /// Hedge mode /// From f62083c8cf93925c93eea8d6267bc611ca5e8e32 Mon Sep 17 00:00:00 2001 From: arodus <18667020+arodus@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:57:34 +0100 Subject: [PATCH 3/7] Add dedicated brokerage for inverse futures --- .../BybitBrokerageTests.cs | 15 +++- ...tInverseFuturesBrokerageAdditionalTests.cs | 36 +++++++++ .../BybitInverseFuturesBrokerageTests.cs | 49 ++++++++++- .../Api/BybitAccountApiEndpoint.cs | 13 ++- .../BybitBrokerage.Brokerage.cs | 2 +- QuantConnect.BybitBrokerage/BybitBrokerage.cs | 23 +++--- .../BybitBrokerageFactory.cs | 25 ++++-- .../BybitInverseFuturesBrokerage.cs | 81 +++++++++++++++++++ .../BybitInverseFuturesBrokerageFactory.cs | 52 ++++++++++++ 9 files changed, 268 insertions(+), 28 deletions(-) create mode 100644 QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs create mode 100644 QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs create mode 100644 QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs diff --git a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs index e6179a9..943b17d 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs @@ -21,6 +21,7 @@ using QuantConnect.Brokerages.Bybit.Api; using QuantConnect.Brokerages.Bybit.Models.Enums; using QuantConnect.Configuration; +using QuantConnect.Data; using QuantConnect.Interfaces; using QuantConnect.Lean.Engine.DataFeeds; using QuantConnect.Logging; @@ -62,8 +63,16 @@ protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISec var websocketUrl = Config.Get("bybit-websocket-url", "wss://stream-testnet.bybit.com"); _client = CreateRestApiClient(apiKey, apiSecret, apiUrl); - return new BybitBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm.Object, orderProvider, - securityProvider, new AggregationManager(), null); + + return CreateBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm.Object, orderProvider, securityProvider, new AggregationManager()); + } + + protected virtual IBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, + string websocketUrl, IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, + IDataAggregator aggregator) + { + return new BybitBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, orderProvider, securityProvider, new AggregationManager(), null); + } protected virtual decimal TakerFee => BybitFeeModel.TakerNonVIPFee; @@ -198,7 +207,7 @@ public override void GetAccountHoldings() var afterQuantity = afterHoldings == null ? 0 : afterHoldings.Amount; var fee = order.Quantity * TakerFee; - + Assert.AreEqual(GetDefaultQuantity(), afterQuantity - beforeQuantity + fee); } diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs new file mode 100644 index 0000000..dda904c --- /dev/null +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs @@ -0,0 +1,36 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using NUnit.Framework; +using QuantConnect.Brokerages; +using QuantConnect.Interfaces; +using QuantConnect.Lean.Engine.DataFeeds; + +namespace QuantConnect.BybitBrokerage.Tests +{ + [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] + public class BybitInverseFuturesBrokerageAdditionalTests : BybitBrokerageAdditionalTests + { + protected override string BrokerageName => nameof(BybitInverseFuturesBrokerage); + + + protected override Brokerage CreateBrokerage(IAlgorithm algorithm, string apiKey, string apiSecret, + string apiUrl, string websocketUrl) + { + return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, new AggregationManager(), + null); + } + } +} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs index 79b1938..bd8f515 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs @@ -13,9 +13,19 @@ * limitations under the License. */ +using System; +using System.Linq; +using System.Threading; using NUnit.Framework; using QuantConnect.BybitBrokerage.Models.Enums; +using QuantConnect.Data; +using QuantConnect.Interfaces; +using QuantConnect.Lean.Engine.DataFeeds; +using QuantConnect.Logging; +using QuantConnect.Orders; +using QuantConnect.Securities; using QuantConnect.Tests.Brokerages; +using QuantConnect.Util; namespace QuantConnect.BybitBrokerage.Tests; @@ -27,10 +37,18 @@ public partial class BybitInverseFuturesBrokerageTests : BybitBrokerageTests protected override SecurityType SecurityType => SecurityType.Future; protected override BybitProductCategory Category => BybitProductCategory.Inverse; - protected override decimal TakerFee => 0.00025m; + protected override decimal TakerFee => 0.0000015m; protected override decimal GetDefaultQuantity() => 10m; + protected override IBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, + string websocketUrl, IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, + IDataAggregator aggregator) + { + return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, orderProvider, securityProvider, new AggregationManager(), null); + + } + /// /// Provides the data required to test each order type in various cases /// @@ -88,10 +106,33 @@ public override void LongFromShort(OrderTestParameters parameters) { base.LongFromShort(parameters); } - - [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] + + + [Test] public override void GetAccountHoldings() { - base.GetAccountHoldings(); + Log.Trace(""); + Log.Trace("GET ACCOUNT HOLDINGS"); + Log.Trace(""); + var before = Brokerage.GetCashBalance(); + + var order = new MarketOrder(Symbol, GetDefaultQuantity(), DateTime.UtcNow); + PlaceOrderWaitForStatus(order); + + Thread.Sleep(3000); + + var after = Brokerage.GetCashBalance(); + + CurrencyPairUtil.DecomposeCurrencyPair(Symbol, out var baseCurrency, out _); + var beforeHoldings = before.FirstOrDefault(x => x.Currency == baseCurrency); + var afterHoldings = after.FirstOrDefault(x => x.Currency == baseCurrency); + + var beforeQuantity = beforeHoldings == null ? 0 : beforeHoldings.Amount; + var afterQuantity = afterHoldings == null ? 0 : afterHoldings.Amount; + + var fee = 0.00000015m; + + Assert.AreEqual(0, afterQuantity - beforeQuantity + fee); } + } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs index d486e98..2ce927e 100644 --- a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs +++ b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs @@ -13,6 +13,7 @@ * limitations under the License. */ +using System; using System.Collections.Generic; using QuantConnect.Brokerages.Bybit.Models; using QuantConnect.Securities; @@ -40,13 +41,19 @@ public BybitAccountApiEndpoint(ISymbolMapper symbolMapper, string apiPrefix, ISe /// /// Obtain wallet balance, query asset information of each currency, and account risk rate information /// - /// The product category + /// The account type to fetch wallet balances for /// The wallet balances - public BybitBalance GetWalletBalances() + public BybitBalance GetWalletBalances(BybitAccountType accountType) { + if (accountType is not (BybitAccountType.Contract or BybitAccountType.Unified)) + { + throw new ArgumentOutOfRangeException(nameof(accountType), + "Wallet balances can only be fetched for 'UNIFIED' and 'CONTRACT'"); + } + var parameters = new KeyValuePair[] { - new("accountType", "UNIFIED") + new("accountType", accountType.ToStringInvariant().ToUpperInvariant()) }; var result = diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs index df57756..0fd6d18 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs @@ -122,7 +122,7 @@ public override List GetAccountHoldings() public override List GetCashBalance() { return ApiClient.Account - .GetWalletBalances().Assets + .GetWalletBalances(WalletAccountType).Assets .Select(x => new CashAmount(x.WalletBalance, x.Asset)).ToList(); } diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.cs index 3cadeb4..5677863 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs @@ -47,12 +47,6 @@ namespace QuantConnect.Brokerages.Bybit; [BrokerageFactory(typeof(BybitBrokerageFactory))] public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler { - private static readonly List SupportedBybitProductCategories = new() { BybitProductCategory.Spot, BybitProductCategory.Linear, BybitProductCategory.Inverse }; - - private static readonly List SuppotedSecurityTypes = new() { SecurityType.Crypto, SecurityType.CryptoFuture }; - - private static readonly string MarketName = Market.Bybit; - private readonly Dictionary _subscriptionManagers = new(); private IAlgorithm _algorithm; @@ -68,6 +62,12 @@ public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler private bool _unsupportedResolutionOpenInterestHistoryLogged; private bool _invalidTimeRangeHistoryLogged; + protected virtual string MarketName => Market.Bybit; + protected virtual BybitAccountType WalletAccountType => BybitAccountType.Unified; + protected virtual SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.Crypto, SecurityType.CryptoFuture }; + protected virtual BybitProductCategory[] SupportedBybitProductCategories { get; } = + { BybitProductCategory.Spot, BybitProductCategory.Linear }; + /// /// Order provider /// @@ -91,7 +91,7 @@ public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler /// /// Parameterless constructor for brokerage /// - public BybitBrokerage() : base(MarketName) + public BybitBrokerage() : base(Market.Bybit) { } @@ -130,7 +130,7 @@ public BybitBrokerage(string apiKey, string apiSecret, string restApiUrl, string public BybitBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel = BybitVIPLevel.VIP0) - : base(MarketName) + : base(Market.Bybit) { Initialize( webSocketBaseUrl, @@ -340,8 +340,9 @@ protected virtual bool CanSubscribe(Symbol symbol) if (baseCanSubscribe && symbol.SecurityType == SecurityType.CryptoFuture) { - //Can only subscribe to non-future pairs - return CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency) && quoteCurrency is "USDT" or "USD"; + return CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out _, out var quoteCurrency) && + (quoteCurrency is "USDT" || SupportedBybitProductCategories.Contains(BybitProductCategory.Inverse) && + quoteCurrency is "USD"); } return baseCanSubscribe; @@ -500,7 +501,7 @@ private class ModulesReadLicenseRead : QuantConnect.Api.RestResponse /// Checks whether the specified symbol is supported by this brokerage by its security type /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsSupported(Symbol symbol) + protected bool IsSupported(Symbol symbol) { return SuppotedSecurityTypes.Contains(symbol.SecurityType); } diff --git a/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs b/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs index ea6529e..c62bb68 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs @@ -30,11 +30,6 @@ namespace QuantConnect.Brokerages.Bybit /// public class BybitBrokerageFactory : BrokerageFactory { - /// - /// The default order book depth for this brokerage - /// - protected virtual int DefaultOrderBookDepth => 50; - /// /// Gets the brokerage data required to run the brokerage from configuration/disk /// @@ -100,12 +95,30 @@ public override IBrokerage CreateBrokerage(LiveNodePacket job, IAlgorithm algori var aggregator = Composer.Instance.GetExportedValueByTypeName( Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false); - var brokerage = new BybitBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); + var brokerage = CreateBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); Composer.Instance.AddPart(brokerage); return brokerage; } + /// + /// Creates a new BybitBrokerage instance + /// + /// The api key + /// The api secret + /// The rest api url + /// The web socket base url + /// The algorithm instance is required to retrieve account type + /// The aggregator for consolidating ticks + /// The live job packet + /// Bybit VIP level + /// New BybitBrokerage instance + protected virtual BybitBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, string wsUrl, + IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel) + { + return new BybitBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); + } + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs new file mode 100644 index 0000000..edfbcb7 --- /dev/null +++ b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs @@ -0,0 +1,81 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using QuantConnect.Brokerages; +using QuantConnect.BybitBrokerage.Models.Enums; +using QuantConnect.Data; +using QuantConnect.Interfaces; +using QuantConnect.Packets; +using QuantConnect.Securities; + +namespace QuantConnect.BybitBrokerage; + +/// +/// Bybit inverse futures brokerage implementation +/// +[BrokerageFactory(typeof(BybitInverseFuturesBrokerageFactory))] +public class BybitInverseFuturesBrokerage : BybitBrokerage +{ + protected override SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.Crypto, SecurityType.CryptoFuture }; + protected override BybitProductCategory[] SupportedBybitProductCategories { get; } = { BybitProductCategory.Inverse }; + protected override BybitAccountType WalletAccountType => BybitAccountType.Contract; + + /// + /// Parameterless constructor for brokerage + /// + public BybitInverseFuturesBrokerage() + { + } + + /// + /// Constructor for brokerage + /// + /// api key + /// api secret + /// The rest api url + /// The web socket base url + /// the algorithm instance is required to retrieve account type + /// the aggregator for consolidating ticks + /// The live job packet + /// Bybit VIP level + public BybitInverseFuturesBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, + IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job, + BybitVIPLevel vipLevel = BybitVIPLevel.VIP0) + : base(apiKey, apiSecret, restApiUrl, webSocketBaseUrl, algorithm, algorithm?.Portfolio?.Transactions, + algorithm?.Portfolio, aggregator, job, vipLevel) + { + } + + /// + /// Constructor for brokerage + /// + /// The api key + /// The api secret + /// The rest api url + /// The web socket base url + /// The algorithm instance is required to retrieve account type + /// The order provider is required to retrieve orders + /// The security provider is required + /// The aggregator for consolidating ticks + /// The live job packet + /// Bybit VIP level + public BybitInverseFuturesBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, + IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, + IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel = BybitVIPLevel.VIP0) + : base(apiKey, apiSecret, restApiUrl, webSocketBaseUrl, algorithm, orderProvider, + securityProvider, aggregator, job, vipLevel) + { + } +} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs new file mode 100644 index 0000000..23df35d --- /dev/null +++ b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs @@ -0,0 +1,52 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using QuantConnect.BybitBrokerage.Models.Enums; +using QuantConnect.Data; +using QuantConnect.Interfaces; +using QuantConnect.Packets; + +namespace QuantConnect.BybitBrokerage; + +/// +/// Factory method to create Bybit inverse brokerage +/// +public class BybitInverseFuturesBrokerageFactory : BybitBrokerageFactory +{ + /// + /// Initializes a new instance of the class + /// + public BybitInverseFuturesBrokerageFactory(): base(typeof(BybitInverseFuturesBrokerage)) + { + } + + /// + /// Creates a new BybitBrokerage instance + /// + /// The api key + /// The api secret + /// The rest api url + /// The web socket base url + /// The algorithm instance is required to retrieve account type + /// The aggregator for consolidating ticks + /// The live job packet + /// Bybit VIP level + /// New BybitBrokerage instance + protected override BybitBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, string wsUrl, IAlgorithm algorithm, + IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel) + { + return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); + } +} \ No newline at end of file From 75da2ab03827f63c4201a44ea2fe7f209681fb80 Mon Sep 17 00:00:00 2001 From: Romazes Date: Wed, 4 Mar 2026 22:15:33 +0200 Subject: [PATCH 4/7] refactor: Bybit Inverse Futures to new namespace, cleanup - Move Bybit Inverse Futures brokerage and tests to QuantConnect.Brokerages.Bybit namespace for consistency. - Simplify GetWalletBalances to always use "UNIFIED" account type. - Remove unused SwitchPositionMode method from BybitPositionApiEndpoint. - Refactor MarketName and WalletAccountType handling in BybitBrokerage. - Restrict BybitInverseFuturesBrokerage to CryptoFuture/Inverse only. - Override GetBrokerageModel in BybitInverseFuturesBrokerageFactory. - Move PositionMode enum to new namespace. - Update test assertions and using directives. - Remove redundant and unused code for clarity. --- .../BybitBrokerageTests.cs | 2 +- ...tInverseFuturesBrokerageAdditionalTests.cs | 3 +-- ...rseFuturesBrokerageHistoryProviderTests.cs | 6 +++--- ...ybitInverseFuturesBrokerageTests.Stream.cs | 2 +- .../BybitInverseFuturesBrokerageTests.cs | 4 ++-- .../Api/BybitAccountApiEndpoint.cs | 14 +++---------- .../Api/BybitPositionApiEndpoint.cs | 20 ------------------- .../BybitBrokerage.Brokerage.cs | 2 +- QuantConnect.BybitBrokerage/BybitBrokerage.cs | 4 ++-- .../BybitInverseFuturesBrokerage.cs | 12 +++++------ .../BybitInverseFuturesBrokerageFactory.cs | 16 +++++++++++---- .../Models/Enums/PositionMode.cs | 2 +- 12 files changed, 32 insertions(+), 55 deletions(-) diff --git a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs index 943b17d..8e226c9 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs @@ -207,7 +207,7 @@ public override void GetAccountHoldings() var afterQuantity = afterHoldings == null ? 0 : afterHoldings.Amount; var fee = order.Quantity * TakerFee; - + Assert.AreEqual(GetDefaultQuantity(), afterQuantity - beforeQuantity + fee); } diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs index dda904c..b33448d 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs @@ -14,11 +14,10 @@ */ using NUnit.Framework; -using QuantConnect.Brokerages; using QuantConnect.Interfaces; using QuantConnect.Lean.Engine.DataFeeds; -namespace QuantConnect.BybitBrokerage.Tests +namespace QuantConnect.Brokerages.Bybit.Tests { [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] public class BybitInverseFuturesBrokerageAdditionalTests : BybitBrokerageAdditionalTests diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs index 31f8523..4ed646f 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs @@ -16,7 +16,7 @@ using System; using NUnit.Framework; -namespace QuantConnect.BybitBrokerage.Tests +namespace QuantConnect.Brokerages.Bybit.Tests { [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] public class BybitInverseFuturesBrokerageHistoryProviderTests : BybitBrokerageHistoryProviderTests @@ -46,9 +46,9 @@ public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan } [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] - public override void GetEmptyHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) + public override void ReturnsNullOnInvalidHistoryRequest(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { - base.GetEmptyHistory(symbol, resolution, period, tickType); + base.ReturnsNullOnInvalidHistoryRequest(symbol, resolution, period, tickType); } } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs index 0bdf798..3c745aa 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.Stream.cs @@ -15,7 +15,7 @@ using NUnit.Framework; -namespace QuantConnect.BybitBrokerage.Tests +namespace QuantConnect.Brokerages.Bybit.Tests { [TestFixture] public partial class BybitInverseFuturesBrokerageTests diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs index bd8f515..c2ea321 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs @@ -17,7 +17,7 @@ using System.Linq; using System.Threading; using NUnit.Framework; -using QuantConnect.BybitBrokerage.Models.Enums; +using QuantConnect.Brokerages.Bybit.Models.Enums; using QuantConnect.Data; using QuantConnect.Interfaces; using QuantConnect.Lean.Engine.DataFeeds; @@ -27,7 +27,7 @@ using QuantConnect.Tests.Brokerages; using QuantConnect.Util; -namespace QuantConnect.BybitBrokerage.Tests; +namespace QuantConnect.Brokerages.Bybit.Tests; [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] public partial class BybitInverseFuturesBrokerageTests : BybitBrokerageTests diff --git a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs index 2ce927e..24f168f 100644 --- a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs +++ b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs @@ -13,7 +13,6 @@ * limitations under the License. */ -using System; using System.Collections.Generic; using QuantConnect.Brokerages.Bybit.Models; using QuantConnect.Securities; @@ -41,19 +40,12 @@ public BybitAccountApiEndpoint(ISymbolMapper symbolMapper, string apiPrefix, ISe /// /// Obtain wallet balance, query asset information of each currency, and account risk rate information /// - /// The account type to fetch wallet balances for /// The wallet balances - public BybitBalance GetWalletBalances(BybitAccountType accountType) - { - if (accountType is not (BybitAccountType.Contract or BybitAccountType.Unified)) - { - throw new ArgumentOutOfRangeException(nameof(accountType), - "Wallet balances can only be fetched for 'UNIFIED' and 'CONTRACT'"); - } - + public BybitBalance GetWalletBalances() + { var parameters = new KeyValuePair[] { - new("accountType", accountType.ToStringInvariant().ToUpperInvariant()) + new("accountType", "UNIFIED") }; var result = diff --git a/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs b/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs index ba9eae5..2e43e6c 100644 --- a/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs +++ b/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs @@ -57,24 +57,4 @@ public IEnumerable GetPositions(BybitProductCategory category return FetchAll("/position/list", category, 200, parameters, true); } - - /// - /// It supports to switch the position mode for USDT perpetual and Inverse futures. - /// If you are in one-way Mode, you can only open one position on Buy or Sell side. If you are in hedge mode, you can open both Buy and Sell side positions simultaneously. - /// - /// The product category - /// The symbol for which the mode should be changed - /// The mode which should be set - public void SwitchPositionMode(BybitProductCategory category, Symbol symbol, PositionMode mode) - { - var ticker = SymbolMapper.GetBrokerageSymbol(symbol); - var requestBody = new - { - category, - mode = (int)mode, - symbol = ticker - }; - - ExecutePostRequest("/position/switch-mode", requestBody); - } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs index 0fd6d18..df57756 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs @@ -122,7 +122,7 @@ public override List GetAccountHoldings() public override List GetCashBalance() { return ApiClient.Account - .GetWalletBalances(WalletAccountType).Assets + .GetWalletBalances().Assets .Select(x => new CashAmount(x.WalletBalance, x.Asset)).ToList(); } diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.cs index 5677863..01af39d 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs @@ -47,6 +47,8 @@ namespace QuantConnect.Brokerages.Bybit; [BrokerageFactory(typeof(BybitBrokerageFactory))] public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler { + private static readonly string MarketName = Market.Bybit; + private readonly Dictionary _subscriptionManagers = new(); private IAlgorithm _algorithm; @@ -62,8 +64,6 @@ public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler private bool _unsupportedResolutionOpenInterestHistoryLogged; private bool _invalidTimeRangeHistoryLogged; - protected virtual string MarketName => Market.Bybit; - protected virtual BybitAccountType WalletAccountType => BybitAccountType.Unified; protected virtual SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.Crypto, SecurityType.CryptoFuture }; protected virtual BybitProductCategory[] SupportedBybitProductCategories { get; } = { BybitProductCategory.Spot, BybitProductCategory.Linear }; diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs index edfbcb7..5d7c796 100644 --- a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs @@ -13,14 +13,13 @@ * limitations under the License. */ -using QuantConnect.Brokerages; -using QuantConnect.BybitBrokerage.Models.Enums; using QuantConnect.Data; -using QuantConnect.Interfaces; using QuantConnect.Packets; using QuantConnect.Securities; +using QuantConnect.Interfaces; +using QuantConnect.Brokerages.Bybit.Models.Enums; -namespace QuantConnect.BybitBrokerage; +namespace QuantConnect.Brokerages.Bybit; /// /// Bybit inverse futures brokerage implementation @@ -28,9 +27,8 @@ namespace QuantConnect.BybitBrokerage; [BrokerageFactory(typeof(BybitInverseFuturesBrokerageFactory))] public class BybitInverseFuturesBrokerage : BybitBrokerage { - protected override SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.Crypto, SecurityType.CryptoFuture }; + protected override SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.CryptoFuture }; protected override BybitProductCategory[] SupportedBybitProductCategories { get; } = { BybitProductCategory.Inverse }; - protected override BybitAccountType WalletAccountType => BybitAccountType.Contract; /// /// Parameterless constructor for brokerage @@ -38,7 +36,7 @@ public class BybitInverseFuturesBrokerage : BybitBrokerage public BybitInverseFuturesBrokerage() { } - + /// /// Constructor for brokerage /// diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs index 23df35d..102b758 100644 --- a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs +++ b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs @@ -13,12 +13,13 @@ * limitations under the License. */ -using QuantConnect.BybitBrokerage.Models.Enums; using QuantConnect.Data; -using QuantConnect.Interfaces; using QuantConnect.Packets; +using QuantConnect.Securities; +using QuantConnect.Interfaces; +using QuantConnect.Brokerages.Bybit.Models.Enums; -namespace QuantConnect.BybitBrokerage; +namespace QuantConnect.Brokerages.Bybit; /// /// Factory method to create Bybit inverse brokerage @@ -28,10 +29,17 @@ public class BybitInverseFuturesBrokerageFactory : BybitBrokerageFactory /// /// Initializes a new instance of the class /// - public BybitInverseFuturesBrokerageFactory(): base(typeof(BybitInverseFuturesBrokerage)) + public BybitInverseFuturesBrokerageFactory() : base(typeof(BybitInverseFuturesBrokerage)) { } + /// + /// Gets a brokerage model that can be used to model this brokerage's unique behaviors + /// + /// The order provider + public override IBrokerageModel GetBrokerageModel(IOrderProvider orderProvider) => + new BybitInverseFuturesBrokerageModel(AccountType.Margin); + /// /// Creates a new BybitBrokerage instance /// diff --git a/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs index 4cacb3d..cb88dd6 100644 --- a/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs +++ b/QuantConnect.BybitBrokerage/Models/Enums/PositionMode.cs @@ -13,7 +13,7 @@ * limitations under the License. */ -namespace QuantConnect.BybitBrokerage.Models.Enums; +namespace QuantConnect.Brokerages.Bybit.Models.Enums; /// /// Bybit position mode From 1f3360a76f2d84b1ea7b17b6d93c73064761e971 Mon Sep 17 00:00:00 2001 From: Romazes Date: Thu, 5 Mar 2026 00:07:04 +0200 Subject: [PATCH 5/7] feat: minor formatting update test:fix: correct ETHUSD symbol --- .../BybitInverseFuturesBrokerageHistoryProviderTests.cs | 2 +- QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs index 4ed646f..4c810f8 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs @@ -21,7 +21,7 @@ namespace QuantConnect.Brokerages.Bybit.Tests [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] public class BybitInverseFuturesBrokerageHistoryProviderTests : BybitBrokerageHistoryProviderTests { - private static readonly Symbol ETHUSD = Symbol.Create("ETHUSDT", SecurityType.CryptoFuture, Market.Bybit); + private static readonly Symbol ETHUSD = Symbol.Create("ETHUSD", SecurityType.CryptoFuture, Market.Bybit); private static TestCaseData[] ValidHistory { diff --git a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs index 24f168f..c022d32 100644 --- a/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs +++ b/QuantConnect.BybitBrokerage/Api/BybitAccountApiEndpoint.cs @@ -42,7 +42,7 @@ public BybitAccountApiEndpoint(ISymbolMapper symbolMapper, string apiPrefix, ISe /// /// The wallet balances public BybitBalance GetWalletBalances() - { + { var parameters = new KeyValuePair[] { new("accountType", "UNIFIED") From 3065d5771f3a44824126ce122e656f8cd1c363a7 Mon Sep 17 00:00:00 2001 From: Romazes Date: Thu, 5 Mar 2026 19:40:21 +0200 Subject: [PATCH 6/7] refactor: consolidate Bybit brokerages into single BybitBrokerage class Removed BybitInverseFuturesBrokerage and its factory, merging all Bybit product support into the main BybitBrokerage class. Updated supported product categories and security types to include inverse futures. Refactored tests and removed redundant test fixtures. Simplifies codebase and centralizes Bybit brokerage logic. fix: add [TestCase] with defaults to ReturnsNullOnInvalidHistoryRequest refactor: bybitBrokerage instantiation and IsSupported method Changed IsSupported to private static in BybitBrokerage. Removed the CreateBrokerage method from BybitBrokerageFactory and replaced its usage with direct instantiation, simplifying the factory logic. revert: bybit factory --- ...tInverseFuturesBrokerageAdditionalTests.cs | 35 -------- ...rseFuturesBrokerageHistoryProviderTests.cs | 5 +- .../BybitInverseFuturesBrokerageTests.cs | 2 +- QuantConnect.BybitBrokerage/BybitBrokerage.cs | 10 +-- .../BybitBrokerageFactory.cs | 25 ++---- .../BybitInverseFuturesBrokerage.cs | 79 ------------------- .../BybitInverseFuturesBrokerageFactory.cs | 60 -------------- 7 files changed, 15 insertions(+), 201 deletions(-) delete mode 100644 QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs delete mode 100644 QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs delete mode 100644 QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs deleted file mode 100644 index b33448d..0000000 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageAdditionalTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. - * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -using NUnit.Framework; -using QuantConnect.Interfaces; -using QuantConnect.Lean.Engine.DataFeeds; - -namespace QuantConnect.Brokerages.Bybit.Tests -{ - [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] - public class BybitInverseFuturesBrokerageAdditionalTests : BybitBrokerageAdditionalTests - { - protected override string BrokerageName => nameof(BybitInverseFuturesBrokerage); - - - protected override Brokerage CreateBrokerage(IAlgorithm algorithm, string apiKey, string apiSecret, - string apiUrl, string websocketUrl) - { - return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, new AggregationManager(), - null); - } - } -} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs index 4c810f8..ae51f28 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs @@ -46,9 +46,10 @@ public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan } [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] - public override void ReturnsNullOnInvalidHistoryRequest(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) + [TestCase(default, default, default, default)] + public override void ReturnsNullOnInvalidHistoryRequest( + Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { - base.ReturnsNullOnInvalidHistoryRequest(symbol, resolution, period, tickType); } } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs index c2ea321..7ac78dd 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageTests.cs @@ -45,7 +45,7 @@ protected override IBrokerage CreateBrokerage(string apiKey, string apiSecret, s string websocketUrl, IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator) { - return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, orderProvider, securityProvider, new AggregationManager(), null); + return new BybitBrokerage(apiKey, apiSecret, apiUrl, websocketUrl, algorithm, orderProvider, securityProvider, new AggregationManager(), null); } diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.cs index 01af39d..d65bf90 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs @@ -47,6 +47,10 @@ namespace QuantConnect.Brokerages.Bybit; [BrokerageFactory(typeof(BybitBrokerageFactory))] public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler { + private static readonly List SupportedBybitProductCategories = new() { BybitProductCategory.Spot, BybitProductCategory.Linear, BybitProductCategory.Inverse }; + + private static readonly List SuppotedSecurityTypes = new() { SecurityType.Crypto, SecurityType.CryptoFuture }; + private static readonly string MarketName = Market.Bybit; private readonly Dictionary _subscriptionManagers = new(); @@ -64,10 +68,6 @@ public partial class BybitBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler private bool _unsupportedResolutionOpenInterestHistoryLogged; private bool _invalidTimeRangeHistoryLogged; - protected virtual SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.Crypto, SecurityType.CryptoFuture }; - protected virtual BybitProductCategory[] SupportedBybitProductCategories { get; } = - { BybitProductCategory.Spot, BybitProductCategory.Linear }; - /// /// Order provider /// @@ -501,7 +501,7 @@ private class ModulesReadLicenseRead : QuantConnect.Api.RestResponse /// Checks whether the specified symbol is supported by this brokerage by its security type /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool IsSupported(Symbol symbol) + private static bool IsSupported(Symbol symbol) { return SuppotedSecurityTypes.Contains(symbol.SecurityType); } diff --git a/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs b/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs index c62bb68..ea6529e 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerageFactory.cs @@ -30,6 +30,11 @@ namespace QuantConnect.Brokerages.Bybit /// public class BybitBrokerageFactory : BrokerageFactory { + /// + /// The default order book depth for this brokerage + /// + protected virtual int DefaultOrderBookDepth => 50; + /// /// Gets the brokerage data required to run the brokerage from configuration/disk /// @@ -95,30 +100,12 @@ public override IBrokerage CreateBrokerage(LiveNodePacket job, IAlgorithm algori var aggregator = Composer.Instance.GetExportedValueByTypeName( Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false); - var brokerage = CreateBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); + var brokerage = new BybitBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); Composer.Instance.AddPart(brokerage); return brokerage; } - /// - /// Creates a new BybitBrokerage instance - /// - /// The api key - /// The api secret - /// The rest api url - /// The web socket base url - /// The algorithm instance is required to retrieve account type - /// The aggregator for consolidating ticks - /// The live job packet - /// Bybit VIP level - /// New BybitBrokerage instance - protected virtual BybitBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, string wsUrl, - IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel) - { - return new BybitBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); - } - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs deleted file mode 100644 index 5d7c796..0000000 --- a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerage.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. - * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -using QuantConnect.Data; -using QuantConnect.Packets; -using QuantConnect.Securities; -using QuantConnect.Interfaces; -using QuantConnect.Brokerages.Bybit.Models.Enums; - -namespace QuantConnect.Brokerages.Bybit; - -/// -/// Bybit inverse futures brokerage implementation -/// -[BrokerageFactory(typeof(BybitInverseFuturesBrokerageFactory))] -public class BybitInverseFuturesBrokerage : BybitBrokerage -{ - protected override SecurityType[] SuppotedSecurityTypes { get; } = { SecurityType.CryptoFuture }; - protected override BybitProductCategory[] SupportedBybitProductCategories { get; } = { BybitProductCategory.Inverse }; - - /// - /// Parameterless constructor for brokerage - /// - public BybitInverseFuturesBrokerage() - { - } - - /// - /// Constructor for brokerage - /// - /// api key - /// api secret - /// The rest api url - /// The web socket base url - /// the algorithm instance is required to retrieve account type - /// the aggregator for consolidating ticks - /// The live job packet - /// Bybit VIP level - public BybitInverseFuturesBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, - IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job, - BybitVIPLevel vipLevel = BybitVIPLevel.VIP0) - : base(apiKey, apiSecret, restApiUrl, webSocketBaseUrl, algorithm, algorithm?.Portfolio?.Transactions, - algorithm?.Portfolio, aggregator, job, vipLevel) - { - } - - /// - /// Constructor for brokerage - /// - /// The api key - /// The api secret - /// The rest api url - /// The web socket base url - /// The algorithm instance is required to retrieve account type - /// The order provider is required to retrieve orders - /// The security provider is required - /// The aggregator for consolidating ticks - /// The live job packet - /// Bybit VIP level - public BybitInverseFuturesBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, - IAlgorithm algorithm, IOrderProvider orderProvider, ISecurityProvider securityProvider, - IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel = BybitVIPLevel.VIP0) - : base(apiKey, apiSecret, restApiUrl, webSocketBaseUrl, algorithm, orderProvider, - securityProvider, aggregator, job, vipLevel) - { - } -} \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs b/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs deleted file mode 100644 index 102b758..0000000 --- a/QuantConnect.BybitBrokerage/BybitInverseFuturesBrokerageFactory.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. - * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -using QuantConnect.Data; -using QuantConnect.Packets; -using QuantConnect.Securities; -using QuantConnect.Interfaces; -using QuantConnect.Brokerages.Bybit.Models.Enums; - -namespace QuantConnect.Brokerages.Bybit; - -/// -/// Factory method to create Bybit inverse brokerage -/// -public class BybitInverseFuturesBrokerageFactory : BybitBrokerageFactory -{ - /// - /// Initializes a new instance of the class - /// - public BybitInverseFuturesBrokerageFactory() : base(typeof(BybitInverseFuturesBrokerage)) - { - } - - /// - /// Gets a brokerage model that can be used to model this brokerage's unique behaviors - /// - /// The order provider - public override IBrokerageModel GetBrokerageModel(IOrderProvider orderProvider) => - new BybitInverseFuturesBrokerageModel(AccountType.Margin); - - /// - /// Creates a new BybitBrokerage instance - /// - /// The api key - /// The api secret - /// The rest api url - /// The web socket base url - /// The algorithm instance is required to retrieve account type - /// The aggregator for consolidating ticks - /// The live job packet - /// Bybit VIP level - /// New BybitBrokerage instance - protected override BybitBrokerage CreateBrokerage(string apiKey, string apiSecret, string apiUrl, string wsUrl, IAlgorithm algorithm, - IDataAggregator aggregator, LiveNodePacket job, BybitVIPLevel vipLevel) - { - return new BybitInverseFuturesBrokerage(apiKey, apiSecret, apiUrl, wsUrl, algorithm, aggregator, job, vipLevel); - } -} \ No newline at end of file From ea4a1fd3fbddcba6ba9515760bae058bcb1e228e Mon Sep 17 00:00:00 2001 From: Romazes Date: Fri, 6 Mar 2026 20:48:25 +0200 Subject: [PATCH 7/7] refactor: Bybit category selection by brokerage name Replaced SupportedBybitProductCategories with GetWorkingProductCategories to select product categories based on brokerage name. Updated GetOpenOrders, GetAccountHoldings, and GetCashBalance to use this logic. GetCashBalance now returns a single USD balance for Inverse category. Added GetWorkingProductCategories method. --- .../BybitBrokerage.Brokerage.cs | 14 +++++++++----- QuantConnect.BybitBrokerage/BybitBrokerage.cs | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs index df57756..96e1383 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.Brokerage.cs @@ -43,7 +43,7 @@ public partial class BybitBrokerage public override List GetOpenOrders() { var orders = new List(); - foreach (var category in SupportedBybitProductCategories) + foreach (var category in GetWorkingProductCategories(_algorithm.BrokerageName)) { orders.AddRange(ApiClient.Trade.GetOpenOrders(category) .Select(bybitOrder => @@ -98,7 +98,7 @@ public override List GetOpenOrders() public override List GetAccountHoldings() { var holdings = new List(); - foreach (var category in SupportedBybitProductCategories) + foreach (var category in GetWorkingProductCategories(_algorithm.BrokerageName)) { holdings.AddRange(ApiClient.Position.GetPositions(category) .Select(bybitPosition => new Holding @@ -121,9 +121,13 @@ public override List GetAccountHoldings() /// The current cash balance for each currency available for trading public override List GetCashBalance() { - return ApiClient.Account - .GetWalletBalances().Assets - .Select(x => new CashAmount(x.WalletBalance, x.Asset)).ToList(); + var balances = ApiClient.Account.GetWalletBalances(); + if (GetWorkingProductCategories(_algorithm.BrokerageName).Contains(BybitProductCategory.Inverse)) + { + return [new CashAmount(balances.TotalAvailableBalance ?? 0, "USD")]; + } + + return balances.Assets.Select(x => new CashAmount(x.WalletBalance, x.Asset)).ToList(); } /// diff --git a/QuantConnect.BybitBrokerage/BybitBrokerage.cs b/QuantConnect.BybitBrokerage/BybitBrokerage.cs index d65bf90..b042af1 100644 --- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs +++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs @@ -545,6 +545,16 @@ private static BybitProductCategory GetBybitProductCategory(Symbol symbol) } } + private IEnumerable GetWorkingProductCategories(BrokerageName brokerageName) + { + if (brokerageName == BrokerageName.BybitInverseFutures) + { + return [BybitProductCategory.Inverse]; + } + + return [BybitProductCategory.Spot, BybitProductCategory.Linear]; + } + /// /// Validate the user of this project has permission to be using it via our web API. ///