From 2ec489287fafe43517c5e7cc3b46372ac383f4e6 Mon Sep 17 00:00:00 2001 From: Sebastian Karasek Date: Mon, 6 Nov 2023 14:11:35 +0100 Subject: [PATCH] Fix tests and small refactoring to avoid duplicate code (#5) * Fix and cleanup tests * Address review --- .../BybitBrokerageHistoryProviderTests.cs | 159 ++++++++--------- .../BybitBrokerageTests.Stream.cs | 2 +- .../BybitBrokerageTests.cs | 13 +- ...bitFuturesBrokerageHistoryProviderTests.cs | 161 ++---------------- .../BybitFuturesBrokerageTests.Stream.cs | 43 +---- .../BybitFuturesBrokerageTests.cs | 88 +++------- 6 files changed, 121 insertions(+), 345 deletions(-) diff --git a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageHistoryProviderTests.cs index b110fc2..4a2bb95 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageHistoryProviderTests.cs @@ -54,10 +54,10 @@ private static TestCaseData[] ValidHistory return new[] { // valid - new TestCaseData(ETHUSDT, Resolution.Tick, Time.OneMinute, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Minute, Time.OneHour, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade, false), + new TestCaseData(ETHUSDT, Resolution.Tick, Time.OneMinute, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Minute, Time.OneHour, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade), }; } } @@ -98,10 +98,9 @@ private static TestCaseData[] InvalidHistory [Test] [TestCaseSource(nameof(ValidHistory))] - public virtual void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType, - bool throwsException) + public virtual void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { - BaseHistoryTest(_brokerage, symbol, resolution, period, tickType, throwsException, false); + BaseHistoryTest(_brokerage, symbol, resolution, period, tickType, false); } [Test] @@ -109,111 +108,103 @@ public virtual void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan p [TestCaseSource(nameof(InvalidHistory))] public virtual void GetEmptyHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { - BaseHistoryTest(_brokerage, symbol, resolution, period, tickType, false, true); + BaseHistoryTest(_brokerage, symbol, resolution, period, tickType, true); } protected static void BaseHistoryTest(Brokerage brokerage, Symbol symbol, Resolution resolution, - TimeSpan period, TickType tickType, bool throwsException, bool emptyData) + TimeSpan period, TickType tickType, bool emptyData) { - TestDelegate test = () => - { - var historyProvider = new BrokerageHistoryProvider(); - historyProvider.SetBrokerage(brokerage); - historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, - null, null, null, null, - false, new DataPermissionManager(), null)); + var historyProvider = new BrokerageHistoryProvider(); + historyProvider.SetBrokerage(brokerage); + historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, + null, null, null, null, + false, new DataPermissionManager(), null)); - var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); + var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); - var now = DateTime.UtcNow.AddDays(-1); - var requests = new[] - { - new HistoryRequest(now.Add(-period), - now, - resolution == Resolution.Tick ? typeof(Tick) : typeof(TradeBar), - symbol, - resolution, - marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType), - marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType), - resolution, - false, - false, - DataNormalizationMode.Adjusted, - tickType) - }; + var now = DateTime.UtcNow.AddDays(-1); + var requests = new[] + { + new HistoryRequest(now.Add(-period), + now, + resolution == Resolution.Tick ? typeof(Tick) : typeof(TradeBar), + symbol, + resolution, + marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType), + marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType), + resolution, + false, + false, + DataNormalizationMode.Adjusted, + tickType) + }; - var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc).ToArray(); - foreach (var slice in historyArray) + var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc).ToArray(); + foreach (var slice in historyArray) + { + if (resolution == Resolution.Tick) { - if (resolution == Resolution.Tick) - { - foreach (var tick in slice.Ticks[symbol]) - { - Log.Trace("{0}: {1} - {2} / {3}", tick.Time.ToStringInvariant("yyyy-MM-dd HH:mm:ss.fff"), - tick.Symbol, tick.BidPrice, tick.AskPrice); - } - } - else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar)) + foreach (var tick in slice.Ticks[symbol]) { - Log.Trace($"QuoteBar: {quoteBar}"); - } - else if (slice.Bars.TryGetValue(symbol, out var bar)) - { - Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}", bar.Time, bar.Symbol, bar.Open, bar.High, - bar.Low, bar.Close); + Log.Trace("{0}: {1} - {2} / {3}", tick.Time.ToStringInvariant("yyyy-MM-dd HH:mm:ss.fff"), + tick.Symbol, tick.BidPrice, tick.AskPrice); } } - - if (emptyData) + else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar)) { - Assert.Zero(historyProvider.DataPointCount); + Log.Trace($"QuoteBar: {quoteBar}"); } - else + else if (slice.Bars.TryGetValue(symbol, out var bar)) { - Assert.Greater(historyProvider.DataPointCount, 0); + Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}", bar.Time, bar.Symbol, bar.Open, bar.High, + bar.Low, bar.Close); } + } - if (historyProvider.DataPointCount > 0) - { - // Ordered by time - Assert.That(historyArray, Is.Ordered.By("Time")); + if (emptyData) + { + Assert.Zero(historyProvider.DataPointCount); + } + else + { + Assert.Greater(historyProvider.DataPointCount, 0); + } - // No repeating bars - var timesArray = historyArray.Select(x => x.Time).ToArray(); - Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count()); + if (historyProvider.DataPointCount > 0) + { + // Ordered by time + Assert.That(historyArray, Is.Ordered.By("Time")); - foreach (var slice in historyArray) + // No repeating bars + var timesArray = historyArray.Select(x => x.Time).ToArray(); + Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count()); + + foreach (var slice in historyArray) + { + var data = slice.AllData[0]; + Assert.AreEqual(symbol, data.Symbol); + + if (data.DataType != MarketDataType.Tick) { - var data = slice.AllData[0]; - Assert.AreEqual(symbol, data.Symbol); Assert.AreEqual(resolution.ToTimeSpan(), data.EndTime - data.Time); } + } - // No missing bars - if (resolution != Resolution.Tick && historyProvider.DataPointCount >= 2) + // No missing bars + if (resolution != Resolution.Tick && historyProvider.DataPointCount >= 2) + { + var diff = resolution.ToTimeSpan(); + for (var i = 1; i < timesArray.Length; i++) { - var diff = resolution.ToTimeSpan(); - for (var i = 1; i < timesArray.Length; i++) - { - Assert.AreEqual(diff, timesArray[i] - timesArray[i - 1]); - } + Assert.AreEqual(diff, timesArray[i] - timesArray[i - 1]); } } - - Log.Trace("Data points retrieved: " + historyProvider.DataPointCount); - }; - - if (throwsException) - { - Assert.Throws(test); - } - else - { - Assert.DoesNotThrow(test); } + + Log.Trace("Data points retrieved: " + historyProvider.DataPointCount); } - protected virtual Brokerage CreateBrokerage() + private Brokerage CreateBrokerage() { var apiKey = Config.Get("bybit-api-key"); var apiSecret = Config.Get("bybit-api-secret"); diff --git a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.Stream.cs b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.Stream.cs index a055dad..7a7c2dc 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.Stream.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.Stream.cs @@ -41,7 +41,7 @@ private static TestCaseData[] TestParameters } [Test, TestCaseSource(nameof(TestParameters))] - public void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) + public virtual void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) { StreamsData(symbol, resolution, throwsException, Brokerage); } diff --git a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs index 16188f5..343fe89 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitBrokerageTests.cs @@ -36,11 +36,13 @@ namespace QuantConnect.BybitBrokerage.Tests [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] public partial class BybitBrokerageTests : BrokerageTests { - protected static Symbol BTCUSDT = Symbol.Create("BTCUSDT", SecurityType.Crypto, "bybit"); + private static Symbol BTCUSDT = Symbol.Create("BTCUSDT", SecurityType.Crypto, "bybit"); private BybitApi _client; protected override Symbol Symbol { get; } = BTCUSDT; protected override SecurityType SecurityType => SecurityType.Crypto; + protected virtual BybitProductCategory Category => BybitProductCategory.Spot; + protected override decimal GetDefaultQuantity() => 0.0005m; protected override bool IsAsync() => false; @@ -49,7 +51,10 @@ public partial class BybitBrokerageTests : BrokerageTests protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) { + var model = new BybitBrokerageModel(AccountType.Margin); + var algorithm = new Mock(); + algorithm.SetupGet(x => x.BrokerageModel).Returns(model); var apiKey = Config.Get("bybit-api-key"); var apiSecret = Config.Get("bybit-api-secret"); @@ -61,6 +66,8 @@ protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISec securityProvider, new AggregationManager(), null); } + protected virtual decimal TakerFee => BybitFeeModel.TakerNonVIPFee; + protected virtual BybitApi CreateRestApiClient(string apiKey, string apiSecret, string apiUrl) { return new BybitApi(SymbolMapper, null, apiKey, apiSecret, apiUrl); @@ -69,7 +76,7 @@ protected virtual BybitApi CreateRestApiClient(string apiKey, string apiSecret, protected override decimal GetAskPrice(Symbol symbol) { var brokerageSymbol = SymbolMapper.GetBrokerageSymbol(symbol); - return _client.Market.GetTicker(BybitProductCategory.Spot, brokerageSymbol).Ask1Price!.Value; + return _client.Market.GetTicker(Category, brokerageSymbol).Ask1Price!.Value; } /// @@ -190,7 +197,7 @@ public override void GetAccountHoldings() var beforeQuantity = beforeHoldings == null ? 0 : beforeHoldings.Amount; var afterQuantity = afterHoldings == null ? 0 : afterHoldings.Amount; - var fee = order.Quantity * BybitFeeModel.TakerNonVIPFee; + var fee = order.Quantity * TakerFee; Assert.AreEqual(GetDefaultQuantity(), afterQuantity - beforeQuantity + fee); } diff --git a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageHistoryProviderTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageHistoryProviderTests.cs index 3a0ae6b..e8de3fd 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageHistoryProviderTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageHistoryProviderTests.cs @@ -14,38 +14,15 @@ */ using System; -using System.Linq; using NUnit.Framework; -using QuantConnect.Brokerages; -using QuantConnect.Configuration; -using QuantConnect.Data; -using QuantConnect.Tests; -using QuantConnect.Logging; -using QuantConnect.Securities; -using QuantConnect.Data.Market; -using QuantConnect.Lean.Engine.DataFeeds; -using QuantConnect.Lean.Engine.HistoricalData; namespace QuantConnect.BybitBrokerage.Tests { [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] - public class BybitFuturesBrokerageHistoryProviderTests + public class BybitFuturesBrokerageHistoryProviderTests : BybitBrokerageHistoryProviderTests { private static readonly Symbol ETHUSDT = Symbol.Create("ETHUSDT", SecurityType.CryptoFuture, Market.Bybit); - private Brokerage _brokerage; - [OneTimeSetUp] - public void Setup() - { - _brokerage = CreateBrokerage(); - } - - [OneTimeTearDown] - public void TearDown() - { - _brokerage?.Disconnect(); - _brokerage?.Dispose(); - } private static TestCaseData[] ValidHistory { @@ -54,142 +31,26 @@ private static TestCaseData[] ValidHistory return new[] { // valid - new TestCaseData(ETHUSDT, Resolution.Tick, Time.OneMinute, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Minute, Time.OneHour, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade, false), - new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.OpenInterest, false) - - - }; - } - } - - private static TestCaseData[] NoHistory - { - get - { - return new[] - { - new TestCaseData(ETHUSDT, Resolution.Tick, TimeSpan.FromSeconds(15), TickType.Trade), - new TestCaseData(ETHUSDT, Resolution.Second, Time.OneMinute, TickType.Trade), - new TestCaseData(ETHUSDT, Resolution.Minute, Time.OneHour, TickType.Quote), - }; - } - } - - private static TestCaseData[] InvalidHistory - { - get - { - return new[] - { - // invalid period, no error, empty result - new TestCaseData(Symbols.EURUSD, Resolution.Daily, TimeSpan.FromDays(-15), false), - - // invalid symbol, throws "System.ArgumentException : Unknown symbol: XYZ" - new TestCaseData(Symbol.Create("XYZ", SecurityType.CryptoFuture, Market.Bybit), Resolution.Daily, - TimeSpan.FromDays(15), true), - - // invalid security type, throws "System.ArgumentException : Invalid security type: Equity" - new TestCaseData(Symbols.AAPL, Resolution.Daily, TimeSpan.FromDays(15), false), + new TestCaseData(ETHUSDT, Resolution.Tick, Time.OneMinute, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Minute, Time.OneHour, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Daily, TimeSpan.FromDays(15), TickType.Trade), + new TestCaseData(ETHUSDT, Resolution.Hour, Time.OneDay, TickType.OpenInterest) }; } } [Test, TestCaseSource(nameof(ValidHistory))] - public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType, - bool throwsException) + public override void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType) { - TestDelegate test = () => - { - var historyProvider = new BrokerageHistoryProvider(); - historyProvider.SetBrokerage(_brokerage); - historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, - null, null, null, null, - false, new DataPermissionManager(), null)); - - var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); - - var now = DateTime.UtcNow.AddDays(-1); - var requests = new[] - { - new HistoryRequest(now.Add(-period), - now, - resolution == Resolution.Tick ? typeof(Tick) : typeof(TradeBar), - symbol, - resolution, - marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType), - marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType), - resolution, - false, - false, - DataNormalizationMode.Adjusted, - tickType) - }; - - var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc).ToArray(); - foreach (var slice in historyArray) - { - if (resolution == Resolution.Tick) - { - foreach (var tick in slice.Ticks[symbol]) - { - Log.Debug($"{tick}"); - } - } - else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar)) - { - Log.Debug($"{quoteBar}"); - } - else if (slice.Bars.TryGetValue(symbol, out var tradeBar)) - { - Log.Debug($"{tradeBar}"); - } - } - - Assert.Greater(historyProvider.DataPointCount, 0); - - if (historyProvider.DataPointCount > 0) - { - // Ordered by time - Assert.That(historyArray, Is.Ordered.By("Time")); - - // No repeating bars - var timesArray = historyArray.Select(x => x.Time).ToArray(); - Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count()); - } - - Log.Trace("Data points retrieved: " + historyProvider.DataPointCount); - }; - - if (throwsException) - { - Assert.Throws(test); - } - else - { - Assert.DoesNotThrow(test); - } + base.GetsHistory(symbol, resolution, period, tickType); } - protected virtual Brokerage CreateBrokerage() + [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) { - var apiKey = Config.Get("bybit-api-key"); - var apiSecret = Config.Get("bybit-api-secret"); - var apiUrl = Config.Get("bybit-api-url", "https://api-testnet.bybit.com"); - var websocketUrl = Config.Get("bybit-websocket-url", "wss://stream-testnet.bybit.com"); - - return new BybitBrokerage( - apiKey, - apiSecret, - apiUrl, - websocketUrl, - null, - new AggregationManager(), - null - ); + base.GetEmptyHistory(symbol, resolution, period, tickType); } } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.Stream.cs b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.Stream.cs index b818b3e..d48c349 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.Stream.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.Stream.cs @@ -14,10 +14,6 @@ */ using NUnit.Framework; -using System.Threading; -using QuantConnect.Data; -using QuantConnect.Logging; -using QuantConnect.Data.Market; namespace QuantConnect.BybitBrokerage.Tests { @@ -39,44 +35,9 @@ private static TestCaseData[] TestParameters } [Test, TestCaseSource(nameof(TestParameters))] - public void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) + public override void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) { - var cancellationToken = new CancellationTokenSource(); - var brokerage = (BybitBrokerage)Brokerage; - - SubscriptionDataConfig[] configs; - if (resolution == Resolution.Tick) - { - var tradeConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig(symbol, resolution), tickType: TickType.Trade); - var quoteConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig(symbol, resolution), tickType: TickType.Quote); - configs = new[] { tradeConfig, quoteConfig }; - } - else - { - configs = new[] { - GetSubscriptionDataConfig(symbol, resolution), - GetSubscriptionDataConfig(symbol, resolution) - }; - } - - foreach (var config in configs) - { - ProcessFeed(brokerage.Subscribe(config, (s, e) => { }), - cancellationToken, - (baseData) => { if (baseData != null) { Log.Trace($"{baseData}"); } - }); - } - - Thread.Sleep(20000); - - foreach (var config in configs) - { - brokerage.Unsubscribe(config); - } - - Thread.Sleep(20000); - - cancellationToken.Cancel(); + base.StreamsData(symbol, resolution, throwsException); } } } \ No newline at end of file diff --git a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.cs b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.cs index 7201a6a..160321d 100644 --- a/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.cs +++ b/QuantConnect.BybitBrokerage.Tests/BybitFuturesBrokerageTests.cs @@ -1,54 +1,34 @@ -using Moq; +/* + * 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.BybitBrokerage.Api; using QuantConnect.BybitBrokerage.Models.Enums; -using QuantConnect.Configuration; -using QuantConnect.Interfaces; -using QuantConnect.Lean.Engine.DataFeeds; -using QuantConnect.Securities; +using QuantConnect.Orders.Fees; using QuantConnect.Tests.Brokerages; namespace QuantConnect.BybitBrokerage.Tests; - [TestFixture, Explicit("Requires valid credentials to be setup and run outside USA")] -public partial class BybitFuturesBrokerageTests : BrokerageTests +public partial class BybitFuturesBrokerageTests : BybitBrokerageTests { - protected static Symbol BTCUSDT = Symbol.Create("BTCUSDT", SecurityType.CryptoFuture, "bybit"); - private BybitApi _client; + private static Symbol BTCUSDT = Symbol.Create("BTCUSDT", SecurityType.CryptoFuture, "bybit"); protected override Symbol Symbol { get; } = BTCUSDT; protected override SecurityType SecurityType => SecurityType.Future; - protected virtual ISymbolMapper SymbolMapper => new SymbolPropertiesDatabaseSymbolMapper(Market.Bybit); + protected override BybitProductCategory Category => BybitProductCategory.Linear; protected override decimal GetDefaultQuantity() => 0.001m; - protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) - { - var algorithm = new Mock(); - var apiKey = Config.Get("bybit-api-key"); - var apiSecret = Config.Get("bybit-api-secret"); - var apiUrl = Config.Get("bybit-api-url", "https://api-testnet.bybit.com"); - 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); - } - - protected virtual BybitApi CreateRestApiClient(string apiKey, string apiSecret, string apiUrl) - { - return new BybitApi(SymbolMapper, null, apiKey, apiSecret, apiUrl); - } - - - protected override bool IsAsync() => false; - - protected override decimal GetAskPrice(Symbol symbol) - { - var brokerageSymbol = SymbolMapper.GetBrokerageSymbol(symbol); - return _client.Market.GetTicker(BybitProductCategory.Linear, brokerageSymbol).Ask1Price!.Value; - } - /// /// Provides the data required to test each order type in various cases @@ -66,15 +46,6 @@ private static TestCaseData[] OrderParameters() }; } - private static Symbol[] InverseSymbols() - { - return new[] - { - QuantConnect.Symbol.Create("BTCUSD", SecurityType.CryptoFuture, Market.Bybit), - QuantConnect.Symbol.Create("BTCUSDZ23", SecurityType.CryptoFuture, Market.Bybit) - }; - } - [Test, TestCaseSource(nameof(OrderParameters))] public override void CancelOrders(OrderTestParameters parameters) { @@ -117,24 +88,9 @@ public override void LongFromShort(OrderTestParameters parameters) base.LongFromShort(parameters); } - [Test, TestCaseSource(nameof(InverseSymbols))] - public void InversePairNotSupported(Symbol symbol) + [Ignore("The brokerage is shared between different product categories, therefore this test is only required in the base class")] + public override void GetAccountHoldings() { - var parameter = new MarketOrderTestParameters(symbol); - var order = parameter.CreateLongOrder(GetDefaultQuantity()); - - BrokerageMessageEvent brokerageMessageEvent = null; - - void OnBrokerageOnMessage(object sender, BrokerageMessageEvent @event) - { - brokerageMessageEvent = @event; - Brokerage.Message -= OnBrokerageOnMessage; - } - - Brokerage.Message += OnBrokerageOnMessage; - - Assert.IsFalse(Brokerage.PlaceOrder(order)); - Assert.IsNotNull(brokerageMessageEvent); - Assert.AreEqual($"Symbol is not supported {order.Symbol}", brokerageMessageEvent.Message); + base.GetAccountHoldings(); } } \ No newline at end of file