diff --git a/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs
new file mode 100644
index 0000000..0bbe66c
--- /dev/null
+++ b/QuantConnect.BybitBrokerage.Tests/BybitInverseFuturesBrokerageHistoryProviderTests.cs
@@ -0,0 +1,58 @@
+/*
+ * 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, false),
+ new TestCaseData(ETHUSD, Resolution.Minute, Time.OneHour, TickType.Trade, false),
+ new TestCaseData(ETHUSD, Resolution.Hour, Time.OneDay, TickType.Trade, false),
+ new TestCaseData(ETHUSD, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade, false),
+ new TestCaseData(ETHUSD, Resolution.Hour, Time.OneDay, TickType.OpenInterest, false)
+ };
+ }
+ }
+
+
+ [Test, TestCaseSource(nameof(ValidHistory))]
+ public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType,
+ bool throwsException)
+ {
+ base.GetsHistory(symbol, resolution, period, tickType, throwsException);
+ }
+
+ [Ignore("Same as base")]
+ public override void GetEmptyHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType,
+ bool throwsException)
+ {
+ base.GetEmptyHistory(symbol, resolution, period, tickType, throwsException);
+ }
+ }
+}
\ 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..6231156
--- /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("Base")]
+ 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 363d3f6..b75a823 100644
--- a/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs
+++ b/QuantConnect.BybitBrokerage/Api/BybitPositionApiEndpoint.cs
@@ -49,10 +49,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 e36dcff..87dd524 100644
--- a/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs
+++ b/QuantConnect.BybitBrokerage/BybitBrokerage.Messaging.cs
@@ -147,7 +147,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")
};
@@ -178,7 +178,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 2dacbb1..a9d401c 100644
--- a/QuantConnect.BybitBrokerage/BybitBrokerage.cs
+++ b/QuantConnect.BybitBrokerage/BybitBrokerage.cs
@@ -48,7 +48,7 @@ namespace QuantConnect.BybitBrokerage;
[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 };
@@ -307,8 +307,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;
@@ -483,13 +483,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 c8d0584..b26d1fb 100644
--- a/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs
+++ b/QuantConnect.BybitBrokerage/Models/ByBitResponse.cs
@@ -22,8 +22,7 @@ namespace QuantConnect.BybitBrokerage.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